agents-inc 0.165.0 → 0.166.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/CHANGELOG.md +15 -0
- package/dist/{chunk-B5UUHBAM.js → chunk-25MPBIK3.js} +3 -3
- package/dist/{chunk-VPJUCVU7.js → chunk-2VUYFTUB.js} +6 -6
- package/dist/{chunk-BGU25XAY.js → chunk-4NDBUJHK.js} +8 -8
- package/dist/{chunk-5M3PQNXI.js → chunk-6L75SQZU.js} +2 -2
- package/dist/{chunk-YNOOZFIB.js → chunk-6LF4CQBY.js} +2 -2
- package/dist/{chunk-UBSSIIWD.js → chunk-7JNJ52CD.js} +4 -4
- package/dist/{chunk-IM45LLQX.js → chunk-A4KDXNOT.js} +47 -137
- package/dist/chunk-A4KDXNOT.js.map +1 -0
- package/dist/{chunk-6SW6SB7H.js → chunk-DAIEQJIF.js} +3 -3
- package/dist/{chunk-AQXKAPCD.js → chunk-ENGYJCTF.js} +1 -3
- package/dist/{chunk-AQXKAPCD.js.map → chunk-ENGYJCTF.js.map} +1 -1
- package/dist/{chunk-6AIZPSEI.js → chunk-G4JK7WVO.js} +15 -16
- package/dist/chunk-G4JK7WVO.js.map +1 -0
- package/dist/{chunk-WTANOSXK.js → chunk-G6UREQ4V.js} +9 -9
- package/dist/chunk-G6UREQ4V.js.map +1 -0
- package/dist/{chunk-V5CWACR5.js → chunk-GE3WKJ6Q.js} +4 -4
- package/dist/{chunk-V5CWACR5.js.map → chunk-GE3WKJ6Q.js.map} +1 -1
- package/dist/{chunk-JV4TKXEN.js → chunk-HHIYT3PI.js} +4 -4
- package/dist/{chunk-WIFIAQZU.js → chunk-HWEKHVLE.js} +6 -6
- package/dist/{chunk-5P26XBZO.js → chunk-JQRJQ4SS.js} +3 -3
- package/dist/{chunk-Y5SNGMB7.js → chunk-LFWLEDUG.js} +6 -6
- package/dist/{chunk-TRTVOVHR.js → chunk-MAWNVT2C.js} +4 -4
- package/dist/{chunk-57KU6SPH.js → chunk-MPTNC32T.js} +3 -3
- package/dist/{chunk-MBUGQI2M.js → chunk-NBXXFIIW.js} +3 -3
- package/dist/{chunk-42TNV2TK.js → chunk-PMJWD27C.js} +3 -3
- package/dist/{chunk-X2KUI7V3.js → chunk-PNB3524H.js} +5 -5
- package/dist/{chunk-IVNKU4DM.js → chunk-PXWG7KFO.js} +2 -2
- package/dist/chunk-PXWG7KFO.js.map +1 -0
- package/dist/{chunk-LXXGZAD3.js → chunk-QHDPLLK6.js} +3 -3
- package/dist/{chunk-TV5Y53R2.js → chunk-RAHSOJQ2.js} +2 -2
- package/dist/{chunk-CTUJO23Z.js → chunk-RZDXDMT6.js} +2 -2
- package/dist/{chunk-PSX7CT6V.js → chunk-SAYZWCH6.js} +2 -2
- package/dist/{chunk-MWDY76MT.js → chunk-SCOQ34YM.js} +2 -2
- package/dist/{chunk-4C7GL4F7.js → chunk-SXVHSOTH.js} +4 -4
- package/dist/{chunk-E6CHHXGY.js → chunk-T6UWJAB3.js} +2 -2
- package/dist/{chunk-F2ZWFWTP.js → chunk-TODCQFRB.js} +2 -2
- package/dist/{chunk-CEBDGZID.js → chunk-TTY6DPJN.js} +3 -3
- package/dist/{chunk-CBMAO6OP.js → chunk-TZ2YJJKK.js} +5 -5
- package/dist/{chunk-WSGX4IWC.js → chunk-V3I7VQ7N.js} +4 -4
- package/dist/{chunk-GKPW33FP.js → chunk-V5WXIM2F.js} +2 -2
- package/dist/{chunk-6CY6PW5X.js → chunk-VAPTVR3J.js} +3 -3
- package/dist/{chunk-CK5RM3DJ.js → chunk-WVUDLKIO.js} +2 -2
- package/dist/{chunk-HR4YDSJK.js → chunk-WWIFNPJG.js} +12 -12
- package/dist/{chunk-P3KJCYSR.js → chunk-XZEVWPX6.js} +7 -7
- package/dist/{chunk-AAWZED5M.js → chunk-Y3VIRVVE.js} +10 -58
- package/dist/chunk-Y3VIRVVE.js.map +1 -0
- package/dist/{chunk-XATIKM3P.js → chunk-Y47EV74W.js} +7 -7
- package/dist/{chunk-UR3RRTPO.js → chunk-ZR4YPKXQ.js} +4 -4
- package/dist/{chunk-UCORXS4D.js → chunk-ZXKBERQU.js} +2 -2
- package/dist/commands/build/marketplace.js +6 -6
- package/dist/commands/build/plugins.js +8 -8
- package/dist/commands/compile.js +14 -15
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/doctor.js +59 -156
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +40 -41
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +12 -13
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/init.js +39 -39
- package/dist/commands/list.js +9 -9
- package/dist/commands/new/marketplace.js +6 -6
- package/dist/commands/search.js +11 -11
- package/dist/commands/share.js +11 -12
- package/dist/commands/share.js.map +1 -1
- package/dist/commands/uninstall.js +39 -69
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +8 -9
- package/dist/commands/update.js.map +1 -1
- package/dist/components/common/removal-plan-confirm.js +2 -2
- package/dist/components/common/select-list.js +2 -2
- package/dist/components/wizard/category-grid.js +4 -4
- package/dist/components/wizard/checkbox-grid.js +4 -4
- package/dist/components/wizard/domain-selection.js +9 -9
- package/dist/components/wizard/run-wizard-session.js +26 -26
- package/dist/components/wizard/scroll-affordance.js +2 -2
- package/dist/components/wizard/skill-agent-summary.js +5 -5
- package/dist/components/wizard/source-grid.js +5 -5
- package/dist/components/wizard/stack-selection.js +7 -7
- package/dist/components/wizard/step-agents.js +8 -8
- package/dist/components/wizard/step-build.js +7 -7
- package/dist/components/wizard/step-confirm.js +9 -9
- package/dist/components/wizard/step-sources.js +8 -8
- package/dist/components/wizard/step-stack.js +8 -8
- package/dist/components/wizard/summary-panel.js +8 -8
- package/dist/components/wizard/toast.js +2 -2
- package/dist/components/wizard/wizard-layout.js +12 -12
- package/dist/components/wizard/wizard-tabs.js +2 -2
- package/dist/components/wizard/wizard.js +25 -25
- package/dist/hooks/init.js +50 -40
- package/dist/hooks/init.js.map +1 -1
- package/dist/load-agent-defs-3C27ENC7.js +14 -0
- package/dist/recompile-project-agents-DGNBCU3N.js +18 -0
- package/dist/{source-loader-RWZAYJ7E.js → source-loader-7KZ3MD5O.js} +4 -4
- package/dist/stores/wizard-store.js +4 -4
- package/package.json +1 -1
- package/src/schemas/project-config.schema.json +1 -1
- package/src/schemas/project-source-config.schema.json +1 -1
- package/dist/chunk-6AIZPSEI.js.map +0 -1
- package/dist/chunk-AAWZED5M.js.map +0 -1
- package/dist/chunk-IM45LLQX.js.map +0 -1
- package/dist/chunk-IVNKU4DM.js.map +0 -1
- package/dist/chunk-WTANOSXK.js.map +0 -1
- package/dist/load-agent-defs-JHLE6MAE.js +0 -14
- package/dist/recompile-project-agents-ZPP5NOLZ.js +0 -18
- /package/dist/{chunk-B5UUHBAM.js.map → chunk-25MPBIK3.js.map} +0 -0
- /package/dist/{chunk-VPJUCVU7.js.map → chunk-2VUYFTUB.js.map} +0 -0
- /package/dist/{chunk-BGU25XAY.js.map → chunk-4NDBUJHK.js.map} +0 -0
- /package/dist/{chunk-5M3PQNXI.js.map → chunk-6L75SQZU.js.map} +0 -0
- /package/dist/{chunk-YNOOZFIB.js.map → chunk-6LF4CQBY.js.map} +0 -0
- /package/dist/{chunk-UBSSIIWD.js.map → chunk-7JNJ52CD.js.map} +0 -0
- /package/dist/{chunk-6SW6SB7H.js.map → chunk-DAIEQJIF.js.map} +0 -0
- /package/dist/{chunk-JV4TKXEN.js.map → chunk-HHIYT3PI.js.map} +0 -0
- /package/dist/{chunk-WIFIAQZU.js.map → chunk-HWEKHVLE.js.map} +0 -0
- /package/dist/{chunk-5P26XBZO.js.map → chunk-JQRJQ4SS.js.map} +0 -0
- /package/dist/{chunk-Y5SNGMB7.js.map → chunk-LFWLEDUG.js.map} +0 -0
- /package/dist/{chunk-TRTVOVHR.js.map → chunk-MAWNVT2C.js.map} +0 -0
- /package/dist/{chunk-57KU6SPH.js.map → chunk-MPTNC32T.js.map} +0 -0
- /package/dist/{chunk-MBUGQI2M.js.map → chunk-NBXXFIIW.js.map} +0 -0
- /package/dist/{chunk-42TNV2TK.js.map → chunk-PMJWD27C.js.map} +0 -0
- /package/dist/{chunk-X2KUI7V3.js.map → chunk-PNB3524H.js.map} +0 -0
- /package/dist/{chunk-LXXGZAD3.js.map → chunk-QHDPLLK6.js.map} +0 -0
- /package/dist/{chunk-TV5Y53R2.js.map → chunk-RAHSOJQ2.js.map} +0 -0
- /package/dist/{chunk-CTUJO23Z.js.map → chunk-RZDXDMT6.js.map} +0 -0
- /package/dist/{chunk-PSX7CT6V.js.map → chunk-SAYZWCH6.js.map} +0 -0
- /package/dist/{chunk-MWDY76MT.js.map → chunk-SCOQ34YM.js.map} +0 -0
- /package/dist/{chunk-4C7GL4F7.js.map → chunk-SXVHSOTH.js.map} +0 -0
- /package/dist/{chunk-E6CHHXGY.js.map → chunk-T6UWJAB3.js.map} +0 -0
- /package/dist/{chunk-F2ZWFWTP.js.map → chunk-TODCQFRB.js.map} +0 -0
- /package/dist/{chunk-CEBDGZID.js.map → chunk-TTY6DPJN.js.map} +0 -0
- /package/dist/{chunk-CBMAO6OP.js.map → chunk-TZ2YJJKK.js.map} +0 -0
- /package/dist/{chunk-WSGX4IWC.js.map → chunk-V3I7VQ7N.js.map} +0 -0
- /package/dist/{chunk-GKPW33FP.js.map → chunk-V5WXIM2F.js.map} +0 -0
- /package/dist/{chunk-6CY6PW5X.js.map → chunk-VAPTVR3J.js.map} +0 -0
- /package/dist/{chunk-CK5RM3DJ.js.map → chunk-WVUDLKIO.js.map} +0 -0
- /package/dist/{chunk-HR4YDSJK.js.map → chunk-WWIFNPJG.js.map} +0 -0
- /package/dist/{chunk-P3KJCYSR.js.map → chunk-XZEVWPX6.js.map} +0 -0
- /package/dist/{chunk-XATIKM3P.js.map → chunk-Y47EV74W.js.map} +0 -0
- /package/dist/{chunk-UR3RRTPO.js.map → chunk-ZR4YPKXQ.js.map} +0 -0
- /package/dist/{chunk-UCORXS4D.js.map → chunk-ZXKBERQU.js.map} +0 -0
- /package/dist/{load-agent-defs-JHLE6MAE.js.map → load-agent-defs-3C27ENC7.js.map} +0 -0
- /package/dist/{recompile-project-agents-ZPP5NOLZ.js.map → recompile-project-agents-DGNBCU3N.js.map} +0 -0
- /package/dist/{source-loader-RWZAYJ7E.js.map → source-loader-7KZ3MD5O.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/lib/loading/source-loader.ts","../src/cli/lib/installation/is-home-directory.ts","../src/cli/lib/metadata-keys.ts","../src/cli/utils/string.ts","../src/cli/utils/errors.ts","../src/cli/utils/fs.ts","../src/cli/lib/installation/install-layout.ts","../../compile/src/providers/codex/agent-role-toml.ts","../../compile/src/providers/codex/roster.ts","../../compile/src/agent-source.ts","../src/cli/lib/config-gate/gate-token.ts","../src/cli/utils/logger.ts","../src/cli/lib/validate-kebab-name.ts","../src/cli/utils/messages.ts","../src/cli/types/generated/source-types.ts","../src/cli/utils/type-guards.ts","../src/cli/lib/configuration/config.ts","../src/cli/lib/schemas.ts","../src/cli/lib/schema-validator.ts","../src/cli/types/matrix.ts","../src/cli/lib/configuration/config-loader.ts","../src/cli/lib/installation/install-base-dir.ts","../../compile/src/seed-to-config.ts","../../compile/src/config-source.ts","../../compile/src/installed-format.ts","../../compile/src/typed-object.ts","../src/cli/lib/configuration/config-merger.ts","../src/cli/lib/configuration/project-config.ts","../src/cli/lib/stacks/stacks-loader.ts","../../compile/src/config-types-source.ts","../src/cli/lib/configuration/config-types-io.ts","../src/cli/lib/skills/skill-metadata.ts","../src/cli/lib/versioning.ts","../src/cli/utils/yaml-schema.ts","../src/cli/lib/skills/skill-copier.ts","../src/cli/lib/skills/skill-plugin-compiler.ts","../src/cli/lib/plugins/plugin-manifest.ts","../src/cli/lib/plugins/plugin-ref.ts","../src/cli/lib/plugins/plugin-finder.ts","../src/cli/lib/plugins/plugin-info.ts","../src/cli/lib/installation/installation.ts","../src/cli/lib/installation/local-installer.ts","../src/cli/lib/loading/loader.ts","../src/cli/utils/frontmatter.ts","../src/cli/lib/loading/source-fetcher.ts","../src/cli/lib/marketplace-generator.ts","../src/cli/lib/loading/multi-source-loader.ts","../src/cli/lib/resolver.ts","../src/cli/lib/installation/source-scopes.ts","../src/cli/lib/installation/detect-installations.ts","../src/cli/lib/hosts/claude-host.ts","../src/cli/utils/exec.ts","../src/cli/lib/plugins/plugin-settings.ts","../src/cli/lib/hosts/codex-host.ts","../src/cli/lib/hosts/offered-placements.ts","../src/cli/lib/hosts/host-for.ts","../src/cli/lib/installation/mode-migrator.ts","../src/cli/lib/plugins/plugin-validator.ts","../src/cli/lib/validation-result.ts","../src/cli/lib/plugins/plugin-discovery.ts","../src/cli/lib/skills/local-skill-loader.ts","../src/cli/lib/skills/unresolved-skill-entries.ts","../src/cli/lib/skills/local-skill-mover.ts","../src/cli/lib/matrix/matrix-loader.ts","../src/cli/lib/matrix/skill-resolution.ts","../src/cli/lib/matrix/matrix-resolver.ts","../src/cli/lib/configuration/skill-audit.ts","../src/cli/lib/matrix/matrix-health-check.ts"],"sourcesContent":["import os from \"os\";\nimport { unique } from \"remeda\";\nimport path from \"path\";\nimport {\n EJECT_SOURCE,\n MARKETPLACE_JSON,\n PROJECT_ROOT,\n SKILL_CATEGORIES_PATH,\n SKILL_RULES_PATH,\n SKILLS_DIR_PATH,\n LOCAL_PSEUDO_CATEGORY,\n STANDARD_FILES,\n} from \"../../consts\";\nimport { defaultCategories } from \"../configuration/default-categories\";\nimport { defaultStacks } from \"../configuration/default-stacks\";\nimport { isHomeDirectory } from \"../installation/is-home-directory\";\nimport { LOCAL_DEFAULTS, METADATA_KEYS } from \"../metadata-keys\";\nimport type {\n AgentDefinition,\n AgentName,\n CategoryDefinition,\n CategoryMap,\n CategoryPath,\n Domain,\n ExtractedSkillMetadata,\n MergedSkillsMatrix,\n ResolvedSkill,\n ResolvedStack,\n SkillAssignment,\n SkillConfig,\n SkillId,\n SkillRulesConfig,\n SkillScope,\n Stack,\n Category,\n} from \"../../types\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { fileExists } from \"../../utils/fs\";\nimport { verbose, warn } from \"../../utils/logger\";\nimport { marketplaceManifestMissing, marketplaceManifestUnreadable } from \"../../utils/messages\";\nimport { isAgentName } from \"../../utils/type-guards\";\nimport { typedEntries, typedFromEntries, typedKeys, typedValues } from \"../../utils/typed-object\";\nimport {\n isDefaultSource,\n isLocalSource,\n isPublicCatalogueCheckout,\n loadGlobalSourceConfig,\n loadSourceRepoConfig,\n offersBuiltInStacks,\n resolveSource,\n type ResolvedConfig,\n type SourceCaller,\n} from \"../configuration\";\nimport { discoverLocalSkills, type LocalSkillDiscoveryResult } from \"../skills\";\nimport {\n checkMatrixHealth,\n claimSlug,\n extractAllSkills,\n loadSkillCategories,\n loadSkillRules,\n mergeMatrixWithSkills,\n relationshipsForSource,\n} from \"../matrix\";\nimport { loadAllAgents } from \"./loader\";\nimport { validateLoadedMarketplaceName } from \"../marketplace-generator\";\nimport {\n fetchFromSource,\n fetchMarketplace,\n MarketplaceManifestAbsentError,\n MarketplaceNameRefusedError,\n} from \"./source-fetcher\";\nimport { loadSkillsFromAllSources, marketplaceSource } from \"./multi-source-loader\";\nimport { loadStacks, resolveAgentConfigToSkills } from \"../stacks\";\nimport { initializeMatrix, matrix as currentMatrix } from \"../matrix/matrix-provider\";\nimport { BUILT_IN_MATRIX } from \"../../types/generated/matrix\";\n\n/**\n * What a load reads the marketplace for, which decides whether a marketplace other than the\n * default public catalogue without a valid manifest stops it (owner ruling 2026-10-02).\n *\n * - `\"fetch\"`: a command that takes from the marketplace — installs, edits, searches or ejects\n * from it. Refused, naming the builds that write the manifest.\n * - `\"upkeep\"`: a load that only keeps an installation that already exists in step with a change\n * made elsewhere — a global uninstall pruning the projects registered under it, a global change\n * fanned out to them. Everything it touches is already installed, so it goes on: \"if I want to\n * uninstall something, I don't care if it's broken, I just want it gone\".\n */\nexport type SourceLoadPurpose = \"fetch\" | \"upkeep\";\n\nexport type SourceLoadOptions = {\n /** What the load is for — see {@link SourceLoadPurpose}. Defaults to `\"fetch\"`. */\n purpose?: SourceLoadPurpose;\n /**\n * Whether this load may reach the init-time source rungs — see {@link SourceCaller}.\n * Defaults to `\"stored\"`: the ambient environment can only be reached by a caller that\n * names itself `init`, so no path arrives there by omission.\n */\n caller?: SourceCaller;\n sourceFlag?: string;\n projectDir?: string;\n devMode?: boolean;\n /** Skip loading skills from extra sources (multi-source). Only needed for wizard UI tagging. */\n skipExtraSources?: boolean;\n /**\n * The caller only needs the matrix, not skill files on disk. For the default\n * source this skips the `fetchFromSource` clone (the matrix is the pre-computed\n * BUILT_IN_MATRIX anyway) so the load stays offline; `sourcePath` comes back\n * empty. Sources that must be read from disk to build the matrix (local paths,\n * custom remotes) are unaffected.\n */\n matrixOnly?: boolean;\n};\n\nexport type SourceLoadResult = {\n matrix: MergedSkillsMatrix;\n sourceConfig: ResolvedConfig;\n sourcePath: string;\n isLocal: boolean;\n marketplace?: string;\n /**\n * The skills the loaded marketplace itself carries, which are the only ones `sourcePath` holds\n * files for. The matrix holds more: local skills merged in from `.claude/skills`, and the global\n * installation's plugin skills seated from the marketplace that installation was made from.\n */\n marketplaceSkillIds: ReadonlySet<SkillId>;\n};\n\n/** A marketplace's catalogue as read, before anything on this machine joins its matrix. */\ntype CatalogueRead = Omit<SourceLoadResult, \"marketplaceSkillIds\">;\n\nexport async function loadSkillsMatrixFromSource(\n options: SourceLoadOptions = {},\n): Promise<SourceLoadResult> {\n const {\n purpose = \"fetch\",\n caller = \"stored\",\n sourceFlag,\n projectDir,\n devMode = false,\n matrixOnly = false,\n } = options;\n\n // ABORT on an unreadable config. Every skill this returns is resolved against the marketplace\n // named here, so a run that got past this rung on a config it could not read would install from\n // a marketplace nobody chose — which is the whole of what the refusal exists to stop.\n const sourceConfig = await resolveSource({ caller, flag: sourceFlag, projectDir });\n const { source } = sourceConfig;\n\n verbose(`Loading skills from source: ${source}`);\n\n const catalogue = await resolveBaseResult(sourceConfig, { purpose, devMode, matrixOnly });\n\n const resolvedProjectDir = projectDir || process.cwd();\n\n // Everything the marketplace itself carries, read before any local skill is merged on\n // top: past this point a skill's provenance is no longer legible from the matrix, and\n // an id the merge INTRODUCES is one nothing but the copy on disk backs.\n const result: SourceLoadResult = {\n ...catalogue,\n marketplaceSkillIds: new Set(typedKeys<SkillId>(catalogue.matrix.skills)),\n };\n\n // Load global local skills first, then project local skills — project wins on conflict\n const homeDir = os.homedir();\n if (!isHomeDirectory(resolvedProjectDir)) {\n result.matrix = await mergeDiscoveredLocalSkills(result.matrix, homeDir, \"global\");\n }\n result.matrix = await mergeDiscoveredLocalSkills(result.matrix, resolvedProjectDir, \"project\");\n await seatGlobalInstallationSkills(result.matrix, source, purpose);\n\n if (!options.skipExtraSources) {\n await loadSkillsFromAllSources(\n result.matrix,\n sourceConfig,\n resolvedProjectDir,\n result.marketplace,\n idsOutsideMarketplace(result.matrix, result.marketplaceSkillIds),\n );\n }\n\n checkMatrixHealth(result.matrix);\n initializeMatrix(result.matrix);\n\n return result;\n}\n\n/**\n * Seats the global installation's plugin skills this catalogue does not carry, as the marketplace\n * that installation was made from describes them.\n *\n * A global installation from one marketplace under a project from another is a supported layout,\n * and every session in that project inherits the global entries — shown locked in the wizard,\n * compiled into the global sub-agents. An ejected global skill already reaches this matrix through\n * the global local-skill merge, from its copy under `~/.claude/skills`. A plugin leaves no such\n * copy: Claude's plugin cache holds the skill's SKILL.md and none of the catalogue's metadata. So a\n * load of the project's marketplace held no entry for it, and a project setup dropped it — the\n * wizard called it missing and listed it as removed, and the global sub-agent recompiled in the\n * same run lost the usage sentence its own catalogue states.\n *\n * The other marketplace is read only when the global installation names a skill this one lacks,\n * so a project on the global's own marketplace loads nothing more. A seated entry keeps none of\n * its relationships: they name skills of a catalogue this session does not offer, and the entry\n * is here to be shown and compiled, never picked against.\n */\nasync function seatGlobalInstallationSkills(\n matrix: MergedSkillsMatrix,\n loadedSource: string,\n purpose: SourceLoadPurpose,\n): Promise<void> {\n const uncarried = await globalPluginSkillsUncarried(matrix);\n if (uncarried.length === 0) return;\n\n const globalCatalogue = await loadGlobalInstallationCatalogue(loadedSource, purpose);\n if (globalCatalogue === null) return;\n\n for (const id of uncarried) seatFromCatalogue(matrix, globalCatalogue, id);\n}\n\n/**\n * The global installation's plugin skills this matrix holds no entry for.\n *\n * DEGRADE on an unreadable global config: every command that needs it readable has refused it\n * before loading, and `doctor` and `uninstall`, which run without it, must still run — so its\n * skills simply stay unseated, as they were before this pass existed.\n */\nasync function globalPluginSkillsUncarried(matrix: MergedSkillsMatrix): Promise<SkillId[]> {\n try {\n const globalConfig = await loadGlobalSourceConfig();\n return (globalConfig?.skills ?? [])\n .filter(isActivePlugin)\n .filter((skill) => matrix.skills[skill.id] === undefined)\n .map((skill) => skill.id);\n } catch (error) {\n verbose(`Global installation's skills not seated — ${getErrorMessage(error)}`);\n return [];\n }\n}\n\n/** An entry still configured, installed as a marketplace's plugin rather than ejected. */\nfunction isActivePlugin(skill: SkillConfig): boolean {\n return !skill.excluded && skill.origin !== EJECT_SOURCE;\n}\n\n/**\n * The catalogue of the marketplace the global installation was made from, or null when that is\n * the one already loaded — whatever it lacks the global's own marketplace lacks too — or when it\n * cannot be loaded, which leaves the skills unseated rather than failing a project command over\n * another installation's marketplace.\n */\nasync function loadGlobalInstallationCatalogue(\n loadedSource: string,\n purpose: SourceLoadPurpose,\n): Promise<CatalogueRead | null> {\n try {\n const globalSourceConfig = await resolveSource({ caller: \"stored\", projectDir: os.homedir() });\n if (globalSourceConfig.source === loadedSource) return null;\n return await resolveBaseResult(globalSourceConfig, {\n purpose,\n devMode: false,\n matrixOnly: true,\n });\n } catch (error) {\n verbose(`Global installation's marketplace not loaded — ${getErrorMessage(error)}`);\n return null;\n }\n}\n\n/** One global skill, as its own catalogue holds it, carried under its own marketplace's name. */\nfunction seatFromCatalogue(\n matrix: MergedSkillsMatrix,\n catalogue: CatalogueRead,\n id: SkillId,\n): void {\n const skill = catalogue.matrix.skills[id];\n // Withdrawn from its own marketplace too, so absent is the truth and the session says so.\n if (!skill) return;\n\n matrix.skills[id] = asSeatedGlobalSkill(skill, catalogue);\n claimSlug(matrix.slugMap, skill.slug, id);\n carryCategory(matrix, catalogue.matrix, skill.category);\n}\n\n/** The entry as a session here shows and compiles it: none of its relationships, its own name. */\nfunction asSeatedGlobalSkill(skill: ResolvedSkill, catalogue: CatalogueRead): ResolvedSkill {\n return {\n ...skill,\n conflictsWith: [],\n requires: [],\n alternatives: [],\n discourages: [],\n availableSources: [marketplaceSource(catalogue.sourceConfig, catalogue.marketplace)],\n };\n}\n\n/**\n * A category the matrix does not define arrives with the skill placed in it, or the wizard has no\n * screen to place that skill on. `local` is never defined, as {@link ensureCategoryDefined} says.\n */\nfunction carryCategory(\n matrix: MergedSkillsMatrix,\n from: MergedSkillsMatrix,\n categoryId: CategoryPath,\n): void {\n if (categoryId === LOCAL_PSEUDO_CATEGORY || matrix.categories[categoryId]) return;\n const category = from.categories[categoryId];\n if (category) matrix.categories[categoryId] = category;\n}\n\n/**\n * Skills the merged matrix holds that the marketplace never offered — the local merge's own\n * additions, and the global installation's skills seated from its own marketplace. This\n * marketplace can install none of them, so they are the ids the tagging pass must leave its\n * entry off.\n */\nfunction idsOutsideMarketplace(\n matrix: MergedSkillsMatrix,\n marketplaceSkillIds: ReadonlySet<SkillId>,\n): ReadonlySet<SkillId> {\n return new Set(typedKeys<SkillId>(matrix.skills).filter((id) => !marketplaceSkillIds.has(id)));\n}\n\n/**\n * The shipped catalogue, in a copy this load may write into. Every collection the\n * local-skill merge writes to is copied: `BUILT_IN_MATRIX` is a module constant,\n * so a shared reference would leave one project's local skill in the catalogue\n * every later load reads.\n */\nfunction copyOfBuiltInMatrix(): MergedSkillsMatrix {\n return {\n ...BUILT_IN_MATRIX,\n skills: { ...BUILT_IN_MATRIX.skills },\n categories: { ...BUILT_IN_MATRIX.categories },\n suggestedStacks: [...BUILT_IN_MATRIX.suggestedStacks],\n slugMap: {\n slugToId: { ...BUILT_IN_MATRIX.slugMap.slugToId },\n },\n };\n}\n\n/** What {@link resolveBaseResult} needs of the caller's options, with their defaults applied. */\ntype BaseLoadOptions = Required<Pick<SourceLoadOptions, \"purpose\" | \"devMode\" | \"matrixOnly\">>;\n\n/**\n * Resolves the base matrix for the configured source: the pre-computed\n * BUILT_IN_MATRIX for the default source, otherwise a local or remote load.\n */\nasync function resolveBaseResult(\n sourceConfig: ResolvedConfig,\n { purpose, devMode, matrixOnly }: BaseLoadOptions,\n): Promise<CatalogueRead> {\n refuseReservedRecordedName(sourceConfig);\n const { source } = sourceConfig;\n if (isDefaultSource(source) && !devMode) {\n // Default source: use pre-computed BUILT_IN_MATRIX instead of loading from disk.\n // Still resolve sourcePath via fetchFromSource so skill files can be read\n // (e.g. for eject-mode copy) — unless the caller declared matrixOnly, in\n // which case the fetch (a network clone on a cold cache) is skipped entirely.\n // The fetch is cached, so no network call if the clone already exists.\n const sourcePath = matrixOnly ? \"\" : (await fetchFromSource(source)).path;\n return {\n matrix: copyOfBuiltInMatrix(),\n sourceConfig,\n sourcePath,\n isLocal: false,\n ...(sourceConfig.marketplace !== undefined && { marketplace: sourceConfig.marketplace }),\n };\n }\n\n const isLocal = isLocalSource(source) || devMode;\n return isLocal\n ? loadFromLocal(source, sourceConfig, purpose)\n : loadFromRemote(source, sourceConfig, purpose);\n}\n\n/**\n * The way out of a reserved name an installation recorded. The manifest is not where it came from,\n * so renaming the marketplace is no way out: the file to correct is the config that recorded it.\n */\nfunction recordedNameWayOut(configPath: string): string {\n return `set this installation up again, or correct the marketplaceName it recorded in '${configPath}'`;\n}\n\n/**\n * Refuses a load labelled by a reserved name the installation's config recorded, as a manifest\n * carrying it is refused. The recorded name outranks the manifest's — so an install made before\n * the name was reserved, or a config edited by hand, would otherwise carry it past the manifest's\n * check, and every plugin installed under `eject` would be recorded as an ejected copy.\n */\nfunction refuseReservedRecordedName({ marketplace, marketplaceRecordedIn }: ResolvedConfig): void {\n if (marketplace === undefined) return;\n const reservedName = validateLoadedMarketplaceName(\n marketplace,\n recordedNameWayOut(marketplaceRecordedIn),\n );\n if (reservedName) throw new MarketplaceNameRefusedError(reservedName);\n}\n\ntype MarketplaceLabels = Pick<SourceLoadResult, \"marketplace\">;\n\n/**\n * Which state a marketplace's manifest is in, as far as naming the marketplace goes.\n *\n * Four states rather than two because the failures are not one event, even where they end\n * the same way. A marketplace with no manifest has not been built; one whose manifest is\n * there and unreadable was built, or edited, into a file the reader rejects, and its\n * refusal has to carry the reader's reason — collapsing the two reported every schema\n * violation in that file as an absent file, and a reader who checked found it exactly\n * where the message said it was not. A manifest naming the marketplace something Claude\n * Code registers no plugin under is refused under a type of its own. `doctor`'s\n * `ConfigState` splits its own the same way and for the same reason.\n */\ntype ManifestState =\n | { kind: \"absent\" }\n | { kind: \"refused\"; reason: string }\n | { kind: \"unreadable\"; reason: string }\n | { kind: \"named\"; name: string };\n\n/**\n * {@link ManifestState} for one marketplace. Which failure it was is read off the throw's\n * TYPE rather than its text: `fetchMarketplace` is the only thing that can tell a file it\n * never found from one it found and refused, and a refused NAME from every other refusal,\n * so it says which and nothing here matches on a sentence.\n */\nasync function readManifestState(source: string): Promise<ManifestState> {\n try {\n const { marketplace } = await fetchMarketplace(source);\n return { kind: \"named\", name: marketplace.name };\n } catch (error) {\n if (error instanceof MarketplaceManifestAbsentError) return { kind: \"absent\" };\n if (error instanceof MarketplaceNameRefusedError) {\n return { kind: \"refused\", reason: getErrorMessage(error) };\n }\n return { kind: \"unreadable\", reason: getErrorMessage(error) };\n }\n}\n\n/**\n * Thrown when a marketplace other than the default public catalogue publishes no valid\n * `.claude-plugin/marketplace.json`: it has none, or one that does not parse, or one the\n * schema refuses.\n *\n * A type rather than a sentence for the reason the fetcher's own manifest errors are types:\n * `doctor` files this finding against the manifest at a severity that turns on who is\n * reading — the author of an unbuilt repository is one build from the fix, and a consumer\n * cannot load the marketplace at all — so it has to be told apart from a load that merely\n * failed without matching on the message.\n */\nexport class MarketplaceManifestRequiredError extends Error {}\n\n/** A manifest this load could not name the marketplace from. */\ntype ManifestUnusable = Extract<ManifestState, { kind: \"absent\" | \"unreadable\" }>;\n\n/**\n * Resolves the marketplace name from the source's `.claude-plugin/marketplace.json`.\n * A `marketplace` already recorded in the project config wins.\n *\n * Every state but `named` ABORTS a `\"fetch\"` of a marketplace other than the default public\n * catalogue (owner ruling, 2026-10-02: \"Why not just make it a requirement?\"). Carrying on past\n * an absent or unreadable manifest labelled every skill `agents-inc` and left the only failure\n * to a Plugin install, after Confirm. A manifest naming the marketplace something Claude\n * Code registers no plugin under keeps its own type, because nothing in that marketplace is\n * installable whoever reads it.\n */\nasync function resolveMarketplaceLabels(\n manifestRoot: string,\n sourceConfig: ResolvedConfig,\n purpose: SourceLoadPurpose,\n): Promise<MarketplaceLabels> {\n const state = await readManifestState(manifestRoot);\n\n switch (state.kind) {\n case \"named\": {\n const marketplace = sourceConfig.marketplace ?? state.name;\n verbose(`Using marketplace name from ${MARKETPLACE_JSON}: ${marketplace}`);\n return { marketplace };\n }\n case \"refused\":\n throw new MarketplaceNameRefusedError(state.reason);\n case \"absent\":\n case \"unreadable\":\n return labelWithoutManifest(state, sourceConfig, purpose);\n default: {\n const exhaustive: never = state;\n return exhaustive;\n }\n }\n}\n\n/**\n * A load that may go on without a usable manifest keeps the label its config recorded. Every\n * other load is refused, naming what is wrong with the file and the builds that write it.\n */\nfunction labelWithoutManifest(\n state: ManifestUnusable,\n sourceConfig: ResolvedConfig,\n purpose: SourceLoadPurpose,\n): MarketplaceLabels {\n const { source } = sourceConfig;\n if (goesOnWithoutManifest(source, purpose)) {\n verbose(`'${source}' has no usable ${MARKETPLACE_JSON}; keeping the label its config recorded`);\n return configuredLabel(sourceConfig);\n }\n\n throw new MarketplaceManifestRequiredError(\n state.kind === \"absent\"\n ? marketplaceManifestMissing(source)\n : marketplaceManifestUnreadable(source, state.reason),\n );\n}\n\n/**\n * The two loads a missing or unreadable manifest does not stop: any load of the default public\n * catalogue, whose name is the CLI's own and which dev mode reads from `PROJECT_ROOT`, which ships\n * none; and an `\"upkeep\"` load, which touches nothing that is not already installed.\n */\nfunction goesOnWithoutManifest(source: string, purpose: SourceLoadPurpose): boolean {\n return isDefaultSource(source) || purpose === \"upkeep\";\n}\n\n/** The label a config already recorded, which outlives a manifest this load could not name. */\nfunction configuredLabel(sourceConfig: ResolvedConfig): MarketplaceLabels {\n return sourceConfig.marketplace === undefined ? {} : { marketplace: sourceConfig.marketplace };\n}\n\n/** Merges any discovered local skills for `dir` into the matrix, logging the find. */\nasync function mergeDiscoveredLocalSkills(\n matrix: MergedSkillsMatrix,\n dir: string,\n label: SkillScope,\n): Promise<MergedSkillsMatrix> {\n const discovered = await discoverLocalSkills(dir);\n if (!discovered || discovered.skills.length === 0) return matrix;\n verbose(\n `Found ${discovered.skills.length} ${label} local skill(s) in ${discovered.localSkillsPath}`,\n );\n return mergeLocalSkillsIntoMatrix(matrix, discovered);\n}\n\nasync function loadFromLocal(\n source: string,\n sourceConfig: ResolvedConfig,\n purpose: SourceLoadPurpose,\n): Promise<CatalogueRead> {\n // Resolved through `fetchFromSource` — the same call `loadFromRemote` makes — rather\n // than joined here, so a path the user named and the CLI cannot read is REFUSED with\n // the loader's own message. Reading it directly returned an empty matrix instead, and\n // `init`/`edit` went on to mount a wizard over nothing the user asked for.\n const skillsPath = isLocalSource(source) ? (await fetchFromSource(source)).path : PROJECT_ROOT;\n\n verbose(`Loading skills from local path: ${skillsPath}`);\n\n const mergedMatrix = await loadAndMergeFromBasePath(skillsPath, source);\n const labels = await resolveMarketplaceLabels(skillsPath, sourceConfig, purpose);\n\n return {\n matrix: mergedMatrix,\n sourceConfig,\n sourcePath: skillsPath,\n isLocal: true,\n ...labels,\n };\n}\n\nasync function loadFromRemote(\n source: string,\n sourceConfig: ResolvedConfig,\n purpose: SourceLoadPurpose,\n): Promise<CatalogueRead> {\n verbose(`Fetching skills from remote source: ${source}`);\n\n const fetchResult = await fetchFromSource(source);\n\n verbose(`Fetched to: ${fetchResult.path}`);\n\n const mergedMatrix = await loadAndMergeFromBasePath(fetchResult.path, source);\n const labels = await resolveMarketplaceLabels(source, sourceConfig, purpose);\n\n return {\n matrix: mergedMatrix,\n sourceConfig,\n sourcePath: fetchResult.path,\n isLocal: false,\n ...labels,\n };\n}\n\n/**\n * The matrix a marketplace on disk describes — its own skills, its own\n * categories and stacks, and the built-in relationship rules narrowed to the\n * slugs it actually ships.\n *\n * This is the load an AUTHOR's command makes, and it is deliberately not\n * {@link loadSkillsMatrixFromSource}: that one merges the invoking machine's\n * `~/.claude/skills` and the project's own into the result, which is right for\n * an install and wrong for anything published — a catalogue carrying the\n * author's private skills offers consumers skills that exist on one machine.\n * The local merge lives one layer up, in the install path alone.\n *\n * A marketplace's base path is also the only word anything has for WHICH\n * marketplace it is, so it stands as the source string too.\n */\nexport async function loadMarketplaceMatrix(marketplaceDir: string): Promise<MergedSkillsMatrix> {\n const matrix = await loadAndMergeFromBasePath(marketplaceDir, marketplaceDir);\n return { ...matrix, categories: categoriesTheseSkillsAreIn(matrix) };\n}\n\n/**\n * The categories a marketplace's own skills are in, and nothing else.\n *\n * {@link loadAndMergeFromBasePath} merges the built-in taxonomy underneath the\n * marketplace's own, so a skill sitting in a built-in category resolves to that\n * category's real definition rather than the humanized stand-in\n * `synthesizeCategory` writes. Right for the merge and wrong for the artefact: a\n * published catalogue cannot claim categories the marketplace ships nothing in,\n * and 102 of them arrived that way — beside a `skills` and a `suggestedStacks`\n * that were the marketplace's own.\n *\n * Membership is read off the SKILLS rather than off the marketplace's own\n * `skill-categories.ts`, because the two disagree in both directions: a skill may\n * sit in a category its author never declared, and a declared category may hold\n * nothing. Narrowing by what is declared would leave a consumer holding a skill\n * whose category the catalogue does not define, which is this bug with the sides\n * swapped.\n */\nfunction categoriesTheseSkillsAreIn(matrix: MergedSkillsMatrix): CategoryMap {\n const occupied = new Set<CategoryPath>(typedValues(matrix.skills).map((skill) => skill.category));\n\n return typedFromEntries(\n typedEntries<Category, CategoryDefinition>(matrix.categories).filter(([id]) =>\n occupied.has(id),\n ),\n );\n}\n\n/**\n * Builds the matrix for a source read from disk, from the files under\n * `basePath`. `source` is the source string that base path stands for — the\n * loader's only word for WHICH marketplace it is reading, and one of the two\n * things {@link resolveOfferedStacks} decides the built-in catalogue's fate on.\n */\nasync function loadAndMergeFromBasePath(\n basePath: string,\n source: string,\n): Promise<MergedSkillsMatrix> {\n // ABORT on an unreadable config. This file is where a marketplace declares which directories\n // its skills and stacks live in, so falling back to the defaults would walk a tree the\n // marketplace says is somewhere else and report the catalogue as empty.\n const sourceProjectConfig = await loadSourceRepoConfig(basePath);\n\n const skillsDirRelPath = sourceProjectConfig?.skillsDir ?? SKILLS_DIR_PATH;\n const stacksRelFile = sourceProjectConfig?.stacksFile;\n\n const { categories, sourceRules } = await loadSourceTaxonomy(basePath);\n\n const skillsDir = path.join(basePath, skillsDirRelPath);\n verbose(`Skills from source: ${skillsDir}`);\n\n const skills = await extractAllSkills(skillsDir);\n await refuseCatalogueCollisions(basePath, source, skills);\n\n const relationships = relationshipsForSource(skills, sourceRules);\n const mergedMatrix = mergeMatrixWithSkills(categories, relationships, skills);\n initializeMatrix(mergedMatrix);\n\n // Assigned unconditionally: a source offering no stacks is a matrix carrying\n // none, which is the whole of what the wizard needs to skip the stack step.\n const stacks = await resolveOfferedStacks(basePath, stacksRelFile, source);\n mergedMatrix.suggestedStacks = stacks.map((stack) => convertStackToResolvedStack(stack));\n\n const agentDefinedDomains = domainsDeclaredBy(await loadAllAgents(basePath));\n const domainCount = typedKeys(agentDefinedDomains).length;\n if (domainCount > 0) {\n mergedMatrix.agentDefinedDomains = agentDefinedDomains;\n verbose(`Loaded ${domainCount} agent domain definition(s)`);\n }\n\n return mergedMatrix;\n}\n\n/** What a source declares about its skills' taxonomy, beside the CLI's own. */\ntype SourceTaxonomy = {\n /** The CLI's built-in categories, with the source's own layered over them where it has any. */\n categories: CategoryMap;\n /** The source's own relationship rules, for {@link relationshipsForSource} to merge. */\n sourceRules: SkillRulesConfig | undefined;\n};\n\n/**\n * Reads a source's categories file and rules file, either of which it may leave out. Its\n * categories are layered over the CLI's built-in ones; its rules come back as they are, and\n * undefined when it ships none.\n */\nasync function loadSourceTaxonomy(basePath: string): Promise<SourceTaxonomy> {\n const sourceCategoriesPath = path.join(basePath, SKILL_CATEGORIES_PATH);\n const sourceRulesPath = path.join(basePath, SKILL_RULES_PATH);\n const hasSourceCategories = await fileExists(sourceCategoriesPath);\n const hasSourceRules = await fileExists(sourceRulesPath);\n\n const sourceCategories = hasSourceCategories\n ? await loadSkillCategories(sourceCategoriesPath)\n : undefined;\n if (sourceCategories) {\n verbose(\n `Loaded source categories: ${sourceCategoriesPath} (${typedKeys(sourceCategories).length} categories)`,\n );\n }\n const categories: CategoryMap = sourceCategories\n ? { ...defaultCategories, ...sourceCategories }\n : defaultCategories;\n\n const sourceRules = hasSourceRules ? await loadSkillRules(sourceRulesPath) : undefined;\n if (sourceRules) {\n verbose(`Loaded source rules: ${sourceRulesPath}`);\n }\n\n if (hasSourceCategories || hasSourceRules) {\n verbose(`Matrix merged: CLI (${typedKeys(defaultCategories).length} categories) + source`);\n } else {\n verbose(`Matrix from CLI only (source has no categories/rules files)`);\n }\n\n return { categories, sourceRules };\n}\n\n/** The domain each agent's own metadata.yaml declares, for the agents that declare one. */\nfunction domainsDeclaredBy(\n agents: Partial<Record<AgentName, AgentDefinition>>,\n): Partial<Record<AgentName, Domain>> {\n return typedFromEntries(\n typedEntries<AgentName, AgentDefinition>(agents).flatMap(([agentId, agentDef]) =>\n agentDef.domain ? [[agentId, agentDef.domain] as const] : [],\n ),\n );\n}\n\n/** Every skill id the shipped catalogue owns — the ids no other marketplace may take. */\nconst CATALOGUE_SKILL_IDS: ReadonlySet<SkillId> = new Set(typedKeys(BUILT_IN_MATRIX.skills));\n\n/** How many colliding ids a refusal lists before summarising the rest. */\nconst MAX_REPORTED_COLLISIONS = 10;\n\n/**\n * Refuses a marketplace shipping skill ids the public catalogue already owns.\n *\n * A skill id is the directory the skill installs into, and Claude reads\n * `~/.claude` and `./.claude` together, so two marketplaces naming one id means\n * one silently shadows the other. `build marketplace` refuses those ids at author\n * time; this is what catches a marketplace that skipped that build, was\n * hand-edited, or is lying — nothing a source ships is unforgeable, so the\n * consumer's own load has to ask the question again.\n *\n * The SOURCE is refused, not the colliding skills: dropping them would hand the\n * user a marketplace quietly missing the skills they chose it for, leave the\n * catalogue's own copies standing in under those ids, and tell the author\n * nothing. One loud refusal naming the fix beats a partial load that hides it.\n */\nasync function refuseCatalogueCollisions(\n basePath: string,\n source: string,\n skills: ExtractedSkillMetadata[],\n): Promise<void> {\n const collidingIds = skills.map((skill) => skill.id).filter((id) => CATALOGUE_SKILL_IDS.has(id));\n if (collidingIds.length === 0) return;\n if (await isPublicCatalogueCheckout(basePath)) return;\n\n throw new Error(catalogueCollisionError(collidingIds, source));\n}\n\nfunction catalogueCollisionError(collidingIds: SkillId[], source: string): string {\n const listed = collidingIds.slice(0, MAX_REPORTED_COLLISIONS).map((id) => ` ${id}`);\n const unlisted = collidingIds.length - listed.length;\n\n return [\n `Marketplace '${source}' ships ${collidingIds.length} skill id(s) the public catalogue ` +\n `already owns:`,\n ...listed,\n ...(unlisted > 0 ? [` ... and ${unlisted} more`] : []),\n `A skill id is the directory the skill installs into, so these would shadow the public ` +\n `catalogue's own skills. Every id must carry its marketplace's name as a namespace — ` +\n `'<marketplace>-<id>'. Rename each skill and the 'name' in its SKILL.md, then re-run ` +\n `'build marketplace', which refuses the same ids before they are published.`,\n ].join(\"\\n\");\n}\n\n/**\n * The stacks a source offers the wizard: the ones it ships, or — for the public\n * catalogue alone — the CLI's built-in catalogue standing in when it ships none.\n *\n * A custom marketplace gets no such stand-in. Handing it one meant offering a\n * catalogue of stacks written against a different catalogue of skills, under a\n * name the user never asked for, with most of each stack silently dropped for\n * naming ids the chosen source does not carry. A marketplace ships its own\n * stacks or offers none, and none means a wizard with no stack step rather than\n * one showing somebody else's list.\n */\nasync function resolveOfferedStacks(\n basePath: string,\n stacksFile: string | undefined,\n source: string,\n): Promise<Stack[]> {\n const sourceStacks = await loadStacks(basePath, stacksFile);\n if (sourceStacks.length > 0) {\n verbose(`Offering the ${sourceStacks.length} stacks the source ships`);\n return sourceStacks;\n }\n\n if (await offersBuiltInStacks(basePath, source)) {\n verbose(\n `The public catalogue ships no stacks — offering the ${defaultStacks.length} built-in stacks`,\n );\n return defaultStacks;\n }\n\n verbose(`Marketplace '${source}' ships no stacks, and gets no built-in stand-in — offering none`);\n return [];\n}\n\n/**\n * A stack's sub-agents split by whether the CLI declares one.\n *\n * The keys are read as the STRINGS a stack file spells: `typedKeys` types them `AgentName` because\n * `Stack[\"agents\"]` is keyed by it, but they arrive from a marketplace's own `config/stacks.ts` and\n * nothing between that file and here narrows them — so the membership test below is a real\n * question rather than a formality, and the widening is what lets it be asked.\n *\n * Narrowed with `isAgentName` and deliberately NOT cast. Only the CLI's own `src/agents/` declares\n * a sub-agent a compile pass can honour — that directory is the whole of the roster (owner ruling\n * 2026-08-21) and is what `AGENT_NAMES` is generated from — so this is the union's own membership\n * test rather than a second list to keep in step.\n */\nfunction declaredAgentsIn(stack: Stack): { declared: AgentName[]; undeclared: string[] } {\n const named: string[] = typedKeys<AgentName>(stack.agents);\n return {\n declared: named.filter(isAgentName),\n undeclared: named.filter((name) => !isAgentName(name)),\n };\n}\n\n/**\n * What a stack naming a sub-agent the CLI does not ship is told to the user.\n *\n * The stack is DROPPED FROM rather than refused, and that posture is deliberate. A stack is a\n * suggestion the wizard offers, not an install contract, so refusing it would take every\n * sub-agent in it — the valid ones included — over one typo in a marketplace the user may not\n * own. It is also the posture the rest of this conversion already takes: `resolveStackAgentSkills`\n * drops a skill id the matrix does not carry, and one function answering the same question two\n * ways is worse than either answer. Contrast `refuseCatalogueCollisions` above, which refuses\n * the whole source because a colliding id is UNSAFE — two marketplaces silently shadowing each\n * other on disk — where an undeclared sub-agent is merely uncompilable.\n *\n * What the drop must not be is SILENT, which is what it was: the wizard narrowed these names\n * out of its own grid and told nobody. `warn()` is buffered during a source load and painted as\n * the wizard's startup band, so this reaches the user rather than a stderr the first repaint\n * scrolls away. The stack is named because a marketplace ships many, and the sub-agents are\n * named rather than counted because only the name says what to fix.\n */\nfunction undeclaredAgentsWarning(stack: Stack, undeclared: readonly string[]): string {\n const named = undeclared.map((name) => `'${name}'`).join(\", \");\n return (\n `Stack '${stack.id}' names ${undeclared.length} sub-agent(s) this CLI does not define: ` +\n `${named}. Left out of the stack — a sub-agent must be one the CLI ships.`\n );\n}\n\n/**\n * What a stack naming a skill the catalogue does not carry is told to the user.\n *\n * The skill counterpart of {@link undeclaredAgentsWarning}, and it exists for the same reason: a\n * marketplace's `config/stacks.ts` is authored by hand against a catalogue that moves, so a stack\n * outliving one of its own skills is an ordinary authoring mistake rather than a corrupt file.\n */\nfunction withdrawnSkillsWarning(stack: Stack, withdrawn: readonly string[]): string {\n const named = withdrawn.map((id) => `'${id}'`).join(\", \");\n return (\n `Stack '${stack.id}' names ${withdrawn.length} skill(s) this marketplace's catalogue does ` +\n `not carry: ${named}. Left out of the stack — selecting it would install nothing.`\n );\n}\n\n// Stack values are already skill IDs — no alias resolution needed\nexport function convertStackToResolvedStack(stack: Stack): ResolvedStack {\n const { declared, undeclared } = declaredAgentsIn(stack);\n if (undeclared.length > 0) warn(undeclaredAgentsWarning(stack, undeclared));\n\n const agentConfigs = declared.flatMap((agentId) => {\n const agentConfig = stack.agents[agentId];\n return agentConfig ? [{ agentId, agentConfig }] : [];\n });\n\n const skills = typedFromEntries(\n agentConfigs.map(\n ({ agentId, agentConfig }) => [agentId, resolveStackAgentSkills(agentConfig)] as const,\n ),\n );\n\n // First-seen order across agents, matching the historical seen-Set accumulation — and filtered\n // against the matrix by the SAME question `resolveStackAgentSkills` asks above. The two used to\n // disagree: the per-category map kept only ids the catalogue carried while this list kept every\n // id the file named, and this is the one that reaches a user. `wizard.tsx` returns it verbatim\n // as the selection when a stack is picked, and the editor's read-model counts and lists it — so\n // a stack outliving one of its own skills selected an id nothing could resolve, and the mismatch\n // surfaced only once somebody picked that stack.\n const named = unique(\n agentConfigs.flatMap(({ agentConfig }) =>\n resolveAgentConfigToSkills(agentConfig).map((ref) => ref.id),\n ),\n );\n const allSkillIds = named.filter((id) => id in currentMatrix.skills);\n const withdrawn = named.filter((id) => !(id in currentMatrix.skills));\n if (withdrawn.length > 0) warn(withdrawnSkillsWarning(stack, withdrawn));\n\n verbose(\n `Stack '${stack.id}' has ${allSkillIds.length} skills from ${agentConfigs.length} agents`,\n );\n\n return {\n id: stack.id,\n name: stack.name,\n description: stack.description,\n skills,\n allSkillIds,\n philosophy: stack.philosophy || \"\",\n };\n}\n\n/** Per-category skill ids for one stack agent, keeping only ids present in the current matrix. */\nfunction resolveStackAgentSkills(\n agentConfig: Partial<Record<Category, SkillAssignment[]>>,\n): Partial<Record<Category, SkillId[]>> {\n const byCategory = typedEntries<Category, SkillAssignment[]>(agentConfig)\n .map(([category, assignments]) => ({\n category,\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- typedEntries/Object.entries launders the `| undefined` a Partial<Record> admits out of its result type, so this guard reads as dead while still covering an explicitly-undefined slot\n validIds: (assignments ?? []).filter((a) => a.id in currentMatrix.skills).map((a) => a.id),\n }))\n .filter(({ validIds }) => validIds.length > 0);\n return typedFromEntries(\n byCategory.map(({ category, validIds }) => [category, validIds] as const),\n );\n}\n\n/**\n * Whether this matrix carries a definition for the category. `local` never is\n * one — it is the trapdoor a skill wears when it belongs to no category at all.\n */\nfunction declaresCategory(matrix: MergedSkillsMatrix, category: CategoryPath): boolean {\n return category !== LOCAL_PSEUDO_CATEGORY && matrix.categories[category] !== undefined;\n}\n\n/**\n * Why a custom skill was dropped, and which file places it.\n *\n * The categories on offer are deliberately not listed: they are the whole\n * catalogue's, and a refusal that prints a hundred names is one nobody reads.\n * Whatever the user picked the category in renders them already.\n */\nfunction undeclaredCategoryRefusal(\n metadata: ExtractedSkillMetadata,\n category: CategoryPath,\n): string {\n const metadataPath = path.join(metadata.path, STANDARD_FILES.METADATA_YAML);\n return (\n `Skipping local skill '${metadata.id}': ${METADATA_KEYS.CATEGORY} '${category}' is not one this ` +\n `installation declares, so the skill belongs in no grid tab and can be given to no sub-agent. ` +\n `Set ${METADATA_KEYS.CATEGORY} in ${metadataPath} to a category that already exists — a skill ` +\n `is placed in the taxonomy, it does not extend it.`\n );\n}\n\nexport function mergeLocalSkillsIntoMatrix(\n matrix: MergedSkillsMatrix,\n localResult: LocalSkillDiscoveryResult,\n): MergedSkillsMatrix {\n for (const metadata of localResult.skills) {\n const existingSkill = matrix.skills[metadata.id];\n\n // If overwriting an existing remote skill, inherit its category unconditionally.\n // Otherwise, use whatever the local skill declared in its metadata.yaml.\n const category = existingSkill?.category ?? metadata.category;\n\n // A custom skill is PLACED in the taxonomy — its category is picked from the\n // ones that exist, never invented — so one naming a category nothing declares\n // means no pick happened. Synthesizing a definition for it is what let a\n // fabricated category read as a real placement while the skill sat in a tab\n // nothing draws. Local skills that claim no `custom` flag keep the old\n // behaviour below; narrowing that is matrix hygiene, not this rule.\n if (metadata.custom === true && !declaresCategory(matrix, category)) {\n warn(undeclaredCategoryRefusal(metadata, category));\n continue;\n }\n\n const resolvedSkill = toLocalResolvedSkill(metadata, existingSkill, category);\n matrix.skills[metadata.id] = resolvedSkill;\n\n // Completes the map over the matrix this merge is building: the skill went\n // into `matrix.skills` and the slug map stayed as the source left it, so every\n // slug a user had written themselves resolved to nothing.\n claimSlug(matrix.slugMap, resolvedSkill.slug, metadata.id);\n\n ensureCategoryDefined(matrix, category, metadata.domain);\n\n verbose(`Added local skill: ${metadata.id} (category: ${category})`);\n }\n\n return matrix;\n}\n\n/**\n * A local skill as the matrix holds it. One that overrides a skill the source already carries\n * inherits that skill's slug, display name and relationships; one new to the matrix takes its\n * slug and display name from its own metadata and relates to nothing. The category arrives\n * already resolved, because the caller needs it first to refuse a custom skill placed nowhere.\n */\nfunction toLocalResolvedSkill(\n metadata: ExtractedSkillMetadata,\n existingSkill: ResolvedSkill | undefined,\n category: CategoryPath,\n): ResolvedSkill {\n return {\n id: metadata.id,\n slug: existingSkill?.slug ?? metadata.slug,\n displayName: existingSkill?.displayName ?? metadata.displayName,\n description: metadata.description,\n ...(metadata.activationDescription !== undefined && {\n activationDescription: metadata.activationDescription,\n }),\n ...(metadata.usageGuidance !== undefined && { usageGuidance: metadata.usageGuidance }),\n\n category,\n\n author: LOCAL_DEFAULTS.AUTHOR,\n\n conflictsWith: existingSkill?.conflictsWith ?? [],\n requires: existingSkill?.requires ?? [],\n alternatives: existingSkill?.alternatives ?? [],\n discourages: existingSkill?.discourages ?? [],\n\n path: metadata.path,\n\n local: true,\n ...(metadata.localPath !== undefined && { localPath: metadata.localPath }),\n ...(metadata.custom !== undefined && { custom: metadata.custom }),\n };\n}\n\n/**\n * Gives a local skill's category a definition in the matrix when it has none, so config-types\n * generation can discover its domain and category. Unlike the custom-skill refusal above, this\n * never judges the category: a non-custom local skill may name one nothing declares, and gets a\n * synthesized definition here.\n */\nfunction ensureCategoryDefined(\n matrix: MergedSkillsMatrix,\n category: CategoryPath,\n domain: Domain,\n): void {\n // `local` is a pseudo-category, not a real Category union member, so it is never defined.\n if (category === LOCAL_PSEUDO_CATEGORY) return;\n if (matrix.categories[category]) return;\n\n matrix.categories[category] = {\n id: category,\n displayName: category,\n description: `Local skill category`,\n domain,\n exclusive: false,\n order: 0,\n };\n verbose(`Added local category: ${category} (domain: ${domain})`);\n}\n","import fs from \"fs\";\nimport os from \"os\";\n\n/**\n * True when `dir` is the user's home directory — the global installation root.\n *\n * Symlink-safe: compares via `fs.realpathSync` so a symlinked $HOME (common on\n * macOS) still matches. Falls back to a plain string compare when either path\n * cannot be resolved (e.g. does not exist yet). Calls `os.homedir()` at runtime,\n * as every home-dir reader in the codebase now does, so it agrees with test\n * home-dir mocks.\n */\nexport function isHomeDirectory(dir: string): boolean {\n try {\n return fs.realpathSync(dir) === fs.realpathSync(os.homedir());\n } catch {\n return dir === os.homedir();\n }\n}\n","import { STANDARD_FILES, STANDARD_DIRS } from \"../consts\";\n\n/**\n * YAML field names used in skill metadata.yaml files.\n * Centralized to avoid string duplication across loaders and compilers.\n */\nexport const METADATA_KEYS = {\n DISPLAY_NAME: \"displayName\",\n CLI_DESCRIPTION: \"cliDescription\",\n CATEGORY: \"category\",\n FORKED_FROM: \"forkedFrom\",\n CONTENT_HASH: \"contentHash\",\n USAGE_GUIDANCE: \"usageGuidance\",\n CUSTOM: \"custom\",\n} as const;\n\n/**\n * What a skill discovered on disk is attributed to.\n *\n * Forced rather than defaulted: the merge writes it over whatever the file says,\n * because a local skill answers to the machine it sits on and not to a handle.\n *\n * It used to have a `CATEGORY` and a `DOMAIN` beside it — `dummy-category` and\n * `dummy`, a taxonomy in no union, placing a skill in a tab nothing draws and a\n * stack no sub-agent reads. They were scaffold placeholders for `new skill` and\n * `import skill`, and both commands were deleted; nothing has read either since.\n */\nexport const LOCAL_DEFAULTS = {\n AUTHOR: \"@dummy-author\",\n} as const;\n\n/**\n * Files included when computing a skill's content hash.\n * Shared by versioning.ts (for plugin version bumps) and\n * skill-plugin-compiler.ts (for plugin compilation).\n */\nexport const SKILL_CONTENT_FILES = [STANDARD_FILES.SKILL_MD, STANDARD_FILES.REFERENCE_MD] as const;\n\n/**\n * Directories included when computing a skill's content hash.\n * Shared by versioning.ts and skill-plugin-compiler.ts.\n */\nexport const SKILL_CONTENT_DIRS = [STANDARD_DIRS.EXAMPLES, STANDARD_DIRS.SCRIPTS] as const;\n","/*\n * `no-control-regex` bans exactly the characters the five patterns below exist to match, and it is\n * right everywhere else in this package — a control character in a regex is almost always someone\n * pasting a byte they did not mean to. The rule takes no options, so there is no `^_`-style escape\n * hatch to reach for: matching a control character deliberately and matching one by accident are\n * the same expression to it.\n *\n * Kept INLINE rather than moved into `eslint.config.js`, which is the opposite of the usual call\n * and is the point of the row this came from. An override would permit control-character regexes\n * anywhere in the package, and what makes this a sanitiser rather than a patch per site is that\n * there is one of it. The next such regex SHOULD be reported, and this disable is what leaves the\n * rule able to report it.\n */\n/* eslint-disable no-control-regex */\n\n/**\n * An operating-system command — window title, hyperlink, clipboard write — and the payload it\n * carries. BEL and ST (`ESC \\`) are the two terminators a terminal takes; end-of-input is the\n * third alternative here because a terminal reading an UNTERMINATED one swallows everything after\n * it waiting for a terminator that never arrives. A tail left behind is a tail nobody would see.\n */\nconst OSC = /\\u001B\\][\\s\\S]*?(?:\\u0007|\\u001B\\\\|$)/;\n\n/**\n * A control sequence: cursor movement, erase-line, scroll region, colour. Parameter bytes, then\n * intermediate bytes, then a final byte — and the final byte is OPTIONAL so that a sequence left\n * incomplete is removed too. A terminal holds a fragment open and reads whatever follows as its\n * parameters, which makes half a sequence worse than a whole one rather than safer.\n */\nconst CSI = /\\u001B\\[[0-?]*[ -/]*[@-~]?/;\n\n/**\n * Every other escape — charset selection, `ESC c` full reset — and a bare one at the end of the\n * text. `.` deliberately does not match a newline, so `ESC` before a line break costs the escape\n * and not the break.\n */\nconst OTHER_ESCAPE = /\\u001B.?/;\n\n/** The same introducers as single 8-bit bytes, which some terminals honour, and the rest of C1. */\nconst C1 = /[\\u0080-\\u009F]/;\n\n/**\n * The C0 controls and DEL, less the only two that appear in text a person wrote: tab and\n * newline. Everything else in the range either moves the cursor (carriage return,\n * backspace, vertical tab, form feed) or is a protocol byte, and none of them belong in prose.\n *\n * Carriage return is the one worth naming, because it is half of the reproduction this exists\n * for: on its own it returns the cursor to column zero and lets what follows overwrite the line\n * the CLI just printed in its own voice. Dropping it also turns a `CRLF` body into a `LF` one,\n * which is the right answer twice over — the line break survives and the cursor move does not.\n */\nconst C0 = /[\\u0000-\\u0008\\u000B-\\u001F\\u007F]/;\n\n/* eslint-enable no-control-regex */\n\n/**\n * One pattern matching whichever of the constructs above comes first at each position.\n *\n * Global, because the point is to remove every occurrence rather than to find one. Safe to hold at\n * module scope despite that flag: `String.prototype.replace` resets `lastIndex` on a global regex,\n * and nothing here calls `test` or `exec`, which are the two that would carry state between calls.\n */\nfunction anyOf(patterns: RegExp[]): RegExp {\n return new RegExp(patterns.map((pattern) => pattern.source).join(\"|\"), \"g\");\n}\n\n/**\n * Ordered longest-construct-first, which is load-bearing rather than tidy: alternation is tried\n * left to right at each position, so {@link OTHER_ESCAPE} listed before {@link CSI} would eat the\n * `[` and leave the parameters behind as text.\n */\nconst TERMINAL_CONTROLS = anyOf([OSC, CSI, OTHER_ESCAPE, C1, C0]);\n\n/**\n * Text a terminal will PRINT, out of text it would otherwise OBEY.\n *\n * For anything this CLI did not author: a body off the wire, whatever arrived on stdin, and the\n * metadata in a skills repository somebody else wrote — which is the reachable one, because\n * `--marketplace` is a supported input rather than an attack. A short body carrying `ESC[2K` and\n * a carriage return repaints the line the CLI printed above it, so a store's refusal can forge a\n * sentence in the CLI's own voice, and nothing here stripped it.\n *\n * It reproduces the terminal's OWN parse rather than the sentence a reader sees, so what goes is\n * every byte a terminal would have swallowed as part of a sequence — not the escape characters\n * alone. {@link CSI} consumes an unbounded run of printable parameter and intermediate bytes after\n * `ESC[`, and an unterminated {@link OSC} runs to the end of the input, both of which a terminal\n * would have consumed identically. Printable text lost that way was never going to be printed.\n *\n * What it does not do is edit prose. A forged sentence carrying no controls survives whole, which\n * is the whole point — deciding what a store is allowed to SAY is not this function's business, and\n * a sanitiser that rewrote wording would be unreadable the first time an honest body tripped it.\n *\n * Newline and tab survive, and that direction of error is the one worth guarding: a multi-line\n * zod message is what the store really writes on the share route, and a sanitiser strict enough\n * to flatten it mangles every honest refusal to stop a rare hostile one. This is the CLI half of\n * a threat the editor settled by rendering the same foreign text through a React-escaped `<pre>`.\n */\nexport function stripTerminalControls(text: string): string {\n return text.replace(TERMINAL_CONTROLS, \"\");\n}\n\n/**\n * Foreign text, made inert and then bounded — in that order, which is the part that matters.\n *\n * Stripping FIRST is a correctness requirement, not a preference. A cut taken first can land\n * inside an escape sequence, and what it leaves is a fragment a terminal holds open, reading the\n * ellipsis and whatever the caller prints next as the sequence's missing parameters. The order is\n * owned here rather than left to callers precisely because there is a wrong way round to do it.\n *\n * It also decides what the budget buys. Escape bytes are invisible, so a budget spent on them\n * buys a reader nothing; measured after the strip, every character it allows is one somebody can\n * actually read.\n *\n * Every call site is text this CLI did not write — a refusal off the wire, an excerpt of stdin, a\n * rule author's `reason`, a catalogue description — so the strip belongs to the function they all\n * already call rather than to each of them separately. Where foreign text needs no bound,\n * {@link stripTerminalControls} is the same guarantee on its own.\n */\nexport function truncateText(text: string, maxLength: number): string {\n const inert = stripTerminalControls(text);\n if (inert.length <= maxLength) return inert;\n return inert.slice(0, maxLength - 1) + \"\\u2026\";\n}\n\n/**\n * A count and its noun, the noun pluralised unless the count is one — `1 skill`, `0 skills`,\n * `2 skill plugins`. The noun is given in the singular and takes a plain `s`, which every noun a\n * count line here counts in does.\n */\nexport function plural(count: number, noun: string): string {\n return `${count} ${noun}${count === 1 ? \"\" : \"s\"}`;\n}\n\n/** Converts a kebab-case string to a space-separated Title Case string. */\nexport function toTitleCase(kebabCase: string): string {\n return kebabCase\n .split(\"-\")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \");\n}\n\n/**\n * Locale-free string ordering for anything emitted into a file somebody commits.\n *\n * Declared in `@workspace/compile` because the emitters moved there — `generateStackAgentConfig`\n * orders a config-types.ts property list with it — and re-exported here so no CLI call site\n * moved. The reason it is not `localeCompare` lives with the declaration.\n */\nexport { bytewise } from \"@workspace/compile\";\n","import { stripTerminalControls } from \"./string\";\n\n/**\n * Extract a human-readable message from an unknown error value.\n *\n * Human-readable is the whole reason the sanitising is here: every caller of this is on its way to\n * a terminal, so this is the last point at which the text is still a value rather than output.\n *\n * The message is treated as foreign because it usually is, which is the part that is easy to get\n * backwards. The `Error` was constructed by Node or by a library, so it LOOKS like the CLI's own\n * text — but a parser writes the input that broke it into the message it throws. `JSON.parse`\n * answers `Unexpected token '<ESC>', \"{\"a\":<ESC>[2K}\" is not valid JSON`, quoting the bytes\n * verbatim, and those bytes came from a marketplace's `metadata.yaml`, a plugin manifest or a\n * pipe. Provenance follows the input, not the object.\n *\n * Newlines survive, so a multi-line message stays multi-line — see `stripTerminalControls`.\n */\nexport function getErrorMessage(error: unknown): string {\n return stripTerminalControls(error instanceof Error ? error.message : String(error));\n}\n","import fs from \"fs-extra\";\nimport fg from \"fast-glob\";\nimport os from \"os\";\nimport path from \"path\";\nimport { LEGACY_SOURCE_DIR, PROVIDERS, STANDARD_FILES } from \"../consts\";\nimport { sourceDir } from \"../lib/installation/install-layout.js\";\n// The gate's private token module, imported here by exception (eslint records\n// it): this file is the write choke point every pair write funnels through, and\n// `gate-token.ts` is a dependency-free leaf, so the import cannot cycle.\nimport { assertGateToken } from \"../lib/config-gate/gate-token.js\";\n\n/**\n * True when `child` resolves to `parent` or inside it. Purely lexical\n * (no symlink resolution) — the caller decides throw-vs-warn policy.\n */\nexport function isPathWithin(child: string, parent: string): boolean {\n const resolvedChild = path.resolve(child);\n const resolvedParent = path.resolve(parent);\n return resolvedChild === resolvedParent || resolvedChild.startsWith(resolvedParent + path.sep);\n}\n\nexport async function readFile(filePath: string): Promise<string> {\n return fs.readFile(filePath, \"utf-8\");\n}\n\n/**\n * Reads a file with a size limit check before reading content.\n * Throws if the file exceeds maxSizeBytes. Prevents DoS from oversized files.\n */\nexport async function readFileSafe(filePath: string, maxSizeBytes: number): Promise<string> {\n const stats = await fs.stat(filePath);\n if (stats.size > maxSizeBytes) {\n throw new Error(\n `File too large: '${filePath}' is ${stats.size} bytes (limit: ${maxSizeBytes} bytes)`,\n );\n }\n return fs.readFile(filePath, \"utf-8\");\n}\n\nexport async function readFileOptional(filePath: string, fallback = \"\"): Promise<string> {\n try {\n return await fs.readFile(filePath, \"utf-8\");\n } catch {\n return fallback;\n }\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n return fs.pathExists(filePath);\n}\n\nexport async function directoryExists(dirPath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(dirPath);\n return stat.isDirectory();\n } catch {\n return false;\n }\n}\n\nexport async function listDirectories(dirPath: string): Promise<string[]> {\n try {\n const entries = await fs.readdir(dirPath, { withFileTypes: true });\n return entries.filter((e) => e.isDirectory()).map((e) => e.name);\n } catch {\n return [];\n }\n}\n\n/**\n * @param dot Include files and directories whose name starts with a dot. Off by default, which\n * is what a scan LOOKING for something wants; a read that has to reproduce a directory\n * faithfully wants it on, since a file the read skips is one the copy silently loses.\n */\nexport async function glob(\n pattern: string,\n cwd: string,\n { dot = false }: { dot?: boolean } = {},\n): Promise<string[]> {\n return fg(pattern, { cwd, onlyFiles: true, dot });\n}\n\n/** The two files the gate owns, wherever a global pair sits. */\nconst PAIR_HALVES = [STANDARD_FILES.CONFIG_TS, STANDARD_FILES.CONFIG_TYPES_TS];\n\n/**\n * Every folder a GLOBAL config pair can sit in: the one every pre-rename installation carries,\n * and one per provider under the new root.\n *\n * All of them, rather than the one this home is on, because the guard has to hold against the\n * write it did not expect. A tripwire that knew only the folder in use would let a write into any\n * other one through with nothing failing anywhere — and the gate's static layers cannot see that\n * at all, since a write that simply lands somewhere they were not told about satisfies every one\n * of them.\n */\nfunction globalPairFolders(): string[] {\n const home = os.homedir();\n return [\n path.join(home, LEGACY_SOURCE_DIR),\n ...PROVIDERS.map((provider) => sourceDir(home, provider)),\n ];\n}\n\n/** Every path either half of the global pair can have. */\nfunction everyGlobalPairPath(): string[] {\n return globalPairFolders().flatMap((folder) =>\n PAIR_HALVES.map((half) => path.join(folder, half)),\n );\n}\n\n/**\n * True when `resolvedPath` is one of the two halves of the global config pair.\n *\n * Compares resolved paths rather than matching on the filename, so it holds\n * against every way of naming the same file — a concatenated path, a relative\n * one, a fragment assembled at runtime — which is exactly what a static check\n * cannot do.\n */\nfunction isGlobalPairPath(resolvedPath: string): boolean {\n return everyGlobalPairPath().includes(resolvedPath);\n}\n\nexport async function writeFile(filePath: string, content: string): Promise<void> {\n // Runtime tripwire: every write in the CLI funnels through here, so a pair\n // write attempted without the gate's token dies at its first execution\n // whatever route it took to get here. Costs one path compare per write.\n const resolvedPath = path.resolve(filePath);\n if (isGlobalPairPath(resolvedPath)) assertGateToken(resolvedPath);\n\n await fs.ensureDir(path.dirname(filePath));\n await fs.writeFile(filePath, content, \"utf-8\");\n}\n\nexport async function ensureDir(dirPath: string): Promise<void> {\n await fs.ensureDir(dirPath);\n}\n\nexport async function remove(filePath: string): Promise<void> {\n await fs.remove(filePath);\n}\n\n/**\n * True when `dirPath` holds nothing, and true when it cannot be read at all —\n * an absent directory holds nothing either. Both callers ask the same question\n * of a directory they are about to write into or remove.\n */\nexport async function isDirectoryEmpty(dirPath: string): Promise<boolean> {\n try {\n const entries = await fs.readdir(dirPath);\n return entries.length === 0;\n } catch {\n return true;\n }\n}\n\n/**\n * Removes `dir` when it exists and holds nothing; true when it was removed.\n *\n * A scope directory (`.claude/skills/`, `.claude/agents/`) is an artefact of\n * what it holds, so the removal that empties it takes it too. Emptiness here is\n * FILESYSTEM emptiness and never roster emptiness — a hand-authored agent or any\n * other user-owned file keeps its directory alive, whatever a config says.\n */\nexport async function removeDirIfEmpty(dir: string): Promise<boolean> {\n if (!(await directoryExists(dir))) return false;\n if (!(await isDirectoryEmpty(dir))) return false;\n await remove(dir);\n return true;\n}\n\n/**\n * Copies a tree into an installation, and makes what it wrote writable by its new owner.\n *\n * **`eject` means the user owns the copy**, so the copy has to be editable however the SOURCE\n * happened to be stored. `fs-extra` preserves mode, and nothing normalised it: a marketplace on a\n * read-only mount, in a Nix store path, or written under a restrictive umask produced skills the\n * user could not subsequently edit — and the failure did not surface at the install. It surfaced\n * later, at an unrelated `edit` or mode switch, as `EACCES` on a file the user never made\n * read-only. Every caller of this function is an install or an eject, so every destination is the\n * user's.\n *\n * The owner's write bit is ADDED rather than the mode replaced. A skill may legitimately ship an\n * executable script, and flattening to `644` would break it on the way in — the destination should\n * differ from the source in exactly one respect, which is that its owner can write it.\n *\n * Directories take the same bit for the same reason: a read-only directory refuses a file added\n * beside the copy, which is what an eject-then-edit does next.\n */\nexport async function copy(src: string, dest: string): Promise<void> {\n await fs.copy(src, dest);\n await grantOwnerWrite(dest);\n}\n\nconst OWNER_WRITE = 0o200;\n\nasync function grantOwnerWrite(target: string): Promise<void> {\n const entry = await fs.stat(target);\n await fs.chmod(target, entry.mode | OWNER_WRITE);\n\n if (!entry.isDirectory()) return;\n\n const children = await fs.readdir(target);\n await Promise.all(children.map((child) => grantOwnerWrite(path.join(target, child))));\n}\n","import fs from \"fs\";\nimport os from \"os\";\nimport path from \"path\";\n\nimport {\n compilesForCodex,\n hasCodexRoleMarker,\n hasProvenanceMarker,\n} from \"@workspace/compile/agent-source\";\n\nimport {\n CLAUDE_DIR,\n LEGACY_SOURCE_DIR,\n PLUGINS_SUBDIR,\n PROVIDERS,\n SOURCE_ROOT_DIR,\n sourceDirName,\n STANDARD_DIRS,\n STANDARD_FILES,\n type Provider,\n} from \"../../consts.js\";\nimport type { AgentName } from \"../../types/agents.js\";\nimport type { SkillScope } from \"../../types/config.js\";\n\n/**\n * Which folder a scope keeps its agents-inc source in, and how to build a path under it.\n *\n * A new installation is created in `.agents-inc/<provider>/` at both scopes. An installation made\n * before that flip keeps `.claude-src/`, is read there and written there indefinitely, and moves\n * only when a user moves it by hand — there is no command that moves one. So the two answers here\n * have converged and differ in nothing today:\n *\n * - {@link resolveSourceDir} says which layout a scope is ON, which is what doctor's Layout row\n * and the rival-folder refusal each need.\n * - {@link sourceFolderInUse} says which folder this release reads from and writes to, which is\n * where every path the CLI builds under a source folder comes from.\n *\n * They are kept as two names because they answer two questions, and a provider whose folders both\n * exist is answered differently by each.\n *\n * It is also where the HOST roles live — `userConfigRoot`, `agentsDir`, `skillsDir` and the rest\n * of the group under {@link installBaseDir} below — rather than in a second funnel beside it. A\n * source folder and a host directory are one question asked twice: both answer \"where does this\n * installation put things\", and both have to answer it per provider.\n */\n\n/** Which of a scope's two possible source folders is read, and what else is on disk beside it. */\nexport type SourceFolder = {\n /** Absolute path of the folder. */\n dir: string;\n /** The same folder as a user writes it: `.agents-inc/claude`, or `.claude-src`. */\n relName: string;\n /** Whether it is the name every installation made before the rename carries. */\n legacy: boolean;\n /**\n * Whether this provider's new folder and the folder it replaces are BOTH on disk.\n *\n * Provider-scoped, not \"the root holds two folders\": the legacy name belonged to Claude, so a\n * `.claude-src/` beside a Codex installation is a second installation rather than a rival half\n * of this one, and refusing a Codex write on account of it would refuse the one arrangement the\n * ruling explicitly allows.\n */\n both: boolean;\n};\n\n/**\n * A scope's two possible source folders for one provider: the legacy one, the current one, and\n * the parent the current one sits in.\n *\n * `null` for a provider that never had a legacy folder — the name being retired is Claude's, so a\n * Codex installation has only ever had one folder and no sentence about two applies to it.\n *\n * Both ends are named as a user writes them as well as resolved, because every sentence about the\n * layout names both folders and is read by someone looking at their own disk. Moving a folder\n * from `from` to `to` is a thing the USER does by hand; nothing in this CLI moves one.\n */\nexport type SourceFolderMove = {\n /** The legacy folder: where a pre-rename installation's source is. */\n from: SourceFolderEnd;\n /** The provider folder under the new root: where this release creates one. */\n to: SourceFolderEnd;\n /** The `.agents-inc/` parent `to` sits in, which a manual move has to create. */\n parent: SourceRoot;\n};\n\n/** One end of a move: the absolute directory, and the relative name a message uses. */\nexport type SourceFolderEnd = {\n dir: string;\n relName: string;\n};\n\n/**\n * Every folder name under `.agents-inc/` that belongs to this product, in roster order.\n *\n * The one caller is the `.gitignore` remedy, which has to name all of them: a rule narrowed to the\n * provider a user happens to be on today hides the other one the day they install it, and the\n * whole point of that message is that the user does not meet this again.\n */\nexport function everySourceFolderName(): string[] {\n return PROVIDERS.map(sourceDirName);\n}\n\n/** `provider`'s two folder names under `root`, whatever is actually on disk. */\nexport function plannedSourceFolderMove(root: string, provider: Provider): SourceFolderMove | null {\n const legacy = legacyFolderFor(root, provider);\n if (legacy === null) return null;\n\n return {\n from: { dir: legacy, relName: LEGACY_SOURCE_DIR },\n to: { dir: sourceDir(root, provider), relName: sourceDirName(provider) },\n parent: { dir: path.join(root, SOURCE_ROOT_DIR), relName: SOURCE_ROOT_DIR },\n };\n}\n\n/**\n * The folder this scope is NOT on, as a compiled agent's own prompt would spell it.\n *\n * An installed `agent-summoner` carries an instruction about where to author new sub-agents, and\n * a copy compiled under the other layout aims that instruction at a folder this installation does\n * not read — so the files it writes never compile and nothing reports it. This is the string that\n * finding looks for. `null` where the provider has only one folder it could ever be on.\n */\nexport function unusedSourceFolderName(root: string, provider: Provider): string | null {\n const move = plannedSourceFolderMove(root, provider);\n if (move === null) return null;\n return sourceFolderInUse(root, provider).legacy ? move.to.relName : move.from.relName;\n}\n\n/** The folder a provider's source lives in under `root`, whether or not anything is there. */\nexport function sourceDir(root: string, provider: Provider): string {\n return path.join(root, SOURCE_ROOT_DIR, provider);\n}\n\n/** The parent a scope's provider folders sit under: where it is, and how a message names it. */\nexport type SourceRoot = {\n /** Absolute path of the parent. */\n dir: string;\n /** The same folder as a user writes it: `.agents-inc`. */\n relName: string;\n};\n\n/**\n * The `.agents-inc/` parent of the folder `provider` is read from under `root`, or `null` for a\n * scope still on the legacy name.\n *\n * `null` rather than a path, because `.claude-src/` has no parent belonging to this product: its\n * parent is the scope root, and a caller that removed THAT would take a user's project with it.\n * So the one caller that acts on this — uninstall's cleanup, which removes the parent once the\n * last provider folder under it is gone — cannot reach the destructive case at all.\n */\nexport function sourceRootOf(root: string, provider: Provider): SourceRoot | null {\n if (sourceFolderInUse(root, provider).legacy) return null;\n return { dir: path.join(root, SOURCE_ROOT_DIR), relName: SOURCE_ROOT_DIR };\n}\n\n/**\n * The provider a run creates an installation under when the root holds none.\n *\n * It is the ONE place this package still names a provider without reading one, and it is a\n * parameter of the run rather than a property of the disk: `init --from <id> --provider codex` is\n * what changes it, through {@link chooseProviderForThisRun}. So a root with nothing installed and\n * a run that was told nothing gets Claude, which is what every such root got before the flag\n * existed.\n *\n * It is deliberately not a default parameter on {@link sourceFolderInUse} and the rest, which is\n * what `DEFAULT_PROVIDER` was until C2. A default is invisible at every call site; this is\n * reachable only through {@link providerInUse}, whose name says the answer was read.\n */\nconst PROVIDER_OF_A_NEW_INSTALLATION: Provider = \"claude\";\n\n/**\n * The provider `--provider` named for THIS RUN, and nothing when no flag was given.\n *\n * **It is a location parameter of one invocation, which is why it is process state rather than an\n * argument.** The alternative was threading a provider through every path builder, and the shape\n * that would take is this census, run in `packages/cli`:\n *\n * ```\n * grep -rn \"providerInUse(\" src --include='*.ts' --include='*.tsx' \\\n * | grep -v \"__tests__\\|\\.test\\.\" | grep -v \"install-layout.ts:\"\n * ```\n *\n * They sit in `config-gate/`, `configuration/`, `loading/`, `compiler.ts` and six commands, and\n * the ones that decide where a write LANDS are reached from inside `writeScopedFromWizard` and\n * `propagateGlobalChangesToProjects` rather than from a command. A parameter that stops at the\n * first module boundary is worse than none: it reads as threaded at every call site it reaches\n * and answers off the disk everywhere after it, which is the half-routed write this funnel exists\n * against.\n *\n * `setVerbose` in `utils/logger.ts` is the same shape and the precedent — a flag of the run, held\n * where every layer below the command can see it, in a process that runs exactly one command.\n *\n * **It is set before anything reads a path and never after.** A run that chose a provider\n * mid-flight would have already resolved some paths off the disk, which is how two answers to one\n * question get into one installation.\n */\nlet providerChosenForThisRun: Provider | undefined;\n\n/**\n * Names the provider this run is about, ahead of whatever the disk says.\n *\n * Two commands' worth of reasons, and neither is served by reading the folder:\n *\n * - `init --from <id> --provider codex` creates a folder that does not exist yet, so there is no\n * disk to read. This is the case D15 makes the flag's whole purpose.\n * - `edit`, `uninstall`, `share` and `eject` in a scope holding BOTH folders: the disk has two\n * answers, `providerInUse` resolves them by roster order, and a command that acted on the\n * roster's first answer would act on a user's other installation with nothing on screen saying\n * so. Those commands refuse instead, and this is what the flag they name does.\n */\nexport function chooseProviderForThisRun(provider: Provider): void {\n providerChosenForThisRun = provider;\n}\n\n/**\n * Drops the choice, for a test process that outlives one run.\n *\n * Production never calls it: a CLI process runs one command and exits. A spec that set a choice\n * and did not clear it would leak it into every later spec in the same worker, which is the one\n * failure mode process state has that an argument does not.\n */\nexport function forgetTheProviderChosenForThisRun(): void {\n providerChosenForThisRun = undefined;\n}\n\n/**\n * Which provider's installation a run over `root` is about, read off the folder.\n *\n * The folder is the only record of a provider — there is no field in `config.ts` and nothing in\n * a shared payload carries one — so this is the whole of \"the provider is derivable after the\n * install\", for every caller that holds a directory and nothing else. It is also the ONE function\n * that answers it: `providerAt` asked the same question on rungs of its own until C2, answering\n * `[]` for every pre-rename machine and giving a bare `mkdir` equal standing with a live\n * installation, and the list a caller needs in order to see that a root holds two is\n * `detectInstallations`, which carries the scope and the config path with it.\n *\n * The rungs are {@link sourceFolderOnDisk}'s, asked across providers instead of across names: an\n * installation that holds a `config.ts` wins over one that merely holds a folder, because a\n * half-built or abandoned folder beside a live installation must not take the run away from it.\n * An EMPTY folder is on no rung at all, so `mkdir -p .agents-inc/codex` decides nothing.\n *\n * `undefined` is a caller that is rendering for NO installation — the compile engine built over\n * no project is the one — and gets the provider a new installation is created under, because\n * there is no disk to read.\n *\n * **A root holding a live installation of EACH provider is answered by roster order**, which is\n * Claude. That is a known limit rather than a reading of the disk: `--provider` is what picks one\n * on a greenfield install, and `detectInstallations` is what a caller uses to see that there are\n * two.\n *\n * **It refused a Codex answer by name until C4, and no longer does.** `refuseAProviderWithNoHost`\n * and the `PROVIDERS_WITH_A_HOST` roster beside it existed for the window in which the folder\n * could say `codex` and every path built under that answer was Claude's — `compile` reading\n * `.agents-inc/codex/` and writing `.md` sub-agents into `.claude/agents/`, with nothing able to\n * report it. C4 closed that window by building the host rather than by widening the roster, which\n * is why both are deleted rather than edited: a roster naming one provider and a `PROVIDERS` list\n * naming two is a disagreement waiting to be resolved in the wrong direction.\n *\n * **`--provider` beats the disk, and only where a run was given one.** The flag is the answer to\n * the two questions the folder cannot answer — a greenfield install has no folder, and a scope\n * holding two has two — so a run that was told one is about that provider at every root it\n * touches. Nothing else changes: which FOLDER that provider is read from is still\n * {@link sourceFolderInUse}'s ladder, so a pre-rename `.claude-src/` is still found by a run that\n * named `claude` out loud. See {@link chooseProviderForThisRun}.\n */\nexport function providerInUse(root: string | undefined): Provider {\n if (providerChosenForThisRun !== undefined) return providerChosenForThisRun;\n if (root === undefined) return PROVIDER_OF_A_NEW_INSTALLATION;\n return providerOnDisk(root);\n}\n\n/** The rung ladder: a live installation first, a started folder next, the new-installation default last. */\nfunction providerOnDisk(root: string): Provider {\n // Rung by rung rather than both at once: each predicate probes the disk, and the second rung's\n // answer is never needed when the first one has a live installation to name.\n const live = PROVIDERS.find((provider) => holdsAnInstallation(root, provider));\n if (live !== undefined) return live;\n\n const started = PROVIDERS.find((provider) => holdsASourceFolder(root, provider));\n return started ?? PROVIDER_OF_A_NEW_INSTALLATION;\n}\n\n/** Whether `provider`'s source folder under `root` holds a config — a live installation. */\nfunction holdsAnInstallation(root: string, provider: Provider): boolean {\n return holdsAConfig(sourceFolderInUse(root, provider).dir);\n}\n\n/** Whether `provider` has a source folder under `root` at all, config or not. */\nfunction holdsASourceFolder(root: string, provider: Provider): boolean {\n return sourceFolderOnDisk(root, provider) !== null;\n}\n\n/**\n * Which folder `provider`'s source is read from under `root`, and the state of the two names\n * beside it. A scope with neither folder is named under the new layout.\n */\nexport function resolveSourceDir(root: string, provider: Provider): SourceFolder {\n return describeSourceFolder(\n sourceFolderOnDisk(root, provider) ?? sourceDir(root, provider),\n root,\n provider,\n );\n}\n\n/**\n * Which folder `provider`'s source is read from and written to under `root` — the answer every\n * path the CLI builds under a source folder comes from.\n *\n * @param provider is threaded, never defaulted. It carried `DEFAULT_PROVIDER` until C2, and\n * deleting that default is what turned the census into a compiler error apiece: a defaulted\n * provider lets a call site nobody visited go on answering `.agents-inc/claude/` for a Codex\n * run and exit 0, which is the half-routed state this module exists against. A caller holding\n * only a directory asks {@link providerInUse} for the answer rather than assuming one.\n */\nexport function sourceFolderInUse(root: string, provider: Provider): SourceFolder {\n return describeSourceFolder(\n sourceFolderOnDisk(root, provider) ?? newInstallationDir(root, provider),\n root,\n provider,\n );\n}\n\n/**\n * The config file as a user sees it written, relative to the scope root:\n * `.claude-src/config.ts`, or `.agents-inc/claude/config.ts`.\n *\n * One builder rather than one per command, because every message naming that file has to name the\n * folder this scope is ACTUALLY on. A message assembled from a constant tells a user on the old\n * name to edit a file that is not there — and the three commands that print it each used to hold\n * their own copy of the string.\n */\nexport function relativeConfigPath(root: string, provider: Provider): string {\n return `${sourceFolderInUse(root, provider).relName}/${STANDARD_FILES.CONFIG_TS}`;\n}\n\n/**\n * The source folder a compile writes into, as an agent's own prompt spells it, for a caller that\n * may not have an installation to name.\n *\n * `createLiquidEngine` is the caller and both of its states are real: an engine built over a\n * project names THAT project's folder, so a compiled agent tells an agent to author where this\n * install actually reads; an engine built over no project — every render that is not writing into\n * one — names the folder a new installation is created in.\n */\nexport function sourceFolderName(root: string | undefined, provider: Provider): string {\n if (root === undefined) return sourceDirName(provider);\n return sourceFolderInUse(root, provider).relName;\n}\n\n/**\n * The preference order, one rung per line, answering `null` when neither name is on disk.\n *\n * A config decides the winner before content does, so a legacy installation keeps being read while\n * an empty or half-built new folder sits beside it — which is what an interrupted migration leaves\n * behind, and taking a live config away from it would be the one unrecoverable outcome here.\n */\nfunction sourceFolderOnDisk(root: string, provider: Provider): string | null {\n const preferred = sourceDir(root, provider);\n const legacy = legacyFolderFor(root, provider);\n\n if (holdsAConfig(preferred)) return preferred;\n if (legacy !== null && holdsAConfig(legacy)) return legacy;\n if (holdsAnything(preferred)) return preferred;\n if (legacy !== null && directoryExists(legacy)) return legacy;\n return null;\n}\n\n/**\n * Where a scope holding no source folder at all gets one CREATED.\n *\n * Every provider now gets `.agents-inc/<provider>/`, Claude included — this function IS the flip,\n * and it is the whole of it: every production path under a source folder is built from\n * {@link sourceFolderInUse}, so one return decides them all.\n *\n * It says nothing about an installation that already exists. {@link sourceFolderOnDisk} answers\n * first and prefers whichever folder holds a config, so a scope on `.claude-src/` goes on being\n * read AND written where it is, indefinitely; nothing in this CLI moves one.\n */\nfunction newInstallationDir(root: string, provider: Provider): string {\n return sourceDir(root, provider);\n}\n\n/**\n * The legacy folder as a candidate for `provider`, which only Claude ever has.\n *\n * `null` for every other provider. Every rung that names the old folder comes through here — the\n * one preferring a legacy folder holding a `config.ts`, and the bare-folder rung under it — so a\n * provider that never had one cannot be sent to it by either.\n */\nfunction legacyFolderFor(root: string, provider: Provider): string | null {\n return provider === \"claude\" ? path.join(root, LEGACY_SOURCE_DIR) : null;\n}\n\nfunction describeSourceFolder(dir: string, root: string, provider: Provider): SourceFolder {\n const legacy = dir === legacyFolderFor(root, provider);\n\n return {\n dir,\n relName: legacy ? LEGACY_SOURCE_DIR : sourceDirName(provider),\n legacy,\n both: bothFoldersPresent(root, provider),\n };\n}\n\n/**\n * Whether this provider's new folder and the folder it replaces are both on disk AS RIVALS.\n *\n * The state the write commands refuse on: with two folders the preference order picks whichever\n * holds a `config.ts`, and that can be the stale one.\n */\nfunction bothFoldersPresent(root: string, provider: Provider): boolean {\n const legacyFolder = legacyFolderFor(root, provider);\n if (legacyFolder === null) return false;\n return directoryExists(sourceDir(root, provider)) && directoryExists(legacyFolder);\n}\n\n/**\n * Which directory a scope is rooted at: the user's home for `\"global\"`, the project otherwise.\n *\n * `os.homedir()` at call time rather than at module load, for the reason `globalInstallRoot`\n * writes out in `consts.ts` — a frozen copy answers from whichever home the first import saw, and\n * every later reader writes under a directory that has since been removed.\n *\n * It is declared here rather than in `install-base-dir.ts`, which re-exports it under the name its\n * ~20 callers already write: every host role below is rooted at this answer, and\n * `install-base-dir.ts` imports THIS module, so the layout cannot ask it back without a cycle.\n */\nexport function installBaseDir(projectDir: string, scope: SkillScope | undefined): string {\n return scope === \"global\" ? os.homedir() : projectDir;\n}\n\n/**\n * Where Codex keeps a user's state when `CODEX_HOME` names nowhere, and a project's own beside it.\n */\nconst CODEX_DIR = \".codex\";\n\n/**\n * The environment variable that relocates everything Codex keeps for a user.\n *\n * Exported for the one surface that has to agree with this read and cannot see it:\n * `e2e-runner-environment.test.ts` resolves the variable a bracket read names by IMPORTING the\n * constant, so renaming it moves what every spawn door must answer for and reddens them until\n * they follow. A value restated there would go on naming the old variable in silence.\n */\nexport const CODEX_HOME_VAR = \"CODEX_HOME\";\n\n/**\n * Where a Codex project's skills are committed, relative to the repository root.\n *\n * A Codex project skill is a file in the repository rather than an install: it reaches the model\n * in that repository and nowhere else, with no plugin, no marketplace and no trust entry. So this\n * names a directory a user commits, which is why it is not under `.codex/` with the rest of a\n * project's Codex state.\n */\nconst CODEX_PROJECT_SKILLS_PATH = \".agents/skills\";\n\n/** Codex's single configuration file: marketplaces, plugin switches, trust and hooks alike. */\nconst CODEX_CONFIG_FILE = \"config.toml\";\n\n/**\n * Claude Code's own state file — per-project records, the trust dialog's answer among them — in\n * the directory {@link claudeStateRoot} names. Only ever READ by this CLI.\n */\nconst CLAUDE_STATE_FILE = \".claude.json\";\n\n/**\n * The environment variable that moves Claude Code's state file out of the home directory.\n *\n * Exported for `e2e-runner-environment.test.ts`, which resolves the variable a bracket read names\n * by IMPORTING the constant — {@link CODEX_HOME_VAR}'s reason, one host over.\n */\nexport const CLAUDE_CONFIG_DIR_VAR = \"CLAUDE_CONFIG_DIR\";\n\n/**\n * The file the claude CLI records every plugin install in, inside a plugins directory.\n *\n * Exported because two surfaces have to agree on it and neither can read the other's copy: the\n * {@link pluginRegistry} role here, and `getInstalledPluginsRegistryPath` in\n * `lib/plugins/plugin-settings.ts`, which reads the registry back. That module imports this one\n * rather than the reverse — this file is the leaf, and `utils/fs.ts` already imports it.\n */\nexport const INSTALLED_PLUGINS_FILE = \"installed_plugins.json\";\n\n/**\n * Everything one (provider, scope) cell of an installation puts where the HOST reads it.\n *\n * Decided in one place, so two roles of one cell cannot disagree about the root they hang off.\n * `null` is a role this host does not have at this scope — a measured absence, never a path the\n * CLI would write and the host would ignore, which is the half-routed state this funnel exists\n * against.\n *\n * **`agentsDir` is NOT among them, and stopped being on 2026-09-21.** It carried `| null` for the\n * one cell that answered it — Codex at project scope — and that measurement was overturned, so the\n * union had no inhabitant left: an absence nothing can produce is a branch every call site writes\n * and no test can reach, which is this repository's own\n * `a-path-helper-that-names-one-layout-turns-every-absence-it-asserts-into-a-tautology`. Widening\n * it again is one character the day a host registers no sub-agents at a scope; the dead branch it\n * would otherwise license lands at every C5 call site first. A non-null answer still says only\n * where a role GOES — {@link codexProjectRoles} carries the condition under which the host reads\n * it — and this narrowing is a proposal the implementer or the owner may overturn.\n */\ntype HostRoles = {\n userConfigRoot: string;\n agentsDir: string;\n skillsDir: string;\n pluginsDir: string | null;\n pluginRegistry: string | null;\n permissionFiles: string[];\n};\n\n/**\n * One cell of the table, chosen by host and then by scope.\n *\n * The provider is a required argument on every role that reaches this, never a defaulted one. A\n * defaulted host would let a call site that was missed go on writing into `.claude/` and exit 0 —\n * the failure the whole funnel is written against — where a required one is a compiler error at\n * each site instead.\n */\nfunction hostRoles(provider: Provider, scope: SkillScope, projectDir: string): HostRoles {\n switch (provider) {\n case \"claude\":\n return claudeRoles(installBaseDir(projectDir, scope));\n case \"codex\":\n return scope === \"global\" ? codexGlobalRoles() : codexProjectRoles(projectDir);\n default: {\n const _exhaustive: never = provider;\n return _exhaustive;\n }\n }\n}\n\n/**\n * Claude, at either scope. The scope root is the whole of the difference between the two — a\n * global installation and a project one hold the same five things under their own `.claude/` —\n * which is why this table is written once where the Codex tables are written twice.\n */\nfunction claudeRoles(scopeRoot: string): HostRoles {\n const root = path.join(scopeRoot, CLAUDE_DIR);\n const plugins = path.join(root, PLUGINS_SUBDIR);\n\n return {\n userConfigRoot: root,\n agentsDir: path.join(root, STANDARD_DIRS.AGENTS),\n skillsDir: path.join(root, STANDARD_DIRS.SKILLS),\n pluginsDir: plugins,\n pluginRegistry: path.join(plugins, INSTALLED_PLUGINS_FILE),\n // Both spellings, because `lib/permission-checker.tsx` reads both: the settings file this CLI\n // writes, and the developer's own overlay beside it, which it never writes and must not miss.\n permissionFiles: [\n path.join(root, STANDARD_FILES.SETTINGS_JSON),\n path.join(root, STANDARD_FILES.SETTINGS_LOCAL_JSON),\n ],\n };\n}\n\n/**\n * Codex at global scope, hung off whichever root `$CODEX_HOME` names.\n *\n * `pluginRegistry` is `null` because Codex records installed plugins in its own `config.toml`\n * and writes no registry file anywhere — an absence, not a file this step has not found yet.\n */\nfunction codexGlobalRoles(): HostRoles {\n const root = codexUserRoot();\n\n return {\n userConfigRoot: root,\n agentsDir: path.join(root, STANDARD_DIRS.AGENTS),\n skillsDir: path.join(root, STANDARD_DIRS.SKILLS),\n pluginsDir: path.join(root, PLUGINS_SUBDIR),\n pluginRegistry: null,\n permissionFiles: [path.join(root, CODEX_CONFIG_FILE)],\n };\n}\n\n/**\n * Codex at project scope, where `agentsDir` is a path the HOST only reads under a condition and\n * two roles are `null`.\n *\n * **`agentsDir` IS a directory here, and this answer was `null` until 2026-09-21 on a measurement\n * that has since been overturned.** A role file at `<project-root>/.codex/agents/<anything>.toml`\n * DOES register on the pinned 0.155.1 — settled by a tie-break over 23 captured `codex exec` runs\n * after two lanes disagreed, with the instrument calibrated both ways (no role file → `agent_type`\n * absent from `spawn_agent`; a global role → present and named). No `.git` is needed and the cwd\n * may be a subdirectory. The role id is the file's `name` key rather than its filename, and the\n * file must carry `name`, `description` AND `developer_instructions` or it is dropped with a\n * startup warning.\n *\n * **THE CONDITION TRAVELS WITH THE PATH, because a role that only works when the user's global\n * config trusts this project is not the same as one that just works.** Registration requires\n * `[projects.\"<exact absolute path>\"] trust_level = \"trusted\"` in the GLOBAL\n * `$CODEX_HOME/config.toml`. Four kill switches were each measured, and each produces nothing with\n * NO warning anywhere: no `[projects]` entry at all; `trust_level = \"untrusted\"`, which beats a\n * permissive sandbox flag; a trailing slash on the path key; and the trust declared in the\n * project's own `.codex/config.toml`, which is correctly refused as self-authorisation. So this\n * path is where a compiled role GOES; whether Codex reads it is the user's global config's answer,\n * the CLI must detect that entry rather than write it silently, and no caller may read a non-null\n * answer here as \"this will be picked up\".\n *\n * **The trap for anyone re-measuring it**, and why the first measurement went wrong: every false\n * negative was a trust failure rather than a registration failure, and `--sandbox workspace-write`\n * or `danger-full-access` makes Codex WRITE that trust entry into the global config itself. The\n * tool under test mutates the independent variable, so a later run in the same home registers for\n * a reason the experiment never set. Reset the config between runs.\n *\n * **What stays UNMEASURED:** whether a spawned sub-agent's context actually receives the role's\n * `developer_instructions`. The mock's router refused the `spawn_agent` call, so registration is\n * proven and delivery is not — and `spawn_agent` is not a top-level tool, it is nested in a\n * `\"type\":\"namespace\"` tool, `multi_agent_v1`.\n *\n * `pluginsDir` is `null` because Codex installs plugins for a machine and not for a project:\n * no subcommand takes a scope, and `codex plugin add` run inside a project writes the switch to\n * the global config and silently un-scopes it. Plugin+project is refused by name instead.\n *\n * `$CODEX_HOME` does not reach this cell at all — a project's Codex state is its own directory,\n * and a role built from the variable would follow a developer's shell out of the repository.\n */\nfunction codexProjectRoles(projectDir: string): HostRoles {\n const root = path.join(projectDir, CODEX_DIR);\n\n return {\n userConfigRoot: root,\n agentsDir: path.join(root, STANDARD_DIRS.AGENTS),\n skillsDir: path.join(projectDir, CODEX_PROJECT_SKILLS_PATH),\n pluginsDir: null,\n pluginRegistry: null,\n permissionFiles: [path.join(root, CODEX_CONFIG_FILE)],\n };\n}\n\n/**\n * The root Codex keeps a user's state under: `$CODEX_HOME` where it names one, `~/.codex`\n * otherwise.\n *\n * Read at call time for {@link installBaseDir}'s reason, one host over: the variable is inherited\n * by every `codex` process this CLI spawns, so a value frozen at import decides where a later\n * command writes.\n *\n * An EXPORTED-BUT-EMPTY variable is read as no answer rather than as the root of the filesystem.\n * `path.join(\"\", \"skills\")` is `skills` — a relative path — so an empty `CODEX_HOME` would root\n * every Codex path at whichever directory the process happens to be running in.\n */\nfunction codexUserRoot(): string {\n const relocated = process.env[CODEX_HOME_VAR];\n if (relocated === undefined || relocated === \"\") return path.join(os.homedir(), CODEX_DIR);\n return relocated;\n}\n\n/**\n * Codex's own GLOBAL configuration file — the one that decides whether a project's role files are\n * read at all.\n *\n * Exported because the trust check has to name this exact file to a user and must not spell the\n * path a second time.\n *\n * **It is the user's file, and this CLI writes one thing into it: `[projects.\"<path>\"]\n * trust_level` for a project it installed into**, since 2026-09-26 (owner: _\"it should be\n * automated on install\"_, CLI-893). `trustCodexProject` merges it in, never overrides a level the\n * user already set, and the install prints what it wrote. _Until then that entry was only read,\n * and the install printed the line for the user to add._\n */\nexport function codexGlobalConfigFile(): string {\n return path.join(codexUserRoot(), CODEX_CONFIG_FILE);\n}\n\n/**\n * `~/.claude.json`, or `$CLAUDE_CONFIG_DIR/.claude.json` while that variable names a directory,\n * where Claude Code records whether each project's trust dialog was accepted —\n * `projects[<path>].hasTrustDialogAccepted`. Read from the shipped binary 2.1.259, 2026-09-03: a\n * PROJECT sub-agent's frontmatter hooks are dropped until that is `true`, so the completion gate\n * compiled into `<project>/.claude/agents/` does nothing in an untrusted folder. The CLI reads it\n * to say so, and never writes it (owner, 2026-09-26: tell the user).\n */\nexport function claudeStateFile(): string {\n return path.join(claudeStateRoot(), CLAUDE_STATE_FILE);\n}\n\n/**\n * The directory Claude Code keeps its state file in: `$CLAUDE_CONFIG_DIR` where it names one, the\n * home directory otherwise. Watched with Claude Code 2.1.288 under a scratch HOME on 2026-10-03:\n * set, the file is `$CLAUDE_CONFIG_DIR/.claude.json` — even where the variable names `~/.claude`,\n * the tree HOME already implies — and unset or empty, it is `~/.claude.json`.\n *\n * Read at call time and with an empty value read as no answer, for {@link codexUserRoot}'s reasons.\n */\nfunction claudeStateRoot(): string {\n const relocated = process.env[CLAUDE_CONFIG_DIR_VAR];\n if (relocated === undefined || relocated === \"\") return os.homedir();\n return relocated;\n}\n\n/** Where this host keeps the configuration and state of one scope's installation. */\nexport function userConfigRoot(provider: Provider, scope: SkillScope, projectDir: string): string {\n return hostRoles(provider, scope, projectDir).userConfigRoot;\n}\n\n/**\n * Where this host reads compiled sub-agents at this scope.\n *\n * It answers where a role file GOES, never that the host will pick it up: Codex reads\n * `<project>/.codex/agents/` only while the user's GLOBAL `$CODEX_HOME/config.toml` trusts that\n * exact absolute path, and says nothing at all when it does not — see {@link codexProjectRoles}\n * for the condition and the four ways it silently fails.\n */\nexport function agentsDir(provider: Provider, scope: SkillScope, projectDir: string): string {\n return hostRoles(provider, scope, projectDir).agentsDir;\n}\n\n/** Where this host reads skills that are copied in rather than installed as a plugin. */\nexport function skillsDir(provider: Provider, scope: SkillScope, projectDir: string): string {\n return hostRoles(provider, scope, projectDir).skillsDir;\n}\n\n/** Where this host stages installed plugins, or `null` where it installs none at this scope. */\nexport function pluginsDir(\n provider: Provider,\n scope: SkillScope,\n projectDir: string,\n): string | null {\n return hostRoles(provider, scope, projectDir).pluginsDir;\n}\n\n/**\n * The file this host records its plugin installs in, or `null` where it keeps no such file.\n *\n * `null` is not \"unknown\": Codex records installs in the same `config.toml` its switches and\n * trust entries live in, so a caller that went looking for a registry there would find nothing\n * whatever this answered.\n */\nexport function pluginRegistry(\n provider: Provider,\n scope: SkillScope,\n projectDir: string,\n): string | null {\n return hostRoles(provider, scope, projectDir).pluginRegistry;\n}\n\n/**\n * Every file this host reads permissions from at this scope, in precedence order.\n *\n * A list rather than one path, because Claude Code reads a settings file and a developer's own\n * overlay beside it, and a single answer can only ever name one of the two.\n */\nexport function permissionFiles(\n provider: Provider,\n scope: SkillScope,\n projectDir: string,\n): string[] {\n return hostRoles(provider, scope, projectDir).permissionFiles;\n}\n\n/**\n * The skills directory as a user writes it FROM THE SCOPE ROOT — `.claude/skills`,\n * `.codex/skills`, `.agents/skills` — which is the spelling a message shows and a skill's\n * recorded `path` carries.\n *\n * Derived from {@link skillsDir} rather than declared a second time per host, so the two cannot\n * disagree: a prefix naming a directory the installer does not write is a place a user is told to\n * look and finds nothing in.\n *\n * A relocated `$CODEX_HOME` has no scope-root-relative spelling at all — being outside the home\n * directory is the whole point of the variable — so the absolute path is what a reader gets.\n * Answering `../elsewhere/codex-state/skills` would spell it relative to a root the user never\n * typed, and every consumer joining it back onto the scope root would still be right by accident.\n */\nexport function skillsPathPrefix(\n provider: Provider,\n scope: SkillScope,\n projectDir: string,\n): string {\n const skills = skillsDir(provider, scope, projectDir);\n const fromScopeRoot = pathUnder(installBaseDir(projectDir, scope), skills);\n\n return fromScopeRoot ?? skills;\n}\n\n/**\n * The roots that SAY which provider an installation at this scope belongs to: this host's own\n * state root, any skills directory sitting outside it, and the source folder.\n *\n * Not a list of directories uninstall may remove. `.claude/` holds a user's own agents and skills\n * beside ours, and uninstall already decides per directory whether it is empty enough to go. What\n * this answers is which roots a command reads to know WHOSE installation it is looking at, which\n * is what \"the folder says the provider, so no command needs a flag\" rests on.\n *\n * The source folder comes from {@link sourceFolderInUse} rather than from {@link sourceDir}, so\n * an installation still on the legacy name is named where it is actually read from.\n */\nexport function ownedRoots(provider: Provider, scope: SkillScope, projectDir: string): string[] {\n const host = userConfigRoot(provider, scope, projectDir);\n const skills = skillsDir(provider, scope, projectDir);\n const source = sourceFolderInUse(installBaseDir(projectDir, scope), provider).dir;\n\n return [host, ...(isUnder(host, skills) ? [] : [skills]), source];\n}\n\n/**\n * `dir` spelled from `root`, POSIX-separated — `null` where it does not sit under `root` at all.\n *\n * `path.relative` rather than a prefix comparison, because the question is about DIRECTORIES and\n * not about strings: a root spelled with a trailing separator, and a sibling whose name merely\n * begins with the root's, are both answered wrongly by the comparison and correctly by this.\n * POSIX-separated because what comes back is a NAME — it is shown to users and written into\n * manifests, the same reason `sourceDirName` gives one folder over.\n */\nfunction pathUnder(root: string, dir: string): string | null {\n const relative = path.relative(root, dir);\n const escapes = relative === \"..\" || relative.startsWith(`..${path.sep}`);\n\n if (relative === \"\" || escapes || path.isAbsolute(relative)) return null;\n return relative.split(path.sep).join(\"/\");\n}\n\n/** Whether `dir` sits under `root`. A root does not count as being under itself. */\nfunction isUnder(root: string, dir: string): boolean {\n return pathUnder(root, dir) !== null;\n}\n\n/** How a compiled sub-agent is written on one host, and how one of ours is recognised again. */\nexport type AgentCodec = {\n /** The extension a compiled agent file carries. */\n extension: string;\n /** The glob that lists every compiled agent in an agents directory. */\n listGlob: string;\n /**\n * Whether this content is an agent THIS CLI compiled.\n *\n * ONE marker, TWO positions, which is why this is a per-host function rather than one shared\n * predicate. A compiled Claude agent carries the line as its first body line, under the\n * frontmatter fence; a Codex agent ROLE DEFINITION carries the same line as the first line of\n * its `developer_instructions`. Both readers match on SHAPE and on POSITION, so a file whose\n * prose merely quotes the marker further down is the user's and is left alone.\n */\n hasMarker: (content: string) => boolean;\n};\n\n/** A fresh codec per call rather than one shared object, so no caller holds another's by identity. */\nexport function agentCodec(provider: Provider): AgentCodec {\n switch (provider) {\n case \"claude\":\n return agentFormat(\".md\", hasProvenanceMarker);\n case \"codex\":\n return agentFormat(\".toml\", hasCodexRoleMarker);\n default: {\n const _exhaustive: never = provider;\n return _exhaustive;\n }\n }\n}\n\n/** One host's codec from its extension alone, so the glob and the extension cannot diverge. */\nfunction agentFormat(extension: string, hasMarker: (content: string) => boolean): AgentCodec {\n return { extension, listGlob: `*${extension}`, hasMarker };\n}\n\n/**\n * Whether `provider` compiles THIS sub-agent at all.\n *\n * One declaration rather than a branch at each compile door, which is the shape its predecessor\n * `compilesSubAgents` had and the reason it had it: a caller that never heard of a provider\n * cannot write the wrong roster by omission, and a host added later is a compiler error here.\n *\n * What changed with C5 is the QUESTION, not the shape. There is a Codex renderer now — agent\n * ROLE DEFINITION files, `.toml`, per {@link agentCodec} — so the answer is no longer about the\n * provider alone: sixteen of the eighteen shipped sub-agents compile onto Codex and two do not.\n * `agent-summoner` and `skill-summoner` are left out for v1 because their roster mechanics on\n * Codex are not proven — the owner's ruling, recorded in that form so it is not reopened by\n * someone correcting a reason that does not hold. `AGENTS_NOT_ON_CODEX` in `@workspace/compile` is\n * where it lives, and its docblock carries the reason this one used to give and why it went.\n */\nexport function hostCompilesAgent(provider: Provider, agent: AgentName): boolean {\n switch (provider) {\n case \"claude\":\n return true;\n case \"codex\":\n return compilesForCodex(agent);\n default: {\n const _exhaustive: never = provider;\n return _exhaustive;\n }\n }\n}\n\n/**\n * Whether this release can tell a user anything true about `provider`'s permission model.\n *\n * One declaration rather than a branch at the door, so a host added later is a compiler error\n * here rather than a silent inheritance of Claude's answer.\n *\n * **It is Claude-only because the notice is Claude Code's, all of it.** The advice\n * `lib/permission-checker.tsx` prints is a `permissions.allow` block in `settings.json`, a file\n * and a key Codex does not have — its equivalent state is `sandbox_mode` and `approval_policy` in\n * the TOML that {@link permissionFiles} answers for that host. A Codex install printed that\n * Claude advice verbatim until 2026-09-22, ending a run that had touched no `.claude/` directory\n * by telling the user to go and edit one.\n *\n * **What it does NOT do is invent the Codex sentence.** Nothing here has been measured against\n * Codex's approval flow, and a notice written on spec would be authoring a user-facing claim\n * rather than reporting one — the same reason `codex-refusal-on-the-read-path.e2e.test.ts` gives\n * for refusing to pin a line that did not exist yet. Saying nothing is the honest answer until\n * somebody measures what there is to say.\n */\nexport function advisesOnPermissions(provider: Provider): boolean {\n switch (provider) {\n case \"claude\":\n return true;\n case \"codex\":\n return false;\n default: {\n const _exhaustive: never = provider;\n return _exhaustive;\n }\n }\n}\n\n/**\n * EVERY PROBE BELOW IS TOTAL, because this module is the only thing between a directory and a\n * path, and `getProjectConfigPath` is reached from ~30 sites that treat it as `path.join`.\n *\n * `statSync(..., { throwIfNoEntry: false })` answers undefined for ENOENT and for ENOTDIR and\n * throws for everything else — EACCES on a parent nobody may look through being the reachable one\n * — and `readdirSync` throws EACCES on a directory it may not list. Neither is a question about\n * the LAYOUT, so neither is allowed to become one: the CLI is sent to the folder the answer names\n * and the read or the write there fails with an errno naming the actual file. One error in front\n * of a user beats two, and no caller of a path builder has a `try` to catch the first in.\n */\nfunction holdsAConfig(dir: string): boolean {\n // `existsSync` swallows every fault already, EACCES included, so this one needs nothing.\n return fs.existsSync(path.join(dir, STANDARD_FILES.CONFIG_TS));\n}\n\n/** True when the directory is there and is not empty — a bare leftover folder is not a scope. */\nfunction holdsAnything(dir: string): boolean {\n return directoryExists(dir) && isNotEmpty(dir);\n}\n\n/**\n * Whether the directory holds anything, answering TRUE when it cannot be listed.\n *\n * The caller has already established that the directory is there; the only question left is\n * whether it is a bare leftover, and a folder locked against this process is not one. Answering\n * false would take a live installation's own folder away from it and name the folder a NEW\n * installation is created in — the half-routed path this module exists to prevent — so the\n * unreadable case goes the way that keeps the CLI pointed where the installation is.\n */\nfunction isNotEmpty(dir: string): boolean {\n try {\n return fs.readdirSync(dir).length > 0;\n } catch {\n return true;\n }\n}\n\n/** Whether `dir` is a directory. A path that cannot be probed is one nothing can be read from. */\nfunction directoryExists(dir: string): boolean {\n try {\n return fs.statSync(dir, { throwIfNoEntry: false })?.isDirectory() ?? false;\n } catch {\n return false;\n }\n}\n","import type { AgentConfig } from \"../../types.js\"\n\n/**\n * One compiled sub-agent as a Codex **agent role definition** file.\n *\n * **The deserializer is strict and the failure is silent, which decides everything below.** Codex\n * 0.155.1 parses `$CODEX_HOME/agents/<file>.toml` and `<project>/.codex/agents/<file>.toml` at\n * startup, and ONE unlisted key drops the WHOLE file — reported as a startup warning nothing in a\n * normal run shows. So an over-generous renderer does not produce a slightly-wrong sub-agent, it\n * produces sixteen sub-agents that do not exist. Every key here was measured against the pinned\n * binary, 2026-09-22, each run under its own `HOME` and `CODEX_HOME` with the global `config.toml`\n * deleted first:\n *\n * # accepted, no startup warning (`model` is accepted and still never written — see\n * # `scalarLines`: every value this product has for it is a Claude model)\n * name / description / developer_instructions / model / model_reasoning_effort /\n * sandbox_mode / approval_policy / instructions / [[hooks.pre_tool_use]] /\n * [features] shell_tool / skills = { enabled = true }\n *\n * # rejected — \"unknown field `<key>`\", and the whole file goes\n * reasoning_effort, effort, disallowed_tools, permissionMode, isolation, experimental,\n * and anything unlisted; tools = [...] and skills = [\"a\"] fail on their VALUE's shape\n *\n * **A frontmatter field with no Codex expression is omitted, never guessed at.** The compile says\n * once what it could not carry — see `./roster` — because an omission nobody is told about is a\n * sub-agent whose permission mode or preloaded skills silently stopped applying.\n *\n * **One field is translated rather than omitted, and exactly one.** `effort` has no Codex key of\n * that name and every value of it has a Codex home, so it travels as `model_reasoning_effort` —\n * see {@link CODEX_EFFORT_KEY} for the measurement and for what the measurement does not cover.\n * Dropping it silently lost the per-agent tuning a shared configuration expresses.\n *\n * **The TOML is written here rather than through a library.** The emitted surface is four scalars\n * and one table, and this package declares no TOML dependency; `agent-role-toml.test.ts` parses\n * every rendered file back with `smol-toml` and compares, so the encoding is held against a real\n * parser rather than against this file's own idea of one.\n */\n\n/**\n * What a role file must carry, or Codex drops it whole.\n *\n * Exported so one place says what they are: the renderer emits them unconditionally and the spec\n * checks the rendered file against this roster by MEMBER, which a count could not do.\n */\nexport const CODEX_REQUIRED_ROLE_KEYS = [\n \"name\",\n \"description\",\n \"developer_instructions\",\n] as const\n\n/**\n * The keys that cost the whole file, each measured as its own one-key role against the pinned\n * binary.\n *\n * Two vocabularies on purpose: `reasoning_effort`, `effort`, `disallowed_tools` and `tools` are\n * TOML keys a renderer might reasonably reach for, while `permissionMode`, `isolation` and\n * `experimental` are the Claude frontmatter fields that would arrive spelled exactly like that.\n * Both are `unknown field` to Codex, and both are absent from everything this module writes.\n */\nexport const CODEX_REJECTED_ROLE_KEYS = [\n \"reasoning_effort\",\n \"effort\",\n \"disallowed_tools\",\n \"tools\",\n \"permissionMode\",\n \"isolation\",\n \"experimental\",\n] as const\n\n/** The tool whose absence is the one per-agent limit Codex CAN express. */\nconst SHELL_TOOL = \"Bash\"\n\n/**\n * One compiled sub-agent's role file.\n *\n * `body` is the frontmatter-free render — `renderAgentBody` in `../../agent-source.ts` — and it\n * becomes `developer_instructions` whole. The role id is the `name` key rather than the filename:\n * measured twice on 0.155.1, a role in `web-developer-role.toml` naming itself `web-developer`\n * reached the model's `spawn_agent` roster as `web-developer`, and one in `anything.toml` naming\n * itself `proj-role` reached it as `proj-role`.\n */\nexport function renderAgentRoleToml(agent: AgentConfig, body: string): string {\n refuseBlankInstructions(agent.name, body)\n\n return [\n ...scalarLines(agent, body),\n // Last, always: every bare key after a table header belongs to that table, so a scalar\n // emitted below `[features]` would become `features.model` and take the file with it.\n ...shellToolTable(agent),\n ].join(\"\\n\")\n}\n\n/**\n * The key and the multi-line delimiter, as one line.\n *\n * Exported because the provenance reader has to find the line the marker sits on and cannot\n * spell this a second time: `hasCodexRoleMarker` in `../../agent-source.ts` looks at the line\n * immediately after it. A writer and a reader with their own copies of a delimiter is how a file\n * this CLI wrote stops being recognisable as ours.\n */\nexport const CODEX_DEVELOPER_INSTRUCTIONS_OPENER = `developer_instructions = \"\"\"`\n\n/**\n * The Codex key an agent's `effort` travels under.\n *\n * **The key is refused and the VALUE is not, which is the whole of this mapping.** A role carrying\n * `effort = \"high\"` is dropped whole — `unknown field \\`effort\\``, the subject absent from\n * `spawn_agent`'s roster while a valid control beside it registers — and the same role carrying\n * `model_reasoning_effort = \"high\"` registers. Measured on the pinned 0.155.1, 2026-09-22, each\n * run under its own `HOME` and `CODEX_HOME` with the global `config.toml` deleted first.\n *\n * **Every level this product can express has a Codex counterpart**, so nothing is reported instead\n * of emitted: all five of `low medium high xhigh max` were put through that rig and every one\n * registered, and Codex's own effort vocabulary — `minimal low medium high xhigh max ultra`, read\n * off the pinned binary's interned variant list — is a superset of ours.\n *\n * **And it RESOLVES, which the offline rig could not settle**: the role deserializer takes the value\n * as a string and accepts one no vocabulary contains, so \"registers\" was never \"resolves\". On a\n * real subscription, codex-cli 0.157.1, 2026-09-26, a role carrying `model_reasoning_effort =\n * \"high\"` was spawned, and the session log recorded `reasoning_effort: high` for it.\n */\nconst CODEX_EFFORT_KEY = \"model_reasoning_effort\"\n\n/**\n * The scalar keys, in the order a reader meets them: who this role is, then the whole prose.\n *\n * **`model` is NEVER written, whatever the agent declares.** Every model this product can name —\n * `MODEL_NAMES` in `@workspace/matrix`: `sonnet opus haiku fable inherit` — is a CLAUDE selector,\n * and Codex has none of them. `model = \"opus\"` parses and registers, which is all the offline rig\n * could see, and then the role cannot be spawned: measured on a real ChatGPT subscription,\n * codex-cli 0.157.1, 2026-09-26, every compiled sub-agent failed to start with `The 'opus' model is\n * not supported when using Codex with a ChatGPT account.` With the line absent, the same role ran\n * on the session's own model. So the role inherits the session's model, and `./roster` reports the\n * setting as one Codex cannot express. _(Until 2026-09-26 this function passed `model` through,\n * on the strength of \"parses and registers [V]\" — true, and not the question.)_\n *\n * `effort` is emitted only when the agent declares one, as {@link CODEX_EFFORT_KEY}; none of the\n * shipped sub-agents does. Nothing else on `AgentConfig` has a Codex expression at all.\n *\n * `body` arrives already carrying the provenance marker on its first line — `renderAgentBody`\n * stamps it, exactly as `renderAgent` does for a Claude agent — so nothing here inserts one and\n * there is no second place the marker can be written from.\n */\nfunction scalarLines(agent: AgentConfig, body: string): string[] {\n return [\n `name = ${basicString(agent.name)}`,\n `description = ${basicString(agent.description)}`,\n ...(agent.effort === undefined\n ? []\n : [`${CODEX_EFFORT_KEY} = ${basicString(agent.effort)}`]),\n developerInstructions(body),\n ]\n}\n\n/** The prose, as a multi-line TOML string whose opening delimiter's own newline TOML discards. */\nfunction developerInstructions(body: string): string {\n return `${CODEX_DEVELOPER_INSTRUCTIONS_OPENER}\\n${asMultilineString(body)}\\n\"\"\"`\n}\n\n/**\n * `[features] shell_tool = false` for an agent granted no Bash, and nothing at all otherwise.\n *\n * The one per-agent limit Codex can express, and today no SHIPPED agent reaches it: of the\n * eighteen definitions exactly one omits Bash — `skill-summoner` — and that is one of the two\n * Codex leaves out. It is rendered because a user-authored agent arrives through the same door.\n */\nfunction shellToolTable(agent: AgentConfig): string[] {\n if (agent.tools.includes(SHELL_TOOL)) return []\n return [\"\", \"[features]\", \"shell_tool = false\"]\n}\n\n/**\n * A blank `developer_instructions` is refused rather than written.\n *\n * Codex answers an empty one with ``.developer_instructions cannot be blank`` and drops the file\n * [V], so writing it would trade a visible compile failure for a sub-agent that silently is not\n * there. The write path collects this as that agent's failure and reports it.\n */\nfunction refuseBlankInstructions(name: string, body: string): void {\n if (body.trim() !== \"\") return\n throw new Error(\n `Cannot write a Codex agent role for \"${name}\": its compiled body is empty, and Codex refuses a blank developer_instructions.`\n )\n}\n\n/**\n * The codepoints TOML refuses RAW in a string, tab and newline excepted — a multi-line string\n * carries both, and a one-line one escapes them by name before this runs.\n *\n * Read off the codepoint rather than matched by a regular expression, which would have to spell\n * control characters into a character class — the construct `no-control-regex` exists to stop,\n * and which is unreadable besides. `0x7f` is DEL, which TOML groups with them.\n */\nfunction isForbiddenRaw(codepoint: number): boolean {\n if (codepoint === 0x7f) return true\n if (codepoint <= 0x08) return true\n return codepoint >= 0x0b && codepoint <= 0x1f\n}\n\n/** A run of three or more quotes: the closing delimiter, wherever it appears in the prose. */\nconst A_CLOSING_DELIMITER = /\"{3,}/g\n\nconst EVERY_BACKSLASH = /\\\\/g\nconst EVERY_QUOTE = /\"/g\n\n/**\n * Every backslash doubled.\n *\n * The one escape that is never optional: a backslash at the end of a line is TOML's line\n * continuation, so an unescaped one would silently swallow the newline after it and glue two\n * paragraphs of a sub-agent's prompt together.\n */\nfunction escapeBackslashes(text: string): string {\n return text.replace(EVERY_BACKSLASH, \"\\\\\\\\\")\n}\n\n/** Any run of quotes long enough to close the string, broken by escaping each quote in it. */\nfunction escapeClosingDelimiters(text: string): string {\n return text.replace(A_CLOSING_DELIMITER, (quotes) =>\n quotes.replace(EVERY_QUOTE, '\\\\\"')\n )\n}\n\n/** The rest, as `\\uXXXX` — which TOML accepts in both string forms. */\nfunction escapeControlCharacters(text: string): string {\n return [...text].map(escapedWhereTomlRefusesItRaw).join(\"\")\n}\n\n/** One character: itself, or its `\\uXXXX` escape where TOML will not take it raw. */\nfunction escapedWhereTomlRefusesItRaw(character: string): string {\n const codepoint = character.charCodeAt(0)\n if (!isForbiddenRaw(codepoint)) return character\n\n return `\\\\u${codepoint.toString(16).padStart(4, \"0\")}`\n}\n\n/** A one-line TOML basic string: every escape TOML defines, and nothing left to interpretation. */\nfunction basicString(value: string): string {\n const literalBackslashes = escapeBackslashes(value)\n const literalQuotes = literalBackslashes.replace(EVERY_QUOTE, '\\\\\"')\n const onOneLine = literalQuotes.replace(/\\n/g, \"\\\\n\").replace(/\\t/g, \"\\\\t\")\n\n return `\"${escapeControlCharacters(onOneLine)}\"`\n}\n\n/**\n * The compiled prose as the inside of a multi-line basic string.\n *\n * Multi-line rather than one escaped line because a user opens this file: the markdown stays\n * readable and its newlines and tabs stay newlines and tabs. What has to be escaped is only what\n * would end the string early or change its meaning — see the two helpers above.\n */\nfunction asMultilineString(body: string): string {\n const literalBackslashes = escapeBackslashes(body)\n const safeDelimiters = escapeClosingDelimiters(literalBackslashes)\n\n return escapeControlCharacters(safeDelimiters)\n}\n","import { AGENT_NAMES } from \"@workspace/matrix\"\n\nimport type { AgentName } from \"../../types.js\"\n\n/**\n * Which sub-agents a Codex installation compiles, and the two sentences a Codex compile owes the\n * user about what it did NOT do.\n *\n * **Two sentences, and they never merge.** One says which sub-agents are ABSENT from this\n * provider; the other says which SETTINGS of the sub-agents that ARE here have no Codex\n * expression. Folded into one \"here is what we dropped\" line, a user cannot tell whether their\n * reviewer exists.\n *\n * **Each is one line, printed once per compile.** All seventeen shipped stacks list both\n * summoners and every Codex install drops them, so once per stack would be seventeen lines of one\n * fact on every install, and once per sub-agent would be thirty-two lines of the other across two\n * scopes.\n */\n\n/**\n * The two sub-agents left out of every Codex install for v1, by the owner's ruling.\n *\n * **The recorded reason, which is not the one this file carried until 2026-09-22:** left out for\n * v1 — their roster mechanics on Codex are not proven. It is D8 of\n * `todo/plans/CLI-codex-provider-plan.md`, written down in that form precisely so nobody reopens\n * the ruling by \"fixing\" a reason that does not hold.\n *\n * Not a capability claim: both compile perfectly well as role files. The sentence that stood here\n * said they author Claude Code skills and sub-agents \"which this provider has no equivalent of\",\n * and the same output contradicts it in the same breath — the line opens by saying Codex compiles\n * sixteen of the eighteen SUB-AGENTS, and `skills = { enabled = true }` is a key a Codex role file\n * takes.\n */\nexport const AGENTS_NOT_ON_CODEX = [\n \"agent-summoner\",\n \"skill-summoner\",\n] as const satisfies readonly AgentName[]\n\nconst leftOut: ReadonlySet<AgentName> = new Set(AGENTS_NOT_ON_CODEX)\n\n/** Whether this sub-agent is compiled onto Codex at all. */\nexport function compilesForCodex(agent: AgentName): boolean {\n return !leftOut.has(agent)\n}\n\n/**\n * The sub-agents a Codex installation DOES compile: the shipped roster minus the two above.\n *\n * Derived rather than spelled out, so a nineteenth sub-agent is on Codex the day it ships and the\n * decision to leave one out is made in exactly one place. `roster.test.ts` holds the sixteen\n * members as its own literal — an expectation derived from the mapping it checks would agree with\n * that mapping however either changes.\n */\nexport const CODEX_AGENT_ROSTER: readonly AgentName[] =\n AGENT_NAMES.filter(compilesForCodex)\n\n/**\n * The six things a Codex agent role file has no way to express, spelled as the compile line names\n * them.\n *\n * **A Claude model** is the one found on a real subscription rather than by the rig: every model\n * this product can name is Claude's, and Codex refuses to spawn a role naming one (codex-cli\n * 0.157.1, 2026-09-26 — `agent-role-toml.ts` `scalarLines` carries the measurement). So the role\n * runs on the session's model, and this line is what tells the user their per-agent model did not\n * travel. Unlike the four below it, EVERY shipped sub-agent declares one.\n *\n * The other five were each measured against the pinned binary's deserializer rather than read off\n * its documentation:\n * `tools` is a configuration struct and not an allowlist, so the read-only sub-agents can still\n * edit files on Codex; `permissionMode`, `isolation` and `experimental` are each an `unknown\n * field` that drops the whole file; and `skills` on a role is a bundled-skills toggle\n * (`{ enabled = true }`) rather than a list of skills to preload.\n *\n * Four of the five are absent from every shipped definition, which is exactly why they are\n * REPORTED rather than quietly not emitted: a user-authored agent setting one would otherwise\n * lose it in silence.\n */\nexport const UNEXPRESSIBLE_ON_CODEX = [\n \"Claude models\",\n \"tool allowlists\",\n \"permissionMode\",\n \"isolation\",\n \"experimental\",\n \"preloaded skills\",\n] as const\n\n/**\n * The line naming the sub-agents this provider does not get, and why.\n *\n * The reason is {@link AGENTS_NOT_ON_CODEX}'s recorded one, stated as a v1 scope decision rather\n * than as a claim about what Codex has — a sentence opening \"Codex compiles 16 of the 18\n * sub-agents\" cannot also say this provider has no sub-agents.\n */\nexport function agentsLeftOutOfCodexMessage(): string {\n return (\n `Codex compiles ${CODEX_AGENT_ROSTER.length} of the ${AGENT_NAMES.length} sub-agents: ` +\n `${inAnEnglishList(AGENTS_NOT_ON_CODEX)} are left out for v1, because their roster ` +\n `mechanics on Codex are not proven.`\n )\n}\n\n/** The line naming the settings a role file cannot carry, whatever the configuration asked for. */\nexport function unexpressibleOnCodexMessage(): string {\n return (\n `Codex cannot express ${inAnEnglishList(UNEXPRESSIBLE_ON_CODEX)}, ` +\n `so the agent role files it wrote carry none of them.`\n )\n}\n\n/**\n * `a, b and c` — built from the constant rather than restated beside it, which is what makes\n * \"names every one of them, exactly once\" a property of the roster instead of a sentence somebody\n * kept in step by hand.\n */\nfunction inAnEnglishList(items: readonly string[]): string {\n const last = items.at(-1)\n if (last === undefined) return \"\"\n if (items.length === 1) return last\n\n return `${items.slice(0, -1).join(\", \")} and ${last}`\n}\n","import type { AgentHookDefinition } from \"@workspace/matrix\"\nimport type { Liquid } from \"liquidjs\"\n\nimport { diagnostics } from \"./diagnostics.js\"\nimport { DEFAULT_PLUGIN_NAME, EJECT_SOURCE } from \"./paths.js\"\nimport { CODEX_DEVELOPER_INSTRUCTIONS_OPENER } from \"./providers/codex/agent-role-toml.js\"\nimport type {\n AgentConfig,\n CompiledAgentData,\n PluginSkillRef,\n Skill,\n} from \"./types.js\"\n\n/**\n * Everything that turns a resolved sub-agent into the markdown an install writes,\n * with two things left behind in the CLI because they read the machine: the five\n * `readFile`s that fetch an agent's partials off disk, and `cliVersion()`, which\n * reads the CLI's own manifest. Both arrive here as data — {@link AgentFiles} and\n * the `version` argument of {@link renderAgent} — which is what lets a browser\n * render the same bytes from the vendored corpus.\n *\n * **The Codex provider's renderer is re-exported from here, and the reason is the package's own\n * `exports` map.** `providers/codex/` has no entry of its own, so this module — the one whose\n * subject is \"how a resolved sub-agent becomes the file a host reads\" — is where a CLI-side\n * caller reaches it. The modules themselves stay separate: the TOML writer imports nothing from\n * here, so the dependency runs one way and neither the root barrel nor the editor's first-paint\n * budget acquires anything new.\n */\nexport {\n CODEX_DEVELOPER_INSTRUCTIONS_OPENER,\n CODEX_REJECTED_ROLE_KEYS,\n CODEX_REQUIRED_ROLE_KEYS,\n renderAgentRoleToml,\n} from \"./providers/codex/agent-role-toml.js\"\nexport {\n AGENTS_NOT_ON_CODEX,\n CODEX_AGENT_ROSTER,\n UNEXPRESSIBLE_ON_CODEX,\n agentsLeftOutOfCodexMessage,\n compilesForCodex,\n unexpressibleOnCodexMessage,\n} from \"./providers/codex/roster.js\"\n\n/** Pattern matching Liquid template delimiters that could enable template injection */\nconst LIQUID_SYNTAX_PATTERN = /\\{\\{|\\}\\}|\\{%|%\\}/g\n\n/**\n * Strips Liquid template syntax (`{{`, `}}`, `{%`, `%}`) from a string value.\n * Prevents template injection when user-controlled data is passed to the Liquid engine.\n *\n * @param value - Input string that may contain Liquid syntax\n * @param fieldName - Name of the field (for warning messages)\n * @returns Sanitized string with Liquid delimiters removed\n */\nexport function sanitizeLiquidSyntax<T extends string>(\n value: T,\n fieldName: string\n): T {\n if (!LIQUID_SYNTAX_PATTERN.test(value)) return value\n LIQUID_SYNTAX_PATTERN.lastIndex = 0\n const sanitized = value.replace(LIQUID_SYNTAX_PATTERN, \"\")\n diagnostics().warn(\n `Stripped Liquid template syntax from '${fieldName}' — possible template injection attempt`\n )\n // Boundary cast: .replace() widens the branded string T; stripping characters keeps it in T's domain\n return sanitized as T\n}\n\nfunction sanitizeStringArray(values: string[], fieldName: string): string[] {\n return values.map((v) => sanitizeLiquidSyntax(v, fieldName))\n}\n\n/**\n * Hook definitions with every author-supplied string stripped of Liquid syntax.\n *\n * These are the only fields on an agent that render as an EXECUTABLE: a `Stop` hook's\n * `command` is a shell line Claude Code runs when the sub-agent finishes. An agent definition\n * can arrive from a marketplace, so the strings here are as author-controlled as `agent.name`\n * beside them — and they were the one part of the definition the sanitiser did not cover,\n * because until this release nothing rendered them.\n *\n * Sanitising is not a substitute for trusting the source: a marketplace whose agents you compile\n * can name any command it likes, and that is a property of installing an agent rather than of\n * this function. What this closes is the narrower hole of a hook string carrying template syntax\n * into a render.\n */\nfunction sanitizeHooks(\n hooks: NonNullable<AgentConfig[\"hooks\"]>\n): NonNullable<AgentConfig[\"hooks\"]> {\n return Object.fromEntries(\n Object.entries(hooks).map(([event, definitions]) => [\n sanitizeLiquidSyntax(event, \"hook.event\"),\n definitions.map(sanitizeHookDefinition),\n ])\n )\n}\n\n/**\n * One definition from {@link sanitizeHooks}: its matcher, and every action it fires.\n *\n * `hooks` is spread unconditionally where `matcher` beside it is guarded, because the two are\n * not both optional: a definition carrying no actions fires nothing, so `AgentHookDefinition`\n * requires the array and every schema that reads an agent refuses a definition without it.\n */\nfunction sanitizeHookDefinition(\n definition: AgentHookDefinition\n): AgentHookDefinition {\n return {\n ...definition,\n ...(definition.matcher !== undefined && {\n matcher: sanitizeLiquidSyntax(definition.matcher, \"hook.matcher\"),\n }),\n hooks: definition.hooks.map(sanitizeHookAction),\n }\n}\n\n/** One action a hook definition fires: its type, and whichever of command, script and prompt it holds. */\nfunction sanitizeHookAction(\n action: AgentHookDefinition[\"hooks\"][number]\n): AgentHookDefinition[\"hooks\"][number] {\n return {\n ...action,\n type: sanitizeLiquidSyntax(action.type, \"hook.type\"),\n ...(action.command !== undefined && {\n command: sanitizeLiquidSyntax(action.command, \"hook.command\"),\n }),\n ...(action.script !== undefined && {\n script: sanitizeLiquidSyntax(action.script, \"hook.script\"),\n }),\n ...(action.prompt !== undefined && {\n prompt: sanitizeLiquidSyntax(action.prompt, \"hook.prompt\"),\n }),\n }\n}\n\n/**\n * Experimental frontmatter options with their author-supplied value stripped of\n * Liquid syntax.\n *\n * Here for the same reason {@link sanitizeHooks} is: the template renders the\n * field, and being rendered is what puts a field in this enumeration. That\n * `cacheTtl` is a closed vocabulary does not exempt it — `model`, `effort`,\n * `permissionMode` and `isolation` are closed vocabularies too and are all\n * sanitised, because a type says nothing about what reached the renderer.\n * {@link renderAgent} is also the editor's preview path, which arrives from a\n * browser without the CLI's Zod loader having parsed anything.\n */\nfunction sanitizeExperimental(\n experimental: NonNullable<AgentConfig[\"experimental\"]>\n): NonNullable<AgentConfig[\"experimental\"]> {\n return {\n ...experimental,\n ...(experimental.cacheTtl !== undefined && {\n cacheTtl: sanitizeLiquidSyntax(\n experimental.cacheTtl,\n \"agent.experimental.cacheTtl\"\n ),\n }),\n }\n}\n\nfunction sanitizeSkills(skills: Skill[]): Skill[] {\n return skills.map((s) => ({\n ...s,\n id: sanitizeLiquidSyntax(s.id, \"skill.id\"),\n description: sanitizeLiquidSyntax(s.description, \"skill.description\"),\n usage: sanitizeLiquidSyntax(s.usage, \"skill.usage\"),\n ...(s.pluginRef !== undefined && {\n pluginRef: sanitizeLiquidSyntax(s.pluginRef, \"skill.pluginRef\"),\n }),\n }))\n}\n\n/**\n * Sanitizes user-controlled metadata fields in compiled agent data to prevent\n * Liquid template injection. Strips `{{`, `}}`, `{%`, `%}` from agent\n * metadata and skill metadata before template rendering.\n *\n * Content fields (identity, playbook, output, criticalRequirementsTop,\n * criticalReminders) are passed through unchanged, because they are not\n * metadata reaching a template — they are PROSE, inlined verbatim, and nothing\n * evaluates them: see {@link SOURCE_FOLDER_PLACEHOLDER} for the one token in a\n * partial that is substituted and why it is a token rather than a render.\n * Stripping the delimiters here would silently rewrite an author's prose — a\n * GitHub Actions example that says `${{ secrets.X }}` means that, and compiles\n * saying that.\n */\nexport function sanitizeCompiledAgentData(\n data: CompiledAgentData\n): CompiledAgentData {\n const sanitizedAgent: AgentConfig = {\n ...data.agent,\n name: sanitizeLiquidSyntax(data.agent.name, \"agent.name\"),\n title: sanitizeLiquidSyntax(data.agent.title, \"agent.title\"),\n description: sanitizeLiquidSyntax(\n data.agent.description,\n \"agent.description\"\n ),\n tools: sanitizeStringArray(data.agent.tools, \"agent.tools\"),\n ...(data.agent.disallowedTools !== undefined && {\n disallowedTools: sanitizeStringArray(\n data.agent.disallowedTools,\n \"agent.disallowedTools\"\n ),\n }),\n ...(data.agent.model !== undefined && {\n model: sanitizeLiquidSyntax(data.agent.model, \"agent.model\"),\n }),\n ...(data.agent.effort !== undefined && {\n effort: sanitizeLiquidSyntax(data.agent.effort, \"agent.effort\"),\n }),\n ...(data.agent.permissionMode !== undefined && {\n permissionMode: sanitizeLiquidSyntax(\n data.agent.permissionMode,\n \"agent.permissionMode\"\n ),\n }),\n ...(data.agent.isolation !== undefined && {\n isolation: sanitizeLiquidSyntax(data.agent.isolation, \"agent.isolation\"),\n }),\n ...(data.agent.experimental !== undefined && {\n experimental: sanitizeExperimental(data.agent.experimental),\n }),\n ...(data.agent.hooks !== undefined && {\n hooks: sanitizeHooks(data.agent.hooks),\n }),\n }\n\n const sanitizedSkills = sanitizeSkills(data.skills)\n const sanitizedPreloaded = sanitizeSkills(data.preloadedSkills)\n const sanitizedDynamic = sanitizeSkills(data.dynamicSkills)\n const sanitizedPreloadedIds = data.preloadedSkillIds.map((id) =>\n sanitizeLiquidSyntax(id, \"preloadedSkillId\")\n )\n\n return {\n agent: sanitizedAgent,\n identity: data.identity,\n playbook: data.playbook,\n output: data.output,\n criticalRequirementsTop: data.criticalRequirementsTop,\n criticalReminders: data.criticalReminders,\n skills: sanitizedSkills,\n preloadedSkills: sanitizedPreloaded,\n dynamicSkills: sanitizedDynamic,\n preloadedSkillIds: sanitizedPreloadedIds,\n }\n}\n\n/**\n * The tool that loads a skill.\n *\n * A sub-agent's `tools:` frontmatter is an ALLOWLIST: an agent that declares one\n * gets exactly what it names, where an agent that omits the key inherits every\n * tool the session has. Every agent compiled here declares one, and no\n * `metadata.yaml` names this — so every agent this product had ever written was\n * unable to invoke a skill, while being instructed in the strongest terms the\n * template can manage to do exactly that.\n *\n * The `skills:` key does not close that gap, which is the non-obvious half and\n * the reason the defect survived: it preloads skill content into the agent's\n * startup context and grants no tool, so a compiled agent can list skills, carry\n * the activation protocol, and still have no way to load one.\n *\n * Granted to every agent rather than only to those with dynamic skills. Skills\n * are this product's atom: an agent has to be able to reach one a user adds\n * after it was compiled, and one its own playbook names in prose. It is a\n * read-only capability — it loads instructions and grants no write access — so\n * the deliberately read-only researchers take it on the same terms.\n */\nconst SKILL_TOOL = \"Skill\"\n\n/**\n * The same definition with {@link SKILL_TOOL} among its tools exactly once.\n *\n * Idempotent and order-stable: a definition already naming it is returned\n * unchanged, by identity, and everything else keeps its declared order with the\n * grant appended. Both halves are about the next compile — a second entry, or a\n * reordered list, would diff the frontmatter of every agent on disk.\n */\nfunction withSkillTool(agent: AgentConfig): AgentConfig {\n if (agent.tools.includes(SKILL_TOOL)) return agent\n return { ...agent, tools: [...agent.tools, SKILL_TOOL] }\n}\n\n/** The five markdown partials a sub-agent is assembled from, however they were fetched. */\nexport type AgentFiles = Pick<\n CompiledAgentData,\n | \"identity\"\n | \"playbook\"\n | \"output\"\n | \"criticalRequirementsTop\"\n | \"criticalReminders\"\n>\n\n/**\n * The template context for one sub-agent.\n *\n * The single assembly point for both front doors — the CLI's write path and the\n * editor's output preview — which is why {@link withSkillTool} is applied here\n * rather than in the eighteen `metadata.yaml` files: a user-authored agent gets\n * the grant on the same terms as a shipped one.\n *\n * The preloaded/dynamic split PRESERVES the order `agent.skills` arrives in, and\n * that order is `config.ts`'s stack key order — so the emitted rows of the\n * sub-agent's skill-activation table are decided by the config writer's\n * canonicalisation rather than by anything here.\n */\nexport function buildAgentTemplateContext(\n name: string,\n agent: AgentConfig,\n files: AgentFiles,\n mapSkill: (skill: Skill) => Skill = (skill) => skill\n): CompiledAgentData {\n const skills = agent.skills.map(mapSkill)\n const preloadedSkills = skills.filter((s) => s.preloaded)\n const dynamicSkills = skills.filter((s) => !s.preloaded)\n const preloadedSkillIds = preloadedSkills.map((s) => s.pluginRef ?? s.id)\n\n diagnostics().verbose(\n `Skills for ${name}: ${preloadedSkills.length} preloaded, ${dynamicSkills.length} dynamic`\n )\n\n return {\n agent: withSkillTool(agent),\n ...files,\n skills,\n preloadedSkills,\n dynamicSkills,\n preloadedSkillIds,\n }\n}\n\n/**\n * The per-skill pluginRef decision. A skill renders as `${id}:${id}` only\n * when it has an explicit non-eject source on its SkillReference — i.e. it was\n * installed from a marketplace. `undefined` source (user-authored local skills\n * with no SkillConfig entry) and `\"eject\"` both fall through to bare id.\n */\nexport function pluginRefFor(skill: Skill): { pluginRef?: PluginSkillRef } {\n if (skill.source === undefined || skill.source === EJECT_SOURCE) return {}\n return { pluginRef: `${skill.id}:${skill.id}` as const }\n}\n\n/**\n * The provenance marker every compiled agent carries: an HTML comment on the first line\n * after the frontmatter, naming the generator and the fact that the file is rewritten\n * rather than edited.\n *\n * **A body comment, deliberately not a frontmatter field.** Claude Code documents its\n * supported frontmatter keys and says nothing about how it treats an unknown one, so a\n * stricter release could reject every agent this CLI has ever written. The body is free-form\n * by contract, which makes a marker there safe, greppable, and the do-not-edit notice at the\n * same time.\n *\n * **Its bytes are constant across releases, and that is the point.** A compiled agent IS a\n * sub-agent's system prompt, so this line is the first cacheable byte of every invocation of\n * it — and while it carried the CLI's version it moved on every release, invalidating the\n * whole prompt prefix of all eighteen agents for a string nothing reads back. The version\n * still travels, in the trailing volatile block where a change to it costs nothing.\n *\n * {@link hasProvenanceMarker} matched on SHAPE while the text varied and still does, so an\n * agent compiled by any release — before this change or after it — is recognised by any other.\n */\nconst MARKER_OPEN = `<!-- Generated by ${DEFAULT_PLUGIN_NAME}`\nconst MARKER_NOTICE = \" — do not edit; compile rewrites this file\"\nconst MARKER_CLOSE = \" -->\"\n\nconst FRONTMATTER_FENCE = \"---\"\n\nexport function provenanceMarker(): string {\n return `${MARKER_OPEN}${MARKER_NOTICE}${MARKER_CLOSE}`\n}\n\n/** Whether a line is a marker this CLI wrote, at any version and under any wording. */\nfunction isProvenanceMarker(line: string): boolean {\n return line.startsWith(MARKER_OPEN) && line.endsWith(MARKER_CLOSE)\n}\n\n/**\n * The index of the first body line: past the closing frontmatter fence when there is one,\n * and the top of the file when there is not — a template override may render no frontmatter,\n * and the marker still needs a defined home.\n */\nfunction bodyStartIndex(lines: readonly string[]): number {\n if (lines[0] !== FRONTMATTER_FENCE) return 0\n const closingFence = lines.indexOf(FRONTMATTER_FENCE, 1)\n if (closingFence === -1) return 0\n return closingFence + 1\n}\n\n/**\n * Whether this CLI compiled the agent file this content came from.\n *\n * The marker's POSITION is part of the claim: an agent that merely quotes the line further\n * down (a prompt about this very feature, say) is the user's, and a sweep reading that as\n * provenance would delete a file nothing here wrote.\n */\nexport function hasProvenanceMarker(content: string): boolean {\n const lines = content.split(\"\\n\")\n const firstBodyLine = lines[bodyStartIndex(lines)]\n return firstBodyLine !== undefined && isProvenanceMarker(firstBodyLine)\n}\n\n/**\n * The same question for a Codex agent ROLE DEFINITION, where the prose lives inside a TOML key\n * rather than under a frontmatter fence.\n *\n * The marker's POSITION is the claim here too — the line immediately after\n * {@link CODEX_DEVELOPER_INSTRUCTIONS_OPENER} — so a role whose own prose quotes the line further\n * down is the user's, and a sweep reading that as provenance would delete a file nothing here\n * wrote. Same shape match as {@link hasProvenanceMarker}, so a role compiled by any release is\n * recognised by any other.\n */\nexport function hasCodexRoleMarker(content: string): boolean {\n const lines = content.split(\"\\n\")\n const opener = lines.indexOf(CODEX_DEVELOPER_INSTRUCTIONS_OPENER)\n const markerLine = opener === -1 ? undefined : lines[opener + 1]\n\n return markerLine !== undefined && isProvenanceMarker(markerLine)\n}\n\n/**\n * The same content carrying exactly one provenance marker, on the first line after the\n * frontmatter.\n *\n * Idempotent by replacement rather than by insertion: content that already carries a marker\n * has that line rewritten rather than a second one stacked beside it. Since the marker's text\n * became constant that replacement is a no-op on anything this release wrote — but it is what\n * upgrades an agent stamped by a release that still spelled the version into the line.\n */\nexport function stampProvenanceMarker(content: string): string {\n const lines = content.split(\"\\n\")\n const bodyStart = bodyStartIndex(lines)\n const replacedLines = hasProvenanceMarker(content) ? 1 : 0\n\n return [\n ...lines.slice(0, bodyStart),\n provenanceMarker(),\n ...lines.slice(bodyStart + replacedLines),\n ].join(\"\\n\")\n}\n\n/** The template every compiled sub-agent is rendered from, by name rather than by path. */\nconst AGENT_TEMPLATE = \"agent\"\n\n/**\n * The template holding everything AFTER the frontmatter fence, which {@link AGENT_TEMPLATE}\n * `{% include %}`s as its own last line.\n *\n * **A host whose sub-agent file has no frontmatter needs the body and only the body.** A Codex\n * agent ROLE DEFINITION carries the compiled prose in one `developer_instructions` key against a\n * deserializer that drops the whole file on an unlisted one, so a Claude-shaped `---` block\n * reaching that renderer is either quoted in as noise or emits keys that lose all sixteen\n * sub-agents at once.\n *\n * **`include` rather than `render`, and rather than concatenating two renders in code.** `include`\n * shares the parent's scope, so the partial reads `agent`, `identity` and the rest exactly as it\n * did when it was one file; and an installation that ejected a whole `agent.liquid` before the\n * split still renders through its own copy rather than having this body appended to it twice.\n */\nconst AGENT_BODY_TEMPLATE = \"agent-body\"\n\n/**\n * The one token in a partial that is not prose.\n *\n * **A partial's text reaches the compiled agent byte for byte.** Anything in one that looks like\n * template syntax — `${{ secrets.X }}` in a GitHub Actions example, `{{ user.name }}`,\n * `{% if x %}` — IS text, in a bundled partial and in a user-authored one alike. An agent\n * definition can arrive from a marketplace or be written by hand in a consuming project, and a\n * partial that reached the Liquid engine would be both a silent rewrite of that author's prose and\n * the template-injection boundary {@link sanitizeLiquidSyntax} exists to hold, gone.\n *\n * One value still has to be install-specific, which is what this token is for: `agent-summoner`'s\n * playbook tells an agent where to author a new sub-agent, and the answer is the source folder THIS\n * installation uses — `.agents-inc/claude/` for one created now, `.claude-src/` for one created\n * before the rename and not yet migrated. A literal is right for one of those and wrong for the\n * other, and the wrong one sends an agent to author into a folder the CLI does not read.\n *\n * So the substitution is an OPT-IN of exactly one token rather than a render of the whole file.\n * Spelled with delimiters no template language in this repository uses and no prose reaches by\n * accident, so a partial that does not carry it is returned by identity and cannot be rewritten by\n * anything here. The repository's own partials that want it are found with:\n *\n * ```\n * grep -rn '@@SOURCE_FOLDER@@' packages/cli/src/agents\n * ```\n *\n * A partial that wants to NAME this token rather than ask for the folder writes\n * {@link SOURCE_FOLDER_ESCAPE}.\n */\nconst SOURCE_FOLDER_PLACEHOLDER = \"@@SOURCE_FOLDER@@\"\n\n/**\n * {@link SOURCE_FOLDER_PLACEHOLDER} with a backslash in front of it, which compiles to the token\n * itself.\n *\n * **A substitution with no escape eats the one lesson that teaches it.** `agent-summoner`'s\n * playbook is where an agent learns to write the token, and the paragraph saying so spelled the\n * token — so every compiled copy read \"the one exception is `.agents-inc/claude`\" and named the\n * token nowhere, teaching the folder literal the token exists to prevent. The escape is what lets\n * a partial say the token's name out loud.\n *\n * A backslash because it is the escape every author already reaches for, and because it composes:\n * the escape is stripped from the text around it, so `\\\\` in front of the token compiles to a\n * backslash and the token — which is how a partial teaches the escape itself. There is no way to\n * write a literal backslash immediately before a SUBSTITUTED token, and nothing needs one.\n */\nconst SOURCE_FOLDER_ESCAPE = `\\\\${SOURCE_FOLDER_PLACEHOLDER}`\n\n/**\n * The product-authored expression that asks an engine for the install's source folder.\n *\n * A constant this file owns, so the only thing the Liquid engine is ever handed here is this\n * string — never a partial. The engine is still what carries the value, because `globals` is where\n * both front doors put it: `createLiquidEngine` in the CLI, over the project it is compiling for,\n * and `createEngineFromTemplates` in the browser, over the layout a new installation gets.\n */\nconst SOURCE_FOLDER_EXPRESSION = \"{{ sourceFolder }}\"\n\n/** The refusal when a partial asks for the source folder and the engine cannot name one. */\nconst NO_SOURCE_FOLDER =\n `A partial names the install's source folder (${SOURCE_FOLDER_PLACEHOLDER}) and the engine ` +\n `rendering it carries no 'sourceFolder' global, so the name would compile away to nothing.`\n\n/** The source folder this engine was built for, asked for through the engine's own globals. */\nfunction sourceFolderOf(engine: Liquid): Promise<string> {\n // Boundary cast: liquidjs types parseAndRender as `Promise<any>` because a template can render\n // to any value. This one renders a global declared `string` by both engine builders.\n return engine.parseAndRender(SOURCE_FOLDER_EXPRESSION) as Promise<string>\n}\n\n/**\n * One partial with every unescaped {@link SOURCE_FOLDER_PLACEHOLDER} replaced by `folder`, every\n * {@link SOURCE_FOLDER_ESCAPE} left naming the token, and every other byte of it untouched.\n *\n * A partial that did not opt in is returned by identity, so nothing here can reach an author's\n * prose. One that ASKS for the folder, in an engine naming no folder, is a refusal rather than a\n * substitution: `strictVariables` is off in both engines — that is what lets a template reference a\n * field an agent omits — so a missing global renders to an empty string, and the partial would\n * compile to `/agents/`, a path that names no installation, in a file nobody reads back. One that\n * only NAMES the token asks for no folder, so it is not held to that.\n */\nfunction substituteSourceFolder(partial: string, folder: string): string {\n if (!partial.includes(SOURCE_FOLDER_PLACEHOLDER)) return partial\n\n const aroundEscapes = partial.split(SOURCE_FOLDER_ESCAPE)\n const asksForTheFolder = aroundEscapes.some((text) =>\n text.includes(SOURCE_FOLDER_PLACEHOLDER)\n )\n if (asksForTheFolder && folder === \"\") throw new Error(NO_SOURCE_FOLDER)\n\n const folderNamedIn = (text: string): string =>\n text.split(SOURCE_FOLDER_PLACEHOLDER).join(folder)\n\n return aroundEscapes.map(folderNamedIn).join(SOURCE_FOLDER_PLACEHOLDER)\n}\n\n/**\n * The same context with each of its five partials carrying this install's source folder.\n *\n * The five are listed as an {@link AgentFiles} literal rather than spread one by one over `data`,\n * which is what makes the enumeration exhaustive: a sixth partial added to that type and forgotten\n * here fails `tsc` on the missing property, where the spread alone would pass it through untouched\n * and silently.\n */\nasync function withSourceFolder(\n engine: Liquid,\n data: CompiledAgentData\n): Promise<CompiledAgentData> {\n const folder = await sourceFolderOf(engine)\n const named = (partial: string): string =>\n substituteSourceFolder(partial, folder)\n\n const partials: AgentFiles = {\n identity: named(data.identity),\n playbook: named(data.playbook),\n output: named(data.output),\n criticalRequirementsTop: named(data.criticalRequirementsTop),\n criticalReminders: named(data.criticalReminders),\n }\n\n return { ...data, ...partials }\n}\n\n/**\n * The deterministic completion gate every writing sub-agent stops against.\n *\n * A `SubagentStop` hook rather than a sentence in the prompt, because the two are different\n * kinds of claim: \"check your work before stopping\" is advice a model may decline to take, and\n * this is a process that runs whether it does or not. Exit 2 is the documented way to BLOCK the\n * stop, and the command's captured output goes to stderr, which is what Claude Code returns to\n * the sub-agent — so a failing typecheck comes back as the compiler's own output and the\n * agent iterates rather than reporting done.\n *\n * **Inert where it cannot be right.** A compiled agent is installed into someone else's\n * repository, and a gate that hard-blocks in a project with no npm — or no `typecheck` script —\n * would make every sub-agent unstoppable. So the first clause exits 0 unless there is both an\n * npm and a `package.json`, and `--if-present` exits 0 for a script the project does not\n * define. What is left is exactly the case the gate is for: a project that declares these\n * checks, failing one of them.\n *\n * **Typecheck only.** The gate runs the project's typecheck script; lint and test are\n * deliberately not in it. A type error means the work does not compile, which is the one\n * failure a stopping agent must not report as done. A lint finding or a failing test is the\n * project's own judgement to gate on, and a project that wants either declares its own `Stop`\n * hook — see {@link declaresOwnGate} — which replaces this one entirely rather than running\n * beside it.\n *\n * Composed for agents holding `Write` or `Edit` by {@link withCompletionGate}, which merges it\n * with whatever the agent declared rather than losing to it.\n */\nconst COMPLETION_GATE_COMMAND =\n \"command -v npm >/dev/null 2>&1 && [ -f package.json ] || exit 0; \" +\n \"out=$(npm run --if-present --silent typecheck 2>&1) \" +\n \"|| { printf '%s\\\\n' \\\"$out\\\" >&2; exit 2; }\"\n\n/** The tools whose presence makes an agent one the gate is for. */\nconst WRITING_TOOLS = [\"Write\", \"Edit\"]\n\n/**\n * The frontmatter spelling of the completion event, which is not the spelling that fires.\n *\n * Claude Code registers a sub-agent's frontmatter hooks through a function that walks its\n * event vocabulary and rewrites exactly one key — `Stop` becomes `SubagentStop`, logged as\n * \"Converting Stop hook to SubagentStop for agent X (subagents trigger SubagentStop)\". The\n * vocabulary contains `SubagentStop` verbatim, so EITHER spelling works when the agent is\n * invoked as a sub-agent.\n *\n * They diverge on the other path. An agent run as the main session through `--agent` has its\n * frontmatter hooks stored raw, with no such rewrite, and every dispatch looks the record up\n * by the event's own name — so a `SubagentStop` key is consulted only for an event a main\n * session never fires, while `Stop` fires natively. `Stop` is therefore correct in both modes\n * and `SubagentStop` in one, which is why this emits `Stop`.\n *\n * Read from the shipped binary at version 2.1.259 on 2026-09-03 rather than from published\n * documentation. Compiled agents written before that release carry `SubagentStop`; both are\n * live, and a reader seeing `Stop:` in frontmatter and `SubagentStop` in a log is seeing the\n * conversion rather than a mismatch.\n */\nconst GATE_EVENT = \"Stop\"\n\n/** The runtime spelling of {@link GATE_EVENT} — what a sub-agent's registration is rewritten to. */\nconst CONVERTED_GATE_EVENT = \"SubagentStop\"\n\n/**\n * The gate as its own hooks record — a fresh one per call.\n *\n * A factory rather than a const because the record is spread into an agent's own\n * hooks and the arrays inside it would otherwise be shared, by identity, with every\n * agent ever compiled in the process; `validResult()` in the CLI's\n * `lib/validation-result.ts` is the same shape for the same reason.\n */\nfunction completionGateHooks(): NonNullable<AgentConfig[\"hooks\"]> {\n return {\n [GATE_EVENT]: [\n { hooks: [{ type: \"command\", command: COMPLETION_GATE_COMMAND }] },\n ],\n }\n}\n\n/**\n * Whether the definition states a completion gate of its own, under either spelling.\n *\n * Both count, because the two ARE one event on the path a compiled agent is normally\n * invoked on — see {@link GATE_EVENT}. Keying only on `Stop` would emit this gate beside a\n * project's `SubagentStop`, and a sub-agent would then run both, which is the opposite of\n * the rule that a project's completion gate is its own to state. `SubagentStop` is also the\n * spelling every agent compiled before 2026-09-03 carries, so it is what a project that\n * copied its gate out of a compiled agent will have written.\n */\nfunction declaresOwnGate(hooks: AgentConfig[\"hooks\"]): boolean {\n if (hooks === undefined) return false\n const stated = [GATE_EVENT, CONVERTED_GATE_EVENT]\n return stated.some((event) => (hooks[event]?.length ?? 0) > 0)\n}\n\n/**\n * The same definition carrying the completion gate alongside whatever it declared.\n *\n * **Composition, not exclusion.** The template used to decide this with an\n * `{% if agent.hooks %}` / `{% elsif tools contains Write %}` pair, so an agent\n * declaring any hook at all — a `PostToolUse` formatter, say — silently lost the\n * completion gate, with nothing reporting it.\n *\n * Merged per EVENT: a declared completion gate replaces this one, because a project stating\n * its own is the rule this product has always documented; every other event is added beside\n * it. An agent holding neither `Write` nor `Edit` is returned unchanged, so the gate is still\n * emitted only where it can mean something.\n *\n * The gate is spread LAST rather than first, which matters only for the degenerate declaration\n * `Stop: []`. {@link declaresOwnGate} reads that as stating no gate, correctly — and spreading\n * the declared record over the gate would then let an empty array clobber it, emitting\n * `hooks: {\"Stop\":[]}` and losing the gate to a key that says nothing. Gate-last cannot lose to\n * a declaration this function has already established is not one.\n *\n * **Composed before the sanitiser, for a narrower reason than that ordering used to claim.** The\n * only value whose sanitisation depends on it is {@link COMPLETION_GATE_COMMAND}, a constant this\n * product authors. An author's own hooks are stripped under either order, because\n * {@link sanitizeCompiledAgentData} walks `agent.hooks` whether or not the gate has been composed\n * into them — measured by rendering a writing agent whose declared hook was poisoned in every\n * field, under both orders: one line of the two renders differed, and the marker in it was the\n * gate's own.\n *\n * Which is a rule nothing can hold, since no fixture can reach that constant. So it is structural\n * instead of remembered: this function is private, {@link prepareForRender} is the one expression\n * that composes with the sanitiser, and {@link renderAgent} has no order left to state.\n */\nfunction withCompletionGate(agent: AgentConfig): AgentConfig {\n const writes = WRITING_TOOLS.some((tool) => agent.tools.includes(tool))\n if (!writes || declaresOwnGate(agent.hooks)) return agent\n return { ...agent, hooks: { ...agent.hooks, ...completionGateHooks() } }\n}\n\n/**\n * The whole of what a render is handed: the completion gate composed into the\n * definition's own hooks, and every author-supplied string stripped of Liquid\n * syntax.\n *\n * The two steps have an order and this is the only expression allowed to state\n * it — written as one nested call rather than two statements, so getting it\n * wrong takes rewriting the expression rather than moving a line. That is worth\n * the indirection because the ordering is unfalsifiable: {@link withCompletionGate}\n * is the reason, and it explains which single value the order decides.\n */\nfunction prepareForRender(data: CompiledAgentData): CompiledAgentData {\n return sanitizeCompiledAgentData({\n ...data,\n agent: withCompletionGate(data.agent),\n })\n}\n\n/**\n * Renders the agent template and stamps the result with the provenance marker.\n *\n * Every compile entry point renders through here, so there is no path that writes a compiled\n * agent this CLI cannot later recognise as its own — which is what `uninstall` reads back\n * when the configuration naming the agents is gone. The stamp replaces rather than inserts,\n * so a template that emits the marker itself still produces exactly one.\n *\n * `version` is an argument because the CLI reads it from its own `package.json` and a browser\n * has no manifest to read; the editor passes `CORPUS_CLI_VERSION`, the release the corpus was\n * vendored at. It reaches the template as `generatorVersion` and renders inside the trailing\n * volatile block rather than into the provenance marker, so a release bump no longer rewrites\n * the first cacheable byte of every compiled agent.\n *\n * The completion gate is composed into the agent's own hooks before the render rather than\n * branched on in the template — see {@link prepareForRender} — so the template holds one\n * unconditional `hooks:` emission and the gate reaches `sanitizeHooks` like any other hook.\n *\n * The five partials are inlined verbatim but for one opted-in token — see\n * {@link SOURCE_FOLDER_PLACEHOLDER} — so an agent whose own text names the install's source folder\n * names the one this engine was built for, and every other byte of an author's prose survives.\n */\nexport async function renderAgent(\n engine: Liquid,\n data: CompiledAgentData,\n version: string\n): Promise<string> {\n return stampProvenanceMarker(\n await renderFromTemplate(engine, AGENT_TEMPLATE, data, version)\n )\n}\n\n/**\n * The same sub-agent WITHOUT its frontmatter — the prose alone, carrying the provenance marker on\n * its first line.\n *\n * It is exactly the tail of {@link renderAgent}, and that is the invariant rather than a golden\n * file: `agent.liquid` ends by including {@link AGENT_BODY_TEMPLATE}, so a body that moved one\n * byte would move the Claude render with it. `agent-body-split.test.ts` asserts the suffix\n * relation over three shipped sub-agents rather than recording the bytes, because a golden the\n * implementing pass can regenerate is a golden the implementing pass will regenerate.\n *\n * The marker is stamped here for the same reason `renderAgent` stamps it: a body with no frontmatter\n * fence takes it on line one, which is where {@link hasProvenanceMarker} looks and where the Codex\n * role renderer expects to find it inside `developer_instructions`.\n */\nexport async function renderAgentBody(\n engine: Liquid,\n data: CompiledAgentData,\n version: string\n): Promise<string> {\n return stampProvenanceMarker(\n await renderFromTemplate(engine, AGENT_BODY_TEMPLATE, data, version)\n )\n}\n\n/** The render both doors share: the same prepared context, against whichever template is named. */\nasync function renderFromTemplate(\n engine: Liquid,\n template: string,\n data: CompiledAgentData,\n version: string\n): Promise<string> {\n const prepared = await withSourceFolder(engine, prepareForRender(data))\n\n // Boundary cast: liquidjs types renderFile as `Promise<any>` because a template\n // can render to any value. The agent template renders a markdown file, and both\n // callers have declared `Promise<string>` since they were written.\n return (await engine.renderFile(template, {\n ...prepared,\n generatorVersion: sanitizeLiquidSyntax(version, \"generatorVersion\"),\n })) as string\n}\n","import { AsyncLocalStorage } from \"node:async_hooks\";\n\n/**\n * The write privilege for the global config pair (`~/.claude-src/config.ts` and\n * its `config-types.ts` sibling).\n *\n * AsyncLocalStorage rather than a module-level boolean: pair writes are async\n * and interleave, so a flag one write clears while another is still in flight\n * revokes a privilege that is still held. The store is scoped to the call tree\n * that opened it, which is exactly the grant being modelled.\n */\nconst gateToken = new AsyncLocalStorage<true>();\n\n/**\n * Thrown when the global pair is written from outside the gate. Names the\n * offending path and the only supported entry point, because every occurrence\n * is a code path that must be moved rather than a user-recoverable condition.\n */\nexport class GlobalPairWriteViolation extends Error {\n constructor(targetPath: string) {\n super(\n `${targetPath} may only be written through config-gate — see src/cli/lib/config-gate/index.ts`,\n );\n this.name = \"GlobalPairWriteViolation\";\n }\n}\n\n/** Runs `fn` holding the pair-write privilege. */\nexport function withGateToken<T>(fn: () => Promise<T>): Promise<T> {\n return gateToken.run(true, fn);\n}\n\n/** True while the current async call tree holds the pair-write privilege. */\nexport function hasGateToken(): boolean {\n return gateToken.getStore() === true;\n}\n\n/** Throws unless the caller holds the pair-write privilege. */\nexport function assertGateToken(targetPath: string): void {\n if (hasGateToken()) return;\n throw new GlobalPairWriteViolation(targetPath);\n}\n","// Logging utility for lib/ modules that don't have access to oclif command context.\n// In oclif commands, prefer using this.log() instead.\n\nlet verboseMode = false;\n\nexport function setVerbose(enabled: boolean): void {\n verboseMode = enabled;\n}\n\nexport function verbose(msg: string): void {\n if (verboseMode) {\n console.log(` ${msg}`);\n }\n}\n\n// Always visible (not gated by verbose mode).\n// Used for user-facing progress output: compilation ticks, summaries, validation results.\nexport function log(msg: string): void {\n console.log(msg);\n}\n\n// --- Startup message buffering ---\n// When buffer mode is enabled (before Ink takes over the terminal), warn() pushes\n// messages into a buffer instead of writing to stderr. The buffer is drained and\n// handed to the wizard, which paints it as a band above the step — stderr is what\n// the wizard's clearTerminal wipes, so a line written there is a line lost.\n\nexport type StartupMessage = {\n level: \"info\" | \"warn\" | \"error\";\n text: string;\n};\n\nlet bufferMode = false;\nlet messageBuffer: StartupMessage[] = [];\n\nexport function enableBuffering(): void {\n bufferMode = true;\n messageBuffer = [];\n}\n\nexport function drainBuffer(): StartupMessage[] {\n const messages = [...messageBuffer];\n messageBuffer = [];\n return messages;\n}\n\nexport function disableBuffering(): void {\n bufferMode = false;\n messageBuffer = [];\n}\n\n// Always visible (not gated by verbose mode).\n// Used for issues the user should know about, like unresolved references.\n//\n// Error/warning message style guide:\n// - Start with a capital letter (restructure if it would capitalize a function name)\n// - End with a period if it's a complete sentence\n// - End without a period if it's a fragment (e.g., \"Skipping 'foo': missing SKILL.md\")\n// - Wrap dynamic values in single quotes: 'value' (not bare or double-quoted)\n// - Do NOT prefix the message with \"Warning:\" — this function adds it automatically\n// - After a colon, use lowercase (e.g., \"Skipping 'foo': invalid frontmatter\")\n// - Use em dash for supplemental info (e.g., \"Missing category — defaulting to 'local'\")\nexport function warn(msg: string): void {\n if (bufferMode) {\n messageBuffer.push({ level: \"warn\", text: msg });\n return;\n }\n console.warn(` Warning: ${msg}`);\n}\n\nconst alreadySaid = new Set<string>();\n\n/**\n * The same warning, said once however many times this process reaches the line that says it.\n *\n * For a warning about the ENVIRONMENT rather than about the work in hand. One unreadable entry in\n * a user's own Codex marketplace registry fails every listing verb Codex has, and a single\n * `doctor` run asks for a listing from plugin discovery and from skill discovery — so one broken\n * entry said the same sentence twice, which reads as two faults.\n *\n * Keyed by the message, so two different causes are both still said. There is deliberately no\n * reset: the scope is one CLI invocation, and every surface that asserts on one of these lines\n * drives a spawned binary, which is a fresh process by construction.\n */\nexport function warnOnce(msg: string): void {\n if (alreadySaid.has(msg)) return;\n alreadySaid.add(msg);\n warn(msg);\n}\n","import { unique } from \"remeda\";\n\nimport { KEBAB_CASE_PATTERN } from \"../consts.js\";\n\n/** The characters {@link KEBAB_CASE_PATTERN} is built from, tested one at a time. */\nconst KEBAB_CASE_CHARACTER = /[a-z0-9-]/;\n\n/**\n * The characters a name carries that kebab-case does not admit, deduplicated and in\n * first-appearance order.\n *\n * Empty when the name breaks the rule some other way — a leading digit, a doubled or\n * a trailing hyphen — which is why a refusal states the rule as well as the list: an\n * author handed `@scope/thing` can act on `@` and `/` directly, and one handed\n * `-thing` has nothing to delete.\n */\nexport function charactersOutsideKebabCase(name: string): string[] {\n return unique([...name].filter((character) => !KEBAB_CASE_CHARACTER.test(character)));\n}\n\n/**\n * Validates a user-supplied entity name against the kebab-case convention.\n * Returns an error message naming the entity (e.g. \"Marketplace\", \"Skill\"),\n * or null when the name is valid.\n */\nexport function validateKebabCaseName(name: string, noun: string): string | null {\n if (!name || name.trim() === \"\") {\n return `${noun} name is required`;\n }\n\n if (!KEBAB_CASE_PATTERN.test(name)) {\n return `${noun} name must be kebab-case (lowercase letters, numbers, and hyphens, starting with a letter)`;\n }\n\n return null;\n}\n","import {\n CLI_INVOKE_COMMAND,\n DEFAULT_BRANDING,\n DEFAULT_PLUGIN_NAME,\n EDITOR_URL,\n LOCAL_SKILLS_PATH,\n MARKETPLACE_JSON,\n PLUGIN_MANIFEST_DIR,\n STANDARD_FILES,\n editorConfigUrl,\n type Provider,\n} from \"../consts.js\";\nimport type { UnusableSkillMetadata } from \"../lib/loading/index.js\";\nimport type { ScopeKind } from \"../lib/installation/source-scopes.js\";\nimport type { ConfigLoadError } from \"../lib/configuration/project-config.js\";\nimport { charactersOutsideKebabCase } from \"../lib/validate-kebab-name.js\";\nimport { plural } from \"./string.js\";\nimport type { AgentName, Category, SkillId } from \"../types/index.js\";\n\nexport const ERROR_MESSAGES = {\n UNKNOWN_ERROR: \"Unknown error occurred\",\n UNKNOWN_ERROR_SHORT: \"Unknown error\",\n NO_INSTALLATION: `No installation found. Run '${CLI_INVOKE_COMMAND} init' first to set up ${DEFAULT_BRANDING.NAME}`,\n FAILED_RESOLVE_SOURCE: \"Failed to resolve marketplace\",\n FAILED_LOAD_AGENT_PARTIALS: \"Failed to load agent partials\",\n FAILED_COMPILE_AGENTS: \"Failed to compile agents\",\n /**\n * What `compile` refuses with when every pass discovered zero skills. It is reached only\n * after an installation was detected, so the state it describes is a configuration with\n * nothing installed under it — the same state `doctor` reports as `config-empty` and\n * names `init` for, because `init` on a config that declares nothing opens the wizard\n * rather than the dashboard. `edit` is the wrong half of the pair here: it modifies the\n * currently installed skills, and there are none to modify.\n */\n NO_SKILLS_TO_COMPILE: `No skills found. Run '${CLI_INVOKE_COMMAND} init' to choose skills, or add your own under ${LOCAL_SKILLS_PATH}/.`,\n} as const;\n\nexport const SUCCESS_MESSAGES = {\n UNINSTALL_COMPLETE: \"Uninstall complete!\",\n PLUGIN_COMPILE_COMPLETE: \"Plugin compile complete!\",\n} as const;\n\n/**\n * How each provider's own CLI is named, and what a user does about it not being there.\n *\n * A table keyed on {@link Provider} rather than a sentence built from the provider's own value:\n * \"Codex CLI\" and \"Claude Code\" are proper names, and the thing to DO about each is a different\n * fact again — one is a product to install, the other is an npm package whose bin has to reach\n * PATH. Neither is derivable from the four letters the folder is named after.\n *\n * The Codex row names the package this repository pins as a devDependency rather than a download\n * page, because the package is a fact this tree can be held against\n * (`packages/cli/package.json` -> `@openai/codex`) and a URL is one it cannot.\n */\nconst HOST_CLI: Record<Provider, { name: string; install: string }> = {\n claude: { name: \"Claude CLI\", install: \"Install Claude Code first: https://claude.ai/code\" },\n codex: {\n name: \"Codex CLI\",\n install: \"Install the '@openai/codex' package first, so that 'codex' is on PATH\",\n },\n};\n\n/**\n * What a command says when the host binary its work goes through is not on the machine.\n *\n * It was a constant naming Claude until C4, with one caller — true while Claude was the only host,\n * and a wrong answer the moment a Codex installation could resolve one: a machine with no `codex`\n * was told to install Claude Code, which is neither the binary that is missing nor a step that\n * would help. The provider comes from the host the caller is already holding, so the line cannot\n * disagree with the installation it is about.\n */\nexport function hostCliNotFound(provider: Provider): string {\n const cli = HOST_CLI[provider];\n return `${cli.name} not found — '${CLI_INVOKE_COMMAND} update' refreshes marketplaces through it. ${cli.install}`;\n}\n\n/**\n * `init`'s closing line, under the name the run prints itself as.\n *\n * A builder rather than a constant because it carries `branding.name`, which is per-installation\n * and cannot be baked in at module load. `init` is its one caller and resolves the name once on\n * its own spine, through `BaseCommand.resolveBrandingName`, which is where the default comes\n * from.\n */\nexport function initSucceeded(brandingName: string): string {\n return `${brandingName} initialized successfully!`;\n}\n\nexport const STATUS_MESSAGES = {\n INSTALLING_PLUGINS: \"Installing skill plugins...\",\n LOADING_SKILLS: \"Loading skills...\",\n LOADING_MARKETPLACE_SOURCE: \"Loading marketplace...\",\n RECOMPILING_AGENTS: \"Recompiling agents...\",\n COMPILING_AGENTS: \"Compiling agents...\",\n DISCOVERING_SKILLS: \"Discovering skills...\",\n RESOLVING_SOURCE: \"Resolving marketplace...\",\n RESOLVING_MARKETPLACE_SOURCE: \"Resolving marketplace...\",\n LOADING_AGENT_PARTIALS: \"Loading agent partials...\",\n FETCHING_REPOSITORY: \"Fetching repository...\",\n COPYING_SKILLS: \"Copying skills...\",\n /**\n * Printed when revalidation found the remote marketplace had moved on. It is the\n * only warning a user gets that this load costs a download rather than a\n * cache read, so it goes out before the download starts, not after.\n */\n MARKETPLACE_HAS_NEWER_CONTENT: \"Marketplace has newer content — fetching the update...\",\n} as const;\n\n/**\n * The partials `readAgentFiles` compiles a sub-agent out of, in the order it reads them —\n * and therefore what `eject agent-partials` puts under the reader's control. Spelled from\n * {@link STANDARD_FILES} rather than as prose so the sentence below cannot name a file the\n * compiler does not read: it named \"templates, agent intro, workflow, and examples\" for\n * years, four nouns matching nothing that ships.\n */\nconst AGENT_PARTIAL_FILES = [\n STANDARD_FILES.IDENTITY_MD,\n STANDARD_FILES.PLAYBOOK_MD,\n STANDARD_FILES.CRITICAL_REQUIREMENTS_MD,\n STANDARD_FILES.CRITICAL_REMINDERS_MD,\n STANDARD_FILES.OUTPUT_MD,\n];\n\nexport const INFO_MESSAGES = {\n NO_CHANGES_MADE: \"No changes made.\",\n RUN_COMPILE: `Run '${CLI_INVOKE_COMMAND} compile' to include imported skills in your agents.`,\n NO_AGENTS_TO_RECOMPILE: \"No agents to recompile\",\n NO_PLUGIN_INSTALLATION: \"No plugin installation found.\",\n NO_LOCAL_INSTALLATION: \"No local installation found.\",\n CONFIG_TYPES_REFRESHED: `Refreshed ${STANDARD_FILES.CONFIG_TYPES_TS}`,\n /**\n * `update` refreshes marketplaces and stops there. An ejected skill is a copy the\n * user owns and may have edited, so overwriting it from the source would discard\n * their work — this line says so once, as information rather than a warning.\n */\n EJECTED_SKILLS_USER_OWNED: `Ejected skills are yours to own — '${CLI_INVOKE_COMMAND} update' does not change them.`,\n NO_PLUGIN_MARKETPLACES: \"No plugin marketplaces are configured — nothing to refresh.\",\n /** Printed under the destination `eject agent-partials` just named, so it names files only. */\n AGENT_PARTIALS_CUSTOMIZABLE: `Each sub-agent directory there holds ${AGENT_PARTIAL_FILES.join(\", \")} — edit those to customize that sub-agent.`,\n} as const;\n\n/**\n * What `uninstall` reports when the directory holds nothing of this CLI's, under the name the run\n * prints itself as.\n *\n * A builder for the same reason as {@link initSucceeded}, and it matters more here: `uninstall`\n * heads its output with the configured name and signs off with it, so a constant would put the\n * shipped name in the middle of a run that says the configured one twice around it.\n */\nexport function notInstalledHere(brandingName: string): string {\n return `${brandingName} is not installed in this project.`;\n}\n\n/** Closing line of a plugin install, printed wherever one runs. */\nexport function pluginsInstalled(count: number): string {\n return `Installed ${plural(count, \"skill plugin\")}`;\n}\n\n/**\n * What an eject copy did, wherever `edit` performs one — a newly added local skill,\n * or a skill switched from plugin mode back to eject. Both copy through\n * `copyLocalSkills` at each skill's own scope, so both owe the same sentence.\n *\n * A count and no destination, deliberately: the copies are split between the\n * project directory and `$HOME` by each skill's scope, and one hardcoded path\n * would misname the other half.\n */\nexport function localSkillsCopied(count: number): string {\n return `Copied ${count} local skill(s)`;\n}\n\n/**\n * What a recompile pass did, as two numbers rather than one.\n *\n * The count it replaced was the roster the pass walked, so a run that rewrote\n * nothing and a run that rewrote everything printed the same sentence — the line\n * reported intent rather than outcome. `rewritten` is agents whose file this pass\n * wrote; `unchanged` is agents it found already correct and left alone.\n *\n * `subject` is the noun each caller counts in, given in the singular and pluralised against\n * `rewritten`, because `compile` reports per scope pass (\"global agent\") and `edit` reports the\n * whole run's (\"agent\").\n */\nexport function recompileSummary(rewritten: number, unchanged: number, subject: string): string {\n return `${plural(rewritten, subject)} rewritten, ${unchanged} unchanged`;\n}\n\n/**\n * The sub-agents a recompile pass could not write, named rather than counted.\n *\n * Read off the pass's `failed` roster rather than off the prose it also returns: that roster is\n * the structured answer to \"which ones did not land\", while `warnings` carries entries that are\n * not failures at all, and a summary built from the prose would file those as work owed.\n */\nexport function agentsNotCompiled(agentNames: readonly AgentName[]): string {\n return `${agentNames.length} sub-agent(s) did not compile: ${agentNames.join(\", \")}`;\n}\n\n/**\n * One thing a run set out to do and did not, paired with the one command that finishes it.\n *\n * Both halves are required. A run that names the failure and no way out has told the user their\n * installation is wrong and left them holding it, and one that names a remedy without saying\n * what it remedies is advice about nothing.\n */\nexport type IncompleteWork = {\n /** What did not happen, in the words it was warned about with where they exist. */\n what: string;\n /** The single next thing that finishes it. */\n recovery: string;\n};\n\n/**\n * The ways out a command names when it finishes with work undone.\n *\n * One sentence per KIND of leftover state rather than one per failure site: what a person does\n * about a plugin registration that outlived the skill it was for is the same whichever of the\n * moments left it there, and three spellings of the same instruction read as three different\n * instructions.\n */\nexport const INCOMPLETE_WORK_RECOVERY = {\n RECOMPILE: `Run '${CLI_INVOKE_COMMAND} compile' — the compiled agents on disk are stale until you do.`,\n INSPECT_INSTALLATION: `Run '${CLI_INVOKE_COMMAND} doctor' to see what this installation is left holding.`,\n DELETE_AGENT_FILE:\n \"Delete the file by hand — Claude Code loads a compiled sub-agent this project no longer configures.\",\n} as const;\n\n/**\n * The account a command ends on when its work landed and part of it did not.\n *\n * It restates warnings the run already printed, deliberately: each was emitted where it\n * happened, which is where it is explicable and where the screens of output after it bury it.\n * This block is what a person reads after the fact, and the only place a non-zero exit from a\n * command that finished is explained.\n *\n * The lead-in claims the changes above LANDED, because that is the whole difference between\n * this ending and a refusal, and it is the sentence a reader would dispute.\n */\nexport function completedWithFailures(failures: readonly IncompleteWork[]): string {\n return [\n `Completed with ${failures.length} failure(s) — the changes above landed, these did not:`,\n ...failures.flatMap(failureLines),\n ].join(\"\\n\");\n}\n\n/** One failure as two lines, the remedy indented under the failure it answers. */\nfunction failureLines({ what, recovery }: IncompleteWork): string[] {\n return [` ${what}`, ` ${recovery}`];\n}\n\n/**\n * The same distinction for the fan-out a global change performs across every\n * OTHER registered project: a project whose agents all came back byte-identical\n * was visited and left alone, and says so instead of being counted as recompiled.\n */\nexport function propagatedRecompileSummary(\n rewritten: number,\n unchanged: number,\n failed: number,\n): string {\n const failureSuffix = failed > 0 ? ` (${failed} failed)` : \"\";\n return `Recompiled agents in ${plural(rewritten, \"registered project\")}, ${unchanged} unchanged${failureSuffix}`;\n}\n\n/**\n * Warning printed for an installed, actively-selected skill that no sub-agent's stack\n * carries. The install itself is correct — the files are on disk and `config.ts` records\n * them — but nothing will ever load the skill, and every other surface reports the run\n * as clean. This line is the only one that says so.\n */\nexport function skillAssignedToNoAgent(skillId: SkillId): string {\n return `Skill '${skillId}' is assigned to no sub-agent — nothing will load it.`;\n}\n\n/**\n * The reason behind {@link skillAssignedToNoAgent} whenever it is the scope rule: a\n * project-scoped skill never reaches a global-scoped sub-agent. Names every sub-agent the\n * rule kept the skill away from, so one line accounts for every dropped pair.\n *\n * Shared by the save path (`init` / `edit`, where the assignment was never built) and by\n * `compile` (where a hand-edited `config.ts` declares the pair and the compile-time filter\n * drops it). One verdict, one sentence — a second spelling would read as a second rule.\n */\nexport function scopeBlockedStackAssignment(agentNames: AgentName[], skillId: SkillId): string {\n const subject = agentNames.length === 1 ? \"Sub-agent\" : \"Sub-agents\";\n const named = agentNames.map((name) => `'${name}'`).join(\", \");\n return `${subject} ${named} cannot carry project-scoped skill '${skillId}' — global-scoped sub-agents only carry global-scoped skills.`;\n}\n\n/**\n * Hint printed when a project-context compile resolves zero project agents but\n * the config still declares global-scope agents. Names the global context and\n * the count so the \"No agents to recompile\" no-op isn't silent after a global\n * stack change.\n */\nexport function globalScopedAgentsHint(count: number): string {\n const [subject, object] = count === 1 ? [\"agent is\", \"it\"] : [\"agents are\", \"them\"];\n return `${count} ${subject} global-scoped — run '${CLI_INVOKE_COMMAND} compile' from your home directory, or edit from this project, to recompile ${object}.`;\n}\n\n/**\n * Summary printed after `update` refreshed every marketplace its config named. A marketplace\n * refresh re-reads the listing and installs nothing, so the installed plugins keep their versions.\n */\nexport function marketplacesRefreshed(count: number): string {\n return `Refreshed ${plural(count, \"marketplace listing\")}. Installed plugins were not changed.`;\n}\n\n/** Warning printed for one marketplace the Claude CLI could not refresh. */\nexport function marketplaceRefreshFailed(marketplace: string, reason: string): string {\n return `Could not update marketplace ${marketplace}: ${reason}`;\n}\n\n/**\n * Warning printed when a remote source could not be reached to check whether the\n * cached copy is still current, and the copy was used anyway.\n *\n * The load succeeds — an offline user gets the marketplace they already have\n * rather than an error — so the line's whole job is to name what it is they got.\n */\nexport function sourceUnreachableUsingCache(source: string): string {\n return `Could not reach ${source} — using the cached copy, which may be out of date.`;\n}\n\n/**\n * Fatal summary naming every marketplace that failed to refresh. Each cause was\n * already warned individually; this is what makes the run exit non-zero.\n */\nexport function marketplacesRefreshFailed(marketplaces: string[]): string {\n const subject = marketplaces.length === 1 ? \"marketplace\" : \"marketplaces\";\n return `${marketplaces.length} ${subject} could not be updated: ${marketplaces.join(\", \")}`;\n}\n\n/**\n * `build marketplace`'s refusal when package.json names no author, so the manifest\n * would carry an owner with no name.\n *\n * Refused rather than warned because `marketplaceOwnerSchema` requires that name: a\n * manifest written without one is a file this CLI's own reader rejects, and a build\n * that exits 0 having produced it reports success for a marketplace nobody can add.\n */\nexport function marketplaceOwnerHasNoName(packageJsonPath: string): string {\n return [\n `A marketplace's owner must have a name, and no name could be read from 'author' in ${packageJsonPath}.`,\n `Nothing was written: a ${MARKETPLACE_JSON} whose 'owner.name' is empty is refused by this CLI's own reader, so the build would have reported success for a marketplace nobody can install from.`,\n `Set 'author' in that file — either \"Jane Doe <jane@example.com>\" or { \"name\": \"Jane Doe\" } — and build again.`,\n ].join(\"\\n\\n\");\n}\n\n/**\n * `build marketplace`'s refusal when package.json carries a version that is only a version\n * to a reader who does not check it.\n *\n * `marketplaceSchema` requires `min(1)` here, and nothing upstream did: the package.json\n * schema types the field as a bare string, and the generator's `??` default treats `\"\"` as\n * a value because it is not nullish. So an empty version reached the manifest, the build\n * exited 0, and the file was refused the first time this CLI read it back — the same\n * write-then-fail-on-read shape the zero-plugin refusal closed.\n */\nexport function marketplaceHasNoVersion(packageJsonPath: string): string {\n return [\n `A marketplace must have a version, and 'version' in ${packageJsonPath} is empty.`,\n `Nothing was written: a ${MARKETPLACE_JSON} whose 'version' is empty is refused by this CLI's own reader, so the build would have reported success for a marketplace nobody can install from.`,\n `Set 'version' in that file — \"0.1.0\" if this is its first release — and build again.`,\n ].join(\"\\n\\n\");\n}\n\n/**\n * `build marketplace`'s refusal when the name read from package.json is not one a\n * marketplace may publish under.\n *\n * The way out is the flag rather than a rename of the npm package: an npm scoped name\n * is a legitimate thing for a package to have and an illegitimate marketplace name, so\n * the two identities are allowed to differ. Every offending character is named, because\n * `@scope/thing` gives an author two edits to make and a rule alone gives them none.\n */\nexport function marketplaceNameNotPublishable(name: string, packageJsonPath: string): string {\n const offenders = charactersOutsideKebabCase(name);\n return [\n `Marketplace name '${name}', read from 'name' in ${packageJsonPath}, is not a name a marketplace may publish under.`,\n ...(offenders.length > 0\n ? [\n `It carries ${offenders.map((character) => `'${character}'`).join(\" and \")}, which a marketplace name may not.`,\n ]\n : []),\n `A marketplace name is kebab-case: lowercase letters, numbers and hyphens, starting with a letter.`,\n `Publish under a name of your own instead: '${CLI_INVOKE_COMMAND} build marketplace --name <your-marketplace>'.`,\n ].join(\"\\n\\n\");\n}\n\n/** A marketplace's manifest as its author has to type the path. */\nconst MARKETPLACE_MANIFEST = `${PLUGIN_MANIFEST_DIR}/${MARKETPLACE_JSON}`;\n\n/**\n * The rule and its remedy, shared by both refusals below: the two builds that write the manifest,\n * in the order an author runs them — `build plugins` writes the bundles `build marketplace` lists.\n */\nconst MARKETPLACE_MANIFEST_REQUIRED = [\n `Every marketplace other than the default one must publish a valid ${MARKETPLACE_MANIFEST}.`,\n `Run '${CLI_INVOKE_COMMAND} build plugins' and then '${CLI_INVOKE_COMMAND} build marketplace' in that marketplace's repository, which write it.`,\n].join(\" \");\n\n/** The refusal of a marketplace other than the default one that publishes no manifest at all. */\nexport function marketplaceManifestMissing(source: string): string {\n return [\n `'${source}' has no ${MARKETPLACE_MANIFEST}, so it is not a marketplace yet.`,\n MARKETPLACE_MANIFEST_REQUIRED,\n ].join(\"\\n\\n\");\n}\n\n/**\n * The refusal of a marketplace other than the default one whose manifest is there and cannot be\n * read — it does not parse, or the schema refuses it. `reason` is the reader's own, so a schema\n * refusal names the field the author has to fix as well as the builds that rewrite the file.\n */\nexport function marketplaceManifestUnreadable(source: string, reason: string): string {\n return [\n `'${source}' has a ${MARKETPLACE_MANIFEST} this CLI cannot read:\\n${reason}`,\n MARKETPLACE_MANIFEST_REQUIRED,\n ].join(\"\\n\\n\");\n}\n\n/**\n * Warning printed when a compile pass finished but the scope's config-types.ts\n * could not be regenerated (e.g. the skills source was unreachable). The compiled\n * agents are fine; only the type unions may still be stale.\n */\nexport function configTypesRefreshFailed(reason: string): string {\n return `Could not refresh ${STANDARD_FILES.CONFIG_TYPES_TS} — type unions may be stale: ${reason}`;\n}\n\n/**\n * Summary printed after a global uninstall pruned the inlined global-scoped\n * config entries from the registered projects.\n */\nexport function registeredProjectsUpdated(count: number): string {\n return `Updated ${count} registered ${count === 1 ? \"project\" : \"projects\"}`;\n}\n\n/**\n * Warning printed when a global uninstall could not prune one registered project whose config is\n * still there — unreadable, or its rewrite failed. The uninstall continues.\n */\nexport function registeredProjectUpdateSkipped(projectPath: string): string {\n return `Could not update registered project at ${projectPath} — its config may still reference the uninstalled global content`;\n}\n\n/** Warning printed when a global change could not reach a registered project whose config.ts cannot be loaded. */\nexport function registeredProjectConfigUnreadable(projectPath: string): string {\n return `Skipped ${projectPath}: its config.ts can't be read.`;\n}\n\n/** Warning printed when a global change found nothing installed at a registered project's path. */\nexport function registeredProjectGone(projectPath: string): string {\n return `Skipped ${projectPath}: nothing is installed there any more.`;\n}\n\n/** Warning printed when a global change left a registered project on the other provider alone. */\nexport function registeredProjectOnAnotherProvider(projectPath: string): string {\n return `Skipped ${projectPath}: it is another provider's installation.`;\n}\n\n/** Warning printed when a global compile's rewrite of a registered project failed. */\nexport function registeredProjectUpdateFailed(projectPath: string): string {\n return `Skipped ${projectPath}: updating it failed.`;\n}\n\n/**\n * The file and the reason behind {@link skillMetadataUnusableError}, LOGGED rather than\n * carried in the error itself: oclif hard-wraps error text at the terminal width, and a path\n * broken across two lines is one nobody can copy. The error names the skills; this names\n * their files, unwrapped, immediately above it.\n *\n * The reason is the reader's own message and can run to several lines — a YAML parse error\n * carries the position and the offending line, which is the point of naming the file at all.\n * For a file that parsed, it is the fields the file leaves out, named as missing.\n */\nexport function skillMetadataUnusableDetail({\n skillDirName,\n metadataPath,\n reason,\n}: UnusableSkillMetadata): string {\n return ` ${skillDirName} — ${metadataPath}\\n ${reason}`;\n}\n\n/**\n * Which skills the refusal is about, and that their files are named above it. Shared by both\n * refusals below because it is one sentence about one verdict — the commands differ on what\n * the file being unreadable COSTS, not on what it says.\n *\n * Every offending skill is named rather than the first, so one run fixes the lot.\n */\nfunction metadataUnusableOpening(entries: UnusableSkillMetadata[]): string {\n const named = entries.map(({ skillDirName }) => `'${skillDirName}'`).join(\", \");\n const subject = entries.length === 1 ? \"that skill\" : \"those skills\";\n return `The ${STANDARD_FILES.METADATA_YAML} of ${named} does not describe ${subject} — the file and the reason are named above.`;\n}\n\n/**\n * The two ways out, and where the whole list of skills in this state is reported. Also shared:\n * a refusal that named a different way out per command would be describing a different fault.\n */\nconst METADATA_UNUSABLE_WAY_OUT = `Fix the file, or delete the skill directory — '${CLI_INVOKE_COMMAND} doctor' reports every skill in this state.`;\n\n/**\n * Refusal printed when `compile` meets an installed skill whose metadata.yaml exists but\n * describes no skill — either nothing can be parsed out of it, or it parses without the\n * fields a skill is described by. It is the sibling of {@link installationConfigsUnreadable} one\n * layer down: the file is there, and nothing can be made of it.\n *\n * Compile refuses rather than skips because a skipped skill is invisible. The same file is\n * refused by the local-skill discovery that regenerates `config-types.ts`, so a compile that\n * loaded the skill from its SKILL.md anyway would write agents around a skill the generated\n * types never carry — which is what it used to do, in the same run, silently.\n */\nexport function skillMetadataUnusableError(entries: UnusableSkillMetadata[]): string {\n return [\n metadataUnusableOpening(entries),\n `A skill this file cannot describe is skipped when ${STANDARD_FILES.CONFIG_TYPES_TS} is regenerated, so compiling it would write agents around a skill the generated types never carry.`,\n METADATA_UNUSABLE_WAY_OUT,\n ].join(\"\\n\");\n}\n\n/**\n * The same refusal raised by `init` and `edit`, where what the file costs is different: the\n * wizard resolves the installed roster against the catalogue, and a skill nothing can be\n * loaded for reaches no screen — so the entry naming it is dropped from `config.ts` and\n * reported as a removal the user never asked for.\n *\n * That is the right answer for a skill the marketplace no longer carries and the wrong one\n * here, where the files are sitting in the install and one repairable file stands between\n * them and the catalogue. So the run stops with the entry intact, exactly as `compile` stops\n * over the same verdict about the same file, rather than spending the record of an install\n * on a YAML typo and billing the marketplace for it.\n */\nexport function savedSkillMetadataUnusableError(entries: UnusableSkillMetadata[]): string {\n return [\n metadataUnusableOpening(entries),\n `A config entry naming a skill this file cannot describe is dropped as one this marketplace does not carry — and a file that can be repaired must not cost an install its record.`,\n METADATA_UNUSABLE_WAY_OUT,\n ].join(\"\\n\");\n}\n\n/**\n * `init --from` installs into a clean directory. A shared configuration is installed whole — its\n * own `assignments` map REPLACES the ownership-derived stack rather than merging with it — so there\n * is no coherent answer to what it should do when it meets a setup that is already there. The\n * refusal below names `edit --from`, which applies the id to that setup, and `uninstall`, which\n * clears the way for this one.\n *\n * A global installation above the directory is not such a setup. It is not this directory's, so\n * the run adds to it what it lacks and leaves the rest as installed — see\n * {@link keptAsInstalledGlobally}.\n */\nconst SHARED_CONFIG_GREENFIELD_HINT =\n \"installing a shared configuration is a fresh setup, not a merge\";\n\n/**\n * Where a freshly minted id can be acted on, which is the whole of what makes it a share.\n *\n * Exactly two things read one — this CLI and the editor the configuration reopens in — and both\n * commands that mint an id (`share`, and `edit --ui`) print both lines, because an id nobody can\n * act on is not a share. One definition rather than two, so the two commands cannot come to\n * describe the same id differently.\n */\nexport function sharedConfigDestinations(id: string): string[] {\n return [\n ` Install it: ${CLI_INVOKE_COMMAND} init --from ${id}`,\n ` Open it: ${editorConfigUrl(id)}`,\n ];\n}\n\n/**\n * What `init --ui` and `edit --ui --from` print under the link: the command that applies an id\n * HERE. `init --from` installs into a directory holding no installation of its own and refuses one\n * that does, where `edit --from` is what applies an id — so the line follows the directory, never\n * the command that opened the link. With no id yet (a bare `init --ui`), it names the command for\n * the id the editor will give.\n */\nexport function applySharedConfigHere(id: string | undefined, installedHere: boolean): string {\n const command = `${CLI_INVOKE_COMMAND} ${installedHere ? \"edit\" : \"init\"} --from`;\n const verb = installedHere ? \"apply\" : \"install\";\n return id === undefined\n ? `Then ${verb} what it gives you with '${command} <id>'.`\n : `To ${verb} it here instead, run '${command} ${id}'.`;\n}\n\n/**\n * `share`'s refusal while anything it would send is an ejected (Local) copy, an editor-added skill\n * included. A share carries plugins only; `edit --ui` still opens the same installation.\n */\nexport function shareRefusesEjectedSkills(skillIds: readonly string[]): string {\n return [\n \"This installation holds ejected skills, and ejected skills cannot be shared:\",\n ...skillIds.map((id) => ` ${id}`),\n \"Only plugins can be shared.\",\n ].join(\"\\n\");\n}\n\n/** What `share` says after the id when the marketplace it names is a folder on this machine. */\nexport function sharedIdNamesAFolder(folder: string): string {\n return `This id names the marketplace folder ${folder}, so it installs only where that folder exists.`;\n}\n\n/**\n * What `share` says after the id when what it sent comes from more than one marketplace. A payload\n * names one, so the others' skills are skipped wherever the id is installed.\n */\nexport function sharedSkillsLeftBehind(skillIds: readonly string[]): string {\n return `A shared id names one marketplace, and these skill(s) come from another, so they will not install elsewhere: ${skillIds.join(\", \")}`;\n}\n\n/** Refusal printed when the directory `init --from <id>` was run in is already installed. */\nexport function sharedConfigExistingInstall(configPath: string, id: string): string {\n return `An installation already exists at ${configPath}. Run '${CLI_INVOKE_COMMAND} uninstall' first — ${SHARED_CONFIG_GREENFIELD_HINT}. ${applySharedConfigHere(id, true)}`;\n}\n\n/**\n * Refusal printed when `init --from` runs at the home directory and the payload carries\n * project-scoped entries.\n *\n * It is NOT a greenfield refusal, and deliberately says nothing about `uninstall`: the payload is\n * installable and the location is not, so the way out is another directory rather than a removal.\n * A global installation holds only global-scoped content, and at the home root both scopes resolve\n * to the same files — so a project-scoped entry does not land elsewhere, it lands in the global\n * config wearing a label that contradicts the file it is in.\n *\n * Every offender is named, skills and sub-agents alike, because they are separate decisions in the\n * payload and only the sharer knows which one they meant — the same reason the unwritable-pair\n * refusal names both halves of every pair.\n */\nexport function sharedConfigProjectScopeAtHome(\n skillIds: readonly SkillId[],\n agentNames: readonly AgentName[],\n): string {\n return [\n \"This configuration cannot be installed here: the home directory is the global scope, and a \" +\n \"global installation holds only global-scoped content — so these project-scoped entries \" +\n \"have nowhere to be written:\",\n ...skillIds.map((id) => ` skill ${id} (scope: project)`),\n ...agentNames.map((name) => ` sub-agent ${name} (scope: project)`),\n \"Run this from inside a project directory, or re-share it with each entry above at global scope.\",\n ].join(\"\\n\");\n}\n\n/**\n * The ids a decode could not place, named rather than counted.\n *\n * \"3 skills were skipped\" cannot be acted on; the ids can, and this is the one moment a user\n * can tell whether what was shared is what they are getting. One definition because both\n * consumers of a shared configuration report it — `init --from` on the way into a clean\n * directory, `edit --from` on the way over an installed one — and a skip that read differently\n * per command would look like a different kind of skip.\n */\nexport function skippedUnknownSkills(skillIds: readonly string[]): string {\n return `Skipped ${skillIds.length} skill(s) this catalog does not know: ${skillIds.join(\", \")}`;\n}\n\n/** The sub-agent half of {@link skippedUnknownSkills}, judged against `AGENT_NAMES`. */\nexport function skippedUnknownAgents(agentNames: readonly string[]): string {\n return `Skipped ${agentNames.length} unknown sub-agent(s): ${agentNames.join(\", \")}`;\n}\n\n/**\n * What a shared configuration brought with it rather than named. Named for the same reason the\n * skips are: these are the entries no catalogue can explain, so this line is the only place a\n * user learns what arrived inside the configuration itself.\n */\nexport function carriedSkillsWritten(skillIds: readonly string[]): string {\n return `Wrote ${skillIds.length} skill(s) this configuration carries: ${skillIds.join(\", \")}`;\n}\n\n/**\n * The fixed text of `edit --from`'s removal plan.\n *\n * Applying a shared configuration makes the installation this run edits MATCH it, so a skill the\n * previous configuration installed and this payload omits is removed. That is the whole reason the\n * command is interactive, and the reason the heading names removal rather than the apply. What the\n * apply adds or changes is listed above it, in {@link SHARED_CONFIG_ARRIVALS}' two lists.\n */\nexport const SHARED_CONFIG_APPLY = {\n PREVIEW_HEADING: \"Applying this configuration will remove:\",\n SKILLS_HEADING: \"Skills:\",\n AGENTS_HEADING: \"Sub-agents:\",\n /** Printed in place of the sections when the payload takes nothing away. */\n NOTHING_REMOVED: \"Nothing is removed — this configuration only adds and re-tunes.\",\n CONFIRM: \"Apply this configuration?\",\n} as const;\n\n/**\n * A removal-plan line for the project's half of a `[P][G]` pair the configuration leaves out. Only\n * this project's copy goes: the global install keeps its own, which the project then reads.\n */\nexport function projectCopyRemoved(subject: string): string {\n return `${subject}: this project's copy is removed; the global one takes over`;\n}\n\n/**\n * Refusal printed when `edit --from` has no terminal to confirm its removals at.\n *\n * A confirm nobody can answer must never become a yes, so this refuses rather than applying\n * silently. It names the other command deliberately: `init --from` installs the same\n * configuration into a clean directory and removes nothing, so it is safe headless and is the\n * whole of what a pipeline can do with an id.\n */\nexport function sharedConfigNeedsTerminal(id: string): string {\n return [\n `Applying configuration '${id}' removes whatever it leaves out, so it has to be confirmed — and there is no terminal here to confirm it at.`,\n `Run '${CLI_INVOKE_COMMAND} edit --from ${id}' from a terminal, or '${CLI_INVOKE_COMMAND} init --from ${id}' in a clean directory, which installs without removing anything.`,\n ].join(\"\\n\");\n}\n\n/**\n * Refusal printed when `edit --from` is run where nothing is installed, terminal or not: there is\n * no installation for the configuration to be applied to. It names `init --from` with the id\n * rather than bare `init`, because the configuration is already in hand and that is the command\n * that installs it here.\n */\nexport function nothingInstalledToApplyTo(id: string): string {\n return `No installation found. Run '${CLI_INVOKE_COMMAND} init --from ${id}' to install configuration '${id}' here.`;\n}\n\n/** The run each wizard-opening command can be swapped for where there is no terminal. */\nconst RUNS_WITHOUT_A_TERMINAL = {\n init: `'${CLI_INVOKE_COMMAND} init --from <id>' installs a configuration built in the editor without one`,\n edit: `'${CLI_INVOKE_COMMAND} edit --ui' opens this installation in the editor without one`,\n} as const;\n\n/**\n * Refusal printed when `init` or `edit` would open the wizard where there is no terminal to open\n * it in — a CI job, a script, a pipe.\n *\n * Mounting it anyway died on Ink's raw-mode error over a React stack trace. A command that cannot\n * run without a terminal \"should break because it's not a valid command\" (owner ruling\n * 2026-10-02), so it breaks on purpose and in words, worded after {@link sharedConfigNeedsTerminal}\n * because it is the same refusal one command over.\n */\nexport function wizardNeedsTerminal(command: keyof typeof RUNS_WITHOUT_A_TERMINAL): string {\n return [\n `'${CLI_INVOKE_COMMAND} ${command}' opens a wizard, and there is no terminal here to open it in.`,\n `Run it from a terminal — ${RUNS_WITHOUT_A_TERMINAL[command]}.`,\n ].join(\"\\n\");\n}\n\n/**\n * Refusal printed when `uninstall` has no terminal to confirm its removals at. A confirm nobody\n * can answer must never become a yes, so `--yes` — the person saying it in advance — is named.\n */\nexport function uninstallNeedsTerminal(): string {\n return [\n \"Uninstalling removes files, so it has to be confirmed — and there is no terminal here to confirm it at.\",\n `Run '${CLI_INVOKE_COMMAND} uninstall' from a terminal, or '${CLI_INVOKE_COMMAND} uninstall --yes' to remove it without being asked.`,\n ].join(\"\\n\");\n}\n\n/**\n * Refusal printed for `init --ui --marketplace`. The editor's address carries a configuration id\n * and nothing else, so a marketplace named here would be dropped on the way — and a flag silently\n * dropped reads as honoured. The one command it names is the same run without the flag, because\n * that runs in every folder: `init --marketplace` refuses in one whose installation came from\n * another marketplace.\n */\nexport function editorLoadsItsOwnMarketplace(named: string): string {\n return `--marketplace '${named}' cannot be handed to the editor: the editor loads marketplaces itself. Run '${CLI_INVOKE_COMMAND} init --ui' and load it there.`;\n}\n\n/**\n * Refusal printed when `init --marketplace` names a marketplace other than the one this folder's\n * own installation was made from. An installation's marketplace is chosen once, when it is made,\n * and every command after `init` reads the one it stored.\n */\nexport function marketplaceFixedAtInstall(stored: string, named: string): string {\n return `This folder's installation was made from the marketplace '${stored}', and an installation's marketplace is chosen once, when it is made — so --marketplace '${named}' was not used. Run '${CLI_INVOKE_COMMAND} init' without it to open this installation, or '${CLI_INVOKE_COMMAND} uninstall' first to set this folder up from another.`;\n}\n\n/**\n * The two lists every `--from` install prints before it writes anything — what goes into this\n * project and what into the global install — and the question `init --from` asks under them at a\n * terminal.\n *\n * Half a shared configuration may land in the global install, which every project on the machine\n * reads, so what lands where is said before anything does. `init --from` prints the lists with no\n * terminal too, where it carries on without asking; `edit --from` prints them above the confirm it\n * already asks, listing only what it adds or changes. At the home directory the run IS the global\n * install, so only the second list can have anything in it.\n *\n * In a project, `init --from` lists a third thing under those two: the global skills it skips\n * because the global install above the project already holds them, each left as installed.\n */\nexport const SHARED_CONFIG_ARRIVALS = {\n PROJECT_HEADING: \"Into this project:\",\n GLOBAL_HEADING: \"Into the global install:\",\n SKIPPED_HEADING: \"Skipped, already in the global install:\",\n INSTALL_CONFIRM: \"Install this configuration?\",\n} as const;\n\n/**\n * The statement for global entries a project run leaves exactly as the global install holds them,\n * though the configuration states them otherwise.\n *\n * From a project, `--from` only ADDS to the global install: it is one installation every project on\n * the machine reads, and a run started in one of them is not a decision about the rest. So a global\n * skill or sub-agent the configuration installs differently, loads differently or tunes\n * differently stays as installed — and is named here, because a difference nobody is told about is\n * a configuration that silently did not arrive. So is a global skill or sub-agent `edit --from`\n * keeps though the configuration leaves it out, and a carried skill whose global copy reads\n * otherwise than the configuration's.\n */\nexport function keptAsInstalledGlobally(\n skillIds: readonly SkillId[],\n agentNames: readonly AgentName[],\n): string {\n return [\n \"Kept as installed in the global install — this configuration states them differently or leaves them out, and a project run only adds to the global install:\",\n ...skillIds.map((id) => ` skill ${id}`),\n ...agentNames.map((name) => ` sub-agent ${name}`),\n `Change them with '${CLI_INVOKE_COMMAND} edit' from your home directory.`,\n ].join(\"\\n\");\n}\n\n/**\n * The removal plan's statement for skills the round trip does not own.\n *\n * `forkedFrom` decides ownership: the CLI stamps it into every skill directory it writes, and a\n * skill written by hand into `.claude/skills/` carries none — so no shared configuration ever\n * carried it, and this one made no statement about it. Deleting it would be this command\n * inventing an instruction nobody gave.\n */\nexport function authoredHereKept(skillIds: readonly SkillId[]): string {\n return [\n \"Kept — written here rather than installed, so a shared configuration never carried them:\",\n ...skillIds.map((id) => ` skill ${id}`),\n `Remove them with '${CLI_INVOKE_COMMAND} edit'.`,\n ].join(\"\\n\");\n}\n\n/**\n * The removal plan's statement for skills this configuration NAMES that this catalogue cannot\n * place.\n *\n * The skips reported earlier say what did not arrive; this says what stayed because of it, and\n * the two are one fact read from either end. A destructive apply removes on intent and never on\n * its own inability: the payload asked for these ids, so their absence from the decode is this\n * catalogue's limit rather than an instruction, and deleting an installed skill over it would\n * delete it because the catalogue moved.\n *\n * The remedy is the catalogue rather than the skill, which is the whole difference from the two\n * statements above: nothing is wrong with what is installed, and nothing the user does to it\n * makes the configuration's instruction applicable.\n */\nexport function unplaceableKept(skillIds: readonly SkillId[]): string {\n return [\n \"Kept — named by this configuration, and this catalogue cannot place them:\",\n ...skillIds.map((id) => ` skill ${id}`),\n `Run '${CLI_INVOKE_COMMAND} update' to refresh this installation's marketplace, then apply the configuration again.`,\n ].join(\"\\n\");\n}\n\n/**\n * A kept skill's row in a category that holds one skill, which the configuration's own skill\n * takes: the skill stays installed, and that sub-agent no longer loads it there.\n */\nexport function keptUnassigned(skillId: SkillId, agentName: AgentName, category: Category): string {\n return `${skillId}: kept, no longer assigned to ${agentName}'s ${category}`;\n}\n\n/**\n * What every refusal over an unreadable config offers besides recreating it: the editor builds a\n * configuration the CLI installs by id, and `doctor` reports the same files as its own findings.\n *\n * `doctor` could not be named until it did — it used to call a config that exists but cannot be\n * read `.claude-src/config.ts not found` and send the reader to `init`, contradicting both lines.\n */\nfunction otherWaysPastUnreadableConfigs(count: number): string[] {\n return [\n `Or build one at ${EDITOR_URL} and install it with '${CLI_INVOKE_COMMAND} init --from <id>'.`,\n `'${CLI_INVOKE_COMMAND} doctor' reports the same ${count === 1 ? \"file\" : \"files\"}, alongside whatever else is wrong here.`,\n ];\n}\n\n/** One config that could not be loaded, as the refusal names it. */\ntype UnreadableConfig = Pick<ConfigLoadError, \"configPath\" | \"reason\" | \"scope\" | \"scopeRoot\">;\n\n/**\n * Refusal printed when a command that must read an installation's configuration meets configs it\n * cannot load. There are no versioned migrations, so an unreadable configuration is recreated\n * rather than repaired — and `uninstall` deliberately keeps working on one, which is what makes\n * the first instruction a real way out rather than a suggestion to delete directories by hand.\n *\n * It says WHOSE config each is and where its way out is taken from. A project reads two configs,\n * its own and the global one it inherits, so a refusal printed in a project can be about either\n * or both — and one naming no folder sent a user with a healthy project config and a broken global\n * one to uninstall the project, deleting the one config that was fine. Naming only the first of\n * two broken ones sends them round twice.\n */\nexport function installationConfigsUnreadable(failures: readonly UnreadableConfig[]): string {\n return [\n ...failures.flatMap(whoseConfigAndItsWayOut),\n ...otherWaysPastUnreadableConfigs(failures.length),\n ].join(\"\\n\");\n}\n\n/** One unreadable config: whose it is, why, and the folder its way out is run from. */\nfunction whoseConfigAndItsWayOut(failure: UnreadableConfig): string[] {\n return [\n `${scopeLabel(failure.scope)}'s config at '${failure.configPath}' could not be loaded: ${failure.reason}`,\n `There is no automatic repair for this — recreate the configuration by running ${recreateConfigFrom(failure.scopeRoot)}.`,\n ];\n}\n\n/**\n * `uninstall`'s warning over a config it cannot read, which it goes past rather than stops on: the\n * plugins and compiled agents the config lists can no longer be identified. It names whose config\n * it read — at the home directory that is the global installation's, never a project's.\n */\nexport function uninstallConfigUnreadable(\n failure: Pick<ConfigLoadError, \"scope\" | \"message\">,\n): string {\n return `Could not read the ${failure.scope} config — plugins and compiled agents it lists may be left behind: ${failure.message}`;\n}\n\n/**\n * The way out of a config nobody can read, run from the folder that holds it: the project, or the\n * home directory for the global config. Shared with `doctor`'s tip, so the report and the refusal\n * send a user to the same place.\n */\nexport function recreateConfigFrom(scopeRoot: string): string {\n return `'${CLI_INVOKE_COMMAND} uninstall', which still works on a config it cannot read, then '${CLI_INVOKE_COMMAND} init', from '${scopeRoot}'`;\n}\n\n/**\n * The same refusal for a config file that belongs to no installation — a marketplace repository's\n * own `config.ts`, which `loadSourceRepoConfig` reads — so there is no scope to name and no folder\n * to send anyone to. `configLoadFailure` is the loader's own message, which already names the file\n * and the reason.\n */\nexport function configUnreadableError(configLoadFailure: string): string {\n return [\n configLoadFailure,\n `There is no automatic repair for this — recreate the configuration: '${CLI_INVOKE_COMMAND} uninstall' still works on a config it cannot read, then '${CLI_INVOKE_COMMAND} init'.`,\n ...otherWaysPastUnreadableConfigs(1),\n ].join(\"\\n\");\n}\n\n/**\n * Warning printed when a global uninstall could not update the registered\n * projects at all (e.g. the skills source failed to load). The uninstall\n * itself still completes.\n */\nexport function registeredProjectsUpdateFailed(reason: string): string {\n return `Could not update registered projects — their configs may still reference the uninstalled global content: ${reason}`;\n}\n\n/**\n * Statement printed in the uninstall removal plan, and again in the summary, for the agent\n * files this run leaves where they are. Every agent the compiler writes carries a provenance\n * marker, so an agent file without one was written by somebody else — and saying so is what\n * makes the removal beside it a claim about provably-ours rather than about a directory.\n *\n * Printed both before the confirmation and after the removal, from the one plan, so what the\n * user approved and what the run reports cannot disagree.\n */\nexport function unmarkedAgentsKept(agentsDir: string, count: number): string {\n const subject = count === 1 ? \"agent\" : \"agents\";\n const object = count === 1 ? \"it\" : \"them\";\n return `Kept ${count} ${subject} in ${agentsDir}/ — no ${DEFAULT_PLUGIN_NAME} marker, so this CLI did not compile ${object}.`;\n}\n\n/**\n * The uninstall removal plan's fixed text: the heading the whole plan is printed under,\n * and the heading each removal is grouped beneath. A heading is a promise about the lines\n * below it, so one is printed only when the plan carries a removal that sits under it.\n * Both renderers — the `--yes` printer and the confirm UI — read them from here, so the\n * preview a user approves and the list a `--yes` run prints cannot drift apart.\n */\nexport const UNINSTALL_PLAN = {\n PREVIEW_HEADING: \"The following will be removed:\",\n PLUGINS_HEADING: \"Plugins:\",\n CLI_MANAGED_FILES_HEADING: \"CLI-managed files:\",\n CONFIG_HEADING: \"Config:\",\n} as const;\n\n/**\n * The plan's line for the local skills directory. The directory is not removed wholesale —\n * only the skills whose `forked-from` metadata names a marketplace are — so the line says\n * which of its contents the run is claiming.\n */\nexport function localSkillsRemoval(skillsDir: string): string {\n return `${skillsDir}/ (matching the marketplace)`;\n}\n\n/**\n * The plan's line for the compiled agents directory, marking it as the CLI's to delete\n * rather than the user's. Printed when the run can name which agents those are — from the\n * configuration, or from the provenance marker each compiled file carries when the\n * configuration is gone. {@link unmarkedAgentsKept} names the rest.\n */\nexport function compiledAgentsRemoval(agentsDir: string): string {\n return `${agentsDir}/ (CLI-compiled)`;\n}\n\n// --- The source folder rename: doctor's Layout row, and the rival-folder refusal --------------\n//\n// Every sentence below names BOTH folders, and never from a literal: which one a scope is on is\n// resolved from disk, and the same sentence is printed by more than one command. The Layout row\n// reports, the write commands refuse — two surfaces describing one state, so one builder each and\n// no command holding its own copy.\n//\n// **No sentence here names a command that moves a source folder, because there is none.** Moving\n// one is a manual step, and the messages that meet a user in that state say so rather than\n// handing out an invocation that would exit 127.\n\n/** How a sentence names the directory a source folder sits under, mid-sentence. */\nexport function scopeNoun(kind: ScopeKind): string {\n return kind === \"project\" ? \"this project\" : \"the global installation\";\n}\n\n/** The same noun where it starts a sentence — doctor's rows and the refusal. */\nexport function scopeLabel(kind: ScopeKind): string {\n return sentenceCase(scopeNoun(kind));\n}\n\nfunction sentenceCase(text: string): string {\n return `${text.slice(0, 1).toUpperCase()}${text.slice(1)}`;\n}\n\n/**\n * Two rival folders in one scope.\n *\n * Shared by doctor's Layout row and the write commands' refusal on purpose: a state one of them\n * calls a collision and the other does not is a state a user cannot get out of.\n *\n * `readFrom` is the folder the resolver ACTUALLY picked and is the only half of this sentence a\n * reader has to be told — the two names in front of the dash are settled by the layout itself.\n * It is a parameter rather than `to` for the reason the state exists: the preference order takes\n * whichever folder holds a `config.ts` before it looks at content, so the live folder is very\n * often the OLD one.\n */\nexport function bothSourceFoldersPresent(from: string, to: string, readFrom: string): string {\n return `both ${from}/ and ${to}/ are on disk — ${readFrom}/ is the one being read`;\n}\n\n/**\n * What a write command says when a scope in play holds two rival source folders.\n *\n * A refusal rather than a warning, and the reason is the preference order: with two folders on\n * disk the resolver prefers whichever holds a config, which can perfectly well be the STALE one —\n * so a write that went ahead would land in a folder nothing compiles, beside a folder holding the\n * sub-agents the user is about to lose sight of. Reading is left alone deliberately: a user in\n * this state has to be able to look at it, which is what `doctor`'s Layout row is for.\n *\n * The remedy is stated as the manual operation it is. Nothing in this CLI merges two source\n * folders or moves one, so the sentence names the folder being read and asks the user to move\n * what they want into it — a sentence that handed out a command would be handing out one that\n * does not exist.\n */\nexport function rivalSourceFoldersRefuseWrites(\n kinds: readonly ScopeKind[],\n from: string,\n to: string,\n readFrom: string,\n): string {\n const subject = sentenceCase(kinds.map(scopeNoun).join(\" and \"));\n const verb = kinds.length === 1 ? \"holds\" : \"hold\";\n const other = readFrom === from ? to : from;\n return `${subject} ${verb} both ${from}/ and ${to}/ — ${readFrom}/ is the one being read, so anything under ${other}/ is invisible to this CLI. No command merges them: move what you want to keep from ${other}/ into ${readFrom}/ yourself, then delete ${other}/. '${CLI_INVOKE_COMMAND} doctor' still reports on either.`;\n}\n\n/**\n * The line the run ENDS on, kept short because oclif hard-wraps its errors at the terminal width.\n *\n * The sentence above it goes through `warn()` for that reason — it names three folders and an\n * invocation, none of which survives being broken across a line — and this is what is left for\n * the error itself to carry.\n */\nexport const WRITE_REFUSED_RIVAL_SOURCE_FOLDERS =\n \"Refusing to write while two source folders are on disk.\";\n\n/**\n * The heading over the registered projects still on the old name, and the caveat it carries.\n *\n * The caveat is not optional politeness: the registry holds a fraction of the installations on a\n * machine — one entry against six on the machine this was written for — so a list printed without\n * it reads as an inventory and under-reports by whatever the factor happens to be.\n */\nexport const REGISTRY_IS_NOT_AN_INVENTORY =\n \"Registered projects still on the old folder — this list is the registry, not an inventory of this machine:\";\n\n/**\n * doctor's Layout row for a scope still on the retired name.\n *\n * It is a `warn` rather than a fail and the sentence has to carry that: nothing is broken, the\n * installation is read and written where it is for as long as the user leaves it there. What the\n * row owes is the name of the folder this release would create and the fact that getting there is\n * a manual move — there is no command, so naming one would send a reader to a 127.\n */\nexport function layoutIsLegacy(label: string, from: string, to: string): string {\n return `${label} is on ${from}/, which this CLI goes on reading and writing — move its contents into ${to}/ by hand to be on the current layout`;\n}\n\n/** doctor's Layout row for a scope this release reads and writes without doing anything. */\nexport function layoutIsCurrent(label: string, to: string): string {\n return `${label} is on ${to}/`;\n}\n\n/**\n * An installed agent whose prompt tells it to author into a folder this installation does not\n * read, so every file it writes there silently never compiles.\n */\nexport function compiledAgentNamesTheOtherFolder(agentFile: string, unusedFolder: string): string {\n return `${agentFile} names a source folder this installation does not use (${unusedFolder}/) — recompile it with '${CLI_INVOKE_COMMAND} compile'`;\n}\n","// AUTO-GENERATED from skills source and agent metadata — do not edit manually\n// Run: bun run generate:types\n\n// ── Skill Map (slug → ID) ─────────────────────────────────────\n\nexport const SKILL_MAP = {\n \"ai-planning\": \"meta-planning-ai-planning\",\n \"ai-reviewing\": \"meta-reviewing-ai-reviewing\",\n \"angular-standalone\": \"web-framework-angular-standalone\",\n \"ant-design\": \"web-ui-ant-design\",\n \"anthropic-sdk\": \"ai-provider-anthropic-sdk\",\n \"api-performance\": \"api-performance-api-performance\",\n \"api-planning\": \"meta-planning-api-planning\",\n \"api-reviewing\": \"meta-reviewing-api-reviewing\",\n \"apollo-server\": \"api-graphql-apollo-server\",\n \"app-links\": \"mobile-deep-linking-app-links\",\n appwrite: \"api-baas-appwrite\",\n astro: \"web-meta-framework-astro\",\n \"auth-security\": \"shared-security-auth-security\",\n \"aws-sdk\": \"infra-platform-aws-sdk\",\n \"axiom-pino-sentry\": \"api-observability-axiom-pino-sentry\",\n \"base-ui\": \"web-ui-base-ui\",\n \"better-auth-drizzle-hono\": \"api-auth-better-auth-drizzle-hono\",\n biome: \"shared-tooling-biome\",\n \"ble-nfc\": \"mobile-hardware-ble-nfc\",\n bullmq: \"api-queue-bullmq\",\n \"chakra-ui\": \"web-ui-chakra-ui\",\n changesets: \"shared-tooling-changesets\",\n chroma: \"api-vector-db-chroma\",\n clack: \"cli-prompts-clack\",\n \"claude-vision\": \"ai-provider-claude-vision\",\n clerk: \"api-auth-clerk\",\n \"cli-commander\": \"cli-framework-cli-commander\",\n \"cli-planning\": \"meta-planning-cli-planning\",\n \"cli-reviewing\": \"meta-reviewing-cli-reviewing\",\n \"cloudflare-workers\": \"infra-platform-cloudflare-workers\",\n cockroachdb: \"api-database-cockroachdb\",\n \"cohere-sdk\": \"ai-provider-cohere-sdk\",\n \"component-library\": \"web-tooling-component-library\",\n \"composable-components\": \"meta-design-composable-components\",\n \"css-animations\": \"web-animation-css-animations\",\n cva: \"web-styling-cva\",\n \"cypress-e2e\": \"web-testing-cypress-e2e\",\n d3: \"web-dataviz-d3\",\n \"date-fns\": \"web-utilities-date-fns\",\n \"design-tokens\": \"web-styling-design-tokens\",\n detox: \"mobile-testing-detox\",\n \"dnd-kit\": \"web-dnd-dnd-kit\",\n docker: \"infra-ci-cd-docker\",\n docusaurus: \"web-meta-framework-docusaurus\",\n drizzle: \"api-database-drizzle\",\n eas: \"mobile-deployment-eas\",\n edgedb: \"api-database-edgedb\",\n elasticsearch: \"api-search-elasticsearch\",\n electron: \"desktop-framework-electron\",\n \"electron-forge\": \"desktop-packaging-electron-forge\",\n \"electron-ipc\": \"desktop-ipc-electron\",\n \"electron-multiwindow\": \"desktop-multiwindow-electron\",\n \"electron-security\": \"desktop-security-electron\",\n \"electron-storage\": \"desktop-storage-electron\",\n \"electron-testing\": \"desktop-testing-electron\",\n \"electron-ui\": \"desktop-ui-electron\",\n \"electron-updater\": \"desktop-updates-electron-updater\",\n elevenlabs: \"ai-provider-elevenlabs\",\n elysia: \"api-framework-elysia\",\n \"error-boundaries\": \"web-error-handling-error-boundaries\",\n \"eslint-prettier\": \"shared-tooling-eslint-prettier\",\n expo: \"mobile-framework-expo\",\n \"expo-router\": \"mobile-navigation-expo-router\",\n express: \"api-framework-express\",\n \"expressive-typescript\": \"meta-design-expressive-typescript\",\n fastify: \"api-framework-fastify\",\n \"file-upload-patterns\": \"web-files-file-upload-patterns\",\n firebase: \"api-baas-firebase\",\n \"framer-motion\": \"web-animation-framer-motion\",\n \"gesture-handler\": \"mobile-animation-gesture-handler\",\n \"git-hooks\": \"shared-tooling-git-hooks\",\n \"github-actions\": \"infra-ci-cd-github-actions\",\n \"google-gemini-sdk\": \"ai-provider-google-gemini-sdk\",\n \"graphql-apollo\": \"web-data-fetching-graphql-apollo\",\n \"graphql-urql\": \"web-data-fetching-graphql-urql\",\n \"headless-ui\": \"web-ui-headless-ui\",\n hono: \"api-framework-hono\",\n \"huggingface-inference\": \"ai-infrastructure-huggingface-inference\",\n \"image-handling\": \"web-files-image-handling\",\n \"infra-reviewing\": \"meta-reviewing-infra-reviewing\",\n jotai: \"web-state-jotai\",\n knex: \"api-database-knex\",\n kubernetes: \"infra-containers-kubernetes\",\n langchain: \"ai-orchestration-langchain\",\n langfuse: \"ai-observability-langfuse\",\n leaflet: \"web-maps-leaflet\",\n lexical: \"web-editor-lexical\",\n litellm: \"ai-infrastructure-litellm\",\n llamaindex: \"ai-orchestration-llamaindex\",\n maestro: \"mobile-testing-maestro\",\n mantine: \"web-ui-mantine\",\n mapbox: \"web-maps-mapbox\",\n meilisearch: \"api-search-meilisearch\",\n mercurius: \"api-graphql-mercurius\",\n \"mistral-sdk\": \"ai-provider-mistral-sdk\",\n mmkv: \"mobile-storage-mmkv\",\n mobx: \"web-state-mobx\",\n modal: \"ai-infrastructure-modal\",\n mongodb: \"api-database-mongodb\",\n mongoose: \"api-database-mongoose\",\n msw: \"web-mocks-msw\",\n mui: \"web-ui-mui\",\n mysql: \"api-database-mysql\",\n \"native-js\": \"web-utilities-native-js\",\n nativewind: \"mobile-styling-nativewind\",\n neon: \"api-baas-neon\",\n nestjs: \"api-framework-nestjs\",\n netlify: \"infra-platform-netlify\",\n \"next-intl\": \"web-i18n-next-intl\",\n nextauth: \"api-auth-nextauth\",\n nextjs: \"web-meta-framework-nextjs\",\n \"ngrx-signalstore\": \"web-state-ngrx-signalstore\",\n nuxt: \"web-meta-framework-nuxt\",\n nx: \"shared-monorepo-nx\",\n \"oclif-ink\": \"cli-framework-oclif-ink\",\n \"offline-first\": \"web-pwa-offline-first\",\n ollama: \"ai-infrastructure-ollama\",\n \"openai-sdk\": \"ai-provider-openai-sdk\",\n \"openai-whisper\": \"ai-provider-openai-whisper\",\n openapi: \"api-specs-openapi\",\n payload: \"api-cms-payload\",\n pinecone: \"api-vector-db-pinecone\",\n pinia: \"web-state-pinia\",\n planetscale: \"api-baas-planetscale\",\n \"playwright-e2e\": \"web-testing-playwright-e2e\",\n \"pnpm-workspaces\": \"shared-monorepo-pnpm-workspaces\",\n postgresql: \"api-database-postgresql\",\n \"posthog-analytics\": \"api-analytics-posthog-analytics\",\n \"posthog-flags\": \"api-flags-posthog-flags\",\n prisma: \"api-database-prisma\",\n promptfoo: \"ai-observability-promptfoo\",\n pulumi: \"infra-iac-pulumi\",\n push: \"mobile-notifications-push\",\n qdrant: \"api-vector-db-qdrant\",\n qwik: \"web-meta-framework-qwik\",\n \"radix-ui\": \"web-ui-radix-ui\",\n react: \"web-framework-react\",\n \"react-hook-form\": \"web-forms-react-hook-form\",\n \"react-intl\": \"web-i18n-react-intl\",\n \"react-native\": \"mobile-framework-react-native\",\n \"react-native-paper\": \"mobile-ui-components-react-native-paper\",\n \"react-native-performance\": \"mobile-performance-react-native\",\n \"react-native-security\": \"mobile-security-react-native\",\n \"react-navigation\": \"mobile-navigation-react-navigation\",\n \"react-query\": \"web-server-state-react-query\",\n \"react-router\": \"web-routing-react-router\",\n \"react-testing-library\": \"web-testing-react-testing-library\",\n \"react-three-fiber\": \"web-3d-react-three-fiber\",\n reanimated: \"mobile-animation-reanimated\",\n recharts: \"web-dataviz-recharts\",\n redis: \"api-database-redis\",\n \"redux-toolkit\": \"web-state-redux-toolkit\",\n remix: \"web-meta-framework-remix\",\n replicate: \"ai-infrastructure-replicate\",\n \"research-methodology\": \"meta-methodology-research-methodology\",\n \"resend-react-email\": \"api-email-resend-react-email\",\n \"result-types\": \"web-error-handling-result-types\",\n reviewing: \"meta-reviewing-reviewing\",\n rxjs: \"web-utilities-rxjs\",\n sanity: \"api-cms-sanity\",\n \"scss-modules\": \"web-styling-scss-modules\",\n sequelize: \"api-database-sequelize\",\n \"service-workers\": \"web-pwa-service-workers\",\n \"setup-axiom-pino-sentry\": \"api-observability-setup-axiom-pino-sentry\",\n \"setup-env\": \"infra-config-setup-env\",\n \"setup-posthog\": \"api-analytics-setup-posthog\",\n \"setup-resend\": \"api-email-setup-resend\",\n \"shadcn-ui\": \"web-ui-shadcn-ui\",\n skia: \"mobile-animation-skia\",\n \"socket-io\": \"web-realtime-socket-io\",\n solidjs: \"web-framework-solidjs\",\n \"sqlite-powersync\": \"mobile-storage-sqlite-powersync\",\n sse: \"web-realtime-sse\",\n sst: \"infra-iac-sst\",\n \"stack-detect\": \"meta-config-stack-detect\",\n storybook: \"web-tooling-storybook\",\n strapi: \"api-cms-strapi\",\n strategies: \"api-caching-strategies\",\n stripe: \"api-commerce-stripe\",\n supabase: \"api-baas-supabase\",\n surrealdb: \"api-database-surrealdb\",\n svelte: \"web-framework-svelte\",\n sveltekit: \"web-meta-framework-sveltekit\",\n swr: \"web-data-fetching-swr\",\n tailwind: \"web-styling-tailwind\",\n tamagui: \"mobile-ui-components-tamagui\",\n \"tanstack-form\": \"web-forms-tanstack-form\",\n \"tanstack-router\": \"web-routing-tanstack-router\",\n \"tanstack-table\": \"web-ui-tanstack-table\",\n tasks: \"mobile-background-tasks\",\n tauri: \"desktop-framework-tauri\",\n \"tauri-backend\": \"desktop-backend-tauri\",\n \"tauri-bundling\": \"desktop-packaging-tauri\",\n \"tauri-mobile\": \"desktop-mobile-tauri\",\n \"tauri-multiwindow\": \"desktop-multiwindow-tauri\",\n \"tauri-plugins\": \"desktop-plugins-tauri\",\n \"tauri-security\": \"desktop-security-tauri\",\n terraform: \"infra-iac-terraform\",\n theming: \"web-styling-theming\",\n tiptap: \"web-editor-tiptap\",\n \"together-ai\": \"ai-infrastructure-together-ai\",\n \"tool-use-patterns\": \"ai-patterns-tool-use-patterns\",\n trpc: \"web-data-fetching-trpc\",\n turborepo: \"shared-monorepo-turborepo\",\n \"turborepo-ci\": \"infra-ci-cd-turborepo-ci\",\n turso: \"api-baas-turso\",\n typeorm: \"api-database-typeorm\",\n \"typescript-config\": \"shared-tooling-typescript-config\",\n unistyles: \"mobile-styling-unistyles\",\n upstash: \"api-database-upstash\",\n \"vee-validate\": \"web-forms-vee-validate\",\n vercel: \"infra-platform-vercel\",\n \"vercel-ai-sdk\": \"ai-orchestration-vercel-ai-sdk\",\n \"vercel-kv\": \"api-database-vercel-kv\",\n \"vercel-postgres\": \"api-database-vercel-postgres\",\n \"view-transitions\": \"web-animation-view-transitions\",\n \"vision-camera\": \"mobile-camera-vision-camera\",\n \"visual-regression\": \"web-testing-visual-regression\",\n vite: \"web-tooling-vite\",\n vitepress: \"web-meta-framework-vitepress\",\n vitest: \"web-testing-vitest\",\n \"vue-composition-api\": \"web-framework-vue-composition-api\",\n \"vue-i18n\": \"web-i18n-vue-i18n\",\n \"vue-test-utils\": \"web-testing-vue-test-utils\",\n vuetify: \"web-ui-vuetify\",\n vueuse: \"web-utilities-vueuse\",\n watermelondb: \"mobile-storage-watermelondb\",\n weaviate: \"api-vector-db-weaviate\",\n \"web-accessibility\": \"web-accessibility-web-accessibility\",\n \"web-performance\": \"web-performance-web-performance\",\n \"web-planning\": \"meta-planning-web-planning\",\n \"web-reviewing\": \"meta-reviewing-web-reviewing\",\n webhooks: \"api-messaging-webhooks\",\n websockets: \"web-realtime-websockets\",\n xquik: \"api-search-xquik\",\n yoga: \"api-graphql-yoga\",\n \"zod-validation\": \"web-forms-zod-validation\",\n zustand: \"web-state-zustand\",\n} as const;\n\nexport type SkillSlug = keyof typeof SKILL_MAP;\nexport type SkillId = (typeof SKILL_MAP)[SkillSlug];\n\n// Derived arrays for Zod enum compatibility\n// (z.enum() requires a readonly tuple, not Object.keys/values)\nexport const SKILL_SLUGS = [\n \"ai-planning\",\n \"ai-reviewing\",\n \"angular-standalone\",\n \"ant-design\",\n \"anthropic-sdk\",\n \"api-performance\",\n \"api-planning\",\n \"api-reviewing\",\n \"apollo-server\",\n \"app-links\",\n \"appwrite\",\n \"astro\",\n \"auth-security\",\n \"aws-sdk\",\n \"axiom-pino-sentry\",\n \"base-ui\",\n \"better-auth-drizzle-hono\",\n \"biome\",\n \"ble-nfc\",\n \"bullmq\",\n \"chakra-ui\",\n \"changesets\",\n \"chroma\",\n \"clack\",\n \"claude-vision\",\n \"clerk\",\n \"cli-commander\",\n \"cli-planning\",\n \"cli-reviewing\",\n \"cloudflare-workers\",\n \"cockroachdb\",\n \"cohere-sdk\",\n \"component-library\",\n \"composable-components\",\n \"css-animations\",\n \"cva\",\n \"cypress-e2e\",\n \"d3\",\n \"date-fns\",\n \"design-tokens\",\n \"detox\",\n \"dnd-kit\",\n \"docker\",\n \"docusaurus\",\n \"drizzle\",\n \"eas\",\n \"edgedb\",\n \"elasticsearch\",\n \"electron\",\n \"electron-forge\",\n \"electron-ipc\",\n \"electron-multiwindow\",\n \"electron-security\",\n \"electron-storage\",\n \"electron-testing\",\n \"electron-ui\",\n \"electron-updater\",\n \"elevenlabs\",\n \"elysia\",\n \"error-boundaries\",\n \"eslint-prettier\",\n \"expo\",\n \"expo-router\",\n \"express\",\n \"expressive-typescript\",\n \"fastify\",\n \"file-upload-patterns\",\n \"firebase\",\n \"framer-motion\",\n \"gesture-handler\",\n \"git-hooks\",\n \"github-actions\",\n \"google-gemini-sdk\",\n \"graphql-apollo\",\n \"graphql-urql\",\n \"headless-ui\",\n \"hono\",\n \"huggingface-inference\",\n \"image-handling\",\n \"infra-reviewing\",\n \"jotai\",\n \"knex\",\n \"kubernetes\",\n \"langchain\",\n \"langfuse\",\n \"leaflet\",\n \"lexical\",\n \"litellm\",\n \"llamaindex\",\n \"maestro\",\n \"mantine\",\n \"mapbox\",\n \"meilisearch\",\n \"mercurius\",\n \"mistral-sdk\",\n \"mmkv\",\n \"mobx\",\n \"modal\",\n \"mongodb\",\n \"mongoose\",\n \"msw\",\n \"mui\",\n \"mysql\",\n \"native-js\",\n \"nativewind\",\n \"neon\",\n \"nestjs\",\n \"netlify\",\n \"next-intl\",\n \"nextauth\",\n \"nextjs\",\n \"ngrx-signalstore\",\n \"nuxt\",\n \"nx\",\n \"oclif-ink\",\n \"offline-first\",\n \"ollama\",\n \"openai-sdk\",\n \"openai-whisper\",\n \"openapi\",\n \"payload\",\n \"pinecone\",\n \"pinia\",\n \"planetscale\",\n \"playwright-e2e\",\n \"pnpm-workspaces\",\n \"postgresql\",\n \"posthog-analytics\",\n \"posthog-flags\",\n \"prisma\",\n \"promptfoo\",\n \"pulumi\",\n \"push\",\n \"qdrant\",\n \"qwik\",\n \"radix-ui\",\n \"react\",\n \"react-hook-form\",\n \"react-intl\",\n \"react-native\",\n \"react-native-paper\",\n \"react-native-performance\",\n \"react-native-security\",\n \"react-navigation\",\n \"react-query\",\n \"react-router\",\n \"react-testing-library\",\n \"react-three-fiber\",\n \"reanimated\",\n \"recharts\",\n \"redis\",\n \"redux-toolkit\",\n \"remix\",\n \"replicate\",\n \"research-methodology\",\n \"resend-react-email\",\n \"result-types\",\n \"reviewing\",\n \"rxjs\",\n \"sanity\",\n \"scss-modules\",\n \"sequelize\",\n \"service-workers\",\n \"setup-axiom-pino-sentry\",\n \"setup-env\",\n \"setup-posthog\",\n \"setup-resend\",\n \"shadcn-ui\",\n \"skia\",\n \"socket-io\",\n \"solidjs\",\n \"sqlite-powersync\",\n \"sse\",\n \"sst\",\n \"stack-detect\",\n \"storybook\",\n \"strapi\",\n \"strategies\",\n \"stripe\",\n \"supabase\",\n \"surrealdb\",\n \"svelte\",\n \"sveltekit\",\n \"swr\",\n \"tailwind\",\n \"tamagui\",\n \"tanstack-form\",\n \"tanstack-router\",\n \"tanstack-table\",\n \"tasks\",\n \"tauri\",\n \"tauri-backend\",\n \"tauri-bundling\",\n \"tauri-mobile\",\n \"tauri-multiwindow\",\n \"tauri-plugins\",\n \"tauri-security\",\n \"terraform\",\n \"theming\",\n \"tiptap\",\n \"together-ai\",\n \"tool-use-patterns\",\n \"trpc\",\n \"turborepo\",\n \"turborepo-ci\",\n \"turso\",\n \"typeorm\",\n \"typescript-config\",\n \"unistyles\",\n \"upstash\",\n \"vee-validate\",\n \"vercel\",\n \"vercel-ai-sdk\",\n \"vercel-kv\",\n \"vercel-postgres\",\n \"view-transitions\",\n \"vision-camera\",\n \"visual-regression\",\n \"vite\",\n \"vitepress\",\n \"vitest\",\n \"vue-composition-api\",\n \"vue-i18n\",\n \"vue-test-utils\",\n \"vuetify\",\n \"vueuse\",\n \"watermelondb\",\n \"weaviate\",\n \"web-accessibility\",\n \"web-performance\",\n \"web-planning\",\n \"web-reviewing\",\n \"webhooks\",\n \"websockets\",\n \"xquik\",\n \"yoga\",\n \"zod-validation\",\n \"zustand\",\n] as const satisfies readonly SkillSlug[];\n\nexport const SKILL_IDS = [\n \"ai-infrastructure-huggingface-inference\",\n \"ai-infrastructure-litellm\",\n \"ai-infrastructure-modal\",\n \"ai-infrastructure-ollama\",\n \"ai-infrastructure-replicate\",\n \"ai-infrastructure-together-ai\",\n \"ai-observability-langfuse\",\n \"ai-observability-promptfoo\",\n \"ai-orchestration-langchain\",\n \"ai-orchestration-llamaindex\",\n \"ai-orchestration-vercel-ai-sdk\",\n \"ai-patterns-tool-use-patterns\",\n \"ai-provider-anthropic-sdk\",\n \"ai-provider-claude-vision\",\n \"ai-provider-cohere-sdk\",\n \"ai-provider-elevenlabs\",\n \"ai-provider-google-gemini-sdk\",\n \"ai-provider-mistral-sdk\",\n \"ai-provider-openai-sdk\",\n \"ai-provider-openai-whisper\",\n \"api-analytics-posthog-analytics\",\n \"api-analytics-setup-posthog\",\n \"api-auth-better-auth-drizzle-hono\",\n \"api-auth-clerk\",\n \"api-auth-nextauth\",\n \"api-baas-appwrite\",\n \"api-baas-firebase\",\n \"api-baas-neon\",\n \"api-baas-planetscale\",\n \"api-baas-supabase\",\n \"api-baas-turso\",\n \"api-caching-strategies\",\n \"api-cms-payload\",\n \"api-cms-sanity\",\n \"api-cms-strapi\",\n \"api-commerce-stripe\",\n \"api-database-cockroachdb\",\n \"api-database-drizzle\",\n \"api-database-edgedb\",\n \"api-database-knex\",\n \"api-database-mongodb\",\n \"api-database-mongoose\",\n \"api-database-mysql\",\n \"api-database-postgresql\",\n \"api-database-prisma\",\n \"api-database-redis\",\n \"api-database-sequelize\",\n \"api-database-surrealdb\",\n \"api-database-typeorm\",\n \"api-database-upstash\",\n \"api-database-vercel-kv\",\n \"api-database-vercel-postgres\",\n \"api-email-resend-react-email\",\n \"api-email-setup-resend\",\n \"api-flags-posthog-flags\",\n \"api-framework-elysia\",\n \"api-framework-express\",\n \"api-framework-fastify\",\n \"api-framework-hono\",\n \"api-framework-nestjs\",\n \"api-graphql-apollo-server\",\n \"api-graphql-mercurius\",\n \"api-graphql-yoga\",\n \"api-messaging-webhooks\",\n \"api-observability-axiom-pino-sentry\",\n \"api-observability-setup-axiom-pino-sentry\",\n \"api-performance-api-performance\",\n \"api-queue-bullmq\",\n \"api-search-elasticsearch\",\n \"api-search-meilisearch\",\n \"api-search-xquik\",\n \"api-specs-openapi\",\n \"api-vector-db-chroma\",\n \"api-vector-db-pinecone\",\n \"api-vector-db-qdrant\",\n \"api-vector-db-weaviate\",\n \"cli-framework-cli-commander\",\n \"cli-framework-oclif-ink\",\n \"cli-prompts-clack\",\n \"desktop-backend-tauri\",\n \"desktop-framework-electron\",\n \"desktop-framework-tauri\",\n \"desktop-ipc-electron\",\n \"desktop-mobile-tauri\",\n \"desktop-multiwindow-electron\",\n \"desktop-multiwindow-tauri\",\n \"desktop-packaging-electron-forge\",\n \"desktop-packaging-tauri\",\n \"desktop-plugins-tauri\",\n \"desktop-security-electron\",\n \"desktop-security-tauri\",\n \"desktop-storage-electron\",\n \"desktop-testing-electron\",\n \"desktop-ui-electron\",\n \"desktop-updates-electron-updater\",\n \"infra-ci-cd-docker\",\n \"infra-ci-cd-github-actions\",\n \"infra-ci-cd-turborepo-ci\",\n \"infra-config-setup-env\",\n \"infra-containers-kubernetes\",\n \"infra-iac-pulumi\",\n \"infra-iac-sst\",\n \"infra-iac-terraform\",\n \"infra-platform-aws-sdk\",\n \"infra-platform-cloudflare-workers\",\n \"infra-platform-netlify\",\n \"infra-platform-vercel\",\n \"meta-config-stack-detect\",\n \"meta-design-composable-components\",\n \"meta-design-expressive-typescript\",\n \"meta-methodology-research-methodology\",\n \"meta-planning-ai-planning\",\n \"meta-planning-api-planning\",\n \"meta-planning-cli-planning\",\n \"meta-planning-web-planning\",\n \"meta-reviewing-ai-reviewing\",\n \"meta-reviewing-api-reviewing\",\n \"meta-reviewing-cli-reviewing\",\n \"meta-reviewing-infra-reviewing\",\n \"meta-reviewing-reviewing\",\n \"meta-reviewing-web-reviewing\",\n \"mobile-animation-gesture-handler\",\n \"mobile-animation-reanimated\",\n \"mobile-animation-skia\",\n \"mobile-background-tasks\",\n \"mobile-camera-vision-camera\",\n \"mobile-deep-linking-app-links\",\n \"mobile-deployment-eas\",\n \"mobile-framework-expo\",\n \"mobile-framework-react-native\",\n \"mobile-hardware-ble-nfc\",\n \"mobile-navigation-expo-router\",\n \"mobile-navigation-react-navigation\",\n \"mobile-notifications-push\",\n \"mobile-performance-react-native\",\n \"mobile-security-react-native\",\n \"mobile-storage-mmkv\",\n \"mobile-storage-sqlite-powersync\",\n \"mobile-storage-watermelondb\",\n \"mobile-styling-nativewind\",\n \"mobile-styling-unistyles\",\n \"mobile-testing-detox\",\n \"mobile-testing-maestro\",\n \"mobile-ui-components-react-native-paper\",\n \"mobile-ui-components-tamagui\",\n \"shared-monorepo-nx\",\n \"shared-monorepo-pnpm-workspaces\",\n \"shared-monorepo-turborepo\",\n \"shared-security-auth-security\",\n \"shared-tooling-biome\",\n \"shared-tooling-changesets\",\n \"shared-tooling-eslint-prettier\",\n \"shared-tooling-git-hooks\",\n \"shared-tooling-typescript-config\",\n \"web-3d-react-three-fiber\",\n \"web-accessibility-web-accessibility\",\n \"web-animation-css-animations\",\n \"web-animation-framer-motion\",\n \"web-animation-view-transitions\",\n \"web-data-fetching-graphql-apollo\",\n \"web-data-fetching-graphql-urql\",\n \"web-data-fetching-swr\",\n \"web-data-fetching-trpc\",\n \"web-dataviz-d3\",\n \"web-dataviz-recharts\",\n \"web-dnd-dnd-kit\",\n \"web-editor-lexical\",\n \"web-editor-tiptap\",\n \"web-error-handling-error-boundaries\",\n \"web-error-handling-result-types\",\n \"web-files-file-upload-patterns\",\n \"web-files-image-handling\",\n \"web-forms-react-hook-form\",\n \"web-forms-tanstack-form\",\n \"web-forms-vee-validate\",\n \"web-forms-zod-validation\",\n \"web-framework-angular-standalone\",\n \"web-framework-react\",\n \"web-framework-solidjs\",\n \"web-framework-svelte\",\n \"web-framework-vue-composition-api\",\n \"web-i18n-next-intl\",\n \"web-i18n-react-intl\",\n \"web-i18n-vue-i18n\",\n \"web-maps-leaflet\",\n \"web-maps-mapbox\",\n \"web-meta-framework-astro\",\n \"web-meta-framework-docusaurus\",\n \"web-meta-framework-nextjs\",\n \"web-meta-framework-nuxt\",\n \"web-meta-framework-qwik\",\n \"web-meta-framework-remix\",\n \"web-meta-framework-sveltekit\",\n \"web-meta-framework-vitepress\",\n \"web-mocks-msw\",\n \"web-performance-web-performance\",\n \"web-pwa-offline-first\",\n \"web-pwa-service-workers\",\n \"web-realtime-socket-io\",\n \"web-realtime-sse\",\n \"web-realtime-websockets\",\n \"web-routing-react-router\",\n \"web-routing-tanstack-router\",\n \"web-server-state-react-query\",\n \"web-state-jotai\",\n \"web-state-mobx\",\n \"web-state-ngrx-signalstore\",\n \"web-state-pinia\",\n \"web-state-redux-toolkit\",\n \"web-state-zustand\",\n \"web-styling-cva\",\n \"web-styling-design-tokens\",\n \"web-styling-scss-modules\",\n \"web-styling-tailwind\",\n \"web-styling-theming\",\n \"web-testing-cypress-e2e\",\n \"web-testing-playwright-e2e\",\n \"web-testing-react-testing-library\",\n \"web-testing-visual-regression\",\n \"web-testing-vitest\",\n \"web-testing-vue-test-utils\",\n \"web-tooling-component-library\",\n \"web-tooling-storybook\",\n \"web-tooling-vite\",\n \"web-ui-ant-design\",\n \"web-ui-base-ui\",\n \"web-ui-chakra-ui\",\n \"web-ui-headless-ui\",\n \"web-ui-mantine\",\n \"web-ui-mui\",\n \"web-ui-radix-ui\",\n \"web-ui-shadcn-ui\",\n \"web-ui-tanstack-table\",\n \"web-ui-vuetify\",\n \"web-utilities-date-fns\",\n \"web-utilities-native-js\",\n \"web-utilities-rxjs\",\n \"web-utilities-vueuse\",\n] as const satisfies readonly SkillId[];\n\n// ── Categories ─────────────────────────────────────────────────\n\nexport const CATEGORIES = [\n \"ai-infrastructure\",\n \"ai-observability\",\n \"ai-orchestration\",\n \"ai-patterns\",\n \"ai-provider\",\n \"api-analytics\",\n \"api-api\",\n \"api-auth\",\n \"api-baas\",\n \"api-caching\",\n \"api-cms\",\n \"api-commerce\",\n \"api-db-host\",\n \"api-document\",\n \"api-email\",\n \"api-graphql\",\n \"api-kv\",\n \"api-messaging\",\n \"api-observability\",\n \"api-orm\",\n \"api-performance\",\n \"api-queue\",\n \"api-search\",\n \"api-specs\",\n \"api-sql-engine\",\n \"api-vector-db\",\n \"cli-framework\",\n \"cli-prompts\",\n \"desktop-backend\",\n \"desktop-framework\",\n \"desktop-ipc\",\n \"desktop-mobile\",\n \"desktop-multiwindow\",\n \"desktop-packaging\",\n \"desktop-plugins\",\n \"desktop-security\",\n \"desktop-storage\",\n \"desktop-testing\",\n \"desktop-ui\",\n \"desktop-updates\",\n \"infra-ci-cd\",\n \"infra-config\",\n \"infra-containers\",\n \"infra-iac\",\n \"infra-platform\",\n \"meta-design\",\n \"meta-methodology\",\n \"meta-planning\",\n \"meta-reviewing\",\n \"mobile-animation\",\n \"mobile-background\",\n \"mobile-camera\",\n \"mobile-deep-linking\",\n \"mobile-deployment\",\n \"mobile-framework\",\n \"mobile-hardware\",\n \"mobile-navigation\",\n \"mobile-notifications\",\n \"mobile-performance\",\n \"mobile-security\",\n \"mobile-storage\",\n \"mobile-styling\",\n \"mobile-testing\",\n \"mobile-ui-components\",\n \"shared-lint\",\n \"shared-monorepo\",\n \"shared-security\",\n \"shared-task-runner\",\n \"shared-tooling\",\n \"web-3d\",\n \"web-accessibility\",\n \"web-animation\",\n \"web-client-state\",\n \"web-dataviz\",\n \"web-dnd\",\n \"web-docs\",\n \"web-e2e\",\n \"web-editor\",\n \"web-error-handling\",\n \"web-file-upload\",\n \"web-files\",\n \"web-form-library\",\n \"web-forms\",\n \"web-framework\",\n \"web-graphql-client\",\n \"web-i18n\",\n \"web-maps\",\n \"web-meta-framework\",\n \"web-mocking\",\n \"web-performance\",\n \"web-pwa\",\n \"web-realtime\",\n \"web-routing\",\n \"web-rpc\",\n \"web-server-state\",\n \"web-streaming\",\n \"web-styling\",\n \"web-testing\",\n \"web-tooling\",\n \"web-ui-components\",\n \"web-ui-kit\",\n \"web-utilities\",\n] as const;\n\nexport type Category = (typeof CATEGORIES)[number];\n\n// ── Domains ────────────────────────────────────────────────────\n\nexport const DOMAINS = [\n \"ai\",\n \"api\",\n \"cli\",\n \"desktop\",\n \"infra\",\n \"meta\",\n \"mobile\",\n \"shared\",\n \"web\",\n] as const;\n\nexport type Domain = (typeof DOMAINS)[number];\n\n// ── Agent Names ────────────────────────────────────────────────\n\nexport const AGENT_NAMES = [\n \"agent-summoner\",\n \"ai-developer\",\n \"ai-researcher\",\n \"ai-tester\",\n \"api-developer\",\n \"api-researcher\",\n \"api-tester\",\n \"cli-developer\",\n \"cli-researcher\",\n \"cli-tester\",\n \"codex-keeper\",\n \"convention-keeper\",\n \"pm\",\n \"reviewer\",\n \"skill-summoner\",\n \"web-developer\",\n \"web-researcher\",\n \"web-tester\",\n] as const;\n\nexport type AgentName = (typeof AGENT_NAMES)[number];\n","import {\n CATEGORIES,\n DOMAINS,\n AGENT_NAMES,\n SKILL_IDS,\n SKILL_SLUGS,\n} from \"../types/generated/source-types\";\nimport type {\n Category,\n Domain,\n AgentName,\n SkillId,\n SkillSlug,\n} from \"../types/generated/source-types\";\nimport type { CategoryPath, SkillAssignment } from \"../types/skills\";\nimport { LOCAL_PSEUDO_CATEGORY } from \"../consts\";\n\n/** Narrows unknown parse output to a plain object record (rejects arrays and primitives). */\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Runtime check that a string is a valid Category value from the generated union */\nexport function isCategory(value: string): value is Category {\n return (CATEGORIES as readonly string[]).includes(value);\n}\n\n/** Runtime check that a string is a valid Domain value from the generated union */\nexport function isDomain(value: string): value is Domain {\n return (DOMAINS as readonly string[]).includes(value);\n}\n\n/** Runtime check that a string is a valid AgentName value from the generated union */\nexport function isAgentName(value: string): value is AgentName {\n return (AGENT_NAMES as readonly string[]).includes(value);\n}\n\n/** Runtime check that a string is a valid CategoryPath (Category | \"local\") */\nexport function isCategoryPath(value: string): value is CategoryPath {\n return value === LOCAL_PSEUDO_CATEGORY || isCategory(value);\n}\n\n/** Runtime check that a string is a valid SkillId from the generated union */\nexport function isSkillId(value: string): value is SkillId {\n return (SKILL_IDS as readonly string[]).includes(value);\n}\n\n/** Runtime check that a string is a valid SkillSlug from the generated union */\nexport function isSkillSlug(value: string): value is SkillSlug {\n return (SKILL_SLUGS as readonly string[]).includes(value);\n}\n\n/**\n * Structural check for a SkillAssignment object (`{ id, preloaded? }`).\n * The id's SkillId-ness is structural, not union-checked: assignments flow from\n * runtime sources whose skills may not be in the generated union.\n */\nexport function isSkillAssignment(value: unknown): value is SkillAssignment {\n if (typeof value !== \"object\" || value === null) return false;\n // Boundary cast: probing an unknown object's field inside the guard\n return typeof (value as { id?: unknown }).id === \"string\";\n}\n","import os from \"os\";\nimport path from \"path\";\nimport { z } from \"zod\";\nimport { DEFAULT_SOURCE } from \"@workspace/compile\";\nimport { fileExists, readFileOptional } from \"../../utils/fs\";\nimport { verbose, warn } from \"../../utils/logger\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport {\n DEFAULT_BRANDING,\n GITHUB_SOURCE,\n LEGACY_SOURCE_DIR,\n PUBLIC_CATALOGUE_PACKAGE,\n SOURCE_ROOT_DIR,\n STANDARD_FILES,\n} from \"../../consts\";\nimport { configUnreadableError, installationConfigsUnreadable } from \"../../utils/messages\";\nimport { formatZodIssues, projectConfigLoaderSchema, projectSourceConfigSchema } from \"../schemas\";\nimport type { ProjectConfig, SourceEntry } from \"../../types\";\nimport {\n ConfigDefaultExportError,\n ConfigSchemaError,\n loadConfig,\n NO_VALID_DEFAULT_EXPORT,\n} from \"./config-loader\";\nimport { getInstalledConfigPath, getProjectConfigPath } from \"../installation/install-base-dir\";\nimport { isHomeDirectory } from \"../installation/is-home-directory\";\nimport type { ScopeKind } from \"../installation/source-scopes\";\n\n// DEFAULT_SOURCE lives in @workspace/compile, because the editor's output preview records it for\n// a configuration naming no marketplace; re-exported here for existing importers of this module.\nexport { DEFAULT_SOURCE };\nexport const SOURCE_ENV_VAR = \"CC_MARKETPLACE\";\n\n// Re-export types that moved to src/cli/types/config.ts for backward compatibility\nexport type { SourceEntry, BrandingConfig } from \"../../types/config\";\n\n// getProjectConfigPath lives in install-base-dir.ts (a neutral leaf) to avoid an\n// import cycle; re-exported here for existing importers of this module.\nexport { getProjectConfigPath };\n\nexport type ResolvedConfig = {\n source: string;\n sourceOrigin: \"flag\" | \"env\" | \"project\" | \"global\" | \"default\";\n} & (RecordedMarketplaceName | { marketplace?: undefined; marketplaceRecordedIn?: undefined });\n\n/**\n * The marketplace name an installation recorded beside its source, and the `config.ts` it was\n * recorded in. A pair, because a refusal of the name sends the reader to the file holding it.\n */\ntype RecordedMarketplaceName = { marketplace: string; marketplaceRecordedIn: string };\n\n/**\n * Who is asking for a marketplace, and therefore whether this run may CHOOSE one.\n *\n * Choosing is an install-time decision (owner ruling 2026-08-09): `--marketplace` is\n * `init`'s flag and nobody else's, and {@link SOURCE_ENV_VAR} is the same choice made\n * without typing it — so the environment rung is read for `init` and for nothing else.\n * Every later command asks as `\"stored\"` and gets what the install recorded: the\n * project config, then the global one, then {@link DEFAULT_SOURCE}.\n *\n * A `\"stored\"` caller may still NAME a marketplace it is reading for its own sake —\n * `doctor` validating a marketplace repository points the loader at a path — which is why\n * the flag is not tied to the caller. What `init` alone gets is the ambient environment.\n */\nexport type SourceCaller = \"init\" | \"stored\";\n\nexport type ResolveSourceRequest = {\n caller: SourceCaller;\n /** The marketplace this run named, where it named one. */\n flag?: string | undefined;\n /** The project whose `config.ts` is the first stored rung. */\n projectDir?: string | undefined;\n};\n\n/**\n * Reads the settings config at `dir`, or answers `null` when there is none to read.\n *\n * **A file that EXISTS and cannot be loaded is raised, never reported as absence** (owner ruling\n * 2026-08-20). `resolveSource` reads the return value alone, so a swallowed failure was\n * indistinguishable from a config that is not there: the run walked past this rung to\n * {@link DEFAULT_SOURCE} and installed from a marketplace nobody named, while the config naming a\n * private one sat unread on disk. Every way a config can fail is on the loud side of that line — a\n * file that could not be evaluated, a module whose exports are all named, a file that declared\n * nothing, and a shape the installation schema refuses.\n *\n * **The file is judged as the full-config reader judges it** (`loadProjectConfigFromDir`) before\n * its settings are read. The settings schema declares only the settings fields and lets everything\n * else through, so judged by it alone an empty file read as absent and a refused `skills` beside a\n * named marketplace read as usable — while `list`, `edit` and `doctor` refused the very same file.\n *\n * A MISSING file keeps its `null`, and that is the whole of what `null` means here: the legitimate\n * state `init` exists for, and the state `edit` reports as \"no installation\".\n *\n * Every call site chose a posture and states it where it stands. All but one ABORT: the marketplace\n * a run installs from is not a thing to guess at, and the two sites that read this file to locate a\n * marketplace's own skills or agent partials would otherwise walk a tree it says is elsewhere. The\n * exception is `validateRegisteredSources`, which DEGRADES — a command whose job is naming what is\n * wrong here has to survive the thing it is naming, so `doctor`'s `safeCheck` turns the raise into\n * a failed row and its `readsConfig: true` rows stand down before reaching here at all. Two further\n * sites are unreachable rather than chosen: `mergeWithExistingConfig` loads the full config first,\n * and `ensureMinimalConfig` reads only where the file is absent.\n */\nasync function loadSourceConfig(\n dir: string,\n scope: ScopeKind,\n): Promise<Partial<ProjectConfig> | null> {\n const scopeLabel = scope === \"project\" ? \"Project\" : \"Global\";\n const configPath = getInstalledConfigPath(dir);\n\n if (!(await fileExists(configPath))) {\n verbose(`${scopeLabel} config not found at ${configPath}`);\n return null;\n }\n\n const unreadable = refuseInstallationConfig(configPath, scope, dir);\n const installation = await readConfigOrRefuse(configPath, projectConfigLoaderSchema, unreadable);\n if (installation === null) throw unreadable(NO_VALID_DEFAULT_EXPORT);\n const settings = readSettings(configPath, installation);\n\n verbose(`Loaded ${scope} config from ${dir}`);\n return settings;\n}\n\n/** How a reader words a config that is there and will not load, from the reason it gives. */\ntype RefuseUnreadable = (reason: string, cause?: unknown) => Error;\n\n/**\n * The refusal for an installation's config, worded as `ensureConfigReadable` words the same file:\n * whose config it is, and the folder the way out is taken from.\n */\nfunction refuseInstallationConfig(\n configPath: string,\n scope: ScopeKind,\n scopeRoot: string,\n): RefuseUnreadable {\n return (reason, cause) =>\n new Error(installationConfigsUnreadable([{ configPath, reason, scope, scopeRoot }]), { cause });\n}\n\n/**\n * The config at `configPath` as `schema` admits it, or `null` when it evaluated and declared\n * nothing — which each caller answers for itself: an installation's file declaring nothing is\n * refused, while a source repo declaring nothing in one folder is asked about the next.\n *\n * Every way of failing raises. Split out from {@link loadSourceConfig} so that function's own body\n * reads as the states it answers, with a file that will not load named once here rather than\n * assembled from a `let` and a `try`.\n */\nasync function readConfigOrRefuse<T>(\n configPath: string,\n schema: z.ZodType<T>,\n unreadable: RefuseUnreadable,\n): Promise<T | null> {\n try {\n return await loadConfig(configPath, schema);\n } catch (error) {\n if (describesItsOwnFault(error)) throw error;\n throw unreadable(getErrorMessage(error), error);\n }\n}\n\n/**\n * The settings an installation's config carries, read out of a config its installation schema has\n * already admitted.\n *\n * Parsed rather than taken as they stand, because that schema lets the settings-only fields through\n * unread — `branding` and the directory overrides are not its fields — and one of the wrong type is\n * refused here as it always was, naming the field.\n */\nfunction readSettings(configPath: string, installation: unknown): Partial<ProjectConfig> {\n const settings = projectSourceConfigSchema.safeParse(installation);\n if (!settings.success) {\n throw new ConfigSchemaError(configPath, formatZodIssues(settings.error.issues));\n }\n return settings.data;\n}\n\n/**\n * Whether a load failure already names the field or the export at fault, and so is handed on as\n * itself rather than re-worded.\n *\n * The two it admits fault a LINE of a file the user still owns and can go and correct. Everything\n * else says only that the file would not evaluate, which is what each reader's own\n * {@link RefuseUnreadable} exists to turn into a way out.\n */\nfunction describesItsOwnFault(error: unknown): boolean {\n return error instanceof ConfigSchemaError || error instanceof ConfigDefaultExportError;\n}\n\n/**\n * The refusal for a marketplace repository's own config that exists and cannot be evaluated.\n *\n * `loadConfig` already names the file and the parser's own reason — `Failed to load config from\n * '<path>': ParseError: Missing semicolon` — so it is handed straight to\n * {@link configUnreadableError} rather than restated. An installation's config is refused by\n * {@link installationConfigsUnreadable} instead, which can say whose config it is.\n */\nconst unreadableSourceRepoConfig: RefuseUnreadable = (reason, cause) =>\n new Error(configUnreadableError(reason), { cause });\n\n/**\n * The config a MARKETPLACE SOURCE REPOSITORY declares about itself, or `null` when it declares\n * none: `<base>/.agents-inc/config.ts`, falling back to `<base>/.claude-src/config.ts`.\n *\n * Its own door, because it answers a different question from every other reader of this file.\n * An INSTALLATION's config lives inside a provider folder — one installation is exactly one\n * provider and the folder is what says which. A source repo's config is provider-NEUTRAL and\n * carries no provider segment: `skillsDir` and `stacksFile` describe the repository's own layout\n * and have nothing to do with a provider, and a marketplace serving both would otherwise have to\n * declare its layout twice.\n *\n * The old name is a fallback with NO sunset. The CLI can never move a folder in a repository it\n * only reads, and an author who moved it would break every consumer still on an older CLI —\n * silently, as \"No skills found\". Keeping both names reachable from one function is what lets\n * \"read `.claude-src` in sources forever\" and \"sunset `.claude-src` for installs\" both be true.\n */\nexport async function loadSourceRepoConfig(\n basePath: string,\n): Promise<Partial<ProjectConfig> | null> {\n for (const folder of SOURCE_REPO_CONFIG_FOLDERS) {\n const declared = await readDeclaredConfig(path.join(basePath, folder));\n if (declared) return declared;\n }\n return null;\n}\n\n/** Where a source repo may declare itself, in the order the first one found wins. */\nconst SOURCE_REPO_CONFIG_FOLDERS = [SOURCE_ROOT_DIR, LEGACY_SOURCE_DIR];\n\n/** The config in one candidate folder, or `null` when that folder declares none. */\nasync function readDeclaredConfig(dir: string): Promise<Partial<ProjectConfig> | null> {\n const configPath = path.join(dir, STANDARD_FILES.CONFIG_TS);\n if (!(await fileExists(configPath))) {\n verbose(`Source config not found at ${configPath}`);\n return null;\n }\n return readConfigOrRefuse(configPath, projectSourceConfigSchema, unreadableSourceRepoConfig);\n}\n\n/**\n * Load source config from a directory's own installation folder.\n *\n * The scope it announces is derived, not assumed: at the home root the file this reads\n * IS the global config, and a caller asking a project question there — `doctor` deciding\n * whether the cwd is a source repository — must not be told a project config was found\n * where none exists.\n */\nexport async function loadProjectSourceConfig(\n projectDir: string,\n): Promise<Partial<ProjectConfig> | null> {\n return loadSourceConfig(projectDir, isHomeDirectory(projectDir) ? \"global\" : \"project\");\n}\n\n/** Load source config from the global home directory's own source folder. */\nexport async function loadGlobalSourceConfig(): Promise<Partial<ProjectConfig> | null> {\n return loadSourceConfig(os.homedir(), \"global\");\n}\n\n/** The effective source config, which scope it was actually loaded from, and its file. */\ntype EffectiveSourceConfig = {\n config: Partial<ProjectConfig>;\n origin: ScopeKind;\n configPath: string;\n};\n\nasync function loadEffectiveSourceConfig(\n projectDir?: string,\n): Promise<EffectiveSourceConfig | null> {\n const ownDir = ownProjectDir(projectDir);\n const own = ownDir === null ? null : await readStoredRung(ownDir, \"project\");\n return own ?? (await readStoredRung(os.homedir(), \"global\"));\n}\n\n/** One stored rung: the config at `dir` and the file it was read from, or null when it has none. */\nasync function readStoredRung(\n dir: string,\n origin: ScopeKind,\n): Promise<EffectiveSourceConfig | null> {\n const config = await loadSourceConfig(dir, origin);\n return config && { config, origin, configPath: getInstalledConfigPath(dir) };\n}\n\n/** The directory whose config is a project's own, or null — see {@link loadOwnProjectSourceConfig}. */\nfunction ownProjectDir(projectDir: string | undefined): string | null {\n return projectDir === undefined || isHomeDirectory(projectDir) ? null : projectDir;\n}\n\n/**\n * A project's OWN source config, and nothing at the home root.\n *\n * `~/.claude-src/config.ts` is the global config, so reading it as a project's would label\n * one file both things at once: `compile` naming `Marketplace: project` beside\n * `Compiling global agents...`, `edit` announcing `(project)` while refusing scope toggles\n * as a global context. The axis is which FILE the settings were read from — never what\n * scope the skill and agent entries inside it carry.\n */\nasync function loadOwnProjectSourceConfig(\n projectDir: string | undefined,\n): Promise<Partial<ProjectConfig> | null> {\n const ownDir = ownProjectDir(projectDir);\n return ownDir === null ? null : loadProjectSourceConfig(ownDir);\n}\n\n/** The marketplace name the effective config recorded, with the file it recorded it in. */\nfunction recordedMarketplaceName(\n effective: EffectiveSourceConfig | null,\n): RecordedMarketplaceName | undefined {\n if (effective?.config.marketplaceName === undefined) return undefined;\n return {\n marketplace: effective.config.marketplaceName,\n marketplaceRecordedIn: effective.configPath,\n };\n}\n\n/**\n * Precedence: flag > env > project > global > default, with the first two rungs\n * reachable by `init` alone — see {@link SourceCaller}.\n */\nexport async function resolveSource(request: ResolveSourceRequest): Promise<ResolvedConfig> {\n const { caller, flag, projectDir } = request;\n const effective = await loadEffectiveSourceConfig(projectDir);\n const storedSource = effective?.config.marketplace ?? DEFAULT_SOURCE;\n // The stored NAME becomes this result's `marketplace` — the ref it was read beside becomes the\n // `source`. It labels that ref and no other: a project set up from another marketplace than the\n // one its global installation stored read the global's name as its own, and installed plugins\n // against a marketplace Claude Code had registered under a different one.\n const recorded = recordedMarketplaceName(effective);\n const labelFor = (source: string) => source === storedSource && recorded;\n\n if (flag !== undefined) {\n assertNamedSourceUsable(flag);\n verbose(`Marketplace named by this run: ${flag}`);\n return { source: flag, sourceOrigin: \"flag\", ...labelFor(flag) };\n }\n\n const envSource = caller === \"init\" ? readEnvSource() : undefined;\n if (envSource !== undefined) {\n return { source: envSource, sourceOrigin: \"env\", ...labelFor(envSource) };\n }\n\n if (effective?.config.marketplace) {\n verbose(`Marketplace from ${effective.origin} config: ${effective.config.marketplace}`);\n return {\n source: effective.config.marketplace,\n sourceOrigin: effective.origin,\n ...labelFor(effective.config.marketplace),\n };\n }\n\n verbose(`Using default marketplace: ${DEFAULT_SOURCE}`);\n return { source: DEFAULT_SOURCE, sourceOrigin: \"default\", ...labelFor(DEFAULT_SOURCE) };\n}\n\n/**\n * How a marketplace this run NAMED is referred to back to whoever named it.\n *\n * Origin-neutral on purpose: `--marketplace` is `init`'s flag and nobody else's, while a\n * `\"stored\"` caller may still name a marketplace it is reading for its own sake — `doctor`\n * points the loader at a marketplace repository. Naming the flag in a sentence that caller\n * reads blames an option it never passed.\n */\nconst NAMED_SOURCE_LABEL = \"The marketplace\";\n\n/**\n * Refuses a named marketplace that cannot be one. Raised rather than warned: somebody named\n * this, so falling through to another would install from a place they did not name.\n */\nfunction assertNamedSourceUsable(flag: string): void {\n if (flag.trim() === \"\") {\n throw new Error(\n `${NAMED_SOURCE_LABEL} cannot be empty. Provide a valid marketplace: a local directory path or a git repository URL (e.g., './my-skills' or 'https://github.com/user/repo')`,\n );\n }\n validateSourceFormat(flag.trim(), NAMED_SOURCE_LABEL);\n}\n\n/**\n * The marketplace {@link SOURCE_ENV_VAR} names, or undefined when it names none this run.\n *\n * Unset, empty and unusable all fall through to the next rung with a warning rather than\n * a refusal — the environment is ambient, so an exported value nobody meant for this run\n * must not be able to fail it. That is the opposite of {@link assertNamedSourceUsable},\n * and deliberately so: one was typed at this command, the other was already there.\n */\nfunction readEnvSource(): string | undefined {\n const envValue = process.env[SOURCE_ENV_VAR];\n if (!envValue) return undefined;\n\n const trimmed = envValue.trim();\n if (trimmed === \"\") {\n warn(`${SOURCE_ENV_VAR} is set but empty — ignoring and falling back to the next rung.`);\n return undefined;\n }\n\n try {\n validateSourceFormat(trimmed, SOURCE_ENV_VAR);\n } catch (error) {\n warn(\n `${SOURCE_ENV_VAR} has an invalid value — ignoring and falling back to the next rung.\\n${getErrorMessage(error)}`,\n );\n return undefined;\n }\n\n verbose(`Marketplace from ${SOURCE_ENV_VAR} env var: ${trimmed}`);\n return trimmed;\n}\n\nexport async function resolveAuthor(projectDir?: string): Promise<string | undefined> {\n const effective = await loadEffectiveSourceConfig(projectDir);\n return effective?.config.author;\n}\n\n/** Resolved branding with defaults applied for any missing fields */\nexport type ResolvedBranding = {\n name: string;\n};\n\n/**\n * Branding resolved per FIELD: this project's, then the global one's, then the shipped default.\n *\n * Per field rather than per file, and that distinction is the whole of this function. Everything\n * else reads {@link loadEffectiveSourceConfig}, which answers with the project's config if that\n * FILE exists and the global one otherwise — right for `marketplace`, where a project's is its own\n * and inheriting one would install from somewhere nobody named. Branding is the opposite kind of\n * field: it is presentation, a user sets it once for themselves, and a project that says nothing\n * about it is not asking for the shipped name back.\n *\n * Read per file it did exactly that. A user who branded globally stopped seeing their own name the\n * moment any project config existed — which is every installed project — and nothing announced it;\n * the name simply reverted. This function's own docblock described the per-field behaviour for as\n * long as the code did not perform it.\n */\nexport async function resolveBranding(projectDir?: string): Promise<ResolvedBranding> {\n const [own, global] = await Promise.all([\n loadOwnProjectSourceConfig(projectDir),\n loadGlobalSourceConfig(),\n ]);\n\n return {\n name: own?.branding?.name ?? global?.branding?.name ?? DEFAULT_BRANDING.NAME,\n };\n}\n\n/**\n * The one marketplace this installation reads skills from, as a {@link SourceEntry}.\n *\n * Distinct from {@link resolveSource}, which answers the same question as a\n * {@link ResolvedConfig} (source string plus where it came from). This is the shape the\n * surfaces that LIST sources want — `search` and `doctor` — and there is exactly one of\n * them: the registered-extras array this used to return alongside it was withdrawn with\n * the marketplace axis itself.\n */\nexport async function resolvePrimarySourceEntry(projectDir?: string): Promise<SourceEntry> {\n const resolvedConfig = await resolveSource({ caller: \"stored\", projectDir });\n return {\n name: \"marketplace\",\n url: resolvedConfig.source,\n description: \"Primary skills marketplace\",\n };\n}\n\nconst REMOTE_PROTOCOLS = [\n GITHUB_SOURCE.GITHUB_PREFIX, // \"github:\"\n GITHUB_SOURCE.GH_PREFIX, // \"gh:\"\n \"gitlab:\",\n \"bitbucket:\",\n \"sourcehut:\",\n \"https://\",\n \"http://\",\n] as const;\n\n// Minimum length after protocol prefix for a valid remote source (e.g., \"org/repo\" = 8 chars min)\nconst MIN_REMOTE_PATH_LENGTH = 3;\nconst MAX_SOURCE_LENGTH = 512;\n\n// Null bytes must never appear in source strings — they can bypass C-level string termination in downstream tools\nconst NULL_BYTE_PATTERN = /\\0/;\n\n// Path traversal sequences in git refs/branches/tags (e.g., \"?branch=../../etc/passwd\")\nconst PATH_TRAVERSAL_PATTERN = /\\.\\./;\n\n// UNC path prefixes (Windows network paths): \\\\server\\share or //server/share\n// These can trigger SMB authentication to attacker-controlled servers\nconst UNC_PATH_PATTERN = /^(?:\\/\\/|\\\\\\\\)/;\n\n// Private/reserved IPv4 ranges that should not appear in source URLs (SSRF prevention)\n// Matches: 127.x.x.x, 10.x.x.x, 172.16-31.x.x, 192.168.x.x, 0.0.0.0, 169.254.x.x\nconst PRIVATE_IPV4_PATTERN =\n /^(?:127\\.\\d+\\.\\d+\\.\\d+|10\\.\\d+\\.\\d+\\.\\d+|172\\.(?:1[6-9]|2\\d|3[01])\\.\\d+\\.\\d+|192\\.168\\.\\d+\\.\\d+|0\\.0\\.0\\.0|169\\.254\\.\\d+\\.\\d+)$/;\n\n// IPv6 loopback and private addresses in URL hostname brackets\nconst PRIVATE_IPV6_PATTERN =\n /^\\[(?:::1|::ffff:(?:127\\.\\d+\\.\\d+\\.\\d+|10\\.\\d+\\.\\d+\\.\\d+|192\\.168\\.\\d+\\.\\d+)|fd[0-9a-f]{2}:.*|fe80:.*)\\]$/i;\n\n/**\n * Validates a marketplace string format before it reaches giget or filesystem operations.\n * Catches obviously invalid formats early with clear error messages.\n *\n * @param source - The trimmed, non-empty marketplace value to validate\n * @param flagName - What carried this value, as the error messages name it back: `init`'s\n * `--marketplace`, {@link SOURCE_ENV_VAR}, or {@link NAMED_SOURCE_LABEL} when no flag did\n */\nexport function validateSourceFormat(source: string, flagName: string): void {\n // Null bytes can bypass C-level string termination in downstream tools (giget, git)\n if (NULL_BYTE_PATTERN.test(source)) {\n throw new Error(\n `${flagName} contains invalid characters.\\n\\n` +\n `Marketplace values must not contain null bytes.\\n` +\n `Examples:\\n` +\n ` ${flagName} ./my-skills\\n` +\n ` ${flagName} github:user/repo`,\n );\n }\n\n if (source.length > MAX_SOURCE_LENGTH) {\n throw new Error(\n `${flagName} value is too long (${source.length} characters, max ${MAX_SOURCE_LENGTH}).\\n\\n` +\n `Provide a shorter marketplace path or URL.\\n` +\n `Examples:\\n` +\n ` ${flagName} ./my-skills\\n` +\n ` ${flagName} github:user/repo`,\n );\n }\n\n const matchedProtocol = REMOTE_PROTOCOLS.find((prefix) => source.startsWith(prefix));\n\n if (matchedProtocol) {\n validateRemoteSource(source, matchedProtocol, flagName);\n } else {\n validateLocalPath(source, flagName);\n }\n}\n\nfunction validateRemoteSource(source: string, protocol: string, flagName: string): void {\n const pathAfterProtocol = source.slice(protocol.length).trim();\n\n if (pathAfterProtocol.length < MIN_REMOTE_PATH_LENGTH) {\n throw new Error(\n `${flagName} has an incomplete URL: \"${source}\"\\n\\n` +\n `A repository path is required after the protocol prefix.\\n` +\n `Examples:\\n` +\n ` ${flagName} github:user/repo\\n` +\n ` ${flagName} https://github.com/user/repo`,\n );\n }\n\n // Block path traversal in any remote marketplace (refs, branches, query params)\n if (PATH_TRAVERSAL_PATTERN.test(pathAfterProtocol)) {\n throw new Error(\n `${flagName} contains path traversal in URL: \"${source}\"\\n\\n` +\n `Remote marketplace URLs must not contain '..' sequences.\\n` +\n `Examples:\\n` +\n ` ${flagName} github:user/repo\\n` +\n ` ${flagName} https://github.com/user/repo`,\n );\n }\n\n // For https:// and http:// URLs, validate basic URL structure\n if (protocol === \"https://\" || protocol === \"http://\") {\n validateHttpUrl(source, flagName);\n return;\n }\n\n // For git shorthand protocols (github:, gh:, gitlab:, etc.), validate org/repo pattern\n validateGitShorthand(source, pathAfterProtocol, flagName);\n}\n\nfunction validateHttpUrl(source: string, flagName: string): void {\n // Basic URL structure check: must have a hostname with at least one dot or localhost\n const afterProtocol = source.replace(/^https?:\\/\\//, \"\");\n // Strip port number for hostname validation (e.g., \"localhost:8080\" -> \"localhost\")\n const hostnameWithPort = afterProtocol.split(\"/\")[0] ?? \"\";\n const hostname = hostnameWithPort.split(\":\")[0] ?? \"\";\n\n if (!namesAcceptedHost(hostname, hostnameWithPort)) {\n throw new Error(\n `${flagName} has an invalid URL: \"${source}\"\\n\\n` +\n `The URL must include a valid hostname.\\n` +\n `Examples:\\n` +\n ` ${flagName} https://github.com/user/repo\\n` +\n ` ${flagName} https://gitlab.company.com/team/skills`,\n );\n }\n\n // Block private/reserved IP addresses (SSRF prevention via giget)\n if (PRIVATE_IPV4_PATTERN.test(hostname) || PRIVATE_IPV6_PATTERN.test(hostnameWithPort)) {\n throw new Error(\n `${flagName} points to a private or reserved IP address: \"${source}\"\\n\\n` +\n `Marketplace URLs must not target private network addresses.\\n` +\n `Use a public hostname instead.\\n` +\n `Examples:\\n` +\n ` ${flagName} https://github.com/user/repo\\n` +\n ` ${flagName} https://gitlab.company.com/team/skills`,\n );\n }\n}\n\n/**\n * Whether the URL names an accepted host: a dotted hostname (github.com), localhost, or a\n * bracketed IPv6 address ([::1]).\n */\nfunction namesAcceptedHost(hostname: string, hostnameWithPort: string): boolean {\n if (!hostname) return false;\n const isBracketedIPv6 = hostnameWithPort.startsWith(\"[\") && hostnameWithPort.includes(\"]\");\n return hostname.includes(\".\") || hostname === \"localhost\" || isBracketedIPv6;\n}\n\nfunction validateGitShorthand(source: string, repoPath: string, flagName: string): void {\n // Git shorthand format: protocol:owner/repo (must have at least owner/repo)\n if (!repoPath.includes(\"/\")) {\n throw new Error(\n `${flagName} has an invalid repository reference: \"${source}\"\\n\\n` +\n `Git shorthand marketplaces require an owner/repo format.\\n` +\n `Examples:\\n` +\n ` ${flagName} github:user/repo\\n` +\n ` ${flagName} gh:organization/skills`,\n );\n }\n}\n\nfunction validateLocalPath(source: string, flagName: string): void {\n // Check for control characters (except common whitespace)\n // eslint-disable-next-line no-control-regex\n const CONTROL_CHAR_PATTERN = /[\\x00-\\x08\\x0E-\\x1F\\x7F]/u;\n if (CONTROL_CHAR_PATTERN.test(source)) {\n throw new Error(\n `${flagName} contains invalid characters: \"${source}\"\\n\\n` +\n `Marketplace paths must not contain control characters.\\n` +\n `Examples:\\n` +\n ` ${flagName} ./my-skills\\n` +\n ` ${flagName} /home/user/skills`,\n );\n }\n\n // Block UNC paths (Windows network paths like \\\\server\\share or //server/share)\n // These can trigger SMB authentication to attacker-controlled servers, leaking credentials\n if (UNC_PATH_PATTERN.test(source)) {\n throw new Error(\n `${flagName} contains a UNC network path: \"${source}\"\\n\\n` +\n `Network paths (\\\\\\\\server\\\\share or //server/share) are not allowed for security reasons.\\n` +\n `Use a local directory path or a remote URL instead.\\n` +\n `Examples:\\n` +\n ` ${flagName} ./my-skills\\n` +\n ` ${flagName} /home/user/skills\\n` +\n ` ${flagName} https://github.com/user/repo`,\n );\n }\n}\n\n/**\n * Whether a resolved marketplace IS the default public one, asked of the source\n * STRING.\n *\n * The one place that question is answered, because more than one surface asks it\n * and they must agree: the install-mode tagger decides whether the marketplace it\n * labels skills with is public or private, and both stack lookups ask it as half\n * of {@link offersBuiltInStacks}. A marketplace named explicitly — by flag, env\n * or config — is the default one when it spells {@link DEFAULT_SOURCE}.\n *\n * A path is not this question's subject. Nothing in a source STRING that happens\n * to be a path says which repository it holds; {@link isPublicCatalogueCheckout}\n * asks the directory instead, and it is the one to use where a directory is in hand.\n */\nexport function isDefaultSource(source: string): boolean {\n return source === DEFAULT_SOURCE;\n}\n\n/** The only field of a repository's package.json this module reads. */\nconst packageIdentitySchema = z.object({ name: z.string() });\n\n/**\n * Whether the DIRECTORY at `basePath` is a checkout of the public catalogue's own\n * repository, read off package identity.\n *\n * Never off the name in `marketplace.json`: that name is a claim the author\n * writes, so a guard keyed on it would exempt exactly the source it exists to\n * catch. {@link PUBLIC_CATALOGUE_PACKAGE} carries what the signal is and is not\n * worth.\n *\n * The build side asks a different question of the same identity and is spelled\n * apart from this one on purpose: `isCatalogueOwnReservedName` in\n * `marketplace-generator.ts` asks whether a marketplace NAME about to be\n * published is the catalogue's own, and takes the package name it already holds\n * rather than a directory to read one from.\n */\nexport async function isPublicCatalogueCheckout(basePath: string): Promise<boolean> {\n const raw = await readFileOptional(path.join(basePath, STANDARD_FILES.PACKAGE_JSON));\n return declaredPackageName(raw) === PUBLIC_CATALOGUE_PACKAGE;\n}\n\n/** The `name` a package.json declares, or null when there is none to read. */\nfunction declaredPackageName(raw: string): string | null {\n let json: unknown;\n try {\n json = JSON.parse(raw);\n } catch {\n return null;\n }\n\n const parsed = packageIdentitySchema.safeParse(json);\n return parsed.success ? parsed.data.name : null;\n}\n\n/**\n * Whether the CLI's built-in stack catalogue stands in for a marketplace that\n * ships no stacks of its own.\n *\n * Two spellings of one marketplace, and BOTH stack lookups must read this rather\n * than either half. `resolveOfferedStacks` decides the list the wizard offers and\n * `loadStackById` resolves the id the user then picked; a rule they answer\n * differently offers a stack and refuses to install it.\n *\n * The built-in stacks ARE the public catalogue's stacks — that repository ships\n * no `config/stacks.ts` at all — so a checkout of it read off a path has to reach\n * them too, and the source string cannot say that a path is that repository.\n */\nexport async function offersBuiltInStacks(basePath: string, source: string): Promise<boolean> {\n return isDefaultSource(source) || (await isPublicCatalogueCheckout(basePath));\n}\n\nexport function isLocalSource(source: string): boolean {\n if (source.startsWith(\"/\") || source.startsWith(\".\")) {\n return true;\n }\n\n const hasRemoteProtocol = REMOTE_PROTOCOLS.some((prefix) => source.startsWith(prefix));\n if (hasRemoteProtocol) return false;\n\n if (source.includes(\"..\") || source.includes(\"~\")) {\n throw new Error(\n `Invalid marketplace path: ${source}. Path traversal patterns like '..' and '~' are not allowed for security reasons. Use absolute paths or remote URLs instead (e.g., '/home/user/skills' or 'https://github.com/user/repo').`,\n );\n }\n return true;\n}\n\n/**\n * Whether two marketplace refs name one marketplace.\n *\n * A folder on disk is one marketplace however its path is spelled, so two local paths are compared\n * resolved against `fromDir` — the directory a relative one is read from — and `path.resolve`\n * drops a trailing slash on the way. A remote ref names one repository only as written.\n */\nexport function isSameMarketplace(a: string, b: string, fromDir: string): boolean {\n if (isLocalSource(a) && isLocalSource(b)) {\n return path.resolve(fromDir, a) === path.resolve(fromDir, b);\n }\n return a === b;\n}\n","import { z } from \"zod\";\nimport { partition } from \"remeda\";\nimport type { LocalSkillMetadata } from \"./skills/skill-metadata\";\nimport type { LocalRawMetadata } from \"./skills/local-skill-loader\";\nimport {\n AUTHOR_HANDLE_PATTERN,\n KEBAB_CASE_PATTERN,\n LOCAL_PSEUDO_CATEGORY,\n STANDARD_FILES,\n} from \"../consts\";\nimport { METADATA_KEYS } from \"./metadata-keys\";\nimport { formatZodIssue } from \"./schema-validator\";\nimport { isRecord } from \"../utils/type-guards\";\nimport { warn } from \"../utils/logger\";\nimport { SKILL_SLUGS, CATEGORIES } from \"../types/generated/source-types\";\nimport {\n AGENT_ISOLATIONS,\n CACHE_TTLS,\n EFFORT_NAMES,\n MODEL_NAMES,\n PERMISSION_MODES,\n} from \"../types/matrix\";\nimport type {\n AgentHookAction,\n AgentHookDefinition,\n AgentIsolation,\n AgentName,\n AgentYamlConfig,\n AlternativeGroup,\n CategoryDefinition,\n CategoryPath,\n ConflictRule,\n DiscourageRule,\n Domain,\n EffortLevel,\n Marketplace,\n MarketplaceMetadata,\n MarketplaceOwner,\n MarketplacePlugin,\n MarketplaceRemoteSource,\n ModelName,\n PermissionMode,\n PluginAuthor,\n PluginManifest,\n ProjectConfig,\n RelationshipDefinitions,\n RequireRule,\n SkillAssignment,\n SkillConfig,\n SkillId,\n SkillSlug,\n Category,\n} from \"../types\";\n\nexport const modelNameSchema = z.enum(MODEL_NAMES) as z.ZodType<ModelName>;\n\nexport const effortLevelSchema = z.enum(EFFORT_NAMES) as z.ZodType<EffortLevel>;\n\nexport const permissionModeSchema = z.enum(PERMISSION_MODES) as z.ZodType<PermissionMode>;\n\nexport const skillSlugSchema = z.enum(SKILL_SLUGS) as z.ZodType<SkillSlug>;\n\n// Accepts: known category, \"local\", or any kebab-case string (custom categories)\nexport const categoryPathSchema = z.string().refine(\n (val): val is CategoryPath => {\n if (val === LOCAL_PSEUDO_CATEGORY) return true;\n if ((CATEGORIES as readonly string[]).includes(val)) return true;\n // Accept any kebab-case string for custom categories\n return KEBAB_CASE_PATTERN.test(val);\n },\n {\n message: \"Must be a valid category path (e.g., 'web-framework', 'shared-testing', or 'local')\",\n },\n) as z.ZodType<CategoryPath>;\n\nexport const agentHookActionSchema: z.ZodType<AgentHookAction> = z.object({\n type: z.enum([\"command\", \"script\", \"prompt\"]),\n command: z.string().exactOptional(),\n script: z.string().exactOptional(),\n prompt: z.string().exactOptional(),\n});\n\n/**\n * A hook definition as a `plugin.json` authored elsewhere may carry one, and `Partial` because\n * nothing in this CLI reads a manifest's hooks — {@link pluginManifestSchema}'s two callers take\n * `name` and `version` and nothing else, and both degrade to skipping the plugin entirely when the\n * parse throws. Refusing a shape we never read would drop the whole plugin from discovery.\n *\n * Deliberately NOT the shape an agent declares: {@link strictHooksRecordSchema} is what both the\n * loader and the compiled-frontmatter reader take, because a definition carrying no actions fires\n * nothing and a `metadata.yaml` writing one is a mistake worth reporting rather than emptying.\n */\nexport const agentHookDefinitionSchema: z.ZodType<Partial<AgentHookDefinition>> = z.object({\n matcher: z.string().exactOptional(),\n hooks: z.array(agentHookActionSchema).exactOptional(),\n});\n\n/** Lenient hooks record — {@link pluginManifestObjectSchema} is its only consumer. */\nexport const hooksRecordSchema = z.record(z.string(), z.array(agentHookDefinitionSchema));\n\n/**\n * The isolation modes Claude Code's sub-agent frontmatter documents.\n *\n * `z.enum(AGENT_ISOLATIONS)` rather than a literal spelling the one member out, which is the\n * bridge pattern its four siblings above use and the only form that MOVES with the vocabulary. A\n * `satisfies z.ZodType<AgentIsolation>` does not compensate: `ZodType`'s output parameter is\n * covariant, so a narrower schema satisfies a wider one and widening the array produced zero `tsc`\n * errors — while every parse of a newly-documented mode failed at runtime.\n */\nexport const agentIsolationSchema = z.enum(AGENT_ISOLATIONS) as z.ZodType<AgentIsolation>;\n\n/**\n * Experimental frontmatter options; `cacheTtl` is the only one Claude Code documents today.\n *\n * `.strict()` HERE rather than at each use site, because the site that most needed it never had\n * it: `agentYamlConfigSchema` reads the `metadata.yaml` a user hand-authors, and a plain\n * `z.object` there emptied `experimental: { cacheTtlSeconds: \"1h\" }` to `{}` before either strict\n * reader saw it — the template then emitted `experimental: {}` (Liquid reads an empty hash as\n * truthy) and the reader had nothing left to refuse.\n */\nexport const agentExperimentalSchema = z\n .object({\n cacheTtl: z.enum(CACHE_TTLS).exactOptional(),\n })\n .strict();\n\n/** Strict hook definition — hooks array is required and must have at least one action */\nconst strictAgentHookDefinitionSchema = z.object({\n matcher: z.string().exactOptional(),\n hooks: z.array(agentHookActionSchema).min(1),\n});\n\n/** Strict hooks record for validation schemas (requires at least one hook action per definition) */\nexport const strictHooksRecordSchema = z.record(\n z.string(),\n z.array(strictAgentHookDefinitionSchema),\n);\n\nexport const skillAssignmentSchema: z.ZodType<SkillAssignment> = z.object({\n id: z.string() as z.ZodType<SkillId>,\n preloaded: z.boolean().exactOptional(),\n local: z.boolean().exactOptional(),\n path: z.string().exactOptional(),\n});\n\n// Lenient: accepts any string for `name` since local/custom skills may not follow strict SkillId pattern\nexport const skillFrontmatterLoaderSchema = z.object({\n /** Lenient (any string): local/custom skills have non-builtin IDs */\n name: z.string() as z.ZodType<SkillId>,\n description: z.string(),\n model: modelNameSchema.exactOptional(),\n});\n\n/**\n * Loader schema for a skill's metadata.yaml.\n *\n * `custom` buys its category NOTHING here. It used to: a `custom: true` skill's\n * category was waved through on a bare kebab-case test while every other skill's\n * went to `categoryPathSchema`. A custom skill is placed in a category that\n * already exists rather than bringing one, so the leniency described a freedom it\n * no longer has, and the same field now answers to the same schema either way.\n * Whether the category is one this installation actually declares is asked where\n * the declarations are — `mergeLocalSkillsIntoMatrix`, not here.\n */\nexport const skillMetadataLoaderSchema = z\n .object({\n category: categoryPathSchema.exactOptional(),\n author: z.string().exactOptional(),\n domain: z.string() as z.ZodType<Domain>,\n custom: z.boolean().exactOptional(),\n })\n .passthrough();\n\n/**\n * Raw metadata.yaml shape read by the matrix loader during skill extraction.\n * Preserved verbatim on the move from matrix-loader.ts.\n */\nexport const matrixRawMetadataSchema = z.object({\n category: categoryPathSchema,\n author: z.string(),\n displayName: z.string().exactOptional(),\n slug: z.string() as z.ZodType<SkillSlug>,\n cliDescription: z.string().exactOptional(),\n usageGuidance: z.string().exactOptional(),\n // Boundary cast: domain is a string at the YAML parse boundary; narrowed to Domain type\n domain: z.string() as z.ZodType<Domain>,\n custom: z.boolean().exactOptional(),\n});\n\nexport const pluginAuthorSchema: z.ZodType<PluginAuthor> = z.object({\n name: z.string().min(1),\n email: z.string().exactOptional(),\n});\n\n// Shared plugin.json shape — the lenient (strip) and strict variants below differ only in unknown-key policy\nconst pluginManifestObjectSchema = z.object({\n name: z.string(),\n version: z.string().exactOptional(),\n description: z.string().exactOptional(),\n author: pluginAuthorSchema.exactOptional(),\n /** Lenient: a plugin authored elsewhere may carry any category string or none at all */\n category: z.string().exactOptional(),\n keywords: z.array(z.string()).exactOptional(),\n commands: z.union([z.string(), z.array(z.string())]).exactOptional(),\n agents: z.union([z.string(), z.array(z.string())]).exactOptional(),\n skills: z.union([z.string(), z.array(z.string())]).exactOptional(),\n hooks: z.union([z.string(), hooksRecordSchema]).exactOptional(),\n});\n\n/** Lenient plugin.json schema (strips unknown keys; used at load boundaries) */\nexport const pluginManifestSchema: z.ZodType<PluginManifest> = pluginManifestObjectSchema;\n\n/** Strict plugin.json schema — rejects unrecognized keys (used by plugin-validator) */\nexport const pluginManifestValidationSchema = pluginManifestObjectSchema.strict();\n\nexport const agentYamlConfigSchema: z.ZodType<AgentYamlConfig> = z.object({\n id: z.string() as z.ZodType<AgentName>,\n title: z.string(),\n description: z.string(),\n model: modelNameSchema.exactOptional(),\n effort: effortLevelSchema.exactOptional(),\n tools: z.array(z.string()),\n disallowedTools: z.array(z.string()).exactOptional(),\n permissionMode: permissionModeSchema.exactOptional(),\n isolation: agentIsolationSchema.exactOptional(),\n /**\n * The same contract `agentFrontmatterValidationSchema` reads the compiled agent back through.\n * The lenient {@link hooksRecordSchema} used to sit here, and every key its definition declares\n * is optional — so a block written with its actions one level flat was stripped to `{}` with no\n * error, `agent.liquid` emitted the empty definition, and the refusal arrived from the\n * frontmatter reader against a compiled `.md` the user never wrote. This is the last boundary\n * that still knows which `metadata.yaml` the value came from.\n */\n hooks: strictHooksRecordSchema.exactOptional(),\n experimental: agentExperimentalSchema.exactOptional(),\n outputFormat: z.string().exactOptional(),\n domain: (z.string() as z.ZodType<Domain>).exactOptional(),\n custom: z.boolean().exactOptional(),\n});\n\n// Defined before projectConfigLoaderSchema so it can reference stackAgentConfigSchema\n// Single skill assignment element: either a bare SkillId string or an object { id, preloaded? }\nconst skillAssignmentElementSchema = z.union([\n z.string() as z.ZodType<SkillId>,\n skillAssignmentSchema,\n]);\n\n/**\n * Agent config within a stack: maps category to skill assignment(s).\n * Lenient: accepts bare string, object, or array from YAML.\n * Consumers normalize all values to SkillAssignment[] after parsing.\n */\nexport const stackAgentConfigSchema = z.record(\n z.string(),\n z.union([skillAssignmentElementSchema, z.array(skillAssignmentElementSchema)]),\n);\n\n/**\n * The top-level keys a saved config carried before the marketplace fields were renamed, each\n * mapped to the field its value lives on now. Data rather than a check per key because both\n * loader schemas read the same file and have to refuse the same keys — and `satisfies` ties every\n * replacement to a field that really exists, so the next rename cannot leave this list stale.\n */\nconst RENAMED_CONFIG_FIELDS = { source: \"marketplace\" } as const satisfies Record<\n string,\n keyof ProjectConfig\n>;\n\n/** The same, for the keys a saved config's SKILL ENTRIES carried. */\nconst RENAMED_SKILL_ENTRY_FIELDS = { source: \"origin\" } as const satisfies Record<\n string,\n keyof SkillConfig\n>;\n\nfunction renamedFieldMessage(oldKey: string, newKey: string): string {\n return `\"${oldKey}\" was renamed to \"${newKey}\". Rename the key in this config — the CLI does not read \"${oldKey}\" any more and will not fall back to it.`;\n}\n\nfunction reportRenamedKeys(\n record: Record<string, unknown>,\n renames: Record<string, string>,\n path: PropertyKey[],\n ctx: z.RefinementCtx,\n): void {\n for (const [oldKey, newKey] of Object.entries(renames)) {\n if (!(oldKey in record)) continue;\n ctx.addIssue({\n code: \"custom\",\n path: [...path, oldKey],\n message: renamedFieldMessage(oldKey, newKey),\n });\n }\n}\n\n/**\n * Refuses a saved config that still names a field by the key it had before the rename.\n *\n * Reads the raw document rather than parse output because neither schema would show it one: both\n * are `.passthrough()`, so a stale top-level key survives as unrecognised data, and the skills\n * array is declared, so a stale key on an entry is stripped before any refinement runs. Either way\n * the run would look for the value under its NEW name, find nothing, and quietly install from the\n * default marketplace instead of the one the config named.\n */\nfunction refuseRenamedFields(config: unknown, ctx: z.RefinementCtx): void {\n if (!isRecord(config)) return;\n\n reportRenamedKeys(config, RENAMED_CONFIG_FIELDS, [], ctx);\n\n const { skills } = config;\n if (!Array.isArray(skills)) return;\n for (const [index, entry] of skills.entries()) {\n if (!isRecord(entry)) continue;\n reportRenamedKeys(entry, RENAMED_SKILL_ENTRY_FIELDS, [\"skills\", index], ctx);\n }\n}\n\n/**\n * Both loader schemas behind the same refusal, piped so it runs on the file as written. A failure\n * here short-circuits the shape check, so a config carrying an old key is answered with the rename\n * it needs rather than with the missing-field noise the rename causes.\n */\nconst renamedFieldGuard = z.unknown().superRefine(refuseRenamedFields);\n\n/** The shape {@link projectConfigLoaderSchema} admits once the rename guard has passed. */\nconst projectConfigFields = z\n .object({\n /** Project/plugin name in kebab-case */\n name: z.string().exactOptional(),\n description: z.string().exactOptional(),\n /** Per-agent configuration with scope (e.g., [{ name: \"web-developer\", scope: \"project\" }]) */\n agents: z\n .array(\n z.object({\n name: z.string(),\n scope: z.enum([\"project\", \"global\"]),\n /** Per-agent overrides of the agent's own metadata defaults */\n model: modelNameSchema.exactOptional(),\n effort: effortLevelSchema.exactOptional(),\n excluded: z.boolean().exactOptional(),\n }),\n )\n .exactOptional(),\n /** Per-skill configuration with scope and provenance */\n skills: z\n .array(\n z.object({\n id: z.string() as z.ZodType<SkillId>,\n scope: z.enum([\"project\", \"global\"]),\n origin: z.string(),\n excluded: z.boolean().exactOptional(),\n }),\n )\n .exactOptional(),\n\n /** Author handle (e.g., \"@vince\") */\n author: z.string().exactOptional(),\n /** Selected domains from the wizard (persisted for edit mode restoration) */\n selectedDomains: z.array(z.string() as z.ZodType<Domain>).exactOptional(),\n /** Agent-to-category-to-skill mappings from selected stack (accepts same formats as stacks.ts) */\n stack: z.record(z.string(), stackAgentConfigSchema).exactOptional(),\n /** The marketplace this install reads skills from, as a path or URL (e.g., \"github:my-org/skills\") */\n marketplace: z.string().exactOptional(),\n /** The name that marketplace's manifest gives it, which plugins are registered under */\n marketplaceName: z.string().exactOptional(),\n /** Separate source for agents when different from skills source */\n agentsSource: z.string().exactOptional(),\n /** Tracked project installation paths (global config only) */\n projects: z.array(z.string()).exactOptional(),\n })\n .passthrough();\n\n/**\n * Lenient loader for a source folder's config.ts (ProjectConfig).\n * name/agents optional since partial configs are valid at load time.\n * Full validation happens in validateProjectConfig().\n */\nexport const projectConfigLoaderSchema = renamedFieldGuard.pipe(projectConfigFields);\n\nconst categoryDefinitionSchema: z.ZodType<CategoryDefinition> = z.object({\n id: z.string() as z.ZodType<Category>,\n displayName: z.string(),\n description: z.string(),\n domain: (z.string() as z.ZodType<Domain>).exactOptional(),\n exclusive: z.boolean(),\n order: z.number(),\n icon: z.string().exactOptional(),\n});\n\n/**\n * What a relationship rule naming an unknown skill says back, in place of the whole\n * generated slug union it was tested against.\n *\n * A rule names skills by slug and every one is held to the PUBLIC catalogue's generated\n * union, so a marketplace author naming a skill they themselves ship is handed roughly 250\n * names belonging to somebody else — which answers a question they did not ask and does not\n * contain the answer to the one they did. Zod's own text for an enum reports the options and\n * never the input, so the slug they actually wrote was the one thing missing from it; the\n * function form is what puts it back.\n *\n * It says \"yet\" deliberately. The constraint is this schema's rather than the loader's — a\n * source's own rules are resolved against that source's own slug map — so the refusal names a\n * limit rather than a law. Whether slugs leave the closed union is a separate question.\n */\nfunction unknownSkillSlugRefusal(input: unknown): string {\n const named = typeof input === \"string\" ? `'${input}'` : \"That value\";\n return (\n `${named} is not a slug the public catalogue carries, and a relationship rule may only ` +\n `name skills the public catalogue carries — this marketplace's own skills cannot be named ` +\n `in one yet. Name a catalogue slug, or leave 'relationships' out: it is optional, and a ` +\n `marketplace shipping no relationship rules loads and installs like any other.`\n );\n}\n\n// Skill references in relationship rules: slugs resolved to canonical IDs by matrix-loader\nconst skillRefInRules = z.enum(SKILL_SLUGS, {\n error: (issue) => unknownSkillSlugRefusal(issue.input),\n}) as z.ZodType<SkillSlug>;\n\n// Shared shape for conflict/discourage/compatibility rules: 2+ slugs plus a reason\nconst skillGroupRuleSchema = z.object({\n skills: z.array(skillRefInRules).min(2),\n reason: z.string(),\n});\n\nconst conflictRuleSchema: z.ZodType<ConflictRule> = skillGroupRuleSchema;\n\nconst discourageRuleSchema: z.ZodType<DiscourageRule> = skillGroupRuleSchema;\n\nconst requireRuleSchema: z.ZodType<RequireRule> = z.object({\n skill: skillRefInRules,\n needs: z.array(skillRefInRules).min(1),\n needsAny: z.boolean().exactOptional(),\n reason: z.string(),\n});\n\nconst alternativeGroupSchema: z.ZodType<AlternativeGroup> = z.object({\n purpose: z.string(),\n skills: z.array(skillRefInRules).min(1),\n});\n\nconst relationshipDefinitionsSchema: z.ZodType<RelationshipDefinitions> = z.object({\n conflicts: z.array(conflictRuleSchema),\n discourages: z.array(discourageRuleSchema),\n requires: z.array(requireRuleSchema),\n alternatives: z.array(alternativeGroupSchema),\n});\n\n/**\n * Standalone skill-categories.ts file schema.\n * Top-level object with version string and categories map using existing categoryDefinitionSchema.\n */\nexport const skillCategoriesFileSchema = z.object({\n version: z.string(),\n categories: z.record(z.string(), categoryDefinitionSchema),\n});\n\n/**\n * Standalone skill-rules.ts file schema.\n * Contains version and aggregate relationship rules between skills.\n */\nexport const skillRulesFileSchema = z.object({\n version: z.string(),\n relationships: relationshipDefinitionsSchema.exactOptional(),\n});\n\n/**\n * Raw metadata from a local skill's metadata.yaml.\n * displayName and category are required — the skill must declare both.\n */\nexport const localRawMetadataSchema = z\n .object({\n /** Short name shown in the wizard grid (e.g., \"my-custom-react\") */\n displayName: z.string(),\n /** Kebab-case short key for alias resolution (e.g., \"react\") */\n slug: z.string() as z.ZodType<SkillSlug>,\n /** One-line description for the wizard */\n cliDescription: z.string().exactOptional(),\n /** Category to place this skill in (e.g., \"web-framework\") */\n category: categoryPathSchema,\n /** When an AI agent should invoke this skill */\n usageGuidance: z.string().exactOptional(),\n /** Domain this skill belongs to (e.g., \"web\", \"api\", \"cli\") */\n domain: z.string() as z.ZodType<Domain>,\n /** True if this skill was created outside the CLI's built-in vocabulary */\n custom: z.boolean().exactOptional(),\n })\n // Passthrough widens the output with an index signature; LocalRawMetadata is the\n // honest declared shape consumers read (same round-1 pattern as localSkillMetadataSchema).\n .passthrough() as z.ZodType<LocalRawMetadata>;\n\n/** Metadata for local skills that were forked/copied from a marketplace skill */\nexport const localSkillMetadataSchema = z\n .object({\n forkedFrom: z\n .object({\n /** Original skill ID before forking — lenient (any string) since custom/extra-source skills have non-builtin IDs */\n skillId: z.string() as z.ZodType<SkillId>,\n /** SHA hash of the original content at fork time (for diff detection) */\n contentHash: z.string(),\n /** ISO date when the fork was created */\n date: z.string(),\n /** Source URL the skill was installed from (e.g., \"github:agents-inc/skills\") */\n source: z.string().exactOptional(),\n /** Directory inside that repository, for a skill only its own bytes can install again */\n path: z.string().exactOptional(),\n })\n .exactOptional(),\n })\n // Passthrough widens the output with an index signature; LocalSkillMetadata carries the\n // same index signature, so this is the honest declared shape for parse results.\n .passthrough() as z.ZodType<LocalSkillMetadata>;\n\nconst stackSchema = z.object({\n id: z.string().min(1),\n name: z.string().min(1),\n description: z.string(),\n /** Maps agent IDs to their category-to-skill assignments */\n agents: z.record(z.string(), stackAgentConfigSchema),\n /** High-level philosophy guiding this stack's technology choices */\n philosophy: z.string().exactOptional(),\n});\n\n// Pre-normalization schema: values may be string or string[].\n// loadStacks() normalizes to StacksConfig (all values SkillId[]) after parsing.\nexport const stacksConfigSchema = z.object({\n stacks: z.array(stackSchema).min(1),\n});\n\nconst marketplaceRemoteSourceSchema: z.ZodType<MarketplaceRemoteSource> = z.object({\n source: z.enum([\"github\", \"url\"]),\n repo: z.string().exactOptional(),\n url: z.string().exactOptional(),\n ref: z.string().exactOptional(),\n});\n\nconst marketplacePluginSchema: z.ZodType<MarketplacePlugin> = z.object({\n name: z.string().min(1),\n /** Local directory path (relative to pluginRoot) or remote source config */\n source: z.union([z.string(), marketplaceRemoteSourceSchema]),\n description: z.string().exactOptional(),\n version: z.string().exactOptional(),\n author: pluginAuthorSchema.exactOptional(),\n /** Lenient: external data may have any category string or none at all */\n category: z.string().exactOptional(),\n keywords: z.array(z.string()).exactOptional(),\n});\n\n// MarketplaceOwner aliases PluginAuthor (identical shape, both require name.min(1))\nconst marketplaceOwnerSchema: z.ZodType<MarketplaceOwner> = pluginAuthorSchema;\n\nconst marketplaceMetadataSchema: z.ZodType<MarketplaceMetadata> = z.object({\n /** Base directory for resolving plugin source paths (e.g., \"plugins/\") */\n pluginRoot: z.string().exactOptional(),\n});\n\n/**\n * What a marketplace name being refused says back, in place of the pattern it was tested against.\n *\n * A raw Zod format issue names the regex, which tells a marketplace author what the CLI checks\n * with and nothing about what to write instead. The rule is spelled the way\n * `marketplaceNameNotPublishable` in `utils/messages.ts` already spells it on the emit side, so\n * the two directions of one rule cannot come to say different things about it.\n *\n * Stated as a `message` on the `regex` check rather than in a `refine`, deliberately: a refinement\n * is unrepresentable in JSON Schema, so `src/schemas/marketplace.schema.json` would silently lose\n * the `pattern` an editor validates `marketplace.json` against.\n */\nconst MARKETPLACE_NAME_REFUSAL =\n \"A marketplace name is kebab-case: lowercase letters, numbers and hyphens, starting with a letter (e.g. 'acme-skills'). Rename it in this manifest — Claude Code registers every plugin under it and accepts no other shape.\";\n\nexport const marketplaceSchema: z.ZodType<Marketplace> = z.object({\n $schema: z.string().exactOptional(),\n /**\n * Kebab-case, because this name is the namespace Claude Code registers plugins under and the\n * CLI piggybacks on what Claude Code accepts (owner ruling 2026-08-20). Held to the same rule\n * `build marketplace` refuses to publish under, so what this CLI emits is what it can read back.\n */\n name: z.string().min(1).regex(KEBAB_CASE_PATTERN, { message: MARKETPLACE_NAME_REFUSAL }),\n version: z.string().min(1),\n description: z.string().exactOptional(),\n owner: marketplaceOwnerSchema,\n metadata: marketplaceMetadataSchema.exactOptional(),\n plugins: z.array(marketplacePluginSchema).min(1),\n});\n\n/**\n * What a cached remote source was fetched from, written beside the cache so the\n * next load can ask whether it is still current in one request.\n *\n * `etag` is absent when the host returned none — a copy that cannot be\n * revalidated at all, which is a different state from one that has not been\n * checked yet.\n */\nexport const sourceRevalidationSchema = z.object({\n /** The tarball URL giget resolved for this source. */\n tar: z.string().min(1),\n etag: z.string().min(1).exactOptional(),\n});\n\n/** Tool permission overrides (allow/deny lists for Claude Code tool access) */\nconst permissionConfigSchema = z.object({\n /** Tool names or patterns to explicitly allow */\n allow: z.array(z.string()).exactOptional(),\n /** Tool names or patterns to explicitly deny */\n deny: z.array(z.string()).exactOptional(),\n});\n\n/** Settings file schema (.claude/settings.yaml) for project-level configuration */\nexport const settingsFileSchema = z\n .object({\n permissions: permissionConfigSchema.exactOptional(),\n })\n .passthrough();\n\n/** Branding overrides for white-labeling the CLI */\nconst brandingConfigSchema = z.object({\n /** Custom CLI name (e.g., \"Acme Dev Tools\") */\n name: z.string().exactOptional(),\n});\n\n/** The shape {@link projectSourceConfigSchema} admits once the rename guard has passed. */\nconst projectSourceConfigFields = z\n .object({\n /** The marketplace this install reads skills from, as a path or URL */\n marketplace: z.string().exactOptional(),\n /** Author handle for this project's config */\n author: z.string().exactOptional(),\n /** The name that marketplace's manifest gives it, which plugins are registered under */\n marketplaceName: z.string().exactOptional(),\n /** Separate source for agent definitions (when different from skills) */\n agentsSource: z.string().exactOptional(),\n /** Branding overrides for white-labeling the CLI */\n branding: brandingConfigSchema.exactOptional(),\n /** Custom skills directory override (default: \"src/skills\") */\n skillsDir: z.string().exactOptional(),\n /** Custom agents directory override (default: \"src/agents\") */\n agentsDir: z.string().exactOptional(),\n /** Custom stacks file path override (default: \"config/stacks.ts\") */\n stacksFile: z.string().exactOptional(),\n /** Custom categories file path override (default: \"config/skill-categories.ts\") */\n categoriesFile: z.string().exactOptional(),\n /** Custom rules file path override (default: \"config/skill-rules.ts\") */\n rulesFile: z.string().exactOptional(),\n })\n .passthrough();\n\n/**\n * Project source configuration from a source folder's config.ts.\n * Stores multi-source settings, custom directory overrides, and bound skills.\n */\nexport const projectSourceConfigSchema = renamedFieldGuard.pipe(projectSourceConfigFields);\n\n// Strict validation schemas enforce all constraints and use .strict() to reject unknown fields,\n// unlike the lenient loader schemas above which use .passthrough() for forward compatibility at parse boundaries\n\n/**\n * Strict schema for a source agent's `metadata.yaml` — compilation's hand-authored INPUT rather\n * than an output, since compiling an agent writes one `.md` file and no YAML at all. It generates\n * `src/schemas/agent.schema.json`, which every `metadata.yaml` points at in its\n * `yaml-language-server` line, and `validateAgents` in `lib/source-validator.ts` is its only\n * runtime caller, globbing `src/agents` and reporting each failure as a source issue.\n *\n * Lenient id (any string) since marketplace agents may use custom identifiers.\n */\nexport const agentYamlGenerationSchema = z\n .object({\n $schema: z.string().exactOptional(),\n id: z.string().min(1),\n title: z.string().min(1),\n description: z.string().min(1),\n model: modelNameSchema.exactOptional(),\n effort: effortLevelSchema.exactOptional(),\n tools: z.array(z.string()).min(1),\n disallowedTools: z.array(z.string()).exactOptional(),\n permissionMode: permissionModeSchema.exactOptional(),\n isolation: agentIsolationSchema.exactOptional(),\n hooks: strictHooksRecordSchema.exactOptional(),\n experimental: agentExperimentalSchema.exactOptional(),\n outputFormat: z.string().exactOptional(),\n domain: (z.string() as z.ZodType<Domain>).exactOptional(),\n custom: z.boolean().exactOptional(),\n })\n .strict();\n\n/**\n * Strict validation for a compiled agent's `.md` frontmatter, read by two callers whose failure\n * modes differ sharply. `validateAgentFrontmatter` in `lib/plugins/plugin-validator.ts` collects\n * the issues and returns an invalid `ValidationResult`, so the agent is reported and the run\n * continues. `parseAgentFrontmatter` in `lib/agents/agent-plugin-compiler.ts` returns the refusal\n * with its reason, and `compileAgentPlugin` throws it at the agent it was asked to package — the\n * loud one, and why a key this schema omits fails a packaging run rather than merely a report.\n *\n * Its `hooks`, `isolation` and `experimental` are the same three schemas `agentYamlConfigSchema`\n * loads a `metadata.yaml` through, deliberately: `agent.liquid` writes all three from what that\n * load returned, so a value one accepts and the other refuses is a compiled agent this CLI cannot\n * read back.\n */\nexport const agentFrontmatterValidationSchema = z\n .object({\n /** Agent name in kebab-case (becomes the Task tool identifier) */\n name: z.string().regex(KEBAB_CASE_PATTERN).min(1),\n description: z.string().min(1),\n /** Comma-separated list of allowed tools */\n tools: z.string().exactOptional(),\n /** Comma-separated list of denied tools */\n disallowedTools: z.string().exactOptional(),\n model: modelNameSchema.exactOptional(),\n effort: effortLevelSchema.exactOptional(),\n permissionMode: permissionModeSchema.exactOptional(),\n isolation: agentIsolationSchema.exactOptional(),\n experimental: agentExperimentalSchema.exactOptional(),\n /** Skill names to preload (embed in agent prompt) */\n skills: z.array(z.string().min(1)).exactOptional(),\n hooks: strictHooksRecordSchema.exactOptional(),\n })\n .strict();\n\n/** Strict validation for SKILL.md frontmatter (matches Claude Code plugin spec) */\nexport const skillFrontmatterValidationSchema = z\n .object({\n name: z.string().min(1),\n description: z.string().min(1),\n /** If true, Claude cannot invoke this skill on its own */\n \"disable-model-invocation\": z.boolean().exactOptional(),\n /** If true, user can invoke this skill directly */\n \"user-invocable\": z.boolean().exactOptional(),\n /** Comma-separated list of tools this skill can use */\n \"allowed-tools\": z.string().exactOptional(),\n model: modelNameSchema.exactOptional(),\n /** \"fork\" means skill runs in a forked context (separate conversation) */\n context: z.enum([\"fork\"]).exactOptional(),\n /** Agent name this skill is scoped to */\n agent: z.string().exactOptional(),\n /** Hint text shown when user invokes the skill */\n \"argument-hint\": z.string().exactOptional(),\n })\n .strict();\n\n/**\n * Provenance object shared verbatim by metadataValidationSchema and\n * customMetadataValidationSchema. The forkedFrom variant in\n * localSkillMetadataSchema (no `version`) is deliberately NOT unified here —\n * its shape differs, so sharing would change validation behavior.\n */\nconst forkedFromSchema = z.object({\n /** Original skill ID */\n skillId: z.string(),\n /** Version of the original at fork time */\n version: z.number().int().min(1).exactOptional(),\n /** Content hash of the original at fork time */\n contentHash: z.string(),\n /** Source URL or identifier */\n source: z.string().exactOptional(),\n /** Directory inside that source, for a skill only its own bytes can install again */\n path: z.string().exactOptional(),\n /** ISO date of the fork */\n date: z.string(),\n});\n\n/**\n * Recommended upper bound for cliDescription in published skills. Exceeding it is\n * advisory only — splitMetadataValidationIssues downgrades it to a warning because\n * the runtime schemas accept any length and the value only feeds wizard description\n * text. Empty (min(1)) remains a hard error.\n */\nconst CLI_DESCRIPTION_MAX_LENGTH = 60;\n\n/**\n * Fields shared by metadataValidationSchema (strict, built-in vocabulary) and\n * customMetadataValidationSchema (relaxed). Only `category` and `slug` differ\n * between the two variants — each adds those via .extend().\n */\nconst skillMetadataBaseSchema = z.object({\n /** Author handle — must start with @ (e.g., \"@vince\") */\n author: z.string().regex(AUTHOR_HANDLE_PATTERN),\n /** Short display name for the wizard grid (max 30 chars) */\n displayName: z.string().min(1).max(30),\n /** One-line description for the wizard (max 60 chars recommended; over-length is a validation warning) */\n cliDescription: z.string().min(1).max(CLI_DESCRIPTION_MAX_LENGTH),\n /** When an AI agent should invoke this skill (min 10 chars to ensure usefulness) */\n usageGuidance: z.string().min(10),\n /** 7-char hex SHA of skill content (for change detection) */\n contentHash: z\n .string()\n .regex(/^[a-f0-9]{7}$/)\n .exactOptional(),\n /** ISO date of last update */\n updated: z.string().exactOptional(),\n /** Provenance tracking when skill was forked from another */\n forkedFrom: forkedFromSchema.exactOptional(),\n /** Domain assignment from metadata */\n domain: (z.string() as z.ZodType<Domain>).exactOptional(),\n /** True if this skill was created outside the CLI's built-in vocabulary */\n custom: z.boolean().exactOptional(),\n});\n\n/**\n * What a published skill's `slug` says back when the public catalogue does not carry it, in\n * place of the whole generated slug union it was tested against.\n *\n * The same defect `unknownSkillSlugRefusal` answers one layer over, and the one an author meets\n * FIRST: they write a `metadata.yaml` before they write a rule. Zod's text for an enum reports\n * the options and never the input, so a marketplace author naming a skill they themselves ship\n * was handed roughly 250 names belonging to somebody else with their own slug missing from it.\n *\n * It differs from the rules-side message in the one way that matters: this refusal has a way\n * out and that one does not. `validateSkillMetadata` reads `custom: true` and validates against\n * `customMetadataValidationSchema`, whose `slug` is any kebab-case name — so the flag is what a\n * skill outside the catalogue's vocabulary is CARRIED by rather than a way around the check\n * (owner ruling 2026-08-22: the union stays closed and `custom: true` is the documented\n * mechanism). Nothing said so until now, which is the whole of what made it read as a trick.\n */\nfunction unknownMetadataSlugRefusal(input: unknown): string {\n const named = typeof input === \"string\" ? `'${input}'` : \"That value\";\n return (\n `${named} is not a slug the public catalogue carries. A published skill's slug is held to ` +\n `that catalogue unless the skill declares it is not from it — add '${METADATA_KEYS.CUSTOM}: true' ` +\n `beside it in this ${STANDARD_FILES.METADATA_YAML} and the slug is read as your marketplace's ` +\n `own, any kebab-case name. That declaration is how a skill outside the catalogue's vocabulary ` +\n `is carried; a skill the catalogue does carry names its catalogue slug and leaves it off.`\n );\n}\n\n/** Strict validation for metadata.yaml in published skills (enforces author format, enum-validated category/slug) */\nexport const metadataValidationSchema = skillMetadataBaseSchema\n .extend({\n /** Domain-prefixed category — must be a known built-in category */\n category: z.enum(CATEGORIES),\n /**\n * Kebab-case short key — must be a known built-in slug, unless the file declares\n * `custom: true` and is judged by {@link customMetadataValidationSchema} instead.\n */\n slug: z.enum(SKILL_SLUGS, {\n error: (issue) => unknownMetadataSlugRefusal(issue.input),\n }),\n })\n .strict();\n\n/** Relaxed validation for custom skill metadata.yaml (any category string, kebab-case slug, allows extra fields) */\nexport const customMetadataValidationSchema = skillMetadataBaseSchema.extend({\n /** Any string category — custom skills may define their own categories */\n category: z.string(),\n /** Kebab-case short key for alias resolution, search, and relationship rules */\n slug: z.string().regex(KEBAB_CASE_PATTERN).min(1).max(50),\n});\n\nconst stackSkillAssignmentSchema = z\n .object({\n id: z.string().min(1),\n /** If true, skill content is embedded in the compiled agent prompt */\n preloaded: z.boolean().exactOptional(),\n })\n .strict();\n\n/** Strict validation for published stack config.yaml (marketplace stacks) */\nexport const stackConfigValidationSchema = z\n .object({\n /** Unique stack identifier in kebab-case */\n id: z.string().regex(KEBAB_CASE_PATTERN).exactOptional(),\n name: z.string().min(1),\n version: z.string(),\n author: z.string().min(1),\n description: z.string().exactOptional(),\n /** ISO date when this stack was first created */\n created: z.string().exactOptional(),\n /** ISO date of last update */\n updated: z.string().exactOptional(),\n /** Primary framework this stack is designed for (e.g., \"nextjs\", \"remix\") */\n framework: z.string().exactOptional(),\n /** All skills used in this stack (flat list, at least one required) */\n skills: z.array(stackSkillAssignmentSchema).min(1),\n /** Agent IDs this stack compiles (at least one required) */\n agents: z.array(z.string().regex(KEBAB_CASE_PATTERN)).min(1),\n /** Per-agent skill assignments: { agentId: { category: [skillAssignment] } } */\n agentSkills: z\n .record(z.string(), z.record(z.string(), z.array(stackSkillAssignmentSchema)))\n .exactOptional(),\n /** High-level philosophy guiding technology choices */\n philosophy: z.string().exactOptional(),\n /** Guiding principles for agents using this stack */\n principles: z.array(z.string().min(1)).exactOptional(),\n tags: z.array(z.string().regex(KEBAB_CASE_PATTERN)).exactOptional(),\n /** Per-skill overrides: alternative suggestions and lock status */\n overrides: z\n .record(\n z.string(),\n z\n .object({\n /** Suggested alternative skill IDs if this one is swapped */\n alternatives: z.array(z.string().min(1)).exactOptional(),\n /** If true, this skill cannot be swapped by the user */\n locked: z.boolean().exactOptional(),\n })\n .strict(),\n )\n .exactOptional(),\n /** Community metrics for sorting/ranking */\n metrics: z\n .object({\n upvotes: z.number().int().min(0).exactOptional(),\n downloads: z.number().int().min(0).exactOptional(),\n })\n .strict()\n .exactOptional(),\n /** Lifecycle hooks triggered by file changes or commands */\n hooks: strictHooksRecordSchema.exactOptional(),\n })\n .strict();\n\n/** Format Zod validation issues into a human-readable string (e.g., \"path.to.field: Expected string; other: Required\") */\nexport function formatZodIssues(issues: z.ZodIssue[]): string {\n return issues.map(formatZodIssue).join(\"; \");\n}\n\n/**\n * Validates raw skill metadata using the relaxed schema for custom skills and\n * the strict schema for built-ins — the one place the custom-vs-strict\n * selection policy lives.\n */\nexport function validateSkillMetadata(rawMetadata: unknown) {\n const schema = isCustomMetadata(rawMetadata)\n ? customMetadataValidationSchema\n : metadataValidationSchema;\n return schema.safeParse(rawMetadata);\n}\n\n/**\n * Names a metadata.yaml's schema failure in the words its author needs: the required\n * fields the file leaves out, listed as missing, and whatever else is wrong said per\n * field. Zod's own text for an absent key reads \"expected string, received undefined\",\n * which describes the type system rather than the file.\n */\nexport function describeMetadataSchemaFailure(\n issues: z.ZodIssue[],\n rawMetadata: Record<string, unknown>,\n): string {\n const [absent, malformed] = partition(issues, (issue) => isAbsentField(issue, rawMetadata));\n return [\n ...(absent.length > 0 ? [nameMissingFields(absent)] : []),\n ...malformed.map(formatZodIssue),\n ].join(\"; \");\n}\n\n/** True for a top-level field the file never declared, as against one it declared wrongly. */\nfunction isAbsentField(issue: z.ZodIssue, rawMetadata: Record<string, unknown>): boolean {\n const [field, ...nested] = issue.path;\n return nested.length === 0 && typeof field === \"string\" && rawMetadata[field] === undefined;\n}\n\nfunction nameMissingFields(absent: z.ZodIssue[]): string {\n const fields = absent.map((issue) => issue.path.join(\".\"));\n return `missing required ${fields.length === 1 ? \"field\" : \"fields\"}: ${fields.join(\", \")}`;\n}\n\nexport type MetadataIssueSplit = {\n /** Hard schema violations — the metadata is broken and must be fixed */\n errors: string[];\n /** Advisory violations (over-length cliDescription) — worth fixing, never fatal */\n warnings: string[];\n};\n\n/** True for the over-length `cliDescription` issue — the only advisory metadata violation. */\nfunction isOverLengthCliDescription(issue: z.ZodIssue): boolean {\n return issue.code === \"too_big\" && issue.path.length === 1 && issue.path[0] === \"cliDescription\";\n}\n\n/** Reads `cliDescription` from raw parsed metadata when it is a string. */\nfunction readCliDescription(raw: unknown): string | undefined {\n if (raw == null || typeof raw !== \"object\") return undefined;\n // Boundary cast: raw comes straight from YAML parsing; the typeof check above narrows to object\n const value = (raw as { cliDescription?: unknown }).cliDescription;\n return typeof value === \"string\" ? value : undefined;\n}\n\n/**\n * Warning text for an over-length `cliDescription`, carrying the actual length.\n * The too_big issue only fires when the value is a string, so the undefined\n * branch is defensive — it falls back to the raw zod issue text.\n */\nfunction formatOverLengthWarning(issue: z.ZodIssue, cliDescription: string | undefined): string {\n if (cliDescription === undefined) return formatZodIssue(issue);\n return `cliDescription is ${cliDescription.length} characters — exceeds the recommended maximum of ${CLI_DESCRIPTION_MAX_LENGTH}`;\n}\n\n/**\n * Splits strict-metadata validation issues into hard errors and advisory warnings.\n *\n * Over-length `cliDescription` (> CLI_DESCRIPTION_MAX_LENGTH chars) is advisory: the\n * runtime schemas accept any length and the value only feeds wizard description text,\n * so validate reports it as a warning carrying the actual length. Empty/missing\n * `cliDescription` and every other issue remain errors.\n */\nexport function splitMetadataValidationIssues(\n error: z.ZodError,\n rawMetadata: unknown,\n): MetadataIssueSplit {\n const [overLength, hardFailures] = partition(error.issues, isOverLengthCliDescription);\n\n const cliDescription = readCliDescription(rawMetadata);\n const warnings = overLength.map((issue) => formatOverLengthWarning(issue, cliDescription));\n\n return { errors: hardFailures.map(formatZodIssue), warnings };\n}\n\n/**\n * Validates that a parsed JSON/YAML value does not exceed a maximum nesting depth.\n * Returns true if the structure is within limits, false if it exceeds maxDepth.\n */\nexport function validateNestingDepth(value: unknown, maxDepth: number): boolean {\n function check(val: unknown, depth: number): boolean {\n if (depth > maxDepth) return false;\n if (Array.isArray(val)) {\n return val.every((item) => check(item, depth + 1));\n }\n if (val !== null && typeof val === \"object\") {\n return Object.values(val).every((v) => check(v, depth + 1));\n }\n return true;\n }\n return check(value, 0);\n}\n\n/**\n * Returns true when raw parsed metadata has `custom: true`.\n * Used to pick between strict (built-in vocabulary) and relaxed (user-authored) validation schemas.\n */\nexport function isCustomMetadata(raw: unknown): boolean {\n if (raw == null || typeof raw !== \"object\") return false;\n if (!(\"custom\" in raw)) return false;\n return raw.custom === true;\n}\n\n/**\n * Logs warnings for unknown fields in a parsed object compared to a list of expected keys.\n * Used at security-critical parsing boundaries for files this CLI owns (marketplace.json), where\n * `.passthrough()` is kept for forward compatibility but unexpected fields should be surfaced.\n * A file owned by another tool is not such a boundary: an unfamiliar key there is that tool's\n * business, and a complete expected-key list for it cannot be maintained.\n */\nexport function warnUnknownFields(\n parsed: Record<string, unknown>,\n expectedKeys: readonly string[],\n context: string,\n): void {\n const expectedSet = new Set(expectedKeys);\n const unknownKeys = Object.keys(parsed).filter((k) => !expectedSet.has(k));\n if (unknownKeys.length > 0) {\n warn(`Unknown fields in ${context}: ${unknownKeys.join(\", \")}`);\n }\n}\n","import { z } from \"zod\";\n\nimport { stripTerminalControls } from \"../utils/string\";\n\n/**\n * One place for the path-prefixed issue rendering shared by every Zod reporter.\n *\n * Which is also why the sanitising is here. Every part of this sentence is built out of the\n * REFUSED DOCUMENT rather than out of the schema: a path segment and an unrecognised key are\n * object keys the document chose, and a message quotes the value it received. So the text this\n * renders is always the text of whatever was being validated — and the documents reaching it are\n * a stranger's `SKILL.md` frontmatter, their `metadata.yaml`, their marketplace manifest and\n * whatever arrived on stdin.\n *\n * Sanitised at the renderer rather than at its callers because there are around twenty of them\n * and a new reporter is a normal thing to add. Made inert rather than shortened: a validation\n * message that lost the key it was naming would stop being a validation message.\n */\nexport function formatZodIssue(issue: z.ZodIssue): string {\n const path = stripTerminalControls(issue.path.join(\".\"));\n if (issue.code === \"unrecognized_keys\") {\n return `Unrecognized key: \"${stripTerminalControls(issue.keys.join('\", \"'))}\"`;\n }\n return path\n ? `${path}: ${stripTerminalControls(issue.message)}`\n : stripTerminalControls(issue.message);\n}\n\nexport function formatZodErrors(error: z.ZodError): string[] {\n return error.issues.map(formatZodIssue);\n}\n","// Vendored byte-for-byte into packages/matrix/src/vendor/ by scripts/generate-matrix-package.ts.\n// ANY edit here — a comment-only one included — obliges `bun run generate:matrix` in packages/cli;\n// `generate:matrix:check` is the gate.\n\nimport type { CategoryPath, SkillSlug, SkillId } from \"./skills\";\nimport type { AgentName } from \"./agents\";\n\nexport type { Category, Domain } from \"./generated/source-types\";\nexport { CATEGORIES, DOMAINS } from \"./generated/source-types\";\n\n// Import locally for use within this file\nimport type { Category, Domain } from \"./generated/source-types\";\n\n/** Claude model selectors for agent configuration */\nexport const MODEL_NAMES = [\"sonnet\", \"opus\", \"haiku\", \"fable\", \"inherit\"] as const;\nexport type ModelName = (typeof MODEL_NAMES)[number];\n\n/** Reasoning effort levels for agent configuration */\nexport const EFFORT_NAMES = [\"low\", \"medium\", \"high\", \"xhigh\", \"max\"] as const;\nexport type EffortLevel = (typeof EFFORT_NAMES)[number];\n\n/** Agent permission modes for Claude Code tool access */\nexport const PERMISSION_MODES = [\n \"default\",\n \"acceptEdits\",\n \"dontAsk\",\n \"bypassPermissions\",\n \"plan\",\n \"delegate\",\n] as const;\nexport type PermissionMode = (typeof PERMISSION_MODES)[number];\n\n/**\n * The one isolation mode Claude Code's sub-agent frontmatter documents.\n *\n * Beside the other frontmatter vocabulary rather than in `agents.ts`, because this file is the half\n * `@workspace/matrix` vendors — and a browser rendering a compiled agent has to spell `isolation`\n * the same way the CLI does or the two front doors emit different frontmatter for the same agent.\n *\n * The absent case is not a member: an agent with no `isolation` shares the session's working tree,\n * and that is the default the key opts out of.\n */\nexport const AGENT_ISOLATIONS = [\"worktree\"] as const;\nexport type AgentIsolation = (typeof AGENT_ISOLATIONS)[number];\n\n/**\n * How long a sub-agent's prompt-cache entries live.\n *\n * The one setting that makes a stable prompt prefix pay: a compiled agent's body is its system\n * prompt, and everything above the trailing volatile block is byte-identical between invocations,\n * so a longer TTL is what lets the second invocation reuse the first one's cache rather than\n * rebuilding it.\n *\n * **Emitted only when an agent declares it, and deliberately never defaulted.** `5m` is Claude\n * Code's own default; `1h` bills cache WRITES at a higher rate, so a generator that set it for\n * every agent it wrote would raise the bill of everyone who installed one without being asked —\n * and it is ignored outright while a subscription runs on usage credits, so the cost would\n * sometimes buy nothing. Whether the trade is worth it depends on how the agent is used, which is\n * the installer's knowledge rather than the author's.\n */\nexport const CACHE_TTLS = [\"5m\", \"1h\"] as const;\nexport type CacheTtl = (typeof CACHE_TTLS)[number];\n\n/**\n * Category definitions indexed by category ID.\n * Partial because not every Category has a category definition (e.g., a marketplace\n * may only define a subset of all possible categories).\n */\nexport type CategoryMap = Partial<Record<Category, CategoryDefinition>>;\n\n/**\n * Full domain selections used throughout the wizard pipeline (store, components, result).\n *\n * Structure: `{ domain: { category: [skillId, ...] } }`\n *\n * - Outer Partial: not all domains need selections (user may skip \"mobile\" entirely)\n * - Inner Partial: within a domain, only some categories may have selections\n * - SkillId[]: a category can have multiple skills unless `CategoryDefinition.exclusive` is true\n */\nexport type DomainSelections = Partial<Record<Domain, Partial<Record<Category, SkillId[]>>>>;\n\n/** Single category definition from skill-categories.ts */\nexport type CategoryDefinition = {\n id: Category;\n displayName: string;\n description: string;\n /** Domain for wizard domain filtering */\n domain?: Domain;\n /** If true, only one skill can be selected in this category (radio behavior). */\n exclusive: boolean;\n /** Display order within domain (lower = earlier) */\n order: number;\n icon?: string;\n};\n\n/** Relationship rules between skills from skill-rules.ts */\nexport type RelationshipDefinitions = {\n /** Selecting one disables the others */\n conflicts: ConflictRule[];\n /** Selecting one shows warning for others but doesn't disable */\n discourages: DiscourageRule[];\n /** Skill A requires skill B to be selected first */\n requires: RequireRule[];\n /** Groups of interchangeable skills for the same purpose */\n alternatives: AlternativeGroup[];\n};\n\n/** Base shape for skill-group rules: a set of related slugs plus a reason */\nexport type SkillGroupRule = {\n /** Skill slugs (resolved to canonical IDs by matrix-loader) */\n skills: SkillSlug[];\n reason: string;\n};\n\n/** Mutual exclusion rule - selecting any one skill disables ALL others */\nexport type ConflictRule = SkillGroupRule;\n\n/** Soft conflict rule - selecting any one shows a warning for ALL others */\nexport type DiscourageRule = SkillGroupRule;\n\n/** Dependency rule - skill A requires skill B to be selected first */\nexport type RequireRule = {\n skill: SkillSlug;\n /** Skill slugs that must be selected before this one */\n needs: SkillSlug[];\n /**\n * If true, only ONE of the `needs` skills is required (OR logic).\n * If false/undefined, ALL are required (AND logic).\n * @default false\n */\n needsAny?: boolean;\n reason: string;\n};\n\n/** Group of interchangeable skills serving the same purpose */\nexport type AlternativeGroup = {\n purpose: string;\n skills: SkillSlug[];\n};\n\n/** Parsed configuration from skill-rules.ts */\nexport type SkillRulesConfig = {\n version: string;\n /** Aggregate relationship rules between skills */\n relationships: RelationshipDefinitions;\n};\n\n/**\n * Slug -> canonical skill ID. Partial because only extracted skills are present.\n *\n * One direction, not two. A reverse `idToSlug` was carried here until 2026-08-23 and had **zero\n * readers anywhere** — every occurrence was a write, and the only thing consuming it was the\n * duplicate-slug asymmetry it made possible. A map nothing reads cannot be out of step with the\n * one that is read, so deleting it retires that whole class rather than guarding it.\n */\nexport type SkillSlugMap = {\n /** Forward: slug -> canonical skill ID */\n slugToId: Partial<Record<SkillSlug, SkillId>>;\n};\n\n/**\n * Output of mergeMatrixWithSkills() combining skill-categories.ts + skill-rules.ts with extracted metadata.\n * This is the primary read model consumed by the wizard and CLI commands.\n */\nexport type MergedSkillsMatrix = {\n version: string;\n categories: CategoryMap;\n /** Indexed by full skill ID for O(1) lookup */\n skills: Partial<Record<SkillId, ResolvedSkill>>;\n /** Stacks with all skill aliases resolved to canonical IDs */\n suggestedStacks: ResolvedStack[];\n /** Bidirectional slug <-> ID mapping */\n slugMap: SkillSlugMap;\n /**\n * Slugs the relationship rules name that no skill in this matrix carries.\n * Absent when every reference resolved. Resolution drops such a reference and\n * warns; carrying the list is what lets `checkMatrixHealth` report the typo\n * against the source that shipped it rather than only logging it.\n */\n unresolvedSlugs?: SkillSlug[];\n /** Explicit domain definitions from agent metadata files */\n agentDefinedDomains?: Partial<Record<AgentName, Domain>>;\n /** ISO timestamp of when this matrix was generated */\n generatedAt: string;\n};\n\n/**\n * Identity/description fields shared by ExtractedSkillMetadata (pre-merge) and\n * ResolvedSkill (post-merge). Both types are `SkillCore & { extras }`; extracting\n * the common shape keeps the two skill surfaces in sync. Purely structural — no\n * runtime change (the intersection is equivalent to the flattened object).\n */\nexport type SkillCore = {\n id: SkillId;\n /** Kebab-case short key for alias resolution, search, and relationship rules (e.g., \"react\") */\n slug: SkillSlug;\n /** Title-cased label for UI display (e.g., \"React\", \"Apollo Client\") */\n displayName: string;\n /** The wizard's short label — `cliDescription` from metadata.yaml when the skill states one. */\n description: string;\n /**\n * The SKILL.md frontmatter `description`: what a compiled sub-agent's skill-activation table\n * shows, because compile reads SKILL.md itself. It differs from `description` for every skill\n * stating a `cliDescription`, so a preview reading `description` showed a line the install never\n * writes (CLI-898). Optional: a catalogue built before it existed carries none.\n */\n activationDescription?: string;\n /** When an AI agent should invoke this skill (decision criteria) */\n usageGuidance?: string;\n /** Matches key in matrix.categories; determines which wizard category grid this skill appears in */\n category: CategoryPath;\n /** Author handle (e.g., \"@vince\") from metadata.yaml */\n author: string;\n /** Relative path from src/ to the skill directory */\n path: string;\n /** True if from .claude/skills/ (user-defined local skill) */\n local?: boolean;\n /** Absolute path to local skill directory */\n localPath?: string;\n /** True if this skill was created outside the CLI's built-in vocabulary */\n custom?: boolean;\n};\n\n/**\n * Single skill with all computed relationships resolved for CLI rendering.\n * Produced by mergeMatrixWithSkills() after resolving aliases, relationships, and sources.\n */\nexport type ResolvedSkill = SkillCore & {\n /** Selecting this skill disables these others (hard exclusion) */\n conflictsWith: SkillRelation[];\n /** Skills that THIS skill requires (must select first) */\n requires: SkillRequirement[];\n /** Other skills that serve the same purpose (informational, not enforced) */\n alternatives: SkillAlternative[];\n /** Selecting this skill shows a warning for these others (soft conflict) */\n discourages: SkillRelation[];\n /** All known sources that provide this skill (populated by multi-source-loader) */\n availableSources?: SkillSource[];\n /** Currently active/installed source (if any) */\n activeSource?: SkillSource;\n};\n\n/** Skill-to-skill relationship with reason */\nexport type SkillRelation = {\n skillId: SkillId;\n reason: string;\n};\n\n/** Resolved skill dependency with AND/OR logic */\nexport type SkillRequirement = {\n skillIds: SkillId[];\n /**\n * If true, only ONE of skillIds is needed (OR).\n * If false, ALL are needed (AND).\n *\n * Always present. The absence this field could have carried is resolved one step upstream:\n * `resolveRelationships` in `lib/matrix/skill-resolution.ts` writes\n * `rule.needsAny ?? false` from the optional {@link RequireRule.needsAny}, so nothing\n * downstream of resolution ever meets an unset value.\n */\n needsAny: boolean;\n reason: string;\n};\n\n/** Alternative skill that serves the same purpose */\nexport type SkillAlternative = {\n skillId: SkillId;\n purpose: string;\n};\n\n/** Stack with resolved skill IDs and agent mappings */\nexport type ResolvedStack = {\n id: string;\n name: string;\n description: string;\n /** Skill selections with resolved full skill IDs by category */\n skills: Partial<Record<AgentName, Partial<Record<Category, SkillId[]>>>>;\n /** Flat list of all skill IDs in this stack */\n allSkillIds: SkillId[];\n philosophy: string;\n /** UI grouping label for the stack selection screen (e.g., \"React\", \"CLI\") */\n group?: string;\n};\n\n/** Short alias used for category-level search (e.g., \"react\", \"zustand\") */\nexport type SkillAlias = string;\n\n/** Source type classification for skill provenance (where the skill comes from) */\nexport const SKILL_SOURCE_TYPES = [\"public\", \"private\", \"local\"] as const;\nexport type SkillSourceType = (typeof SKILL_SOURCE_TYPES)[number];\n\n/**\n * How a project's skills are installed: fully ejected, fully plugin-based, or a\n * mix of both. Derived at runtime from SkillConfig.origin (see deriveInstallMode).\n */\nexport type InstallMode = \"eject\" | \"plugin\" | \"mixed\";\n\n/** A single source from which a skill can be obtained */\nexport type SkillSource = {\n /** Source identifier: \"public\", marketplace name, \"local\" */\n name: string;\n type: SkillSourceType;\n /** Source URL for remote sources (e.g., \"github:acme-corp/claude-skills\") */\n url?: string;\n /** Whether this source's version is currently installed on disk */\n installed: boolean;\n /** How the skill was installed on disk (separate from provenance) — a single skill is never \"mixed\" */\n installMode?: Exclude<InstallMode, \"mixed\">;\n /** True for the primary marketplace source (scoped or default public). Set by multi-source-loader. */\n primary?: boolean;\n};\n\n/** Advisory visual state for a skill option in the wizard UI */\nexport type OptionState =\n | { status: \"normal\" }\n | { status: \"discouraged\"; reason: string }\n | { status: \"incompatible\"; reason: string };\n\n/**\n * Skill option as displayed in the wizard, computed based on current selections.\n * Recomputed by matrix-resolver on every selection change.\n */\nexport type SkillOption = {\n id: SkillId;\n /** True if this skill is currently selected by the user */\n selected: boolean;\n /** True when this skill is selected but has unmet dependency requirements */\n hasUnmetRequirements: boolean;\n /** Explains which requirements are unmet (only set when hasUnmetRequirements is true) */\n unmetRequirementsReason?: string;\n};\n\n/** Result of validating the current skill selections */\nexport type SelectionValidation = {\n valid: boolean;\n errors: ValidationError[];\n};\n\n/** Advisory validation error (non-blocking) */\nexport type ValidationError = {\n type: \"conflict\" | \"missingRequirement\" | \"categoryExclusive\";\n message: string;\n skills: SkillId[];\n};\n\n/**\n * Skill metadata extracted from SKILL.md frontmatter + metadata.yaml before matrix merge.\n *\n * Relationship fields (conflictsWith, requires, etc.) are resolved from\n * centralized group-based declarations in skill-rules.ts — not from individual skill metadata.\n */\nexport type ExtractedSkillMetadata = SkillCore & {\n /** Directory path for filesystem access, e.g. \"web/framework/react\" */\n directoryPath: string;\n /** Domain this skill belongs to (e.g., \"web\", \"api\", \"cli\") */\n domain: Domain;\n};\n","import path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport { createJiti } from \"jiti\";\nimport { fileExists } from \"../../utils/fs\";\nimport { verbose } from \"../../utils/logger\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { isRecord } from \"../../utils/type-guards\";\nimport { formatZodIssues } from \"../schemas\";\nimport type { z } from \"zod\";\n\n/** Resolve agents-inc/config to the source config-exports.ts so jiti can load it in dev. */\nconst CONFIG_EXPORTS_PATH = path.resolve(\n path.dirname(fileURLToPath(import.meta.url)),\n \"../../config-exports.ts\",\n);\n\n/**\n * Thrown when a config file evaluated cleanly but the schema refused its SHAPE.\n *\n * Named apart from the generic load failure because the two mean different things to a caller:\n * a file that cannot be evaluated says only that something is broken, while a refused shape has\n * said exactly what is wrong with a file the user still owns. A loader may reasonably report the\n * first as \"no config\"; reporting the second that way is how a config carrying a stale key ends\n * up silently repointing an install at the default marketplace.\n */\nexport class ConfigSchemaError extends Error {\n constructor(\n readonly configPath: string,\n readonly issues: string,\n ) {\n super(`Config validation failed at '${configPath}': ${issues}`);\n this.name = \"ConfigSchemaError\";\n }\n}\n\n/**\n * Thrown when a config file evaluated cleanly and exported bindings, none of which is the default\n * one every config in this project is read out of.\n *\n * Distinct from {@link ConfigSchemaError} because the two fault different lines of the file. A\n * refused shape names a field the author can go and correct; a module that exports\n * `export const skillRules = {...}` has nothing wrong with its contents at all, and validating\n * the module NAMESPACE against the schema is what told such an author their `version` was missing\n * from a file they can see it in.\n */\nexport class ConfigDefaultExportError extends Error {\n constructor(readonly configPath: string) {\n super(`Config at '${configPath}' has no default export`);\n this.name = \"ConfigDefaultExportError\";\n }\n}\n\n/**\n * The marker every ES module jiti transpiles carries, and a CommonJS one does not. It is the only\n * thing separating `export const x = {}` — a namespace whose keys are named exports — from\n * `module.exports = { x: {} }`, whose keys ARE the default export: both arrive here as a plain\n * object with no `default` key.\n */\nconst ES_MODULE_MARKER = \"__esModule\";\n\n/**\n * The default export, or the namespace when there is none — jiti documents `import(id, { default:\n * true })` as exactly this, and the namespace is imported whole here because the option throws the\n * distinction away and {@link ConfigDefaultExportError} is made of it.\n */\nfunction unwrapDefaultExport(namespace: unknown): unknown {\n if (isRecord(namespace) && namespace.default !== undefined) return namespace.default;\n return namespace;\n}\n\n/** An ES module that exports bindings, none of them the default one. */\nfunction declaresNoDefaultExport(namespace: unknown): boolean {\n return isRecord(namespace) && ES_MODULE_MARKER in namespace && !(\"default\" in namespace);\n}\n\n/**\n * The reason both readers of an installation's config give for one that is there and declared\n * nothing — the file {@link loadConfig} answers `null` for, the same value it gives a missing one,\n * which suits its other callers and not a reader that has already found the file.\n */\nexport const NO_VALID_DEFAULT_EXPORT = \"the file has no valid default export\";\n\n/** Nothing was exported: an empty file, `export {}`, or a default export with no keys. */\nfunction exportsNothing(value: unknown): boolean {\n return value == null || (typeof value === \"object\" && Object.keys(value).length === 0);\n}\n\n/**\n * Loads a TypeScript config file using jiti.\n * Returns null when the file does not exist, and when it exists but exports nothing.\n * Throws {@link ConfigDefaultExportError} for a module whose exports are all named,\n * {@link ConfigSchemaError} on validation failure, and a plain Error for a malformed/broken file.\n *\n * @param configPath - Absolute path to the .ts config file\n * @param schema - Optional Zod schema; when provided, T is inferred from it\n */\nexport async function loadConfig<T>(configPath: string, schema?: z.ZodType<T>): Promise<T | null> {\n if (!(await fileExists(configPath))) {\n verbose(`Config not found at ${configPath}`);\n return null;\n }\n\n let namespace: unknown;\n try {\n // A fresh engine per call, and the module cache stays off, because one run both writes a\n // config and reads it back: `init` writes `config.ts`, loads it, writes it again and loads\n // it twice more, and `compile` re-reads that same file from every path that needs it —\n // installation detection, source resolution, each stack warning, the recompile, and the\n // config-types refresh. A cache spanning a run would answer each read that follows a write\n // with the module as it stood BEFORE it, which is a config the user never wrote. What the\n // cache would save has never been measured, and its ceiling is a few hundred milliseconds\n // on a command already waiting on the network and the disk.\n const jiti = createJiti(import.meta.url, {\n moduleCache: false,\n interopDefault: true,\n alias: { \"agents-inc/config\": CONFIG_EXPORTS_PATH },\n });\n\n namespace = await jiti.import(configPath);\n } catch (error) {\n throw new Error(`Failed to load config from '${configPath}': ${getErrorMessage(error)}`, {\n cause: error,\n });\n }\n\n const raw = unwrapDefaultExport(namespace);\n\n // Empty or whitespace-only files produce an empty module object. Treat this the same as a\n // missing file rather than returning a confusing empty object — and ask it BEFORE the export\n // question, because such a file declares no exports of any kind to have opinions about.\n if (exportsNothing(raw)) {\n verbose(`Config at ${configPath} exports nothing`);\n return null;\n }\n\n if (declaresNoDefaultExport(namespace)) {\n throw new ConfigDefaultExportError(configPath);\n }\n\n if (schema) {\n const result = schema.safeParse(raw);\n if (!result.success) {\n throw new ConfigSchemaError(configPath, formatZodIssues(result.error.issues));\n }\n return result.data;\n }\n\n // Boundary cast: jiti returns unknown, caller provides expected type\n return raw as T;\n}\n","import path from \"path\";\nimport type { Provider } from \"../../consts.js\";\nimport type { SkillScope } from \"../../types/config.js\";\nimport { STANDARD_FILES } from \"../../consts.js\";\nimport {\n agentsDir,\n installBaseDir,\n providerInUse,\n skillsDir,\n sourceFolderInUse,\n} from \"./install-layout.js\";\n\n/**\n * Base directory for a scope's installed artifacts: the home directory for\n * `\"global\"` scope, the project directory otherwise (absent scope defaults to\n * project). Calls `os.homedir()` at runtime so test home-dir mocks apply.\n *\n * Declared in `install-layout.ts`, which every host role is rooted at, and forwarded here under\n * the name its callers already write — this module imports that one, so the answer cannot live\n * in both without a cycle.\n */\nexport { installBaseDir };\n\n/**\n * Path to `provider`'s unified project config under `dir`, inside whichever source folder that\n * installation is on.\n *\n * The resolution is {@link sourceFolderInUse}'s, so the path a caller reads and the path a caller\n * writes are one answer: a scope on the old name keeps its config exactly where it is, a scope\n * someone has migrated is found in the new one, and a scope with neither still gets its config\n * created where this release creates it.\n *\n * **The provider is required, and that is the whole of C2 at this function.** It took none until\n * then, so a root holding an installation of each provider answered the Claude one to every\n * caller — a path that exists and parses, with nothing anywhere able to report that the other\n * installation was the subject. A caller holding only a directory reads the provider off it with\n * {@link providerInUse}.\n */\nexport function getProjectConfigPath(dir: string, provider: Provider): string {\n return path.join(sourceFolderInUse(dir, provider).dir, STANDARD_FILES.CONFIG_TS);\n}\n\n/**\n * The config path of whichever installation `dir` holds, for a caller that holds a directory and\n * nothing else.\n *\n * Its name says the provider was READ rather than assumed, which is the whole difference between\n * this and the default parameter C2 deleted: a default is invisible at the call site, while a\n * call to this one is a visible statement that the folder decided.\n */\nexport function getInstalledConfigPath(dir: string): string {\n return getProjectConfigPath(dir, providerInUse(dir));\n}\n\nexport type InstallPaths = {\n skillsDir: string;\n agentsDir: string;\n configPath: string;\n};\n\n/**\n * The three places one scope's installation puts things, for the ~25 callers that hold a project\n * directory and a scope.\n *\n * **All three now follow the provider, and until C4 only one of them did.** The two directories\n * were composed from `CLAUDE_DIR` and `LOCAL_SKILLS_PATH` here while `configPath` came from\n * {@link getInstalledConfigPath}, so one view answered about two different installations at once:\n * a Codex installation's config was read from `.agents-inc/codex/config.ts` and its skills copied\n * into `.claude/skills/` in the same call, with nothing anywhere able to report it. They are one\n * read now — the provider is resolved once off the scope root and handed to `agentsDir` and\n * `skillsDir`, which take a required provider already.\n *\n * For Claude the answer does not move: `claudeRoles` in `install-layout.ts` composes exactly\n * `<scope root>/.claude/agents` and `<scope root>/.claude/skills`, which is what the two literals\n * spelled.\n *\n * **The provider is still READ rather than passed**, which is the gap C4 leaves open in turn: a\n * greenfield `init --from --provider codex` has no folder to read, and a scope holding an\n * installation of each provider is answered by roster order. Both are `providerInUse`'s stated\n * limits, and closing them is a provider argument threaded from the command — see the C4 report.\n */\nexport function resolveInstallPaths(\n projectDir: string,\n scope: SkillScope = \"project\",\n): InstallPaths {\n const baseDir = installBaseDir(projectDir, scope);\n // One read for all three, so the directories and the config path cannot name two different\n // installations: `providerInUse` probes the disk, and asking it twice in one function is how\n // two answers to one question get into one value object.\n const provider = providerInUse(baseDir);\n\n return {\n skillsDir: skillsDir(provider, scope, projectDir),\n agentsDir: agentsDir(provider, scope, projectDir),\n configPath: getProjectConfigPath(baseDir, provider),\n };\n}\n","import {\n AGENT_NAMES,\n isSeedScopePairWritable,\n resolveAssignment,\n resolveLoadState,\n seedAgentScope,\n SKILL_IDS,\n type LoadState,\n type SeedAgent,\n type SeedLoadState,\n type SeedPayload,\n type SkillTaxonomy,\n} from \"@workspace/matrix\"\nimport { groupBy, indexBy, omit, partition } from \"remeda\"\n\nimport {\n byCategoryDeclarationOrder,\n categoryDomain,\n type CatalogSkill,\n type CompileCatalog,\n} from \"./catalog.js\"\nimport { seatedCatalog } from \"./catalog-seat.js\"\nimport { HAND_WRITTEN_FIELDS } from \"./config-source.js\"\nimport { diagnostics } from \"./diagnostics.js\"\nimport { orderDomains } from \"./domain-order.js\"\nimport {\n CLI_INVOKE_COMMAND,\n DEFAULT_PUBLIC_SOURCE_NAME,\n EJECT_SOURCE,\n GLOBAL_CONFIG_NAME,\n LOCAL_PSEUDO_CATEGORY,\n} from \"./paths.js\"\nimport {\n activeAgentScopeMap,\n effectivelyExcludedSkillIds,\n isActiveAt,\n} from \"./scope-predicates.js\"\nimport { validateSelection } from \"./selection.js\"\nimport { typedEntries, typedFromEntries, typedKeys } from \"./typed-object.js\"\nimport type {\n AgentName,\n AgentScopeConfig,\n Category,\n CategoryPath,\n Domain,\n DomainSelections,\n ProjectConfig,\n SelectionValidation,\n SkillAssignment,\n SkillConfig,\n SkillId,\n SkillScope,\n Stack,\n StackAgentConfig,\n} from \"./types.js\"\n\nexport type SplitConfigResult = {\n global: ProjectConfig\n project: ProjectConfig\n}\n\nexport type ProjectConfigOptions = {\n description?: string\n author?: string\n}\n\n/** How many catalogue ids the verbose diagnostic names when a lookup misses. */\nconst MATRIX_SAMPLE_SIZE = 5\n\nfunction extractCategoryFromPath(\n categoryPath: CategoryPath\n): Category | undefined {\n if (categoryPath === LOCAL_PSEUDO_CATEGORY) return undefined\n // TypeScript narrows CategoryPath to Category after excluding \"local\"\n return categoryPath\n}\n\ntype StackBuildInputs = {\n agentList: AgentName[]\n activeSkillsByCategory: Map<Category, SkillId[]>\n skillScope: Map<SkillId, SkillScope>\n agentScope: Map<AgentName, SkillScope>\n existingStack: Partial<Record<AgentName, StackAgentConfig>>\n catalog: CompileCatalog\n /**\n * Skills that are new to this session's top-level selection (not in the prior\n * `existing.config.skills`). When `undefined`, the per-agent curation\n * preservation rule is disabled and every scope-compatible, resolver-relevant\n * skill lands on every existing agent (legacy behavior). When defined\n * (possibly empty), the preservation rule applies: skills NOT in an agent's\n * prior stack entry and NOT in this set are omitted from that agent's stack —\n * respecting the user's curation.\n */\n newlyAddedSkillIds?: ReadonlySet<SkillId>\n /**\n * Keys of `(agent, skillId)` pairs whose scope-compatibility was GAINED this\n * session — either the skill's scope was flipped so it now reaches this\n * agent, or the agent's scope was flipped so previously-filtered skills now\n * reach it. Parallel to `newlyAddedSkillIds`: when the caller opts into\n * per-agent curation preservation, this set admits triples that the skill-id\n * diff would miss. Keys are produced by `scopeEligibilityKey()`.\n */\n scopeEligibilityGained?: ReadonlySet<string>\n}\n\n/**\n * Encodes an `(agent, skillId)` pair as a single string for set-membership\n * lookups. Both arguments are typed string unions so a `|` delimiter produces\n * a unique, stable key.\n */\nexport function scopeEligibilityKey(\n agent: AgentName,\n skillId: SkillId\n): string {\n return `${agent}|${skillId}`\n}\n\n/** Runtime check that a string is a valid AgentName from the generated union */\nfunction isAgentName(value: string): value is AgentName {\n return (AGENT_NAMES as readonly string[]).includes(value)\n}\n\n/** Runtime check that a string is a valid SkillId from the generated union */\nfunction isSkillId(value: string): value is SkillId {\n return (SKILL_IDS as readonly string[]).includes(value)\n}\n\n/**\n * What the prior save said about this triple, or `undefined` when it carried\n * no entry for it at all. An entry with no flag is not silence: the generator\n * only ever writes `preloaded` where it is true, so a bare `{ id }` read back\n * off disk is the user's curated lazy and outranks any default.\n */\nfunction priorLoadState(\n existingStack: Partial<Record<AgentName, StackAgentConfig>>,\n agent: AgentName,\n category: Category,\n skillId: SkillId\n): LoadState | undefined {\n const prior = existingStack[agent]?.[category]?.find((a) => a.id === skillId)\n if (prior === undefined) return undefined\n\n return prior.preloaded === true ? \"preloaded\" : \"lazy\"\n}\n\n/**\n * The shared mapping's word for a triple nobody has decided on yet — the same\n * table the editor's default assignments read, so a skill picked in either\n * place arrives loaded the same way.\n *\n * Only catalog skills on roster agents are put to it. The mapping is keyed by\n * generated skill id and agent role, so a local skill, a marketplace one or a\n * hand-written agent has no entry it could ever match — those are lazy by\n * rule, not by rescue. `resolveLoadState` throws on ids it does not know, and\n * catching that throw is what would make this a silent fallback.\n */\nfunction mappedLoadState(skillId: SkillId, agent: AgentName): LoadState {\n if (!isSkillId(skillId) || !isAgentName(agent)) return \"lazy\"\n\n return resolveLoadState({ skillId, agentId: agent })\n}\n\n/**\n * How the shared resolver is told about a skill. Targeting reads a domain and a\n * category, never catalog membership, so what goes is the taxonomy the LOADED\n * catalogue carries: a marketplace's skill wears its marketplace's namespace in\n * its id, belongs to no catalog-keyed table, and is still placed by its domain\n * like any other.\n *\n * A category the catalogue gives no domain leaves no taxonomy to state, so the id\n * goes alone and the resolver answers for it — nobody, unless the catalog knows\n * it. `checkMatrixHealth` reports such a category in its own right.\n */\nfunction taxonomyOrIdOf(\n catalog: CompileCatalog,\n skillId: SkillId,\n category: Category\n): SkillId | SkillTaxonomy {\n // Boundary cast: a catalogue category's `domain` is a Domain, typed `string` on the narrow\n // catalogue shape so the wire `Matrix` satisfies it too.\n const domainId = categoryDomain(catalog, category) as Domain | undefined\n if (domainId === undefined) return skillId\n\n return { id: skillId, domainId, categoryId: category }\n}\n\n/**\n * The shared resolver's word on whether this sub-agent would reasonably use\n * this skill — the same targeting the editor's default assignments read, so a\n * pick lands on the same agents from either surface.\n */\nfunction isRelevantPair(\n catalog: CompileCatalog,\n skillId: SkillId,\n category: Category,\n agent: AgentName\n): boolean {\n return resolveAssignment(taxonomyOrIdOf(catalog, skillId, category)).some(\n (target) => target.agentId === agent\n )\n}\n\n/**\n * The relevance rule as it applies inside a stack build: a triple the prior\n * save carries is the user's curation and rides through wherever it\n * sits, cross-domain included; a triple arriving this session lands only where\n * the shared resolver targets it.\n */\nfunction isPreservedOrRelevant(\n agent: AgentName,\n category: Category,\n skillId: SkillId,\n inputs: StackBuildInputs\n): boolean {\n const hasPriorEntry =\n priorLoadState(inputs.existingStack, agent, category, skillId) !== undefined\n return (\n hasPriorEntry || isRelevantPair(inputs.catalog, skillId, category, agent)\n )\n}\n\nfunction getScopeOrThrow<K>(\n map: Map<K, SkillScope>,\n key: K,\n kind: \"skill\" | \"agent\"\n): SkillScope {\n const scope = map.get(key)\n if (scope === undefined) {\n throw new Error(\n `generateProjectConfigFromSkills: ${kind} '${String(key)}' missing from ` +\n `${kind === \"skill\" ? \"skillConfigs\" : \"agentConfigs\"}. ` +\n `Caller must pass a ${kind === \"skill\" ? \"SkillConfig\" : \"AgentScopeConfig\"} ` +\n `for every selected ${kind}.`\n )\n }\n return scope\n}\n\n/**\n * Project skills never reach global agents; global skills reach any agent.\n *\n * The rule itself lives on the wire contract (`isSeedScopePairWritable` in\n * `@workspace/matrix/seed`), because the editor and this CLI each used to carry a verbatim copy\n * of it and a shared rule with three implementations is a rule three surfaces can disagree about.\n * This stays as the name the CLI's own call sites read it under.\n */\nexport function isScopePairCompatible(\n skillScope: SkillScope,\n agentScope: SkillScope\n): boolean {\n return isSeedScopePairWritable(skillScope, agentScope)\n}\n\nfunction isScopeCompatible(\n skillId: SkillId,\n agent: AgentName,\n skillScope: Map<SkillId, SkillScope>,\n agentScope: Map<AgentName, SkillScope>\n): boolean {\n const sScope = getScopeOrThrow(skillScope, skillId, \"skill\")\n const aScope = getScopeOrThrow(agentScope, agent, \"agent\")\n return isScopePairCompatible(sScope, aScope)\n}\n\n/**\n * Decides whether a given `(agent, category, skillId)` triple lands in the\n * agent's stack for this save. The scope filter has already run in the caller\n * — this function only enforces the per-agent curation rule.\n *\n * Branches:\n * - `agent ∉ existingStack` → seed branch (new agent); every scope-compatible\n * skill the shared resolver targets at this agent lands, and with no prior\n * entry to inherit a `preloaded` flag from, each one takes the shared\n * mapping's default (see `toStackAssignment`).\n * - `agent ∈ existingStack` → preservation branch:\n * * skillId was in `existingStack[agent][category]` → KEEP (idempotent).\n * * skillId ∈ `newlyAddedSkillIds` OR `(agent, skillId)` ∈\n * `scopeEligibilityGained` → APPEND (user's session-level addition or\n * scope-compat flip).\n * * otherwise → OMIT (respect user's prior per-agent curation removal).\n *\n * Legacy path: when `newlyAddedSkillIds` is not provided, the curation check\n * is disabled — every scope-compatible skill passes this gate (the relevance\n * filter in `buildAgentStack` still applies). This preserves the contract of\n * callers that pre-date per-agent curation preservation.\n */\nfunction shouldIncludeTriple(\n agent: AgentName,\n category: Category,\n skillId: SkillId,\n inputs: StackBuildInputs\n): boolean {\n // Legacy path: callers that don't opt in keep the seed-everything behavior.\n if (inputs.newlyAddedSkillIds === undefined) return true\n\n const agentExistingStack = inputs.existingStack[agent]\n if (agentExistingStack === undefined) {\n // Seeding branch: agent is new this session → full ownership-derived stack.\n return true\n }\n\n const priorCategory = agentExistingStack[category]\n if (priorCategory && priorCategory.some((a) => a.id === skillId)) return true\n\n if (inputs.newlyAddedSkillIds.has(skillId)) return true\n const scopeEligibility = inputs.scopeEligibilityGained\n if (\n scopeEligibility &&\n scopeEligibility.has(scopeEligibilityKey(agent, skillId))\n ) {\n return true\n }\n return false\n}\n\n/** The prior stack's word for this triple, or the mapping's when it is new. */\nfunction toStackAssignment(\n id: SkillId,\n agent: AgentName,\n category: Category,\n inputs: StackBuildInputs\n): SkillAssignment {\n const prior = priorLoadState(inputs.existingStack, agent, category, id)\n const load = prior ?? mappedLoadState(id, agent)\n\n return load === \"preloaded\" ? { id, preloaded: true } : { id }\n}\n\n/**\n * The selection's categories in the catalogue's own declaration order, so a newly\n * built stack's key order is a property of the roster rather than of the order\n * the skills happened to be picked in — two sessions that select the same\n * skills emit the same bytes, and an agent whose skill set did not change is\n * not rewritten. The writer holds the same rule for a stack it did not build.\n */\nfunction inCanonicalCategoryOrder(\n activeSkillsByCategory: Map<Category, SkillId[]>,\n catalog: CompileCatalog\n): [Category, SkillId[]][] {\n const byDeclaration = byCategoryDeclarationOrder(catalog)\n return [...activeSkillsByCategory].sort(([a], [b]) => byDeclaration(a, b))\n}\n\nfunction buildAgentStack(\n agent: AgentName,\n inputs: StackBuildInputs\n): StackAgentConfig | undefined {\n const agentStack: StackAgentConfig = {}\n for (const [category, skillIds] of inCanonicalCategoryOrder(\n inputs.activeSkillsByCategory,\n inputs.catalog\n )) {\n const assignments = skillIds\n .filter((id) =>\n isScopeCompatible(id, agent, inputs.skillScope, inputs.agentScope)\n )\n .filter((id) => shouldIncludeTriple(agent, category, id, inputs))\n .filter((id) => isPreservedOrRelevant(agent, category, id, inputs))\n .map((id) => toStackAssignment(id, agent, category, inputs))\n if (assignments.length > 0) {\n agentStack[category] = assignments\n }\n }\n return typedKeys<Category>(agentStack).length > 0 ? agentStack : undefined\n}\n\nfunction buildStackForSelection(\n inputs: StackBuildInputs\n): Partial<Record<AgentName, StackAgentConfig>> | undefined {\n // No agents in play → this caller is not managing the stack. Return\n // `undefined` (key omitted) so the merger preserves any existing stack.\n if (inputs.agentList.length === 0) {\n diagnostics().verbose(\n `buildStackForSelection: no agents — returning undefined (stack untouched)`\n )\n return undefined\n }\n\n // Agents are in play → the generator authoritatively rebuilt the stack from\n // the current selection. An empty result is a real \"nothing preloads\" outcome\n // (e.g. the last categorized skill was removed), so return `{}` — NOT\n // `undefined`. The merger trusts `{}` and drops the stale existing stack,\n // whereas `undefined` would resurrect it (the removed-last-skill bug).\n const result: Partial<Record<AgentName, StackAgentConfig>> = {}\n for (const agent of inputs.agentList) {\n const built = buildAgentStack(agent, inputs)\n if (built) result[agent] = built\n }\n return result\n}\n\ntype ResolvedSkillEntry = { skillId: SkillId; category: Category }\n\n/**\n * Resolves selected ids against the catalogue: reports and drops the ids this marketplace does\n * not carry, extracts each skill's category, and drops ids whose every config entry is\n * excluded. A skill with an excluded global entry AND an active project entry is KEPT —\n * the active entry still needs to reach the stack builder.\n */\nfunction resolveValidSkills(\n selectedSkillIds: SkillId[],\n skillConfigs: SkillConfig[],\n catalog: CompileCatalog\n): {\n validSkills: ResolvedSkillEntry[]\n foundCount: number\n skippedCount: number\n} {\n const looked = selectedSkillIds.map((skillId) => ({\n skillId,\n skill: catalog.skills[skillId],\n }))\n const found = looked.filter(\n (\n entry\n ): entry is typeof entry & { skill: NonNullable<typeof entry.skill> } =>\n entry.skill != null\n )\n const absentSkillIds = looked\n .filter((entry) => entry.skill == null)\n .map((entry) => entry.skillId)\n\n reportAbsentSkills(absentSkillIds, catalog)\n\n const excludedSkillIds = effectivelyExcludedSkillIds(skillConfigs)\n\n const validSkills = found\n .map(({ skillId, skill }) => ({\n skillId,\n // Boundary cast: a catalogue category id is a CategoryPath.\n category: extractCategoryFromPath(skill.category as CategoryPath),\n }))\n .filter(\n (entry): entry is typeof entry & { category: Category } =>\n entry.category != null\n )\n .filter((entry) => !excludedSkillIds.has(entry.skillId))\n\n return {\n validSkills,\n foundCount: found.length,\n skippedCount: absentSkillIds.length,\n }\n}\n\n/**\n * Two audiences, one fact: what the user is told about an id this marketplace does not carry,\n * and what the run's verbose diagnostics keep for whoever is debugging the loader.\n *\n * A sample of catalogue keys belongs to the second audience entirely — five arbitrary ids explain\n * nothing to anyone not comparing them against a catalogue — so it goes where this project's\n * logging convention puts a diagnostic, and the warning carries only what a user can act on.\n */\nfunction reportAbsentSkills(\n absentSkillIds: SkillId[],\n catalog: CompileCatalog\n): void {\n if (absentSkillIds.length === 0) return\n\n for (const skillId of absentSkillIds) {\n diagnostics().warn(absentSkillWarning(skillId))\n }\n\n const matrixSample = typedKeys<SkillId>(catalog.skills)\n .slice(0, MATRIX_SAMPLE_SIZE)\n .join(\", \")\n diagnostics().verbose(\n `${absentSkillIds.length} skills absent from the matrix. Matrix keys sample: [${matrixSample}]`\n )\n}\n\n/**\n * What an unplaceable id means and what changes it.\n *\n * The outcome first, because it is the part the user cannot see: the entry stays in `config.ts`\n * — nothing here removes it — and the skill reaches no sub-agent, which is what a stack built\n * without it amounts to. Both ways out are named because the fact has two readings: a catalogue\n * that has moved on since this configuration was written, and an id this one never carried.\n */\nfunction absentSkillWarning(skillId: SkillId): string {\n return (\n `Skill '${skillId}' is not in this marketplace — it stays in the configuration and no ` +\n `sub-agent is given it. Run '${CLI_INVOKE_COMMAND} update' to refresh the marketplace, or ` +\n `remove it with '${CLI_INVOKE_COMMAND} edit'.`\n )\n}\n\n/**\n * Per-skill scope, active-entry-authoritative: when a skill has both an excluded\n * and an active entry (excluded global + active project), excluded entries spread\n * first so active entries overwrite them.\n */\nfunction buildSkillScopeMap(\n skillConfigs: SkillConfig[]\n): Map<SkillId, SkillScope> {\n const [excludedConfigs, activeConfigs] = partition(skillConfigs, (s) =>\n Boolean(s.excluded)\n )\n return new Map(\n [...excludedConfigs, ...activeConfigs].map((s) => [s.id, s.scope])\n )\n}\n\n/**\n * One active AgentScopeConfig per selected agent. When the caller provided\n * agentConfigs, every selected agent MUST have a non-excluded entry (invariant\n * throw); otherwise agents default to project scope.\n */\nfunction resolveActiveAgentConfigs(\n agentList: AgentName[],\n providedConfigs: AgentScopeConfig[] | undefined\n): AgentScopeConfig[] {\n const providedByName = providedConfigs\n ? indexBy(\n providedConfigs.filter((a) => !a.excluded),\n (a) => a.name\n )\n : {}\n return agentList.map((agentName) => {\n if (providedConfigs) {\n const provided = providedByName[agentName]\n if (!provided) {\n throw new Error(\n `generateProjectConfigFromSkills: selected agent '${agentName}' has no ` +\n `non-excluded AgentScopeConfig in agentConfigs.`\n )\n }\n return provided\n }\n return { name: agentName, scope: \"project\" as const }\n })\n}\n\n/**\n * Generates a ProjectConfig from a list of selected skill IDs, rebuilding the\n * stack property (agent -> category -> SkillAssignment[]) from the current\n * wizard selection plus any previously-saved stack entries.\n *\n * Ownership rules (what lands in each agent's stack):\n * - agent is selected AND skill is non-excluded AND agent is non-excluded\n * - scope filter: a project-scoped skill never lands on a global-scoped agent\n * - relevance filter: a NEW triple lands only where the shared resolver targets\n * the (skill, agent) pair — a sub-agent carries only skills it would\n * reasonably use. Prior entries are preserved verbatim, wherever\n * they sit.\n *\n * Load state per (agent, category, skill) triple: a triple `options.existingStack`\n * already carries keeps exactly what it carried — flag or no flag, that entry is\n * the author's stack YAML or the user's own curation. A triple that is new to\n * this save has nobody's word to inherit and takes the shared mapping's default,\n * which is what the editor resolves against too.\n *\n * The catalogue comes from {@link seatedCatalog}, not from an argument, and that\n * module's docblock is where the reason lives.\n */\nexport function generateProjectConfigFromSkills(\n name: string,\n selectedSkillIds: SkillId[],\n options?: ProjectConfigOptions & {\n selectedAgents?: AgentName[]\n skillConfigs?: SkillConfig[]\n agentConfigs?: AgentScopeConfig[]\n existingStack?: Partial<Record<AgentName, StackAgentConfig>>\n /**\n * Skills new to this session (not present in the prior on-disk config).\n * Passing this field (even as an empty array) opts into per-agent\n * curation preservation: existing agents' stack entries are treated as\n * authoritative, and skills absent from a given agent's prior stack are\n * only appended when they appear in this set (or in `scopeEligibilityGained`).\n * When undefined, behavior falls back to seed-everything semantics.\n */\n newlyAddedSkillIds?: readonly SkillId[]\n /**\n * `(agent, skillId)` keys whose scope-compat transitioned from incompatible\n * to compatible this session. Admits scope-flip cases that `newlyAddedSkillIds`\n * (keyed by skill id only) cannot express. Keys are built with\n * {@link scopeEligibilityKey}.\n */\n scopeEligibilityGained?: ReadonlySet<string>\n }\n): ProjectConfig {\n const catalog = seatedCatalog()\n const agentList = options?.selectedAgents\n ? [...options.selectedAgents].sort()\n : []\n\n // Invariant: when selectedAgents is provided, callers must also supply the\n // authoritative SkillConfig and AgentScopeConfig entries so scope lookups\n // never silently default.\n if (agentList.length > 0) {\n if (!options?.skillConfigs) {\n throw new Error(\n `generateProjectConfigFromSkills: selectedAgents was passed without skillConfigs. ` +\n `Callers must pass a SkillConfig for every selected skill.`\n )\n }\n if (!options.agentConfigs) {\n throw new Error(\n `generateProjectConfigFromSkills: selectedAgents was passed without agentConfigs. ` +\n `Callers must pass an AgentScopeConfig for every selected agent.`\n )\n }\n }\n\n // Safe after invariant: when agentList is non-empty these are guaranteed present.\n // When agentList is empty, no scope/ownership work runs so `[]` is a valid no-op.\n const skillConfigs = options?.skillConfigs ?? []\n const agentConfigs = options?.agentConfigs ?? []\n\n diagnostics().verbose(\n `generateProjectConfigFromSkills: ${selectedSkillIds.length} skills, ` +\n `matrix has ${typedKeys<SkillId>(catalog.skills).length} entries, ` +\n `agents=[${agentList.join(\", \")}]`\n )\n\n const { validSkills, foundCount, skippedCount } = resolveValidSkills(\n selectedSkillIds,\n skillConfigs,\n catalog\n )\n\n diagnostics().verbose(\n `generateProjectConfigFromSkills: ${foundCount} found, ${skippedCount} not found, ` +\n `${agentList.length} agents in stack`\n )\n\n const activeSkillsByCategory = new Map(\n typedEntries(groupBy(validSkills, (entry) => entry.category)).map(\n ([category, entries]) => [category, entries.map((entry) => entry.skillId)]\n )\n )\n\n const skillScope = buildSkillScopeMap(skillConfigs)\n const agentScope = activeAgentScopeMap(agentConfigs)\n\n // Opt-in per-agent curation preservation: only when the caller provides the delta set.\n const newlyAddedSkillIdsSet: ReadonlySet<SkillId> | undefined =\n options?.newlyAddedSkillIds === undefined\n ? undefined\n : new Set(options.newlyAddedSkillIds)\n\n const stackProperty = buildStackForSelection({\n agentList,\n activeSkillsByCategory,\n skillScope,\n agentScope,\n catalog,\n existingStack: options?.existingStack ?? {},\n ...(newlyAddedSkillIdsSet !== undefined && {\n newlyAddedSkillIds: newlyAddedSkillIdsSet,\n }),\n ...(options?.scopeEligibilityGained !== undefined && {\n scopeEligibilityGained: options.scopeEligibilityGained,\n }),\n })\n\n const skills: SkillConfig[] =\n options?.skillConfigs ??\n selectedSkillIds.map((id) => ({\n id,\n scope: \"project\" as const,\n origin: EJECT_SOURCE,\n }))\n\n const activeAgentConfigs = resolveActiveAgentConfigs(\n agentList,\n options?.agentConfigs\n )\n // Excluded agents aren't in selectedAgents but must be preserved in config\n const excludedAgentConfigs = agentConfigs.filter((ac) => ac.excluded)\n const finalAgentConfigs: AgentScopeConfig[] = [\n ...activeAgentConfigs,\n ...excludedAgentConfigs,\n ]\n\n return {\n name,\n agents: finalAgentConfigs,\n skills,\n ...(stackProperty && { stack: stackProperty }),\n ...(options?.description && { description: options.description }),\n ...(options?.author && { author: options.author }),\n }\n}\n\n/**\n * One stack entry's load. A flag the author wrote is somebody's word and rides\n * through untouched — a third-party source's stacks file is the explicit tier,\n * and `loadStacks` gives even its bare strings an explicit `preloaded: false`.\n * An entry with no flag at all is a stack stating only WHICH skill an agent\n * gets, so HOW it loads is the shared mapping's answer, exactly as it is for a\n * skill picked by hand. The built-in stacks carry no flags, by design.\n */\nfunction toStackPropertyAssignment(\n assignment: SkillAssignment,\n agent: AgentName\n): SkillAssignment {\n if (assignment.preloaded !== undefined) return assignment\n if (mappedLoadState(assignment.id, agent) === \"lazy\") return assignment\n\n return { ...assignment, preloaded: true }\n}\n\n/**\n * Extracts the stack property (agent -> category -> SkillAssignment[]) from a Stack definition.\n *\n * Stack values are already normalized to SkillAssignment[] by loadStacks().\n * Preserves every assignment, and every load its author stated; an assignment\n * that states none takes the shared mapping's, per `(skill, agent)` pair.\n */\nexport function buildStackProperty(\n stack: Stack\n): Partial<Record<AgentName, StackAgentConfig>> {\n return typedFromEntries(\n typedEntries<AgentName, StackAgentConfig>(stack.agents)\n .filter(\n ([, agentConfig]) =>\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- typedEntries/Object.entries launders the `| undefined` a Partial<Record> admits out of its result type, so this guard reads as dead while still covering an explicitly-undefined slot\n agentConfig && typedKeys<Category>(agentConfig).length > 0\n )\n .map(([agentId, agentConfig]) => {\n const resolvedMappings: StackAgentConfig = typedFromEntries(\n typedEntries<Category, SkillAssignment[]>(agentConfig)\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- typedEntries/Object.entries launders the `| undefined` a Partial<Record> admits out of its result type, so this guard reads as dead while still covering an explicitly-undefined slot\n .filter(([, assignments]) => assignments && assignments.length > 0)\n .map(([category, assignments]) => [\n category,\n assignments.map((assignment) =>\n toStackPropertyAssignment(assignment, agentId)\n ),\n ])\n )\n return [agentId, resolvedMappings] as const\n })\n .filter(([, mappings]) => typedKeys<Category>(mappings).length > 0)\n )\n}\n\n/** Splits one agent's stack per category: global skills → global config, project skills → project config. */\nfunction splitAgentStack(\n agentStack: StackAgentConfig,\n globalSkillIds: ReadonlySet<SkillId>\n): { global: StackAgentConfig; project: StackAgentConfig } {\n const perCategory = typedEntries<Category, SkillAssignment[]>(agentStack)\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- typedEntries/Object.entries launders the `| undefined` a Partial<Record> admits out of its result type, so this guard reads as dead while still covering an explicitly-undefined slot\n .filter(([, assignments]) => assignments !== undefined)\n .map(([category, assignments]) => {\n const [globalOnly, projectOnly] = partition(assignments, (a) =>\n globalSkillIds.has(a.id)\n )\n return { category, globalOnly, projectOnly }\n })\n return {\n global: Object.fromEntries(\n perCategory\n .filter((c) => c.globalOnly.length > 0)\n .map((c) => [c.category, c.globalOnly])\n ),\n project: Object.fromEntries(\n perCategory\n .filter((c) => c.projectOnly.length > 0)\n .map((c) => [c.category, c.projectOnly])\n ),\n }\n}\n\n/**\n * Splits a ProjectConfig by scope into global and project partitions.\n * Skills with `scope: \"global\"` go to the global partition, `scope: \"project\"` to the project partition.\n * Agents are split based on which skills reference them in the stack.\n * Selected domains go to BOTH partitions, because a project owns its own domain selection\n * (owner ruling 2026-08-20). The hand-written fields go to the project partition alone.\n */\nexport function splitConfigByScope(config: ProjectConfig): SplitConfigResult {\n // Every entry is either active-global or project-owned (project-scoped, or an\n // excluded-global tombstone routed to the project partition as an override).\n const [globalSkills, projectSkills] = partition(config.skills, (s) =>\n isActiveAt(s, \"global\")\n )\n const [globalAgents, projectAgents] = partition(config.agents, (a) =>\n isActiveAt(a, \"global\")\n )\n\n // Split stack by agent partition, filtering global agents' stacks to only reference global skills.\n // Project agents keep ALL skill references (both project and global) since global skills are available everywhere.\n const globalSkillIds = new Set(globalSkills.map((s) => s.id))\n const globalStack: NonNullable<ProjectConfig[\"stack\"]> = {}\n const projectStack: NonNullable<ProjectConfig[\"stack\"]> = {}\n\n if (config.stack) {\n for (const agent of globalAgents) {\n const agentStack = config.stack[agent.name]\n if (!agentStack) continue\n const split = splitAgentStack(agentStack, globalSkillIds)\n if (typedKeys<Category>(split.global).length > 0) {\n globalStack[agent.name] = split.global\n }\n if (typedKeys<Category>(split.project).length > 0) {\n projectStack[agent.name] = split.project\n }\n }\n for (const agent of projectAgents) {\n const agentStack = config.stack[agent.name]\n if (agentStack) {\n projectStack[agent.name] = agentStack\n }\n }\n }\n\n // Domains ride the spread onto BOTH partitions: a project owns its own domain selection\n // rather than inheriting the global one (owner ruling 2026-08-20).\n //\n // `stack` is written on BOTH partitions unconditionally, and that is the whole of what\n // keeps each one to its own rows: the spread above carries the undivided stack, so an\n // override that declines to fire hands a partition every row the other partition earned.\n // A derivation that yielded nothing is a partition with no stack, and `{}` is how that is\n // said — the same word `buildStackForSelection` uses and for the same reason, since the\n // merger reads an absent stack as no statement and keeps the stale one. `generateConfigSource`\n // omits an empty stack from the file it writes, so nothing emits `stack: {}` on this account.\n //\n // What the project's author wrote by hand stays on the project partition, as `name` does: the\n // global partition becomes the machine's own config.\n const globalConfig: ProjectConfig = {\n ...omit(config, HAND_WRITTEN_FIELDS),\n name: GLOBAL_CONFIG_NAME,\n agents: globalAgents,\n skills: globalSkills,\n stack: globalStack,\n }\n\n const projectConfig: ProjectConfig = {\n ...config,\n name: config.name,\n agents: projectAgents,\n skills: projectSkills,\n stack: projectStack,\n }\n\n return { global: globalConfig, project: projectConfig }\n}\n\n/**\n * What a completed selection hands the install pipeline.\n *\n * Declared here rather than beside the wizard component that produces it, because\n * `seedToWizardResult` below produces one too and this package cannot import a\n * React module. The CLI's `components/wizard/wizard.tsx` declares its own twin, field\n * for field, and every CLI call site imports that one.\n */\nexport type WizardResultV2 = {\n skills: SkillConfig[]\n selectedAgents: AgentName[]\n agentConfigs: AgentScopeConfig[]\n /**\n * What each sub-agent holds and what preloads, when the producer knows per `(skill, sub-agent)`.\n * A shared configuration installed with `init --from` does: it assigns each skill to named\n * sub-agents at a named load state, and that curation is the whole of what was shared.\n *\n * The wizard has no per-agent granularity — a skill is selected for the project, not for one\n * sub-agent — so it leaves this undefined and the install pipeline's ownership rules build the\n * stack as they always have.\n */\n assignedStack?: Partial<Record<AgentName, StackAgentConfig>>\n selectedStackId: string | null\n /**\n * What the written config should record about itself, when the producer already knows.\n *\n * A shared configuration installed with `init --from` does: its payload carries the sharer's own\n * description, because it names no stack for the install to resolve one out of. The wizard leaves\n * this undefined and the install pipeline takes the applied stack's description instead — there\n * IS a loaded stack on that path, and it is the authority on its own sentence.\n */\n description?: string\n domainSelections: DomainSelections\n selectedDomains: Domain[]\n /**\n * Skill ids from the saved config that could not be resolved against the loaded source matrix\n * this session. The wizard could not represent them, so they are absent from `skills` and the\n * merge removes their config entries. Carried out of the wizard so the command can NAME each\n * removal and say why it happened — a removal the user never asked for must never be silent.\n */\n unresolvableSkillIds: SkillId[]\n cancelled: boolean\n validation: SelectionValidation\n}\n\nexport type SeedMapping = {\n result: WizardResultV2\n /** Ids this catalogue does not know. Reported, never fatal — see the decode policy. */\n skippedSkillIds: string[]\n skippedAgentNames: string[]\n}\n\nconst KNOWN_AGENTS = new Set<string>(AGENT_NAMES)\n\n/** A skill's primary source, or the default marketplace. Mirrors the wizard's own resolution. */\nfunction sourceForSkill(skill: CatalogSkill): string {\n return (\n skill.availableSources?.find((s) => s.primary)?.name ??\n DEFAULT_PUBLIC_SOURCE_NAME\n )\n}\n\nfunction addToDomainSelections(\n selections: DomainSelections,\n domain: Domain,\n category: Category,\n skillId: SkillId\n): void {\n const categorySelections = (selections[domain] ??= {})\n const skillList = (categorySelections[category] ??= [])\n if (!skillList.includes(skillId)) skillList.push(skillId)\n}\n\n/**\n * The stack mirror of {@link addToDomainSelections}: one sub-agent's own category lists, appended\n * in payload order. A `(skill, sub-agent)` pair can only occur once — `skills` is keyed by id — so\n * there is nothing to de-duplicate here.\n */\nfunction addToAgentStack(\n stack: Partial<Record<AgentName, StackAgentConfig>>,\n agent: AgentName,\n category: Category,\n assignment: SkillAssignment\n): void {\n const agentStack = (stack[agent] ??= {})\n const assignments = (agentStack[category] ??= [])\n assignments.push(assignment)\n}\n\n/** A load state is per `(skill, sub-agent)`; `preloaded` is the stack's word for the same thing. */\nfunction toSkillAssignment(\n skillId: SkillId,\n load: SeedLoadState\n): SkillAssignment {\n return { id: skillId, preloaded: load === \"preloaded\" }\n}\n\n/** The payload's `agents` map, split by what this catalog can do with each entry. */\ntype SeedAgentMap = {\n /** Known agents the map has something to say about, keyed by name. */\n known: Map<AgentName, SeedAgent>\n /** Names explicitly switched off — dropped, and their assignment rows ignored with them. */\n switchedOff: Set<string>\n /** Names this catalog does not know. Reported, never fatal — same policy as unknown skill ids. */\n unknown: string[]\n}\n\nfunction readAgentMap(agents: SeedPayload[\"agents\"]): SeedAgentMap {\n const known = new Map<AgentName, SeedAgent>()\n const switchedOff = new Set<string>()\n const unknown: string[] = []\n\n for (const [name, entry] of Object.entries(agents)) {\n if (!isAgentName(name)) unknown.push(name)\n else if (entry.on === false) switchedOff.add(name)\n else known.set(name, entry)\n }\n\n return { known, switchedOff, unknown }\n}\n\n/**\n * A sub-agent's own row. Model and effort ride along on the same terms as its scope — an absent\n * key means \"keep whatever the agent's metadata says\".\n */\nfunction agentScopeConfig(\n name: AgentName,\n entry: SeedAgent | undefined\n): AgentScopeConfig {\n return {\n name,\n scope: seedAgentScope(entry),\n ...(entry?.model !== undefined && { model: entry.model }),\n ...(entry?.effort !== undefined && { effort: entry.effort }),\n }\n}\n\n/** A `(skill, sub-agent)` assignment the config model has nowhere to write. */\ntype UnwritableAssignment = { skillId: SkillId; agent: AgentName }\n\n/**\n * Names every unwritable pair, not just the first: a sharer who fixes one only to be refused for\n * the next learns nothing the first message could not have told them. Both halves of each pair are\n * named because neither alone says what to change — the skill can move to global scope, or the\n * sub-agent can be pinned to the project, and only the sharer knows which they meant.\n */\nfunction unwritableAssignmentsError(\n assignments: UnwritableAssignment[]\n): string {\n return [\n \"This configuration cannot be installed: a project-scoped skill never reaches a sub-agent \" +\n \"that rests at global scope, so these assignments have nowhere to be written:\",\n ...assignments.map(({ skillId, agent }) => ` ${skillId} -> ${agent}`),\n \"Re-share it with each sub-agent above pinned to the project, or each skill above at global scope.\",\n ].join(\"\\n\")\n}\n\n/**\n * Turns a shared configuration into the shape the install pipeline already consumes, so\n * `init --from` reuses `writeProjectConfig` -> skill install -> `compileAgentsAllScopes`\n * unchanged rather than growing a second path that can drift from the wizard's.\n *\n * Unknown ids are skipped, never fatal. Payloads carry catalog slugs precisely so they survive\n * catalog churn: a config shared before a skill was renamed should still install everything else,\n * and failing the whole decode would make every rename retroactively break every shared id.\n *\n * A sub-agent reaches the roster two ways: named by a surviving skill's assignment, or switched on\n * in the `agents` map. The map is the only place a configuration can say anything about an agent\n * no skill mentions, which is what makes a bare (skill-less) agent shareable at all; it also\n * carries that agent's model and effort onto its `AgentScopeConfig`.\n *\n * The `assignments` map is per `(skill, sub-agent)` and carries a load state, so it decides three\n * things the wizard cannot express separately: which sub-agents are selected, which skills land in\n * each one's stack entry, and which of those preload. That is why the result carries an\n * `assignedStack` — the install pipeline's ownership rules broadcast every scope-compatible skill\n * to every selected agent, which would hand a bare sub-agent someone else's skills.\n *\n * An unwritable `(skill, sub-agent)` pair is the one thing here that IS fatal, and it is fatal for\n * the opposite reason to the skips: an unknown id is content this catalog does not have, while an\n * unwritable pair is content it has and cannot place. Because `assignedStack` replaces the derived\n * stack wholesale, no scope filter runs on these rows downstream — they reach the writers, which\n * put them in neither half of the split config and say nothing. Refusing at the decode is what\n * keeps a payload from installing as a quieter configuration than the one that was shared.\n */\nexport function seedToWizardResult(\n payload: SeedPayload,\n catalog: CompileCatalog\n): SeedMapping {\n const domainSelections: DomainSelections = {}\n const assignedStack: Partial<Record<AgentName, StackAgentConfig>> = {}\n const skills: SkillConfig[] = []\n const skippedSkillIds: string[] = []\n const unwritable: UnwritableAssignment[] = []\n const agentNames = new Set<AgentName>()\n const agentMap = readAgentMap(payload.agents)\n const skippedAgentNames = new Set<string>(agentMap.unknown)\n\n for (const [skillId, entry] of Object.entries(payload.skills)) {\n const skill = catalog.skills[skillId]\n const domain = skill?.category\n ? categoryDomain(catalog, skill.category)\n : undefined\n\n if (!skill?.category || domain === undefined) {\n skippedSkillIds.push(skillId)\n continue\n }\n\n // Past the guard the catalogue knows this id, and its category is a real one: the `local`\n // pseudo-category has no domain, so it left with the skips.\n // Boundary casts: both were read out of the catalogue's own keys.\n const id = skillId as SkillId\n const category = skill.category as Category\n\n addToDomainSelections(domainSelections, domain as Domain, category, id)\n\n skills.push({\n id,\n scope: entry.scope,\n // \"eject\" is an origin in its own right; anything else names the marketplace it came from.\n origin: entry.install === \"eject\" ? EJECT_SOURCE : sourceForSkill(skill),\n })\n\n // Only assignments on skills that survived — an agent should not be switched on by a skill\n // this catalog cannot install.\n for (const [agentName, load] of Object.entries(entry.assignments)) {\n if (agentMap.switchedOff.has(agentName)) continue\n if (!KNOWN_AGENTS.has(agentName)) {\n skippedAgentNames.add(agentName)\n continue\n }\n\n // Boundary cast: guarded by KNOWN_AGENTS immediately above.\n const agent = agentName as AgentName\n // Rows the decode was going to ignore anyway have already left, so what reaches here is a\n // pair the payload really asked for — and the config model's one rule about pairs applies.\n if (\n !isScopePairCompatible(\n entry.scope,\n seedAgentScope(agentMap.known.get(agent))\n )\n ) {\n unwritable.push({ skillId: id, agent })\n continue\n }\n\n agentNames.add(agent)\n // The assignment is the curation: this sub-agent holds this skill, at this load state, and\n // no sub-agent the payload did not name holds it at all.\n addToAgentStack(\n assignedStack,\n agent,\n category,\n toSkillAssignment(id, load)\n )\n }\n }\n\n if (unwritable.length > 0)\n throw new Error(unwritableAssignmentsError(unwritable))\n\n // Bare agents: switched on by the map alone, with no skill to carry them in.\n for (const [name, entry] of agentMap.known) {\n if (entry.on === true) agentNames.add(name)\n }\n\n const selectedAgents = [...agentNames]\n\n return {\n result: {\n skills,\n selectedAgents,\n agentConfigs: selectedAgents.map((name) =>\n agentScopeConfig(name, agentMap.known.get(name))\n ),\n assignedStack,\n selectedStackId: payload.stackId,\n // Spread-conditional rather than passed through, because absent and present-holding-undefined\n // are different files on disk: a config describing itself with no key is not one describing\n // itself with an empty sentence, and the writer emits whichever key it is handed.\n ...(payload.description !== undefined && {\n description: payload.description,\n }),\n domainSelections,\n selectedDomains: orderDomains(typedKeys<Domain>(domainSelections)),\n // Nothing was dropped from a *saved config* — the skipped ids came off the wire and are\n // reported to the user directly, so there is no config removal to explain.\n unresolvableSkillIds: [],\n cancelled: false,\n // Revalidated here rather than taken on trust from the app that built the payload. That app\n // validated against ITS catalog; this one skips ids it does not know and carries its own\n // relationship rules, so a configuration that was consistent where it was authored can\n // arrive with a requirement genuinely unmet.\n validation: validateSelection(\n skills.map((skill) => skill.id),\n catalog\n ),\n },\n skippedSkillIds,\n skippedAgentNames: [...skippedAgentNames],\n }\n}\n","import { omit } from \"remeda\"\n\nimport {\n byCategoryDeclarationOrder,\n isExclusiveCategory,\n type CompileCatalog,\n} from \"./catalog.js\"\nimport {\n INDENT_STEP,\n commentEntry,\n isKeyedRecord,\n quoteText,\n renderArrayLine,\n renderKey,\n renderTypeImportLine,\n renderValueLine,\n sourceEntry,\n valueEntries,\n type ArrayEntry,\n type LinePosition,\n} from \"./installed-format.js\"\nimport { DEFAULT_PLUGIN_NAME, GLOBAL_CONFIG_NAME } from \"./paths.js\"\nimport type {\n AgentScopeConfig,\n ProjectConfig,\n SkillAssignment,\n SkillConfig,\n} from \"./types.js\"\n\n/**\n * This module renders `config.ts` sources; it writes nothing, and neither does\n * anything it is called from. Putting either half of a config pair on disk is\n * `config-gate/`'s exclusive privilege in the CLI, because that write owes\n * consequences no caller can be relied on to remember — a rendered half any\n * caller may then write is exactly the ungated write the gate exists to prevent.\n */\n\n/**\n * Which of the three emissions is wanted.\n *\n * At least one of `globalConfig` and `globalImportPath` accompanies\n * `isProjectConfig: true`, and {@link generateProjectConfig} enforces it —\n * `globalConfig` wins where both are given. The invalid pairing is refused at\n * runtime rather than made unrepresentable, which is the repository's usual\n * answer and was measured before it was rejected: the discrimination has to be\n * on `isProjectConfig`'s LITERAL type, and an un-annotated `const options = cond\n * ? { isProjectConfig: true, globalConfig } : undefined` widens that property to\n * `boolean`, so the call stops compiling with a message about inference rather\n * than about the mistake. It costs a file the union's author never opened — the\n * same shape as the Storybook-args collapse in\n * `.ai-docs/agent-findings/2026-08-26-a-discriminated-union-on-component-props-collapses-storybook-args-to-never.md`.\n */\nexport type ConfigSourceOptions = {\n /**\n * When true, generates a project config — inlining the global config's entries\n * when `globalConfig` is given, importing and spreading them when\n * `globalImportPath` is.\n */\n isProjectConfig?: boolean\n\n /**\n * When provided alongside `isProjectConfig`, inlines global skills/agents directly.\n * Produces a self-contained, readable config snapshot.\n */\n globalConfig?: ProjectConfig\n\n /**\n * Absolute path to the global scope's source folder, for the spread form that\n * imports from it rather than inlining it.\n *\n * A PARAMETER rather than a read, because the value is `os.homedir()` and this\n * package runs in a browser. `getGlobalConfigImportPath()` in the CLI's\n * `config-writer.ts` is the one producer, and it has no production caller:\n * `writeProjectConfigPair` is the only site passing `isProjectConfig` and it\n * always passes `globalConfig` too, which takes the inlining branch above.\n */\n globalImportPath?: string\n}\n\n/**\n * The fields a config's author writes by hand and no install produces: the name\n * the CLI prints itself under, and the layout a source repository declares\n * itself with. Each belongs to the file that declares it and to no other, so a\n * rewrite carries it across and nothing copies it to the other scope's file. A\n * project's name in the global config would rename every installation that\n * declares none of its own; the global's in a project's file would read as the\n * project's own declaration, and keep the old value after the global changed.\n */\nexport const HAND_WRITTEN_FIELDS = [\n \"branding\",\n \"skillsDir\",\n \"agentsDir\",\n \"stacksFile\",\n \"categoriesFile\",\n \"rulesFile\",\n] as const satisfies readonly (keyof ProjectConfig)[]\n\n/** Fields that are extracted into typed named variables above the export default */\nconst EXTRACTED_FIELDS = new Set([\n \"skills\",\n \"agents\",\n \"stack\",\n \"selectedDomains\",\n])\n\n/**\n * The loader schema's own field order, which is the order a config read back off\n * disk arrives in. Emitting in it is what makes the writer a fixed point: the\n * three producers of an in-memory config — the wizard's literal, a Zod-parsed\n * load, a merge that appends at the tail — insert their keys in three different\n * orders, and without this the same values would emit as three different files.\n */\nconst CANONICAL_FIELD_ORDER = [\n \"name\",\n \"description\",\n \"agents\",\n \"skills\",\n \"author\",\n \"selectedDomains\",\n \"stack\",\n \"marketplace\",\n \"marketplaceName\",\n \"agentsSource\",\n \"projects\",\n] as const satisfies readonly (keyof ProjectConfig)[]\n\n/**\n * The same rule one level in, for the three record shapes a config carries\n * INSIDE an array. {@link CANONICAL_FIELD_ORDER} reaches the top-level fields\n * and {@link canonicalizeStackOrder} reaches the stack's keys; an entry's own\n * keys were left to whoever minted it, and the printer emits a record's keys in\n * the order it is handed them, so they reached disk in the producer's own.\n *\n * The loader rebuilds every entry through its schema, so a producer that\n * disagrees with the schema is not a fixed point: `toggleSkillScope` mints a\n * tombstone as `{ id, scope, excluded, origin }`, and re-emitting the same\n * config after a load moved the line. An `edit` run that changed nothing about\n * that skill still rewrote it, and a second implementation drawing these bytes\n * drew a line no install writes.\n */\nconst CANONICAL_SKILL_ENTRY_ORDER = [\n \"id\",\n \"scope\",\n \"origin\",\n \"excluded\",\n] as const satisfies readonly (keyof SkillConfig)[]\n\nconst CANONICAL_AGENT_ENTRY_ORDER = [\n \"name\",\n \"scope\",\n \"model\",\n \"effort\",\n \"excluded\",\n] as const satisfies readonly (keyof AgentScopeConfig)[]\n\nconst CANONICAL_ASSIGNMENT_ORDER = [\n \"id\",\n \"preloaded\",\n \"local\",\n \"path\",\n] as const satisfies readonly (keyof SkillAssignment)[]\n\n/**\n * A record rebuilt with the keys the schema names first and in its order. A key\n * the schema does not name is passthrough data the writer has no order of its\n * own to impose, so those keep the order they arrived in, after every named one.\n */\nfunction withKeysInSchemaOrder(\n record: Record<string, unknown>,\n schemaOrder: readonly string[]\n): Record<string, unknown> {\n const named = new Set<string>(schemaOrder)\n const inSchemaOrder = schemaOrder\n .filter((key) => key in record)\n .map((key): [string, unknown] => [key, record[key]])\n const passthrough = Object.entries(record).filter(([key]) => !named.has(key))\n\n return Object.fromEntries([...inSchemaOrder, ...passthrough])\n}\n\n/** The cleaned config rebuilt in the loader schema's top-level field order. */\nfunction canonicalizeFieldOrder(\n cleaned: Record<string, unknown>\n): Record<string, unknown> {\n return withKeysInSchemaOrder(cleaned, CANONICAL_FIELD_ORDER)\n}\n\n/**\n * The cleaned config with the elements of `skills` and `agents` rebuilt in their\n * own schema's key order.\n *\n * An array the config does not carry stays absent: assigning would mint the key,\n * and the emission tells an absent array from an empty one.\n */\nfunction withEntriesInSchemaOrder(\n cleaned: Record<string, unknown>\n): Record<string, unknown> {\n const reordered = { ...cleaned }\n if (Array.isArray(reordered.skills)) {\n reordered.skills = entriesInSchemaOrder(\n reordered.skills,\n CANONICAL_SKILL_ENTRY_ORDER\n )\n }\n if (Array.isArray(reordered.agents)) {\n reordered.agents = entriesInSchemaOrder(\n reordered.agents,\n CANONICAL_AGENT_ENTRY_ORDER\n )\n }\n return reordered\n}\n\n/**\n * Every element of one entry array rebuilt in the schema's key order. The writer\n * emits whatever it is handed, and these arrive off a `JSON.parse`, so an\n * element that is not a keyed record has no keys to order and passes through\n * whole rather than being flattened by `Object.entries`.\n */\nfunction entriesInSchemaOrder(\n entries: unknown[],\n schemaOrder: readonly string[]\n): unknown[] {\n return entries.map((entry: unknown) =>\n isKeyedRecord(entry) ? withKeysInSchemaOrder(entry, schemaOrder) : entry\n )\n}\n\n/** A record rebuilt with its keys reordered; the values themselves are untouched. */\nfunction withKeysOrderedBy<T>(\n record: Record<string, T>,\n compareKeys: (a: string, b: string) => number\n): Record<string, T> {\n return Object.fromEntries(\n Object.entries(record).sort(([a], [b]) => compareKeys(a, b))\n )\n}\n\n/**\n * Code-unit order over two names — what a bare `.sort()` gives, and so what\n * `generateProjectConfigFromSkills` already emits its sub-agent keys in.\n * `localeCompare` is deliberately not used: it orders the same two names\n * differently under different locales, which would make the emitted bytes a\n * property of the machine.\n */\nfunction compareNamesInCodeUnitOrder(a: string, b: string): number {\n if (a === b) return 0\n return a < b ? -1 : 1\n}\n\n/**\n * The stack's key order, decided by the roster rather than by whoever assembled\n * the stack: sub-agents by name, and each sub-agent's categories in the\n * catalogue's declaration order — the two orders the generator already builds a\n * stack in.\n *\n * The generator is not the only producer. The seed decode assembles a stack from\n * a shared payload, in the order that payload lists its skills, so the same\n * curation reached disk as different bytes depending on which end of a share\n * round trip wrote it. That is not merely a noisy diff: a compiled sub-agent\n * lists its dynamic skills in the order its stack entry carries them, so the two\n * ends compiled different files from identical configuration.\n */\nfunction canonicalizeStackOrder(\n stack: Record<string, Record<string, unknown>>,\n catalog: CompileCatalog\n): Record<string, Record<string, unknown>> {\n const byDeclaration = byCategoryDeclarationOrder(catalog)\n const withCategoriesInOrder = Object.entries(stack).map(\n ([agent, categories]) =>\n [agent, withKeysOrderedBy(categories, byDeclaration)] as const\n )\n\n return withKeysOrderedBy(\n Object.fromEntries(withCategoriesInOrder),\n compareNamesInCodeUnitOrder\n )\n}\n\n/** The specifier both emitted config roots import their types from. */\nconst CONFIG_TYPES_SPECIFIER = \"./config-types\"\n\n/** The annotation the emitted `stack` declaration carries. */\nconst STACK_TYPE = \"Partial<Record<ProjectAgentName, StackAgentConfig>>\"\n\n/** Where a top-level `const <name>: <type> = …` declaration puts its value. */\nfunction declarationPosition(name: string, type: string): LinePosition {\n return { indent: 0, prefix: `const ${name}: ${type} = `, suffix: \"\" }\n}\n\n/**\n * One `const <name>: <type> = <value>` declaration, and the blank line the\n * writer puts before it. Both together, because every declaration is separated\n * from the last and the emitted pair's readers key on that blank line.\n */\nfunction declaration(name: string, type: string, value: unknown): string[] {\n return [\"\", renderValueLine(value, declarationPosition(name, type))]\n}\n\n/** The same, for an array whose entries carry comments or written-out source. */\nfunction entryDeclaration(\n name: string,\n type: string,\n entries: readonly ArrayEntry[]\n): string[] {\n return [\"\", renderArrayLine(entries, declarationPosition(name, type))]\n}\n\n/** Where one property of the `export default` table of contents sits. */\nfunction exportFieldPosition(key: string): LinePosition {\n return {\n indent: INDENT_STEP,\n prefix: `${renderKey(key)}: `,\n suffix: \",\",\n }\n}\n\n/** One scalar field as a line of the `export default` table of contents. */\nfunction renderScalarField(key: string, value: unknown): string {\n return renderValueLine(value, exportFieldPosition(key))\n}\n\ntype ConfigArrays = {\n skills: unknown[]\n agents: unknown[]\n stack: Record<string, unknown> | undefined\n selectedDomains: unknown[]\n}\n\n/** The four extracted array/stack fields of a cleaned config, defaulted for emission. */\nfunction extractConfigArrays(cleaned: Record<string, unknown>): ConfigArrays {\n // Boundary cast: cleaned comes from JSON.parse(JSON.stringify(...)) so arrays are plain JSON\n // values. The `??` runs BEFORE the cast on purpose — `cleaned` is a Record of `unknown`, and\n // casting first would tell the checker the value is present when the round-trip drops any key\n // whose value was undefined.\n return {\n skills: (cleaned.skills ?? []) as unknown[],\n agents: (cleaned.agents ?? []) as unknown[],\n stack: cleaned.stack as Record<string, unknown> | undefined,\n selectedDomains: (cleaned.selectedDomains ?? []) as unknown[],\n }\n}\n\n/**\n * Shared pre-emission cleanup: JSON round-trip (drops undefined values), optional\n * `projects` removal (project configs never emit the global tracking list),\n * stack compaction (strip flag-less assignments to bare strings while preserving\n * SkillAssignment[] arrays), and canonical key ordering at all three levels the\n * emitted bytes expose — the top-level fields, the stack's own keys, and each\n * entry inside the `skills`, `agents` and stack-assignment arrays. Every level\n * is ordered here rather than by its producer, so the bytes are decided by the\n * config's values alone.\n */\nfunction cleanForEmission(\n config: ProjectConfig,\n catalog: CompileCatalog,\n options: { dropProjects: boolean }\n): Record<string, unknown> {\n // Boundary cast: `JSON.parse` is typed `any`, and round-tripping an object always\n // yields one — dropping its undefined-valued keys is exactly why this is here.\n const cleaned = JSON.parse(JSON.stringify(config)) as Record<string, unknown>\n if (options.dropProjects) {\n delete cleaned.projects\n }\n if (cleaned.stack) {\n // Boundary cast: cleaned comes from JSON.parse(JSON.stringify(...)), so the stack\n // is a plain JSON record of agent -> category -> assignment arrays\n const compacted = compactStackAssignments(\n cleaned.stack as Record<string, Record<string, unknown[]>>,\n catalog\n )\n cleaned.stack = canonicalizeStackOrder(compacted, catalog)\n }\n return canonicalizeFieldOrder(withEntriesInSchemaOrder(cleaned))\n}\n\n/**\n * Generates a TypeScript config file source from a ProjectConfig object.\n * The typed named variables (skills, agents, stack, selectedDomains) are declared\n * first, with the export default below them acting as a table of contents that\n * refers to each by name.\n *\n * The catalogue is a parameter and never a module this file reaches: the bytes\n * depend on which categories are exclusive and on the order the catalogue\n * declares them, so a renderer reading a singleton would answer differently in\n * the CLI (which merges the machine's local skills in) and in the editor.\n */\nexport function generateConfigSource(\n config: ProjectConfig,\n catalog: CompileCatalog,\n options?: ConfigSourceOptions\n): string {\n if (options?.isProjectConfig) {\n return generateProjectConfig(config, catalog, options)\n }\n\n return generateStandaloneConfig(\n cleanForEmission(config, catalog, { dropProjects: false })\n )\n}\n\n/**\n * The project emission the options name — inlining the global config's entries,\n * or importing and spreading them.\n *\n * Those are the only two, so naming neither is refused rather than answered.\n * Falling through to the standalone writer answered a project request with a\n * GLOBAL-shaped file: `dropProjects` is false there, so the emitted config\n * carries the global `projects` tracking array, which a project root must never\n * hold. Nothing in the CLI reaches this today, but `generateConfigSource` is a\n * public export of this package and the caller that cannot be seen from here is\n * the editor's.\n */\nfunction generateProjectConfig(\n config: ProjectConfig,\n catalog: CompileCatalog,\n options: ConfigSourceOptions\n): string {\n const cleaned = cleanForEmission(config, catalog, { dropProjects: true })\n\n if (options.globalConfig) {\n return generateProjectConfigWithInlinedGlobal(\n cleaned,\n cleanForEmission(options.globalConfig, catalog, { dropProjects: true })\n )\n }\n if (options.globalImportPath !== undefined) {\n return generateProjectConfigWithGlobalImport(\n cleaned,\n options.globalImportPath\n )\n }\n\n throw new Error(\n \"A project config needs the global config it extends: pass `globalConfig` to inline its \" +\n \"entries, or `globalImportPath` to import and spread them. Neither was given, and the \" +\n \"standalone writer this used to fall through to emits a global-shaped config carrying \" +\n \"the `projects` tracking array a project root must never hold.\"\n )\n}\n\n/**\n * Generates a project config source that imports from the global config and extends it.\n * Typed named variables are declared above the export default. The export default at\n * the bottom acts as a table of contents. Arrays (skills, agents, selectedDomains) are\n * spread with globalConfig first, then project items.\n */\nfunction generateProjectConfigWithGlobalImport(\n cleaned: Record<string, unknown>,\n globalImportPath: string\n): string {\n const importPath = `${globalImportPath}/config`\n\n const { skills, agents, stack, selectedDomains } =\n extractConfigArrays(cleaned)\n\n const hasProjectDomains = selectedDomains.length > 0\n const hasStack = stack != null && Object.keys(stack).length > 0\n\n const typeImports = buildTypeImports({\n // Always present, spread from global.\n hasSkills: true,\n hasAgents: true,\n hasStack,\n hasSelectedDomains: hasProjectDomains,\n })\n\n const lines: string[] = [\n `import globalConfig from ${quoteText(importPath)}`,\n renderTypeImportLine(typeImports, CONFIG_TYPES_SPECIFIER),\n ]\n\n lines.push(\n ...entryDeclaration(\"skills\", \"SkillConfig[]\", [\n sourceEntry(\"...globalConfig.skills\"),\n ...valueEntries(skills),\n ])\n )\n lines.push(\n ...entryDeclaration(\"agents\", \"AgentScopeConfig[]\", [\n sourceEntry(\"...globalConfig.agents\"),\n ...valueEntries(agents),\n ])\n )\n\n if (hasStack) {\n lines.push(...declaration(\"stack\", STACK_TYPE, stack))\n }\n\n if (hasProjectDomains) {\n lines.push(\n ...entryDeclaration(\"selectedDomains\", \"Domain[]\", [\n sourceEntry(\"...(globalConfig.selectedDomains ?? [])\"),\n ...valueEntries(selectedDomains),\n ])\n )\n }\n\n const scalarFields = Object.entries(cleaned)\n .filter(([key]) => !EXTRACTED_FIELDS.has(key) && key !== \"name\")\n .map(([key, value]) => renderScalarField(key, value))\n\n const exportFields: string[] = [\n ` ...globalConfig,`,\n renderScalarField(\"name\", resolveProjectName(cleaned)),\n ` skills,`,\n ` agents,`,\n ...(hasStack ? [` stack,`] : []),\n ...(hasProjectDomains ? [` selectedDomains,`] : []),\n ...scalarFields,\n ]\n\n lines.push(``)\n lines.push(`export default {`)\n lines.push(...exportFields)\n lines.push(`} satisfies ProjectConfig`)\n\n lines.push(``)\n return lines.join(\"\\n\")\n}\n\n/**\n * Generates a standalone config source with typed named variables above the export default.\n * The export default at the bottom acts as a table of contents, referencing the named variables.\n */\nfunction generateStandaloneConfig(cleaned: Record<string, unknown>): string {\n const { skills, agents, stack, selectedDomains } =\n extractConfigArrays(cleaned)\n\n const hasSkills = skills.length > 0\n const hasAgents = agents.length > 0\n const hasStack = stack != null && Object.keys(stack).length > 0\n const hasSelectedDomains = selectedDomains.length > 0\n\n const typeImports = buildTypeImports({\n hasSkills,\n hasAgents,\n hasStack,\n hasSelectedDomains,\n })\n\n const lines: string[] = [\n renderTypeImportLine(typeImports, CONFIG_TYPES_SPECIFIER),\n ]\n\n if (hasSkills) {\n lines.push(...declaration(\"skills\", \"SkillConfig[]\", skills))\n }\n\n if (hasAgents) {\n lines.push(...declaration(\"agents\", \"AgentScopeConfig[]\", agents))\n }\n\n if (hasStack) {\n lines.push(...declaration(\"stack\", STACK_TYPE, stack))\n }\n\n if (hasSelectedDomains) {\n lines.push(...declaration(\"selectedDomains\", \"Domain[]\", selectedDomains))\n }\n\n // Extracted fields reference their named variable (or an empty literal when the\n // variable was not emitted); `stack` is omitted entirely when absent.\n const renderExportField = (key: string, value: unknown): string[] => {\n if (!EXTRACTED_FIELDS.has(key)) return [renderScalarField(key, value)]\n if (key === \"skills\") return [` skills${hasSkills ? \"\" : \": []\"},`]\n if (key === \"agents\") return [` agents${hasAgents ? \"\" : \": []\"},`]\n if (key === \"stack\") return hasStack ? [` stack,`] : []\n return [` selectedDomains${hasSelectedDomains ? \"\" : \": []\"},`]\n }\n const exportFields = Object.entries(cleaned).flatMap(([key, value]) =>\n renderExportField(key, value)\n )\n\n lines.push(``)\n lines.push(`export default {`)\n lines.push(...exportFields)\n lines.push(`} satisfies ProjectConfig`)\n\n lines.push(``)\n return lines.join(\"\\n\")\n}\n\n/**\n * Builds the type import list based on which extracted fields are present.\n * ProjectConfig is always included. Other types are included only when used.\n */\nfunction buildTypeImports(flags: {\n hasSkills: boolean\n hasAgents: boolean\n hasStack: boolean\n hasSelectedDomains: boolean\n}): string[] {\n return [\n flags.hasSelectedDomains && \"Domain\",\n \"ProjectConfig\",\n flags.hasStack && \"ProjectAgentName\",\n flags.hasAgents && \"AgentScopeConfig\",\n flags.hasSkills && \"SkillConfig\",\n flags.hasStack && \"StackAgentConfig\",\n ].filter((t): t is string => Boolean(t))\n}\n\n/** Project configs never inherit \"global\" as their name from the globalConfig spread. */\nfunction resolveProjectName(cleaned: Record<string, unknown>): unknown {\n return cleaned.name && cleaned.name !== GLOBAL_CONFIG_NAME\n ? cleaned.name\n : DEFAULT_PLUGIN_NAME\n}\n\ntype InlinedGlobalPartition = {\n /** Global entries with active entries replaced by their project tombstones. */\n globalSkills: unknown[]\n globalAgents: unknown[]\n /** Active (non-excluded) project entries. */\n projectSkills: unknown[]\n projectAgents: unknown[]\n /** Project stack filtered to project-scoped agents only. */\n filteredStack: Record<string, unknown> | undefined\n /** Merged unique global + project values. */\n selectedDomains: unknown[]\n}\n\n/**\n * Pure partition of project + global entries for the inlined snapshot.\n *\n * Excluded globals are routed to the project partition by splitConfigByScope,\n * but render under \"// global\" in the output for readability. When inlining,\n * active global entries are replaced by their excluded tombstones — the\n * tombstone masks the global entry for this project; the active project entry\n * (if any) appears separately in the project section. The project stack keeps\n * only project-scoped agents: global agents' stack entries live in the global\n * config only.\n */\nfunction partitionInlinedConfigEntries(\n cleaned: Record<string, unknown>,\n cleanedGlobal: Record<string, unknown>\n): InlinedGlobalPartition {\n const project = extractConfigArrays(cleaned)\n const global = extractConfigArrays(cleanedGlobal)\n\n const isExcluded = (entry: unknown): boolean =>\n (entry as { excluded?: boolean }).excluded === true\n const idOf = (entry: unknown): string => (entry as { id: string }).id\n const nameOf = (entry: unknown): string => (entry as { name: string }).name\n\n const excludedGlobalSkills = project.skills.filter(isExcluded)\n const excludedGlobalAgents = project.agents.filter(isExcluded)\n const projectSkills = project.skills.filter((s) => !isExcluded(s))\n const projectAgents = project.agents.filter((a) => !isExcluded(a))\n\n const excludedSkillIds = new Set(excludedGlobalSkills.map(idOf))\n const excludedAgentNames = new Set(excludedGlobalAgents.map(nameOf))\n const globalSkills = [\n ...global.skills.filter((s) => !excludedSkillIds.has(idOf(s))),\n ...excludedGlobalSkills,\n ]\n const globalAgents = [\n ...global.agents.filter((a) => !excludedAgentNames.has(nameOf(a))),\n ...excludedGlobalAgents,\n ]\n\n const projectAgentNames = new Set(projectAgents.map(nameOf))\n const filteredStack: Record<string, unknown> | undefined = project.stack\n ? Object.fromEntries(\n Object.entries(project.stack).filter(([agent]) =>\n projectAgentNames.has(agent)\n )\n )\n : undefined\n\n return {\n globalSkills,\n globalAgents,\n projectSkills,\n projectAgents,\n filteredStack,\n selectedDomains: [\n ...new Set([...global.selectedDomains, ...project.selectedDomains]),\n ],\n }\n}\n\n/**\n * Every scalar the inlined snapshot emits, as ONE canonically-ordered sequence.\n * The project's value wins where it carries one, and the global supplies the\n * rest. A global block followed by a project block could not promise this: the\n * first emission writes every global scalar into the project's own file, so on\n * the next re-emit those same keys arrive from the project half instead and two\n * blocks would order them differently for values that never changed.\n *\n * The global's {@link HAND_WRITTEN_FIELDS} are the exception: a project that\n * declares none reads them at run time, so they are left in the global's file.\n */\nfunction mergeInlinedScalarFields(\n cleaned: Record<string, unknown>,\n cleanedGlobal: Record<string, unknown>\n): [string, unknown][] {\n return Object.entries(\n canonicalizeFieldOrder({\n ...omit(cleanedGlobal, HAND_WRITTEN_FIELDS),\n ...cleaned,\n })\n ).filter(([key]) => !EXTRACTED_FIELDS.has(key) && key !== \"name\")\n}\n\n/**\n * Generates a project config with global skills/agents inlined directly.\n * No `import globalConfig` — the output is a self-contained readable snapshot.\n * Global items appear first with a `// global` comment, followed by project items\n * with a `// project` comment (only when project items exist).\n */\nfunction generateProjectConfigWithInlinedGlobal(\n cleaned: Record<string, unknown>,\n cleanedGlobal: Record<string, unknown>\n): string {\n const partition = partitionInlinedConfigEntries(cleaned, cleanedGlobal)\n const {\n globalSkills,\n globalAgents,\n projectSkills,\n projectAgents,\n filteredStack,\n } = partition\n\n const hasGlobalSkills = globalSkills.length > 0\n const hasProjectSkills = projectSkills.length > 0\n const hasSkills = hasGlobalSkills || hasProjectSkills\n\n const hasGlobalAgents = globalAgents.length > 0\n const hasProjectAgents = projectAgents.length > 0\n const hasAgents = hasGlobalAgents || hasProjectAgents\n\n const hasStack =\n filteredStack != null && Object.keys(filteredStack).length > 0\n const hasSelectedDomains = partition.selectedDomains.length > 0\n\n const typeImports = buildTypeImports({\n hasSkills,\n hasAgents,\n hasStack,\n hasSelectedDomains,\n })\n\n const lines: string[] = [\n renderTypeImportLine(typeImports, CONFIG_TYPES_SPECIFIER),\n ]\n\n if (hasSkills) {\n lines.push(\n ...entryDeclaration(\n \"skills\",\n \"SkillConfig[]\",\n scopeSectionEntries(globalSkills, projectSkills)\n )\n )\n }\n\n if (hasAgents) {\n lines.push(\n ...entryDeclaration(\n \"agents\",\n \"AgentScopeConfig[]\",\n scopeSectionEntries(globalAgents, projectAgents)\n )\n )\n }\n\n if (hasStack) {\n lines.push(...declaration(\"stack\", STACK_TYPE, filteredStack))\n }\n\n if (hasSelectedDomains) {\n lines.push(\n ...declaration(\"selectedDomains\", \"Domain[]\", partition.selectedDomains)\n )\n }\n\n const scalarFields = mergeInlinedScalarFields(cleaned, cleanedGlobal)\n\n const exportFields: string[] = [\n renderScalarField(\"name\", resolveProjectName(cleaned)),\n ...scalarFields.map(([key, value]) => renderScalarField(key, value)),\n hasSkills ? ` skills,` : ` skills: [],`,\n hasAgents ? ` agents,` : ` agents: [],`,\n ...(hasStack ? [` stack,`] : []),\n ...(hasSelectedDomains ? [` selectedDomains,`] : []),\n ]\n\n lines.push(``)\n lines.push(`export default {`)\n lines.push(...exportFields)\n lines.push(`} satisfies ProjectConfig`)\n\n lines.push(``)\n return lines.join(\"\\n\")\n}\n\n/**\n * The two halves of an inlined array, each under the comment naming its scope.\n *\n * The comments are entries rather than lines a caller writes around the printer\n * because they are what holds the array open: a `//` line cannot be folded back\n * onto one line, so an array carrying one stays one entry per line however\n * short it is — which is the whole of what keeps these sections legible when a\n * root holds a single skill.\n */\nfunction scopeSectionEntries(\n global: unknown[],\n project: unknown[]\n): ArrayEntry[] {\n return [\n ...(global.length > 0\n ? [commentEntry(\"global\"), ...valueEntries(global)]\n : []),\n ...(project.length > 0\n ? [commentEntry(\"project\"), ...valueEntries(project)]\n : []),\n ]\n}\n\n/** True when the assignment asserts something a bare id could not say on its own. */\nfunction carriesFlags(assignment: SkillAssignment): boolean {\n return Boolean(assignment.preloaded || assignment.local || assignment.path)\n}\n\n/**\n * Structural check for a SkillAssignment object (`{ id, preloaded? }`).\n * The id's SkillId-ness is structural, not union-checked: assignments flow from\n * runtime sources whose skills may not be in the generated union.\n */\nfunction isSkillAssignment(value: unknown): value is SkillAssignment {\n if (typeof value !== \"object\" || value === null) return false\n // Boundary cast: probing an unknown object's field inside the guard\n return typeof (value as { id?: unknown }).id === \"string\"\n}\n\n/**\n * Compacts one SkillAssignment down to the smallest form that still carries its information.\n * - { id: \"...\" } and { id: \"...\", preloaded: false } → \"...\" (the id says everything)\n * - anything carrying a flag (preloaded, local, path) keeps the object form, flags intact\n *\n * The surviving object form is the third member of the entry-order class above:\n * `toStackPropertyAssignment` in `seed-to-config.ts` answers a flag-less\n * assignment with `{ ...assignment, preloaded: true }`, which appends the key at\n * the tail, while the loader's `skillAssignmentSchema` rebuilds it before\n * `local` and `path`.\n */\nfunction compactAssignment(assignment: unknown): unknown {\n if (!isSkillAssignment(assignment)) return assignment\n if (!carriesFlags(assignment)) return assignment.id\n return withKeysInSchemaOrder(assignment, CANONICAL_ASSIGNMENT_ORDER)\n}\n\n/**\n * The emitted value for one category's assignments.\n *\n * An exclusive category can only ever hold one skill, so its array wrapper carries nothing the\n * reader needs and the bare value IS the assignment. Non-exclusive categories keep their array\n * even at length one — there the wrapper is load-bearing, because a second skill may join.\n *\n * Two skills in an exclusive category means the caller built something the config cannot express.\n * Dropping the extra would write a config that does not match what was selected, and nothing\n * downstream could tell, so it fails here instead.\n */\nfunction compactCategoryAssignments(\n category: string,\n assignments: unknown[],\n catalog: CompileCatalog\n): unknown {\n const compacted = assignments.map(compactAssignment)\n if (!isExclusiveCategory(catalog, category)) return compacted\n\n if (compacted.length > 1) {\n throw new Error(\n `Category '${category}' is exclusive but holds ${compacted.length} skills: ${JSON.stringify(compacted)}`\n )\n }\n return compacted[0]\n}\n\n/**\n * Throws what writing `stack` would throw — {@link compactCategoryAssignments}' refusal of a\n * category that holds one skill given more — and writes nothing.\n *\n * For a caller whose write lands after changes it cannot take back: `edit --from` removes skills\n * before it writes the config, so a stack the writer refuses is refused before the first removal.\n */\nexport function refuseUnwritableStack(\n stack: ProjectConfig[\"stack\"],\n catalog: CompileCatalog\n): void {\n for (const agentStack of Object.values(stack ?? {})) {\n compactCategories(agentStack, catalog)\n }\n}\n\nfunction compactCategories(\n categories: Record<string, unknown[]>,\n catalog: CompileCatalog\n): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(categories)\n .filter(\n ([, assignments]) =>\n Array.isArray(assignments) && assignments.length > 0\n )\n .map(([category, assignments]) => [\n category,\n compactCategoryAssignments(category, assignments, catalog),\n ])\n )\n}\n\nfunction compactStackAssignments(\n stack: Record<string, Record<string, unknown[]>>,\n catalog: CompileCatalog\n): Record<string, Record<string, unknown>> {\n return Object.fromEntries(\n Object.entries(stack)\n .map(\n ([agent, categories]) =>\n [agent, compactCategories(categories, catalog)] as const\n )\n .filter(([, categories]) => Object.keys(categories).length > 0)\n )\n}\n\n/**\n * Generates a blank global config source (empty arrays, no import preamble).\n */\nexport function generateBlankGlobalConfigSource(): string {\n return `import type { ProjectConfig } from ${quoteText(CONFIG_TYPES_SPECIFIER)}\n\nexport default {\n name: ${quoteText(GLOBAL_CONFIG_NAME)},\n skills: [],\n agents: [],\n selectedDomains: [],\n} satisfies ProjectConfig\\n`\n}\n","/**\n * The one style the two files an install writes are emitted in.\n *\n * Owner ruling, 2026-08-26: the `config.ts` and `config-types.ts` an install writes\n * land ALREADY FORMATTED, so running prettier over them changes nothing. The\n * settings they are a fixed point of are a USER's rather than this repository's\n * — `parser: \"typescript\", semi: false, singleQuote: true, printWidth: 100,\n * trailingComma: \"all\"` — and they match neither of ours on purpose: the bytes\n * land in somebody else's project, and this repository's own copy is named in\n * `.prettierignore` so nothing here ever formats them.\n *\n * PRETTIER IS DELIBERATELY ABSENT FROM THIS MODULE. It is a devDependency, tsup\n * bundles devDependencies, and calling it from here would inline the TypeScript\n * parser into the published CLI and into the editor's lazily-loaded preview\n * chunk. So what is below reproduces what prettier does to these narrow shapes,\n * and prettier appears only in `contract/emission-scenarios.test.ts`, which runs\n * it over every emitter's output and demands it come back unchanged.\n *\n * The rules were measured against prettier 3.9 rather than reasoned about, and\n * every one of them is the same rule: a construct is flat while its whole line\n * fits in {@link PRINT_WIDTH} counting whatever precedes and follows it, and\n * breaks the moment it does not. Two behaviours are relied on and neither is\n * derivable from that: a `//` line cannot be folded back onto one line, so an\n * array carrying one always breaks; and an object literal whose source has a\n * newline after its `{` stays broken however short it is, which is what lets\n * the `export default` table of contents keep its shape.\n */\n\n/** The column an emitted line may reach — `printWidth` in the settings above. */\nexport const PRINT_WIDTH = 100\n\n/** One level of indentation — `tabWidth` in the settings above. */\nexport const INDENT_STEP = 2\n\n/** The quote `singleQuote: true` asks for, and the one it falls back to. */\nconst PREFERRED_QUOTE = \"'\"\nconst FALLBACK_QUOTE = '\"'\n\n/** A key `quoteProps: \"as-needed\"` leaves unquoted: a plain identifier. */\nconst BARE_KEY = /^[A-Za-z_$][A-Za-z0-9_$]*$/\n\n/** The one form an array and a record with nothing in them can take. */\nconst EMPTY_ARRAY = \"[]\"\nconst EMPTY_RECORD = \"{}\"\n\n/** A JSON object, as distinct from an array, a null or a scalar. */\nexport function isKeyedRecord(\n value: unknown\n): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\n\n/**\n * A string as a TypeScript literal, in the quote prettier would pick: the\n * preferred one, unless the value holds more of it than of the other and\n * swapping would save escapes. A tie keeps the preferred quote.\n */\nexport function quoteText(value: string): string {\n const preferred = occurrences(value, PREFERRED_QUOTE)\n const fallback = occurrences(value, FALLBACK_QUOTE)\n const quote = preferred > fallback ? FALLBACK_QUOTE : PREFERRED_QUOTE\n\n return `${quote}${escapedFor(value, quote)}${quote}`\n}\n\n/** An object key, quoted only where it has to be. */\nexport function renderKey(key: string): string {\n return BARE_KEY.test(key) ? key : quoteText(key)\n}\n\n/**\n * What can sit inside an emitted array.\n *\n * A comment is an entry rather than something a caller splices in around the\n * printer, because a `//` line is what forces the array to break — a\n * hand-assembled array with a section comment and one short entry would\n * otherwise be folded back onto one line and lose the comment's position.\n */\nexport type ArrayEntry =\n | { kind: \"value\"; value: unknown }\n | { kind: \"source\"; source: string }\n | { kind: \"comment\"; text: string }\n\n/** Plain values as array entries. */\nexport function valueEntries(values: readonly unknown[]): ArrayEntry[] {\n return values.map((value) => ({ kind: \"value\", value }))\n}\n\n/** A `//` line between an array's entries. */\nexport function commentEntry(text: string): ArrayEntry {\n return { kind: \"comment\", text }\n}\n\n/** An expression written into an array as it stands, such as a spread. */\nexport function sourceEntry(source: string): ArrayEntry {\n return { kind: \"source\", source }\n}\n\n/**\n * Where a value sits, which is the whole of what decides whether it stays flat.\n */\nexport type LinePosition = {\n /** Columns of indentation the line starts at, and its closing line returns to. */\n indent: number\n /** What precedes the value on its first line, after the indentation. */\n prefix: string\n /** What follows the value on its last line. */\n suffix: string\n}\n\n/** `<indent><prefix><value><suffix>`, broken across lines when it does not fit. */\nexport function renderValueLine(\n value: unknown,\n position: LinePosition\n): string {\n return line(\n renderValue(value, position),\n movesBelowItsPrefix(value),\n position\n )\n}\n\n/** The same, for an array whose entries may be comments or written-out source. */\nexport function renderArrayLine(\n entries: readonly ArrayEntry[],\n position: LinePosition\n): string {\n return line(renderArray(entries, position), entries.length === 0, position)\n}\n\n/** Which of the three shapes prettier gives a union where it sits. */\nexport type UnionLayout = \"inline\" | \"indented\" | \"stacked\"\n\n/** A union that has already left the line it was introduced on. */\nexport type BrokenUnionLayout = Exclude<UnionLayout, \"inline\">\n\n/** Where a union sits, which is what decides which shape it takes. */\nexport type UnionPosition = {\n /** Columns before the union on the line it would sit inline on. */\n headWidth: number\n /** Columns after it on that same line. */\n tailWidth: number\n /** Indentation the union's own lines take once it leaves that line. */\n bodyIndent: number\n}\n\n/**\n * The shape a union takes, which prettier decides in exactly this order:\n * inline while the whole line fits, then its own indented line while THAT\n * fits, and one member per line under a leading `|` only when neither does.\n */\nexport function unionLayout(\n members: readonly string[],\n position: UnionPosition\n): UnionLayout {\n const flat = flatUnion(members)\n const inlineWidth = position.headWidth + flat.length + position.tailWidth\n\n return inlineWidth <= PRINT_WIDTH\n ? \"inline\"\n : brokenUnionLayout(members, position.bodyIndent)\n}\n\n/**\n * The same decision for a union that cannot be inline whatever its width — the\n * sectioned ones, whose `// Custom` heading has already broken the line.\n */\nexport function brokenUnionLayout(\n members: readonly string[],\n bodyIndent: number\n): BrokenUnionLayout {\n return bodyIndent + flatUnion(members).length <= PRINT_WIDTH\n ? \"indented\"\n : \"stacked\"\n}\n\n/** A union's members as their own indented lines, in the shape `layout` names. */\nexport function renderUnionBody(\n members: readonly string[],\n layout: BrokenUnionLayout,\n bodyIndent: number\n): string {\n const padding = spaces(bodyIndent)\n\n return layout === \"indented\"\n ? `${padding}${flatUnion(members)}`\n : members.map((member) => `${padding}| ${member}`).join(\"\\n\")\n}\n\n/** A union's members joined on one line. */\nexport function flatUnion(members: readonly string[]): string {\n return members.join(\" | \")\n}\n\n/**\n * `import type { … } from '…'`, one specifier per line once the single-line\n * form no longer fits.\n */\nexport function renderTypeImportLine(\n specifiers: readonly string[],\n modulePath: string\n): string {\n const from = ` from ${quoteText(modulePath)}`\n const inline = `import type { ${specifiers.join(\", \")} }${from}`\n if (inline.length <= PRINT_WIDTH) return inline\n\n const lines = specifiers.map(\n (specifier) => `${spaces(INDENT_STEP)}${specifier},`\n )\n return [\"import type {\", ...lines, `}${from}`].join(\"\\n\")\n}\n\n/**\n * The finished line, with the value moved below the `key:` or `= ` that\n * introduces it when it is too wide to stay beside it.\n *\n * A value with a prefix of `\"\"` is an array element, which has nothing above it\n * to move under and stays where it is however wide it runs.\n */\nfunction line(\n rendered: string,\n mayMoveBelowPrefix: boolean,\n position: LinePosition\n): string {\n const prefix = position.prefix.trimEnd()\n if (!mayMoveBelowPrefix || prefix === \"\" || fits(rendered, position)) {\n return asLine(rendered, position)\n }\n\n const body = `${spaces(position.indent + INDENT_STEP)}${rendered}${position.suffix}`\n return `${spaces(position.indent)}${prefix}\\n${body}`\n}\n\n/**\n * Whether prettier moves a value below its prefix rather than leaving it past\n * the print width.\n *\n * Nothing in this set can break INSIDE itself, so moving down is the only\n * shortening available to any of them — and the membership was measured\n * against prettier 3.9 rather than reasoned about, because it is not the set a\n * reader would predict: a string, a `null`, an empty array and an empty record\n * all move, while a number and a boolean stay on the line however far past the\n * width they run.\n */\nfunction movesBelowItsPrefix(value: unknown): boolean {\n if (typeof value === \"string\" || value === null) return true\n if (Array.isArray(value)) return value.length === 0\n return isKeyedRecord(value) && Object.keys(value).length === 0\n}\n\nfunction asLine(rendered: string, position: LinePosition): string {\n return `${spaces(position.indent)}${position.prefix}${rendered}${position.suffix}`\n}\n\n/** A value's own text — continuation lines indented, prefix and suffix excluded. */\nfunction renderValue(value: unknown, position: LinePosition): string {\n if (Array.isArray(value)) return renderArray(valueEntries(value), position)\n if (isKeyedRecord(value)) return renderRecord(value, position)\n return renderScalar(value)\n}\n\nfunction renderArray(\n entries: readonly ArrayEntry[],\n position: LinePosition\n): string {\n const flat = flatArray(entries)\n if (flat !== undefined && fits(flat, position)) return flat\n\n const inner = position.indent + INDENT_STEP\n const lines = entries.map((entry) => renderEntryLine(entry, inner))\n return [\"[\", ...lines, `${spaces(position.indent)}]`].join(\"\\n\")\n}\n\nfunction renderEntryLine(entry: ArrayEntry, indent: number): string {\n if (entry.kind === \"comment\") return `${spaces(indent)}// ${entry.text}`\n if (entry.kind === \"source\") return `${spaces(indent)}${entry.source},`\n return renderValueLine(entry.value, { indent, prefix: \"\", suffix: \",\" })\n}\n\nfunction renderRecord(\n record: Record<string, unknown>,\n position: LinePosition\n): string {\n const properties = Object.entries(record)\n // An empty record has nothing to break onto its own lines, so `{}` is the\n // only form it has however little room is left for it.\n if (properties.length === 0) return EMPTY_RECORD\n\n const flat = flatRecord(record)\n if (fits(flat, position)) return flat\n\n const inner = position.indent + INDENT_STEP\n const lines = properties.map(([key, value]) =>\n renderValueLine(value, {\n indent: inner,\n prefix: `${renderKey(key)}: `,\n suffix: \",\",\n })\n )\n return [\"{\", ...lines, `${spaces(position.indent)}}`].join(\"\\n\")\n}\n\n/** The one-line form of an array, or nothing when a comment forbids one. */\nfunction flatArray(entries: readonly ArrayEntry[]): string | undefined {\n const items: string[] = []\n\n for (const entry of entries) {\n // A `//` line cannot be folded back onto one line, so an array holding one\n // has no flat form at all.\n if (entry.kind === \"comment\") return undefined\n items.push(entry.kind === \"source\" ? entry.source : flatValue(entry.value))\n }\n\n return flatList(items)\n}\n\nfunction flatValue(value: unknown): string {\n if (Array.isArray(value)) return flatList(value.map(flatValue))\n if (isKeyedRecord(value)) return flatRecord(value)\n return renderScalar(value)\n}\n\nfunction flatList(items: readonly string[]): string {\n return items.length === 0 ? EMPTY_ARRAY : `[${items.join(\", \")}]`\n}\n\nfunction flatRecord(record: Record<string, unknown>): string {\n const properties = Object.entries(record).map(\n ([key, value]) => `${renderKey(key)}: ${flatValue(value)}`\n )\n return properties.length === 0 ? EMPTY_RECORD : `{ ${properties.join(\", \")} }`\n}\n\nfunction renderScalar(value: unknown): string {\n return typeof value === \"string\" ? quoteText(value) : String(value)\n}\n\nfunction fits(flat: string, position: LinePosition): boolean {\n const width =\n position.indent +\n position.prefix.length +\n flat.length +\n position.suffix.length\n\n return width <= PRINT_WIDTH\n}\n\nfunction occurrences(value: string, character: string): number {\n return value.split(character).length - 1\n}\n\n/**\n * A string's body under one enclosing quote: JSON's own escaping, with the\n * escape moved off the double quote and onto whichever quote encloses it.\n */\nfunction escapedFor(value: string, quote: string): string {\n const jsonBody = JSON.stringify(value).slice(1, -1)\n if (quote === FALLBACK_QUOTE) return jsonBody\n\n return jsonBody.replaceAll('\\\\\"', '\"').replaceAll(\"'\", \"\\\\'\")\n}\n\n/** That many columns of padding. */\nexport function spaces(count: number): string {\n return \" \".repeat(count)\n}\n","// Type-safe Object.entries that preserves key types (avoids `as [K, V][]` casts)\nexport function typedEntries<K extends string, V>(\n obj: Partial<Record<K, V>>\n): [K, V][] {\n return Object.entries(obj) as [K, V][]\n}\n\n// Type-safe Object.keys that preserves key types (avoids `as K[]` casts)\nexport function typedKeys<K extends string>(\n obj: Partial<Record<K, unknown>>\n): K[] {\n return Object.keys(obj) as K[]\n}\n\n// Type-safe Object.fromEntries that preserves key types (avoids `as Partial<Record<K, V>>` casts)\nexport function typedFromEntries<K extends string, V>(\n entries: Iterable<readonly [K, V]>\n): Partial<Record<K, V>> {\n return Object.fromEntries(entries) as Partial<Record<K, V>>\n}\n","import { indexBy, omit, pick, uniqueBy } from \"remeda\";\nimport { HAND_WRITTEN_FIELDS } from \"@workspace/compile/config-source\";\n\nimport type { ProjectConfig } from \"../../types\";\nimport type { AgentScopeConfig, SkillConfig } from \"../../types/config\";\nimport { getProjectConfigPath } from \"../installation/install-base-dir\";\nimport { loadProjectConfig, type LoadedProjectConfig } from \"./project-config\";\nimport { loadProjectSourceConfig } from \"./config\";\nimport { isGlobalTombstone, isProjectOwned, type ScopedEntry } from \"./scope-predicates\";\n\n/**\n * How authoritative `newConfig` is over entries absent from it:\n * - `\"all\"` — global-context EDIT at ~/: the wizard loaded the ENTIRE global config, so any\n * absent agent/skill was removed. Every existing entry is in scope.\n * - `\"owned\"` — project-context EDIT: the wizard loaded the full project roster and owns only\n * PROJECT-OWNED entries (project-scoped + the project's own global tombstones).\n * Inherited global-active entries are read-only and are always preserved.\n * - `undefined` — init / non-edit merges: additive union-preserve (never drop absent entries).\n */\nexport type AuthoritativeScope = \"all\" | \"owned\";\n\nexport type MergeContext = {\n projectDir: string;\n authoritativeScope?: AuthoritativeScope;\n};\n\nexport type MergeResult = {\n config: ProjectConfig;\n merged: boolean;\n existingConfigPath?: string;\n};\n\n/**\n * Compound identity key for an agent entry. Includes scope and the excluded\n * discriminator so that `{name, scope:\"project\"}` and `{name, scope:\"global\"}`\n * (and their tombstone variants) are treated as distinct entries rather than\n * collapsed onto `name` alone.\n */\nconst agentKey = (a: AgentScopeConfig): string =>\n `${a.name}:${a.scope}${a.excluded ? \":excluded\" : \"\"}`;\n\n/**\n * Compound identity key for a skill entry. Same shape as {@link agentKey}:\n * `id:scope` for actives, `id:scope:excluded` for tombstones. Prevents the\n * class of bugs where two distinct-scope entries collide onto `id`.\n */\nconst skillKey = (s: SkillConfig): string => `${s.id}:${s.scope}${s.excluded ? \":excluded\" : \"\"}`;\n\n/** How one roster's entries are told apart: the compound key, and the name or id it extends. */\ntype RosterIdentity<Entry> = {\n keyOf: (entry: Entry) => string;\n identityOf: (entry: Entry) => string;\n};\n\nconst AGENT_IDENTITY: RosterIdentity<AgentScopeConfig> = {\n keyOf: agentKey,\n identityOf: (agent) => agent.name,\n};\n\nconst SKILL_IDENTITY: RosterIdentity<SkillConfig> = {\n keyOf: skillKey,\n identityOf: (skill) => skill.id,\n};\n\n/**\n * True when an existing entry is within the current edit session's authority, so its absence\n * from `newConfig` means a deliberate removal (drop) rather than an untouched entry (preserve).\n *\n * `\"all\"` (global edit): every entry is owned. `\"owned\"` (project edit): only project-scoped\n * entries and the project's own global tombstones — inherited global-active entries belong to\n * the global config and must never be dropped from a project edit.\n */\nfunction isWithinSessionAuthority(entry: ScopedEntry, scope: AuthoritativeScope): boolean {\n if (scope === \"all\") return true;\n return isProjectOwned(entry);\n}\n\n/**\n * One roster — agents or skills — merged by the rules {@link mergeConfigs} states: an existing\n * entry is replaced by the incoming entry with its compound key, dropped when the incoming roster\n * manages its name/id under another key, dropped when it was the project's dual-scope entry and\n * the incoming roster carries nothing for it, dropped when an authoritative session left it out,\n * and otherwise preserved. Incoming entries with new keys are appended, and the result is deduped\n * by compound key, keeping the first occurrence.\n */\nfunction mergeRoster<Entry extends ScopedEntry>(\n incoming: Entry[],\n existing: Entry[],\n identity: RosterIdentity<Entry>,\n authoritativeScope: AuthoritativeScope | undefined,\n): Entry[] {\n const incomingByKey = indexBy(incoming, identity.keyOf);\n const incomingIdentities = new Set(incoming.map(identity.identityOf));\n const existingKeys = new Set(existing.map(identity.keyOf));\n // Names/ids the project managed as dual-scope this session: a global tombstone in the existing\n // config marks an entry whose global install the project actively overrode. When the incoming\n // roster carries NO entry for such a name, the user fully deselected the dual-scope row — both\n // the lingering active project entry and the stale tombstone must drop together, not be\n // preserved — the full-deselect case.\n const dualScopeIdentities = new Set(existing.filter(isGlobalTombstone).map(identity.identityOf));\n\n const updatedExisting = existing.flatMap((entry) => {\n const matching = incomingByKey[identity.keyOf(entry)];\n if (matching !== undefined) return [matching];\n // Name is actively managed by the incoming roster but this exact (scope, excluded) slot is\n // NOT in it → the wizard intentionally dropped this row (scope migration or tombstone\n // cleanup). Drop it.\n if (incomingIdentities.has(identity.identityOf(entry))) return [];\n if (dualScopeIdentities.has(identity.identityOf(entry))) return [];\n // Authoritative edit: an in-authority entry absent from the incoming roster (even a plain\n // active one with no tombstone) was deselected and must be dropped.\n if (authoritativeScope && isWithinSessionAuthority(entry, authoritativeScope)) return [];\n return [entry];\n });\n const added = incoming.filter((entry) => !existingKeys.has(identity.keyOf(entry)));\n return uniqueBy([...updatedExisting, ...added], identity.keyOf);\n}\n\ntype MergeOptions = Pick<MergeContext, \"authoritativeScope\">;\n\n/**\n * Pure merge logic: existing values take precedence for identity fields;\n * agents and skills are merged so that `newConfig` is authoritative for every\n * `name`/`id` it references. Existing entries survive in-place when their\n * compound key matches a new entry (same name, scope, excluded). Existing\n * entries whose NAME/ID appears in new but whose compound key does NOT match\n * a new entry are dropped — this is how scope migrations (P→G, G→P) remove\n * stale rows and how P→G tombstone removal is honored. Existing entries whose\n * name/ID is absent from new are preserved unchanged — EXCEPT names/ids the\n * project owned as dual-scope this session (they carry a global tombstone in the\n * existing config): when new carries nothing for such a name, the user fully\n * deselected the dual-scope row, so both the lingering active project entry and\n * the stale tombstone are dropped together — the full-deselect case.\n *\n * A final compound-key dedup (keeping first occurrence, which in our concat\n * order is the existing-derived or first-new entry) collapses any pre-existing\n * on-disk corruption rather than carrying multiplied duplicates forward.\n *\n * Dual-scope semantics (active at one scope + excluded tombstone at another)\n * are preserved because `newConfig.agents`/`newConfig.skills` carry BOTH\n * entries for the same name/id when that dual state is legitimate (wizard\n * output from `generateProjectConfigFromSkills` + `toggleAgentScope`).\n *\n * Root cause of the duplicate rows this key fixes: the prior name-only key collapsed\n * distinct-scope entries, and the positional `.map()` over existing rewrote\n * every collision slot — multiplying pre-existing duplicates and failing to\n * drop stale rows on scope migration.\n *\n * `authoritativeScope`: a full `cc edit` pass presents the complete roster\n * the wizard could edit, so an entry within that authority which is absent from `newConfig` was\n * deliberately removed and must be dropped (even a plain active entry with no tombstone), rather\n * than union-preserved. `\"all\"` (global edit) covers every entry; `\"owned\"` (project edit) covers\n * only project-scoped entries and the project's own global tombstones — inherited global-active\n * entries are always preserved. `undefined` (init) keeps additive union-preserve.\n *\n * A skill the wizard could not resolve from the loaded source this session is NOT exempt from that\n * drop: it is removed like any other absent entry, and `edit` names it and says why in its Changes\n * block. Exempting it used to keep an entry in `config.ts` that the same run's summary announced as\n * gone and the compiled agent no longer carried — three surfaces, three answers about one skill.\n */\nexport function mergeConfigs(\n newConfig: ProjectConfig,\n existingConfig: ProjectConfig,\n options?: MergeOptions,\n): ProjectConfig {\n const merged = { ...newConfig };\n\n if (existingConfig.name) {\n merged.name = existingConfig.name;\n }\n\n if (existingConfig.description) {\n merged.description = existingConfig.description;\n }\n\n if (existingConfig.marketplace && !newConfig.marketplace) {\n merged.marketplace = existingConfig.marketplace;\n }\n\n merged.agents = mergeRoster(\n merged.agents,\n existingConfig.agents,\n AGENT_IDENTITY,\n options?.authoritativeScope,\n );\n merged.skills = mergeRoster(\n merged.skills,\n existingConfig.skills,\n SKILL_IDENTITY,\n options?.authoritativeScope,\n );\n\n // Stack is the pure output of the mutator — trust newConfig.stack whenever it\n // is defined. Only fall back to existingConfig.stack when the new config has\n // none (preserves existing during non-stack-touching operations).\n if (newConfig.stack === undefined && existingConfig.stack) {\n merged.stack = existingConfig.stack;\n }\n\n if (existingConfig.author) {\n merged.author = existingConfig.author;\n }\n\n if (existingConfig.agentsSource) {\n merged.agentsSource = existingConfig.agentsSource;\n }\n\n // The existing name labels the marketplace it was recorded beside. A project set up from another\n // merges over the GLOBAL config, and that name would otherwise be written in as the project's.\n if (existingConfig.marketplaceName && merged.marketplace === existingConfig.marketplace) {\n merged.marketplaceName = existingConfig.marketplaceName;\n }\n\n // Written by hand into this file and by nothing the session produces, so the file is their only\n // record: a rewrite that dropped them put a white-labelled install back on the shipped name.\n Object.assign(merged, pick(existingConfig, HAND_WRITTEN_FIELDS));\n\n // Preserve the registered project paths from the existing (global) config — the wizard\n // result never carries them, and losing them silently disables propagation of global\n // changes to registered projects — the tombstone reconcile never runs.\n if (existingConfig.projects && !newConfig.projects) {\n merged.projects = existingConfig.projects;\n }\n\n return merged;\n}\n\n/**\n * The config the merge reconciles against, wearing an identity this directory can own.\n *\n * `loadProjectConfig` falls back to `os.homedir()` for a project that carries no config of\n * its own, so a first save into a project sitting under an existing global install\n * reconciles against the GLOBAL config — whose `name` identifies that installation and no\n * directory here. `mergeConfigs`' identity-field carry-forward would then stamp it onto the\n * project's own file.\n *\n * The carry-forward itself is intentional and stays: a project's OWN prior config is how a\n * hand-renamed `config.ts` keeps its name across saves. What decides between the two is the\n * provenance of the load, which is known here and nowhere inside the pure merge — so a\n * config that came from the home fallback lends this save every field except its name and its\n * {@link HAND_WRITTEN_FIELDS}. A project that declares none of those reads the global's at run\n * time, so a copy lent here would become the project's own and keep the old value after the\n * global changed.\n */\nfunction existingConfigForMerge(\n loaded: LoadedProjectConfig,\n projectDir: string,\n ownName: string,\n): ProjectConfig {\n // Against the SAME installation's path: the load says which provider it came out of, and a\n // comparison against another provider's file would read a project's own config as inherited.\n const isProjectsOwnFile = loaded.configPath === getProjectConfigPath(projectDir, loaded.provider);\n if (isProjectsOwnFile) return loaded.config;\n\n return { ...omit(loaded.config, HAND_WRITTEN_FIELDS), name: ownName };\n}\n\nexport async function mergeWithExistingConfig(\n newConfig: ProjectConfig,\n context: MergeContext,\n): Promise<MergeResult> {\n const existingFullConfig = await loadProjectConfig(context.projectDir);\n if (existingFullConfig) {\n // A full `cc edit` pass loads the complete roster, so newConfig is authoritative over the\n // entries it owns — every entry for a global edit (`\"all\"`), or project-owned entries for a\n // project edit (`\"owned\"`). Absent owned entries were deselected and are dropped rather than\n // union-preserved. Init leaves the scope undefined (additive union).\n const existingConfig = existingConfigForMerge(\n existingFullConfig,\n context.projectDir,\n newConfig.name,\n );\n const config = mergeConfigs(newConfig, existingConfig, {\n ...(context.authoritativeScope !== undefined && {\n authoritativeScope: context.authoritativeScope,\n }),\n });\n\n return {\n config,\n merged: true,\n existingConfigPath: existingFullConfig.configPath,\n };\n }\n\n // No existing full config, try simple project source config for author/agentsSource.\n // ABORT on an unreadable config, and unreachable here: `loadProjectConfig` above reads the same\n // file and already threw `ConfigLoadError` for one it could not load, so this rung is only\n // reached when there is no config to read.\n const localConfig = { ...newConfig };\n const existingProjectConfig = await loadProjectSourceConfig(context.projectDir);\n if (existingProjectConfig?.author) {\n localConfig.author = existingProjectConfig.author;\n }\n if (existingProjectConfig?.agentsSource) {\n localConfig.agentsSource = existingProjectConfig.agentsSource;\n }\n\n return { config: localConfig, merged: false };\n}\n","import os from \"os\";\nimport path from \"path\";\nimport { fileExists } from \"../../utils/fs\";\nimport { verbose, warn } from \"../../utils/logger\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport type { Provider } from \"../../consts\";\nimport type { ProjectConfig, ValidationResult } from \"../../types\";\nimport { normalizeStackRecord } from \"../stacks/stacks-loader\";\nimport { projectConfigLoaderSchema } from \"../schemas\";\nimport { formatZodErrors } from \"../schema-validator\";\nimport { getProjectConfigPath } from \"../installation/install-base-dir\";\nimport { providerInUse } from \"../installation/install-layout\";\nimport { isHomeDirectory } from \"../installation/is-home-directory\";\nimport type { ScopeKind } from \"../installation/source-scopes\";\nimport { loadConfig, NO_VALID_DEFAULT_EXPORT } from \"./config-loader\";\n\nexport type LoadedProjectConfig = {\n config: ProjectConfig;\n configPath: string;\n /**\n * Which installation this config was read out of.\n *\n * It says which installation the caller is holding, never which folder name it was found\n * under: a pre-rename `.claude-src/` answers `claude` exactly as `.agents-inc/claude/` does.\n * Carried on the read because nothing inside the file records it — the folder is the only\n * record — so a caller that has to write back, compile, or name a host directory would\n * otherwise have to re-derive the provider and could derive a different one.\n */\n provider: Provider;\n};\n\n/**\n * Thrown when a project config file exists on disk but cannot be loaded into a\n * usable config — a syntax/evaluation error, no default export, or a shape the\n * loader schema rejects. This is deliberately distinct from a MISSING file\n * (which is a legitimate `null`): a corrupt config is an error that callers must\n * surface, never swallow into `null`. Collapsing both into `null` let a broken\n * install pass as absent (e.g. `compile` treating it as config-less and\n * resurrecting every built-in agent).\n *\n * It carries whose installation the file is, because a refusal read from a project can be about\n * either config the project uses, and the way out — `uninstall`, then `init` — is run from the\n * folder holding the broken one: the home directory for the global config.\n */\nexport class ConfigLoadError extends Error {\n readonly scope: ScopeKind;\n\n constructor(\n readonly configPath: string,\n readonly reason: string,\n /** The directory whose installation this config is: a project, or the home directory. */\n readonly scopeRoot: string,\n ) {\n super(`Config at '${configPath}' could not be loaded: ${reason}`);\n this.name = \"ConfigLoadError\";\n this.scope = isHomeDirectory(scopeRoot) ? \"global\" : \"project\";\n }\n}\n\n/**\n * Load project config from a specific directory only (no global fallback).\n *\n * Returns `null` only when the config file does not exist. When the file exists\n * but cannot be parsed into a usable config, throws {@link ConfigLoadError} —\n * the caller decides how to report it.\n *\n * The two lines it announces name the scope of the file it read, the way\n * `loadSourceConfig`'s already do: the config at the home root is the GLOBAL one,\n * and a run there that calls it a project config names a file that is not there.\n */\nexport async function loadProjectConfigFromDir(\n projectDir: string,\n provider: Provider,\n): Promise<LoadedProjectConfig | null> {\n return loadProjectConfigAt(getProjectConfigPath(projectDir, provider), projectDir, provider);\n}\n\n/**\n * {@link loadProjectConfigFromDir} for a config at a path the caller names rather than the one the\n * resolver picks — the second of a scope's two source folders, which the resolver never reads.\n * Same contract: `null` only when the file is absent, {@link ConfigLoadError} when it is there and\n * cannot be loaded.\n */\nexport async function loadProjectConfigAt(\n configPath: string,\n projectDir: string,\n provider: Provider,\n): Promise<LoadedProjectConfig | null> {\n const scope = isHomeDirectory(projectDir) ? \"global\" : \"project\";\n const scopeLabel = scope === \"project\" ? \"Project\" : \"Global\";\n\n if (!(await fileExists(configPath))) {\n verbose(`${scopeLabel} config not found at ${configPath}`);\n return null;\n }\n\n // The file exists. From here, any failure to produce a usable config means the\n // file is corrupt — surface it as ConfigLoadError rather than returning `null`,\n // which is indistinguishable from \"missing\".\n let raw: unknown;\n try {\n // Load raw object and validate with Zod (lenient schema accepts custom values via z.string() casts)\n raw = await loadConfig<ProjectConfig>(configPath);\n } catch (error) {\n throw new ConfigLoadError(configPath, getErrorMessage(error), projectDir);\n }\n\n if (!raw || typeof raw !== \"object\") {\n throw new ConfigLoadError(configPath, NO_VALID_DEFAULT_EXPORT, projectDir);\n }\n\n const result = projectConfigLoaderSchema.safeParse(raw);\n if (!result.success) {\n throw new ConfigLoadError(configPath, formatZodErrors(result.error).join(\"; \"), projectDir);\n }\n\n // Normalize the loose stack values (bare strings, objects, arrays) BEFORE claiming\n // ProjectConfig, so the boundary cast below is the only one on this path.\n const parsed = result.data;\n const normalizedStack = parsed.stack ? normalizeStackRecord(parsed.stack) : undefined;\n if (parsed.name === undefined) {\n warn(\n `Project config at '${configPath}' is missing required 'name' field — defaulting to directory name`,\n );\n }\n if (parsed.skills === undefined) {\n warn(`Project config at '${configPath}' is missing 'skills' array — defaulting to empty`);\n }\n\n // The defaults are applied here rather than mutated in afterwards, so the cast is the\n // last thing that happens and ProjectConfig's required fields are genuinely present.\n // `agents` is defaulted for the same reason `skills` is: the loader schema admits its\n // absence, ProjectConfig declares it required, and every caller was paying for the gap\n // with a `?? []` the type said was dead.\n //\n // Boundary cast: the loader schema is lenient about the string unions (category, slug,\n // domain), so the literal still does not satisfy ProjectConfig even with the defaults in\n // place; validateProjectConfig enforces the strict shape after load.\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- see above\n const config = {\n ...parsed,\n name: parsed.name ?? path.basename(projectDir),\n skills: parsed.skills ?? [],\n agents: parsed.agents ?? [],\n ...(normalizedStack && { stack: normalizedStack }),\n } as ProjectConfig;\n\n verbose(`Loaded ${scope} config from ${configPath}`);\n return {\n config,\n configPath,\n provider,\n };\n}\n\n/**\n * The config of whichever installation `dir` holds, read off the folder.\n *\n * The sibling of `getInstalledConfigPath`, and the form every caller that holds a directory and\n * no provider wants: the alternative is that same resolution written out at each of them, which\n * is one concept with several definitions and no name.\n */\nexport async function loadInstalledConfig(dir: string): Promise<LoadedProjectConfig | null> {\n return loadProjectConfigFromDir(dir, providerInUse(dir));\n}\n\n/**\n * The directories whose config a run reads: the project's own, plus the global one it\n * inlines. At the home root the two collapse into one.\n */\nexport function configDirsInPlay(projectDir: string): string[] {\n return isHomeDirectory(projectDir) ? [projectDir] : [projectDir, os.homedir()];\n}\n\n/**\n * Every config a run would read that exists and cannot be loaded, in the order the run reads\n * them. A directory whose config is absent (legitimate) or loads contributes nothing; any other\n * failure is a real fault and propagates.\n *\n * Exported rather than kept private to its first caller because two surfaces have to agree on\n * exactly which configs are in play: `BaseCommand.ensureConfigReadable`, which refuses to run over\n * one it cannot read, and `doctor`, which reports the same fault. Two answers to that question is\n * how the CLI ended up refusing a file in one command and calling it missing in another.\n */\nexport async function findConfigLoadFailures(projectDir: string): Promise<ConfigLoadError[]> {\n const outcomes = await Promise.all(configDirsInPlay(projectDir).map(configLoadFailure));\n return outcomes.filter((failure): failure is ConfigLoadError => failure !== undefined);\n}\n\nasync function configLoadFailure(dir: string): Promise<ConfigLoadError | undefined> {\n try {\n await loadInstalledConfig(dir);\n return undefined;\n } catch (error) {\n if (error instanceof ConfigLoadError) return error;\n throw error;\n }\n}\n\n/**\n * Load the config of the installation this run is about: the project's own, falling back to the\n * global one.\n *\n * **The fallback stays inside one provider, and the provider is read off the project rather than\n * passed in.** Each provider family inherits only within itself — the owner's ruling, and what\n * `.agents-inc/claude/` beside `.agents-inc/codex/` means — so a Codex project under a Claude\n * global inherits nothing, exactly as it would if the global were absent.\n *\n * The provider is resolved here rather than at each of the dozen callers because every one of\n * them holds a project directory and nothing else: twelve copies of the same resolution is twelve\n * places for it to drift, and the answer comes back on {@link LoadedProjectConfig.provider} for\n * the callers that need it. A caller that knows which installation it wants asks\n * {@link loadProjectConfigFromDir} by name instead.\n */\nexport async function loadProjectConfig(projectDir: string): Promise<LoadedProjectConfig | null> {\n const provider = providerInUse(projectDir);\n const projectResult = await loadProjectConfigFromDir(projectDir, provider);\n if (projectResult) return projectResult;\n\n // Global fallback: try home directory\n const homeDir = os.homedir();\n if (!isHomeDirectory(projectDir)) {\n return loadProjectConfigFromDir(homeDir, provider);\n }\n\n return null;\n}\n\n/**\n * Validates a loaded config value. Shape validity is defined by\n * `projectConfigLoaderSchema` (the single definition); on top of the schema's\n * lenient shape, a usable project config additionally requires `name` and\n * `agents` to be present.\n */\nexport function validateProjectConfig(config: unknown): ValidationResult {\n const result = projectConfigLoaderSchema.safeParse(config);\n if (!result.success) {\n return { valid: false, errors: formatZodErrors(result.error), warnings: [] };\n }\n\n const errors = [\n ...(result.data.name ? [] : [\"name is required and must be a string\"]),\n ...(result.data.agents ? [] : [\"agents is required and must be an array\"]),\n ];\n return { valid: errors.length === 0, errors, warnings: [] };\n}\n","import path from \"path\";\nimport { flatMap, groupBy, mapValues, partition, pipe, unique, uniqueBy } from \"remeda\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { verbose, warn } from \"../../utils/logger\";\nimport { matrix } from \"../matrix/matrix-provider\";\nimport type {\n AgentName,\n SkillAssignment,\n SkillId,\n SkillReference,\n Stack,\n StackAgentConfig,\n Category,\n} from \"../../types\";\nimport { stacksConfigSchema } from \"../schemas\";\nimport { typedEntries } from \"../../utils/typed-object\";\nimport { isSkillAssignment } from \"../../utils/type-guards\";\nimport { LOCAL_PSEUDO_CATEGORY, STACKS_FILE_PATH } from \"../../consts\";\nimport { loadConfig } from \"../configuration/config-loader\";\nimport { offersBuiltInStacks } from \"../configuration/config\";\nimport { defaultStacks } from \"../configuration/default-stacks\";\n\nconst stacksCache = new Map<string, Stack[]>();\n\n/**\n * Normalizes a raw agent config (from Zod-parsed config) to StackAgentConfig.\n * Converts bare strings to `{ id, preloaded: false }` and wraps single values in arrays.\n * Used by both loadStacks() and loadProjectConfig() to handle all 3 config formats:\n * 1. bare string: `framework: \"web-framework-react\"`\n * 2. single object: `framework: { id: \"web-framework-react\", preloaded: true }`\n * 3. array: `methodology: [{ id: ..., preloaded: true }, { id: ... }]`\n */\nexport function normalizeAgentConfig(agentConfig: Record<string, unknown>): StackAgentConfig {\n // Boundary casts: Zod-parsed config has loose types (bare strings, objects, arrays)\n // that are normalized to typed SkillAssignment[] values\n return mapValues(agentConfig, (value) => {\n const items = Array.isArray(value) ? value : [value];\n return items.map((item): SkillAssignment => {\n if (typeof item === \"string\") return { id: item as SkillId, preloaded: false };\n if (isSkillAssignment(item)) return item;\n warn(`Malformed skill assignment in stack data: ${JSON.stringify(item)}`);\n return item as SkillAssignment;\n });\n });\n}\n\n/**\n * Where the live catalog says a skill's entry belongs, or `undefined` when it\n * has nothing to say: an id the matrix does not carry (local, marketplace, or\n * withdrawn) and a skill in the `local` pseudo-category both leave the key the\n * config already spells as the only word available.\n */\nfunction liveCategoryOf(skillId: SkillId): Category | undefined {\n const category = matrix.skills[skillId]?.category;\n if (category === undefined || category === LOCAL_PSEUDO_CATEGORY) return undefined;\n // TypeScript narrows CategoryPath to Category after excluding \"local\"\n return category;\n}\n\ntype PlacedAssignment = {\n storedCategory: Category;\n liveCategory: Category;\n assignment: SkillAssignment;\n};\n\nfunction placeAssignments(agentConfig: StackAgentConfig): PlacedAssignment[] {\n return typedEntries<Category, SkillAssignment[]>(agentConfig).flatMap(\n ([storedCategory, assignments]) =>\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- typedEntries/Object.entries launders the `| undefined` a Partial<Record> admits out of its result type, so this guard reads as dead while still covering an explicitly-undefined slot\n (assignments ?? []).map((assignment) => ({\n storedCategory,\n liveCategory: liveCategoryOf(assignment.id) ?? storedCategory,\n assignment,\n })),\n );\n}\n\n/**\n * One agent's saved stack re-keyed under each skill's live category.\n *\n * A persisted `stack` block names the category each skill sat in when it was\n * written, and every consumer downstream — the generator's preservation\n * lookup, the load-state lookup, the compiled agent's usage line — asks the\n * live catalog. When a release moves a skill between categories the two stop\n * agreeing, and a saved entry nobody can find is a saved entry nobody keeps.\n * Re-keying here is what keeps the question answerable: the category is where\n * an entry is STORED, the id is which skill it names, and only the id is\n * identity.\n *\n * A skill already under its live category wins any collision with a stale\n * duplicate of itself — it is the current word for that pair, and one skill\n * may appear once per agent.\n */\nfunction rekeyToLiveCategories(agentConfig: StackAgentConfig): StackAgentConfig {\n const [settled, moved] = partition(\n placeAssignments(agentConfig),\n (placed) => placed.liveCategory === placed.storedCategory,\n );\n\n if (moved.length > 0) {\n verbose(\n `Re-keyed stack entries to their live category: ` +\n moved\n .map((p) => `${p.assignment.id} (${p.storedCategory} -> ${p.liveCategory})`)\n .join(\", \"),\n );\n }\n\n return mapValues(\n groupBy([...settled, ...moved], (placed) => placed.liveCategory),\n (placed) =>\n uniqueBy(\n placed.map((p) => p.assignment),\n (assignment) => assignment.id,\n ),\n );\n}\n\n/**\n * Normalizes a raw stack record (agent -> raw category config) to the typed form.\n * Applies normalizeAgentConfig to each agent entry, then re-keys the result to\n * the live catalog (see {@link rekeyToLiveCategories}).\n *\n * This is the PERSISTED-CONFIG boundary — `loadProjectConfigFromDir` and the\n * config gate's writer entry. A source's `stacks.ts` deliberately does not pass\n * through here: its category key is the author's heading for the agent prompt,\n * shipped alongside the catalog it references, so there is no drift to\n * reconcile and nothing to overrule.\n */\nexport function normalizeStackRecord(\n rawStack: Record<string, Record<string, unknown>>,\n): Record<string, StackAgentConfig> {\n return mapValues(rawStack, (agentConfig) =>\n rekeyToLiveCategories(normalizeAgentConfig(agentConfig)),\n );\n}\n\nexport async function loadStacks(configDir: string, stacksFile?: string): Promise<Stack[]> {\n const resolvedStacksFile = stacksFile ?? STACKS_FILE_PATH;\n const cacheKey = `${configDir}:${resolvedStacksFile}`;\n const cached = stacksCache.get(cacheKey);\n if (cached) return cached;\n\n const stacksPath = path.join(configDir, resolvedStacksFile);\n\n try {\n const raw = await loadConfig(stacksPath, stacksConfigSchema);\n\n if (raw == null) {\n verbose(`No stacks file found at ${stacksPath}`);\n return [];\n }\n\n // Normalize: all values to SkillAssignment[] so StackAgentConfig is always SkillAssignment[]\n // Boundary casts: Zod stacksConfigSchema outputs loose Record types;\n // narrowing to Stack[\"agents\"] after normalization guarantees SkillAssignment[] values\n const stacks: Stack[] = raw.stacks.map((stack) => ({\n ...stack,\n agents: mapValues(\n stack.agents as Partial<Record<AgentName, Record<string, unknown>>>,\n (agentConfig) => normalizeAgentConfig(agentConfig),\n ),\n }));\n\n stacksCache.set(cacheKey, stacks);\n verbose(`Loaded ${stacks.length} stacks from ${stacksPath}`);\n\n return stacks;\n } catch (error) {\n const errorMessage = getErrorMessage(error);\n throw new Error(`Failed to load stacks from '${stacksPath}': ${errorMessage}`, {\n cause: error,\n });\n }\n}\n\n/**\n * One stack by id, scoped the way the wizard's stack step is.\n *\n * The source's own stacks answer first. The CLI's built-in catalogue stands in\n * only for the public catalogue — the same rule `resolveOfferedStacks` applies to\n * the list the wizard offers, read from the same {@link offersBuiltInStacks} so\n * the two cannot answer differently. They are a pair: that one decides what is\n * OFFERED and this one resolves what was PICKED, so a rule they disagree on\n * offers a stack and then refuses to install it.\n *\n * Under any other source a built-in id names a stack that source does not have,\n * and answering with one would install stacks written against a different\n * catalogue of skills, under a name the user never asked for. Null is the honest\n * answer there; the callers name the id they asked for.\n */\nexport async function loadStackById(\n stackId: string,\n configDir: string,\n source: string,\n): Promise<Stack | null> {\n const stacks = await loadStacks(configDir);\n const stack = stacks.find((s) => s.id === stackId);\n\n if (stack) {\n verbose(`Found stack: ${stack.name} (${stackId})`);\n return stack;\n }\n\n if (!(await offersBuiltInStacks(configDir, source))) {\n verbose(\n `Marketplace '${source}' does not ship stack '${stackId}', and gets no built-in stand-in`,\n );\n return null;\n }\n\n const defaultStack = defaultStacks.find((s) => s.id === stackId) ?? null;\n if (defaultStack) {\n verbose(`Found default stack: ${defaultStack.name} (${stackId})`);\n } else {\n verbose(`Stack '${stackId}' not found in the default marketplace or the built-ins`);\n }\n return defaultStack;\n}\n\n/**\n * What a null from {@link loadStackById} means, said once.\n *\n * Both callers turn that null into a failure, and both have to name the id they\n * asked for and the source they asked — a stack that cannot be found is only\n * actionable if the message says which stack and where it was looked for. One\n * definition so the two surfaces cannot describe the same rule differently.\n */\nexport function stackNotOfferedMessage(stackId: string, source: string): string {\n return (\n `Stack '${stackId}' is not a stack the source '${source}' offers. ` +\n `A marketplace ships its own stacks; the CLI's built-in ones belong to the default ` +\n `public marketplace alone.`\n );\n}\n\n/**\n * The sentence a skill's cue falls back to when the skill states none of its own — the category\n * key, as a whole sentence, because `agent.liquid` renders it verbatim as a bullet.\n *\n * Exported because more than one surface must produce it word for word, which is the carve-out\n * CLAUDE.md makes for a definition every caller is meant to reach rather than restate.\n * `registerSkillOnDisk` in `seed/external-skills.ts` is the second caller: a carried skill's\n * cue is reachable by two routes — that file writes it into the installed `metadata.yaml`, and\n * {@link statedUsageFor} answers for it during the run that seats it, before any metadata exists\n * — so two spellings meant one sub-agent could read a different sentence for the same skill\n * depending on which command last touched it. The editor's preview\n * (`apps/editor/src/features/configure/lib/output-preview.ts`) mirrors this one deliberately\n * rather than importing it.\n */\nexport function defaultUsageGuidance(category: string): string {\n return `Use when working with ${category}.`;\n}\n\n/**\n * The one sentence a compiled sub-agent reads as its cue to load a skill.\n *\n * Every skill states that sentence for itself in its `metadata.yaml` `usageGuidance`, so the\n * catalogue's own words are what a reference carries. {@link defaultUsageGuidance} is what remains\n * when there is nothing to read — an id the matrix does not carry (local, marketplace, withdrawn),\n * or one it carries that states no guidance, which is ordinary rather than malformed since the\n * field is optional on `SkillCore` and on `matrixRawMetadataSchema`.\n *\n * A BLANK sentence counts as none, and `??` alone does not say so: `usageGuidance` is\n * `z.string().exactOptional()`, so a catalogue stating an empty string is valid — and an empty\n * bullet is a row of the activation protocol saying nothing, which is strictly worse than the\n * category sentence it displaced.\n */\nfunction statedUsageFor(skillId: SkillId, category: Category): string {\n const stated = matrix.skills[skillId]?.usageGuidance;\n return stated !== undefined && stated.trim() !== \"\" ? stated : defaultUsageGuidance(category);\n}\n\n// Converts a StackAgentConfig (category -> SkillAssignment[]) to an array of SkillReferences.\n// Values are already normalized to SkillAssignment[] by loadStacks().\nexport function resolveAgentConfigToSkills(agentConfig: StackAgentConfig): SkillReference[] {\n return typedEntries<Category, SkillAssignment[]>(agentConfig).flatMap(([category, assignments]) =>\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- typedEntries/Object.entries launders the `| undefined` a Partial<Record> admits out of its result type, so this guard reads as dead while still covering an explicitly-undefined slot\n (assignments ?? []).map((assignment): SkillReference => ({\n id: assignment.id,\n usage: statedUsageFor(assignment.id, category),\n preloaded: assignment.preloaded ?? false,\n })),\n );\n}\n\n/** Extracts all unique skill IDs from a stack config (agent -> category -> SkillAssignment[]). */\nexport function getStackSkillIds(stack: Record<string, StackAgentConfig>): SkillId[] {\n return pipe(\n Object.values(stack),\n flatMap(resolveAgentConfigToSkills),\n (refs) => refs.map((r) => r.id),\n unique(),\n );\n}\n","import { EFFORT_NAMES, MODEL_NAMES } from \"@workspace/matrix\"\nimport { groupBy, unique } from \"remeda\"\n\nimport { isExclusiveCategory, type CompileCatalog } from \"./catalog.js\"\nimport {\n INDENT_STEP,\n brokenUnionLayout,\n flatUnion,\n quoteText,\n renderKey,\n renderTypeImportLine,\n renderUnionBody,\n spaces,\n unionLayout,\n} from \"./installed-format.js\"\nimport { LOCAL_PSEUDO_CATEGORY } from \"./paths.js\"\nimport {\n activeAgentNames,\n activeProjectAgentNames,\n} from \"./scope-predicates.js\"\nimport { bytewise } from \"./string.js\"\nimport { typedEntries, typedKeys } from \"./typed-object.js\"\nimport type {\n AgentName,\n Category,\n CategoryPath,\n ProjectConfig,\n SkillId,\n} from \"./types.js\"\n\n/**\n * Renders `config-types.ts`; writes nothing. The disk-probing half — deciding\n * whether a project extends a global types file, and computing the relative\n * specifier to it — stayed in the CLI's `config-types-writer.ts`, because a\n * browser has no disk to probe and `path.relative` between two scopes' source\n * folders is a fact about one machine.\n */\n\n/**\n * Emitted for a union with no members. `never` is the identity element for a\n * union: an empty install must accept NO member, and `never | \"web-framework-react\"`\n * reduces to `\"web-framework-react\"`, so a project types file that extends an empty\n * global union still narrows. Emitting `string` here would instead absorb every\n * literal and silently disable type checking of the generated config.ts.\n */\nconst EMPTY_UNION_TYPE = \"never\"\n\n/**\n * Extra just-created skill IDs / agent names / domains / categories to fold into\n * a regenerated config-types.ts (entities that exist in config but not yet in the\n * loaded matrix). buildProjectTypesExtras returns Required<ConfigTypesExtras>.\n */\nexport type ConfigTypesExtras = {\n extraSkillIds?: string[]\n extraAgentNames?: string[]\n extraDomains?: string[]\n extraCategories?: string[]\n}\n\n/**\n * A vocabulary constant as a single-line TypeScript literal union, inside an\n * emitted property where a break would need a layout of its own.\n *\n * That it stays on one line is an assumption about the lists — both are\n * generated from the matrix and both are short — rather than something this\n * function arranges. Nothing guards it here; what does is the fixed-point\n * assertion in `contract/emission-scenarios.test.ts`, which renders both of\n * these lines in every scenario and reddens the moment either grows past the\n * print width, because prettier would then break what this does not.\n */\nfunction formatLiteralUnion(members: readonly string[]): string {\n return flatUnion(members.map(quoteText))\n}\n\n/**\n * Types emitted before the dynamically-generated StackAgentConfig.\n * Includes InstallMode, SkillConfig, AgentScopeConfig, and the generic SkillAssignment.\n */\nexport const PROJECT_CONFIG_TYPES_BEFORE = `export type InstallMode = 'eject' | 'plugin' | 'mixed'\n\nexport type SkillConfig = {\n id: SkillId\n scope: 'project' | 'global'\n origin: string\n excluded?: boolean\n}\n\nexport type AgentScopeConfig = {\n name: AgentName\n scope: 'project' | 'global'\n model?: ${formatLiteralUnion(MODEL_NAMES)}\n effort?: ${formatLiteralUnion(EFFORT_NAMES)}\n excluded?: boolean\n}\n\nexport type SkillAssignment<S extends SkillId = SkillId> = S | { id: S; preloaded: boolean }\n`\n\n/**\n * The ProjectConfig interface, emitted after StackAgentConfig.\n */\nexport const PROJECT_CONFIG_INTERFACE_AFTER = `export interface ProjectConfig {\n /** Project/plugin name (kebab-case) */\n name: string\n\n /** Project description */\n description?: string\n\n /** Per-agent configuration with scope */\n agents: AgentScopeConfig[]\n\n /** Per-skill configuration with scope and provenance */\n skills: SkillConfig[]\n\n /** Author handle (e.g., \"@vince\") */\n author?: string\n\n /** Stack configuration: agent -> category -> skill assignment */\n stack?: Partial<Record<ProjectAgentName, StackAgentConfig>>\n\n /** The marketplace this install reads skills from, as a path or URL */\n marketplace?: string\n\n /** The name that marketplace's manifest gives it, which plugins are registered under */\n marketplaceName?: string\n\n /** Agents source path or URL (when agents come from a different source than skills) */\n agentsSource?: string\n\n /** Selected domains from the wizard */\n selectedDomains?: Domain[]\n\n /** Branding overrides for white-labeling the CLI */\n branding?: { name?: string }\n\n /** Custom skills directory override (default: \"src/skills\") */\n skillsDir?: string\n\n /** Custom agents directory override (default: \"src/agents\") */\n agentsDir?: string\n\n /** Custom stacks file path override (default: \"config/stacks.ts\") */\n stacksFile?: string\n\n /** Custom categories file path override (default: \"config/skill-categories.ts\") */\n categoriesFile?: string\n\n /** Custom rules file path override (default: \"config/skill-rules.ts\") */\n rulesFile?: string\n\n /** Tracked project installation paths (global config only) */\n projects?: string[]\n}\n`\n\n/**\n * Loose StackAgentConfig line emitted when no per-category skill constraint applies. Admits a\n * single assignment as well as an array: project configs always get this line, and they carry the\n * bare (unwrapped) form for exclusive categories.\n */\nexport const STACK_AGENT_CONFIG_LOOSE_LINE =\n \"export type StackAgentConfig = Partial<Record<Category, SkillAssignment | SkillAssignment[]>>\"\n\n/**\n * Assembles a config-types.ts source from its per-alias union lines — the single\n * template shared by generateConfigTypesSource, generateProjectConfigTypesSource,\n * and generateBlankGlobalConfigTypesSource. Their emitted text is identical apart\n * from the alias contents, the StackAgentConfig line, and the optional\n * (project-only) import block.\n *\n * The emitted ProjectConfig interface (PROJECT_CONFIG_INTERFACE_AFTER) deliberately\n * diverges from types/config.ts: it uses the narrowed generated aliases\n * (SelectedAgentName, ProjectAgentName, per-category StackAgentConfig) so a user's\n * config.ts is type-checked against only the installed skills/agents rather than\n * the full runtime union.\n */\nexport function assembleConfigTypesSource(parts: {\n importBlock?: string\n skillId: AliasRhs\n agentName: AliasRhs\n selectedAgentName: AliasRhs\n projectAgentName: AliasRhs\n domain: AliasRhs\n category: AliasRhs\n stackAgentConfig: string\n}): string {\n const importSection = parts.importBlock ? `${parts.importBlock}\\n\\n` : \"\"\n return `// AUTO-GENERATED by agents-inc — DO NOT EDIT\n\n${importSection}${renderAlias(\"SkillId\", parts.skillId)}\n\n${renderAlias(\"AgentName\", parts.agentName)}\n\n${renderAlias(\"SelectedAgentName\", parts.selectedAgentName)}\n\n${renderAlias(\"ProjectAgentName\", parts.projectAgentName)}\n\n${renderAlias(\"Domain\", parts.domain)}\n\n${renderAlias(\"Category\", parts.category)}\n\n${PROJECT_CONFIG_TYPES_BEFORE}\n${parts.stackAgentConfig}\n\n${PROJECT_CONFIG_INTERFACE_AFTER}`\n}\n\n/**\n * What one emitted type alias is assigned.\n *\n * Members rather than the finished text, because whether they sit on the\n * declaration's own line, on an indented line below it, or one per line under a\n * leading `|` is decided by how wide they are once the alias NAME is in front\n * of them — which only the assembler knows.\n */\nexport type AliasRhs =\n | { kind: \"plain\"; members: readonly string[] }\n | {\n kind: \"sectioned\"\n custom: readonly string[]\n marketplace: readonly string[]\n }\n\n/** A union over quoted string literals, or `never` when it has no members. */\nfunction literalUnion(members: readonly string[]): AliasRhs {\n return members.length === 0\n ? typeReference(EMPTY_UNION_TYPE)\n : { kind: \"plain\", members: members.map(quoteText) }\n}\n\n/** A bare type name as an alias's whole right-hand side. */\nfunction typeReference(name: string): AliasRhs {\n return { kind: \"plain\", members: [name] }\n}\n\n/** `export type <name> = <rhs>`, laid out the way prettier lays a union out. */\nfunction renderAlias(name: string, rhs: AliasRhs): string {\n const head = `export type ${name} =`\n if (rhs.kind === \"sectioned\") {\n return `${head}\\n${renderSectionedUnion(rhs.custom, rhs.marketplace)}`\n }\n\n const layout = unionLayout(rhs.members, {\n headWidth: head.length + \" \".length,\n tailWidth: 0,\n bodyIndent: INDENT_STEP,\n })\n\n return layout === \"inline\"\n ? `${head} ${flatUnion(rhs.members)}`\n : `${head}\\n${renderUnionBody(rhs.members, layout, INDENT_STEP)}`\n}\n\n/**\n * A union under its `// Custom` and `// Marketplace` headings.\n *\n * `custom` is non-empty by construction — {@link formatMaybeSectionedUnion} is\n * the only producer of a sectioned right-hand side and it answers with a plain\n * one when nothing is custom. Both headings present puts a comment BETWEEN two\n * members, which prettier cannot fold away, so that union stays one member per\n * line however short it is; a single heading only pushes the members off the\n * declaration's line, and they rejoin below it when they fit.\n */\nfunction renderSectionedUnion(\n custom: readonly string[],\n marketplace: readonly string[]\n): string {\n if (marketplace.length > 0) {\n return [\n sectionHeading(\"Custom\"),\n renderUnionBody(custom, \"stacked\", INDENT_STEP),\n sectionHeading(\"Marketplace\"),\n renderUnionBody(marketplace, \"stacked\", INDENT_STEP),\n ].join(\"\\n\")\n }\n\n return [\n sectionHeading(\"Custom\"),\n renderUnionBody(\n custom,\n brokenUnionLayout(custom, INDENT_STEP),\n INDENT_STEP\n ),\n ].join(\"\\n\")\n}\n\n/** A `// Custom` or `// Marketplace` line above the members it introduces. */\nfunction sectionHeading(text: string): string {\n return `${spaces(INDENT_STEP)}// ${text}`\n}\n\n/**\n * Generates a per-category constrained StackAgentConfig type from skill-by-category groupings.\n * Falls back to the loose line when no categories have skills.\n *\n * The union is over WHICH skill may be assigned; exclusivity is about HOW MANY, so an exclusive\n * category emits a bare `SkillAssignment<...>` (no array) however long its candidate list is. A\n * category the catalogue does not declare is not treated as exclusive, on the same reasoning\n * `isExclusiveCategory` takes: a constraint must fire on a flag the data actually carries.\n */\nfunction generateStackAgentConfig(\n skillsByCategory: Map<Category, SkillId[]>,\n catalog: CompileCatalog\n): string {\n if (skillsByCategory.size === 0) {\n return STACK_AGENT_CONFIG_LOOSE_LINE\n }\n\n const properties = [...skillsByCategory.entries()]\n // A project commits its config-types.ts, so the key order has to be the comparator's rather\n // than the collation of whichever machine last ran the CLI.\n .sort(([a], [b]) => bytewise(a, b))\n .map(([category, skills]) => renderStackProperty(category, skills, catalog))\n\n return [\"export type StackAgentConfig = {\", ...properties, \"}\"].join(\"\\n\")\n}\n\n/**\n * One category's property, with its candidate skills laid out where they sit.\n *\n * The union is inside a type ARGUMENT rather than on a declaration's own line,\n * so its indented and one-per-line forms carry the closing `>` down with them —\n * but the widths that choose between the three are the same ones everywhere\n * else, which is why the decision comes from the shared layout rather than from\n * a count of members.\n */\nfunction renderStackProperty(\n category: Category,\n skills: SkillId[],\n catalog: CompileCatalog\n): string {\n const members = [...skills].sort().map(quoteText)\n const tail = `>${isExclusiveCategory(catalog, category) ? \"\" : \"[]\"}`\n const head = `${spaces(INDENT_STEP)}${renderKey(category)}?: SkillAssignment<`\n const bodyIndent = INDENT_STEP * 2\n\n const layout = unionLayout(members, {\n headWidth: head.length,\n tailWidth: tail.length,\n bodyIndent,\n })\n if (layout === \"inline\") return `${head}${flatUnion(members)}${tail}`\n\n return [\n head,\n renderUnionBody(members, layout, bodyIndent),\n `${spaces(INDENT_STEP)}${tail}`,\n ].join(\"\\n\")\n}\n\n/**\n * Builds a Map of Category -> SkillId[] from the catalogue, filtered to only include\n * categories and skills that are in the provided arrays.\n */\nfunction buildSkillsByCategory(\n skillIds: SkillId[],\n categories: Category[],\n catalog: CompileCatalog\n): Map<Category, SkillId[]> {\n const categorySet = new Set(categories)\n const eligible = [...new Set(skillIds)]\n .map((id) => ({ id, category: catalog.skills[id]?.category }))\n .filter(\n (entry): entry is { id: SkillId; category: Category } =>\n entry.category !== undefined &&\n entry.category !== LOCAL_PSEUDO_CATEGORY &&\n // Boundary cast: a catalogue skill's `category` is a Category, typed `string` on the\n // narrow catalogue shape so the wire `Matrix` satisfies it too. The `has` below IS the\n // runtime check the predicate rests on, so the cast only lets the probe be written.\n categorySet.has(entry.category as Category)\n )\n\n return new Map(\n typedEntries(groupBy(eligible, (entry) => entry.category)).map(\n ([category, entries]) => [category, entries.map((entry) => entry.id)]\n )\n )\n}\n\n/**\n * A category no loaded catalogue declares, which is the whole of what makes one custom.\n *\n * Deliberately not \"a category a custom skill is in\": a custom skill is PLACED in a category that\n * already exists rather than bringing one, so the skills that REFERENCE a category say nothing\n * about who declared it — and reading them that way labelled a category the public catalogue\n * ships as the user's own. The same holds for a category arriving as an extra: an extra is every\n * literal a just-written config.ts holds, most of them the catalogue's.\n */\nfunction isUndeclaredCategory(\n category: Category,\n catalog: CompileCatalog\n): boolean {\n return catalog.categories[category] === undefined\n}\n\n/**\n * A skill the loaded catalogue does not declare, or declares as the user's own.\n *\n * The same rule the category axis takes, plus the one signal skills carry that categories do not:\n * `custom: true` is written into a skill's own metadata, so a skill the catalogue holds AND flags\n * is the user's however it got there. What is NOT read is which argument the id arrived in — an\n * extra is a literal the just-written config.ts holds, and on the project standalone path that is\n * the whole configuration, most of it the catalogue's.\n *\n * `local: true` is deliberately not a second signal: an ejected catalogue skill is copied into\n * `.claude/skills/` and rediscovered as local, so it would label the catalogue's own work custom.\n */\nfunction isCustomSkill(skillId: SkillId, catalog: CompileCatalog): boolean {\n const declared = catalog.skills[skillId]\n return declared === undefined || declared.custom === true\n}\n\n/**\n * An agent the loaded source does not declare, or declares as the user's own.\n *\n * `agentNames` is every agent that source ships and `customAgentNames` the ones it marks custom,\n * so the pair is the agent axis's equivalent of the catalogue: anything outside the first is\n * nobody's declaration, anything inside the second is declared as the user's.\n */\nfunction isCustomAgent(\n agentName: AgentName,\n declared: ReadonlySet<AgentName>,\n flaggedCustom: ReadonlySet<AgentName>\n): boolean {\n return !declared.has(agentName) || flaggedCustom.has(agentName)\n}\n\n/**\n * A domain no category the loaded catalogue declares carries.\n */\nfunction isCustomDomain(\n domain: string,\n declared: ReadonlySet<string>\n): boolean {\n return !declared.has(domain)\n}\n\n/**\n * Generates a config-types.ts source from catalogue data.\n * The generated file provides type safety for config.ts via `import type` + `satisfies`.\n *\n * @param customAgentNames Agent names that are custom (from sources with `custom: true`)\n * @param extras Optional extra skill IDs or agent names to include (for just-created entities)\n * @param config Optional ProjectConfig to narrow unions to only installed items.\n * When provided, SkillId/AgentName/Category/Domain are derived from\n * the config's skills[] and agents[] rather than the full catalogue.\n */\nexport function generateConfigTypesSource(\n catalog: CompileCatalog,\n agentNames: AgentName[],\n customAgentNames: AgentName[] = [],\n extras?: ConfigTypesExtras,\n config?: ProjectConfig\n): string {\n // Boundary cast: extra IDs from CLI args may not match strict union patterns\n const extraSkillIds = (extras?.extraSkillIds ?? []) as SkillId[]\n const extraAgentNamesArr = (extras?.extraAgentNames ?? []) as AgentName[]\n const extraDomainsArr = extras?.extraDomains ?? []\n const extraCategoriesArr = (extras?.extraCategories ?? []) as Category[]\n\n let skillIds: SkillId[]\n let sortedAgents: AgentName[]\n let domains: string[]\n let categories: Category[]\n\n if (config) {\n // Narrow to only installed/configured items\n const configSkillIds = config.skills.map((s) => s.id)\n skillIds = unique([...configSkillIds, ...extraSkillIds]).sort()\n\n const configAgentNames = config.agents.map((a) => a.name)\n sortedAgents = unique([...configAgentNames, ...extraAgentNamesArr]).sort()\n\n const configCategories = deriveCategories(configSkillIds, catalog)\n categories = unique([...configCategories, ...extraCategoriesArr]).sort()\n\n // Also include config.selectedDomains (user-selected) that may not have skills in this scope\n const configDomains = deriveDomains(categories, catalog)\n domains = unique([\n ...configDomains,\n ...(config.selectedDomains ?? []),\n ...extraDomainsArr,\n ]).sort()\n } else {\n // Fall back to the full catalogue (e.g., blank global config)\n skillIds = unique([\n ...typedKeys<SkillId>(catalog.skills),\n ...extraSkillIds,\n ]).sort()\n sortedAgents = unique([...agentNames, ...extraAgentNamesArr]).sort()\n domains = unique([...extractDomains(catalog), ...extraDomainsArr]).sort()\n categories = unique([\n ...typedKeys<Category>(catalog.categories),\n ...extraCategoriesArr,\n ]).sort()\n }\n\n const declaredAgents = new Set<AgentName>(agentNames)\n const flaggedCustomAgents = new Set<AgentName>(customAgentNames)\n const declaredDomains = new Set<string>(extractDomains(catalog))\n\n const skillIdLine = formatMaybeSectionedUnion(skillIds, (id) =>\n isCustomSkill(id, catalog)\n )\n const agentNameLine = formatMaybeSectionedUnion(sortedAgents, (name) =>\n isCustomAgent(name, declaredAgents, flaggedCustomAgents)\n )\n const domainLine = formatMaybeSectionedUnion(domains, (domain) =>\n isCustomDomain(domain, declaredDomains)\n )\n const categoryLine = formatMaybeSectionedUnion(categories, (category) =>\n isUndeclaredCategory(category, catalog)\n )\n\n const selectedAgents = config?.agents ? activeAgentNames(config.agents) : []\n const selectedAgentNameLine =\n selectedAgents.length > 0\n ? literalUnion(selectedAgents)\n : typeReference(\"AgentName\")\n\n const projectScopedAgents = config?.agents\n ? activeProjectAgentNames(config.agents)\n : []\n const projectAgentNameLine =\n projectScopedAgents.length > 0\n ? literalUnion(projectScopedAgents)\n : typeReference(\"SelectedAgentName\")\n\n const skillsByCategory = buildSkillsByCategory(skillIds, categories, catalog)\n const stackAgentConfigType = generateStackAgentConfig(\n skillsByCategory,\n catalog\n )\n\n return assembleConfigTypesSource({\n skillId: skillIdLine,\n agentName: agentNameLine,\n selectedAgentName: selectedAgentNameLine,\n projectAgentName: projectAgentNameLine,\n domain: domainLine,\n category: categoryLine,\n stackAgentConfig: stackAgentConfigType,\n })\n}\n\n// Sorted deriveDomains over every category — kept separate: this is the full-catalogue domain\n// union for the standalone types file, not a per-selection derivation.\nfunction extractDomains(catalog: CompileCatalog): string[] {\n return deriveDomains(typedKeys<Category>(catalog.categories), catalog).sort()\n}\n\n/** Category present and not the \"local\" pseudo-category. */\nconst isNonLocalCategory = (\n category: CategoryPath | undefined\n): category is Category =>\n Boolean(category) && category !== LOCAL_PSEUDO_CATEGORY\n\n/**\n * Derives the set of categories that the given skill IDs belong to,\n * by looking up each skill's category in the catalogue.\n */\nexport function deriveCategories(\n skillIds: SkillId[],\n catalog: CompileCatalog\n): Category[] {\n return unique(\n skillIds\n // Boundary cast: CategoryPath to Category for catalogue key lookup\n .map((id) => catalog.skills[id]?.category as CategoryPath | undefined)\n .filter(isNonLocalCategory)\n )\n}\n\n/**\n * Derives the set of domains that the given categories belong to,\n * by looking up each category's domain in the catalogue.\n */\nexport function deriveDomains(\n categories: Category[],\n catalog: CompileCatalog\n): string[] {\n return unique(\n categories\n .map((cat) => catalog.categories[cat]?.domain)\n .filter((domain): domain is string => domain !== undefined)\n )\n}\n\n/**\n * A union split into its `// Custom` and `// Marketplace` sections when it has\n * custom members, and a plain one when it has none.\n */\nfunction formatMaybeSectionedUnion<T extends string>(\n members: T[],\n isCustom: (member: T) => boolean\n): AliasRhs {\n if (members.length === 0) {\n return typeReference(EMPTY_UNION_TYPE)\n }\n\n const custom = members.filter(isCustom)\n const marketplace = members.filter((m) => !isCustom(m))\n\n // No custom members: no headings to draw, so the union is an ordinary one.\n if (custom.length === 0) {\n return literalUnion(members)\n }\n\n return {\n kind: \"sectioned\",\n custom: custom.map(quoteText),\n marketplace: marketplace.map(quoteText),\n }\n}\n\nexport type ProjectConfigTypesOptions = {\n /**\n * Absolute path to the global scope's source folder.\n * When set, generates import statements that extend global types.\n */\n globalTypesImportPath: string\n /** Project-only skill IDs (not including global) */\n projectSkillIds: string[]\n /** Project-only agent names (not including global) */\n projectAgentNames: string[]\n /** Project-only domains (not including global) */\n projectDomains: string[]\n /** Project-only categories (not including global) */\n projectCategories?: string[]\n /** Selected agent names from config (narrows SelectedAgentName) */\n selectedAgentNames?: string[]\n /** Project-scoped agent names (narrows ProjectAgentName for stack keys) */\n projectScopedAgentNames?: string[]\n}\n\n/**\n * Generates a project config-types.ts source that imports global types and extends them.\n * Each type union is `GlobalType | \"project-item-1\" | \"project-item-2\"`.\n * When projectCategories are provided, Category extends GlobalCategory instead of being `string`.\n */\nexport function generateProjectConfigTypesSource(\n options: ProjectConfigTypesOptions\n): string {\n const importPath = `${options.globalTypesImportPath}/config-types`\n\n const skillIdUnion = formatExtendedUnion(\n \"GlobalSkillId\",\n options.projectSkillIds\n )\n const agentNameUnion = formatExtendedUnion(\n \"GlobalAgentName\",\n options.projectAgentNames\n )\n const domainUnion = formatExtendedUnion(\n \"GlobalDomain\",\n options.projectDomains\n )\n\n const projectCategories = options.projectCategories ?? []\n const categoryUnion = formatExtendedUnion(\"GlobalCategory\", projectCategories)\n\n const selectedAgentNameUnion = options.selectedAgentNames?.length\n ? literalUnion(options.selectedAgentNames)\n : typeReference(\"AgentName\")\n\n const projectAgentNameUnion = options.projectScopedAgentNames?.length\n ? literalUnion(options.projectScopedAgentNames)\n : typeReference(\"SelectedAgentName\")\n\n // Category comes across as GlobalCategory whether or not this project adds\n // any of its own, because the alias is re-exported either way.\n const importBlock = renderTypeImportLine(\n [\n \"SkillId as GlobalSkillId\",\n \"AgentName as GlobalAgentName\",\n \"Domain as GlobalDomain\",\n \"Category as GlobalCategory\",\n ],\n importPath\n )\n\n return assembleConfigTypesSource({\n importBlock,\n skillId: skillIdUnion,\n agentName: agentNameUnion,\n selectedAgentName: selectedAgentNameUnion,\n projectAgentName: projectAgentNameUnion,\n domain: domainUnion,\n category: categoryUnion,\n stackAgentConfig: STACK_AGENT_CONFIG_LOOSE_LINE,\n })\n}\n\n/**\n * Generates blank global config-types source (all types are `never`).\n */\nexport function generateBlankGlobalConfigTypesSource(): string {\n return assembleConfigTypesSource({\n skillId: typeReference(EMPTY_UNION_TYPE),\n agentName: typeReference(EMPTY_UNION_TYPE),\n selectedAgentName: typeReference(EMPTY_UNION_TYPE),\n projectAgentName: typeReference(\"SelectedAgentName\"),\n domain: typeReference(EMPTY_UNION_TYPE),\n category: typeReference(EMPTY_UNION_TYPE),\n stackAgentConfig: STACK_AGENT_CONFIG_LOOSE_LINE,\n })\n}\n\n/**\n * A union that extends a global type alias: `GlobalType` on its own when this\n * project adds nothing, and `GlobalType | \"a\" | \"b\"` when it does.\n */\nfunction formatExtendedUnion(\n globalTypeName: string,\n projectMembers: readonly string[]\n): AliasRhs {\n if (projectMembers.length === 0) {\n return typeReference(globalTypeName)\n }\n\n return {\n kind: \"plain\",\n members: [globalTypeName, ...[...projectMembers].sort().map(quoteText)],\n }\n}\n","import path from \"path\";\n\nimport type { AgentDefinition, AgentName, MergedSkillsMatrix, ProjectConfig } from \"../../types\";\nimport type { Provider } from \"../../consts\";\nimport { globalInstallRoot, STANDARD_FILES } from \"../../consts\";\n// The gate's private token module, imported here by exception (eslint records\n// it): this is one of the two enforcement guards, and `gate-token.ts` is a\n// dependency-free leaf, so the import cannot cycle back through the gate.\nimport { GlobalPairWriteViolation } from \"../config-gate/gate-token.js\";\nimport { providerInUse, sourceFolderInUse } from \"../installation/install-layout\";\nimport { isHomeDirectory } from \"../installation/is-home-directory\";\nimport { fileExists, writeFile } from \"../../utils/fs\";\nimport { verbose } from \"../../utils/logger\";\nimport { typedKeys } from \"../../utils/typed-object\";\nimport {\n generateConfigTypesSource,\n generateProjectConfigTypesSource,\n type ConfigTypesExtras,\n} from \"@workspace/compile/config-types-source\";\n\nimport { loadProjectConfigFromDir } from \"./project-config\";\nimport { activeAgentNames, activeProjectAgentNames } from \"./scope-predicates\";\n\n/**\n * The half of the types writer that reads the machine: whether a global types file exists to\n * extend, the relative specifier to it, and the write itself. Split out from\n * `config-types-writer.ts` when the renderers moved into `@workspace/compile` — those three were\n * the whole reason that module reached `fileExists`, `writeFile`, `loadProjectConfigFromDir` and\n * `globalInstallRoot`, and a browser has none of them. `config-types-writer.ts` re-exports every\n * name below, so no call site moved.\n */\n\n/**\n * Returns the absolute path to `provider`'s global config-types.ts if it exists, or null.\n * Used to determine whether a project config-types.ts should import from global.\n *\n * The provider is the asking PROJECT's, not the global root's: a project inherits only from the\n * global installation of its own provider, so a Codex project under a Claude global finds none\n * and writes a standalone types file — which is the same answer it gets when there is no global\n * installation at all.\n */\nexport async function getGlobalConfigTypesPath(provider: Provider): Promise<string | null> {\n const globalConfigTypesPath = path.join(\n sourceFolderInUse(globalInstallRoot(), provider).dir,\n STANDARD_FILES.CONFIG_TYPES_TS,\n );\n if (await fileExists(globalConfigTypesPath)) {\n return globalConfigTypesPath;\n }\n return null;\n}\n\n/**\n * Computes a relative import path from a project's source folder to the global one.\n * Returns a POSIX-style relative path suitable for TypeScript import statements.\n *\n * Both ends are resolved rather than assumed, so a project and a global on different layouts each\n * contribute their own folder and the specifier spans whatever depth separates them. A project\n * inherits only from the global of the SAME provider, which is why ONE provider argument governs\n * both ends — it was one shared default until C2, and a specifier built from two different\n * providers' folders would name a file the project cannot compile against.\n *\n * Deliberately NOT part of the shared package: it is `path.relative` against the running\n * machine's `$HOME`, so a browser has nothing to compute it from and the preview draws a\n * placeholder for that one line instead of inventing a path.\n */\nfunction computeGlobalTypesImportPath(projectDir: string, provider: Provider): string {\n const projectSourceDir = sourceFolderInUse(projectDir, provider).dir;\n const globalSourceDir = sourceFolderInUse(globalInstallRoot(), provider).dir;\n const relativePath = path.relative(projectSourceDir, globalSourceDir);\n // Convert to POSIX separators for TypeScript imports\n return relativePath.split(path.sep).join(\"/\");\n}\n\nexport type ConfigTypesBackgroundData = {\n matrix: MergedSkillsMatrix;\n agentNames: AgentName[];\n customAgentNames: AgentName[];\n};\n\n/**\n * The one constructor for {@link ConfigTypesBackgroundData}, beside the type it builds.\n *\n * Only `customAgentNames` is derived, and that derivation is the whole reason this is a function\n * rather than an object literal at each call site: it was written out three times — here, in\n * `config-gate/pair-writer.ts` and in `config-gate/propagate.ts` — and three producers of one\n * value are three things that can disagree about which sub-agents an emitted `AgentName` union\n * files under its `// Custom` heading. Closing two of the three would have been worse than\n * closing none: the two that agree make the third read as rigorous while it drifts.\n */\nexport function buildConfigTypesBackgroundData(\n matrix: MergedSkillsMatrix,\n agents: Partial<Record<AgentName, AgentDefinition>>,\n): ConfigTypesBackgroundData {\n const agentNames = typedKeys<AgentName>(agents);\n return {\n matrix,\n agentNames,\n customAgentNames: agentNames.filter((name) => agents[name]?.custom === true),\n };\n}\n\n/**\n * Regenerates config-types.ts with the latest matrix data, merging in any extra entities\n * that were just created (e.g., a new skill or agent). Errors propagate to callers.\n *\n * @param projectDir The project root directory\n * @param backgroundData Promise of the data {@link buildConfigTypesBackgroundData} assembles\n * @param extras Optional extra skill IDs or agent names to include (for just-created entities)\n */\nexport async function regenerateConfigTypes(\n projectDir: string,\n backgroundData: Promise<ConfigTypesBackgroundData>,\n extras?: ConfigTypesExtras,\n): Promise<void> {\n // Read once, at the top, and handed to every path this function builds: the types file, the\n // global one it may extend and the specifier between them all have to name ONE installation.\n const provider = providerInUse(projectDir);\n\n // The home directory's config-types.ts is the global pair's types half, which\n // only config-gate may write. Refusing here rather than leaving it to the\n // write primitive's tripwire names the offending entry point, and — unlike the\n // tripwire — survives a unit test that mocks `utils/fs`.\n if (isHomeDirectory(projectDir)) {\n throw new GlobalPairWriteViolation(\n path.join(sourceFolderInUse(projectDir, provider).dir, STANDARD_FILES.CONFIG_TYPES_TS),\n );\n }\n\n const data = await backgroundData;\n\n const sourceFolderDir = sourceFolderInUse(projectDir, provider).dir;\n\n // When a global installation of this provider exists, the project's config-types.ts\n // imports from the global one.\n const globalConfigTypes = await getGlobalConfigTypesPath(provider);\n const loadedConfig = await loadProjectConfigFromDir(projectDir, provider);\n\n // Otherwise the standalone form, narrowed to the config on disk, exactly as the wizard write\n // path narrows it. The full matrix is the fallback only when there is no config\n // to narrow to — a union covering every skill the source offers would declare\n // literals the sibling config.ts never installs, and `satisfies` would stop\n // catching a config that names one of them.\n const source = globalConfigTypes\n ? renderTypesExtendingGlobal(projectDir, provider, loadedConfig?.config.agents, extras)\n : generateConfigTypesSource(\n data.matrix,\n data.agentNames,\n data.customAgentNames,\n extras,\n loadedConfig?.config,\n );\n\n const configTypesPath = path.join(sourceFolderDir, STANDARD_FILES.CONFIG_TYPES_TS);\n await writeFile(configTypesPath, source);\n verbose(`Regenerated ${STANDARD_FILES.CONFIG_TYPES_TS}`);\n}\n\n/**\n * The project config-types.ts that imports the global one and extends it: `extras` supply the\n * project's own literals, and the config's active agents supply the two agent-name unions.\n */\nfunction renderTypesExtendingGlobal(\n projectDir: string,\n provider: Provider,\n agents: ProjectConfig[\"agents\"] | undefined,\n extras: ConfigTypesExtras | undefined,\n): string {\n const selectedAgentNames = agents ? activeAgentNames(agents) : undefined;\n const projectScopedAgentNames = agents ? activeProjectAgentNames(agents) : undefined;\n const source = generateProjectConfigTypesSource({\n globalTypesImportPath: computeGlobalTypesImportPath(projectDir, provider),\n projectSkillIds: extras?.extraSkillIds ?? [],\n projectAgentNames: extras?.extraAgentNames ?? [],\n projectDomains: extras?.extraDomains ?? [],\n projectCategories: extras?.extraCategories ?? [],\n ...(selectedAgentNames?.length ? { selectedAgentNames } : {}),\n ...(projectScopedAgentNames?.length ? { projectScopedAgentNames } : {}),\n });\n verbose(\"Using project config-types.ts that imports from global\");\n return source;\n}\n","import path from \"path\";\nimport { parse as parseYaml, stringify as stringifyYaml } from \"yaml\";\n\nimport { fileExists, readFile, writeFile } from \"../../utils/fs\";\nimport { getCurrentDate } from \"../versioning\";\nimport { SCHEMA_PATHS, STANDARD_FILES, YAML_FORMATTING } from \"../../consts\";\nimport { yamlSchemaComment, stripYamlSchemaComment } from \"../../utils/yaml-schema\";\nimport type { SkillId } from \"../../types\";\nimport { formatZodIssues, localSkillMetadataSchema } from \"../schemas\";\nimport { warn } from \"../../utils/logger\";\nimport { getErrorMessage } from \"../../utils/errors\";\n\n/**\n * Tracks the original marketplace source of a locally-installed skill.\n *\n * Written into each skill's metadata.yaml under the `forkedFrom` key when a skill\n * is copied from a source repository to the local `.claude/skills/` directory.\n * Used for version comparison, update detection, and provenance tracking.\n */\nexport type ForkedFromMetadata = {\n /** Canonical skill ID from the source repository (e.g., \"cc-ts-react-hook-form\") */\n skillId: SkillId;\n /** SHA-256 hash of the source SKILL.md content at the time of installation */\n contentHash: string;\n /** ISO date string (YYYY-MM-DD) when the skill was installed or last updated */\n date: string;\n /** Source URL the skill was installed from (e.g., \"github:agents-inc/skills\") */\n source?: string;\n /**\n * The skill's own DIRECTORY inside the repository `source` names — `skills/brainstorming`,\n * never the SKILL.md.\n *\n * Recorded only where it is the whole address. A marketplace resolves every id it serves, so a\n * skill ejected from one is installed again by its id and where inside that repository it lived\n * is nobody else's business. A skill a shared configuration CARRIED answers to no catalogue at\n * all, and this pair — repository and directory — is the only address it has: without it, the\n * producer that shares this installation can name the id and not the content behind it.\n */\n path?: string;\n};\n\n/**\n * Full metadata.yaml content for a locally-installed skill.\n *\n * Parsed from the `metadata.yaml` file in each skill directory under `.claude/skills/`.\n * Uses an index signature to preserve unknown fields written by other tools.\n */\nexport type LocalSkillMetadata = {\n /** Provenance metadata linking back to the original source skill, if any */\n forkedFrom?: ForkedFromMetadata;\n [key: string]: unknown;\n};\n\n/**\n * Reads forkedFrom metadata from a skill's metadata.yaml file.\n *\n * This metadata tracks the original marketplace source of a locally-installed skill,\n * enabling version comparison and update detection via content hash matching.\n *\n * @param skillDir - Absolute path to the skill directory (e.g., `/project/.claude/skills/react-hook-form`)\n * @returns The `forkedFrom` metadata if present and valid, `null` if the file doesn't exist,\n * has no `forkedFrom` field, or fails Zod validation (warns on invalid metadata)\n *\n * @example\n * ```ts\n * const metadata = await readForkedFromMetadata(\"/project/.claude/skills/react-hook-form\");\n * if (metadata) {\n * console.log(`Installed from ${metadata.skillId} on ${metadata.date}`);\n * }\n * ```\n */\nexport async function readForkedFromMetadata(skillDir: string): Promise<ForkedFromMetadata | null> {\n const metadata = await readLocalSkillMetadata(skillDir);\n return metadata?.forkedFrom ?? null;\n}\n\n/**\n * Reads the full local skill metadata from a skill's metadata.yaml file.\n *\n * Returns the parsed metadata including `forkedFrom` field.\n * Used by the uninstall command to determine whether a skill was installed by the CLI.\n *\n * @param skillDir - Absolute path to the skill directory\n * @returns The parsed metadata if valid, `null` if the file doesn't exist or is invalid\n */\nexport async function readLocalSkillMetadata(skillDir: string): Promise<LocalSkillMetadata | null> {\n const metadataPath = path.join(skillDir, STANDARD_FILES.METADATA_YAML);\n\n if (!(await fileExists(metadataPath))) {\n return null;\n }\n\n const content = await readFile(metadataPath);\n const read = readYaml(content);\n\n if (!read.parsed) {\n warn(`Invalid metadata.yaml at ${metadataPath}: ${read.reason}`);\n return null;\n }\n\n const result = localSkillMetadataSchema.safeParse(read.value);\n\n if (!result.success) {\n warn(`Invalid metadata.yaml at ${metadataPath}: ${formatZodIssues(result.error.issues)}`);\n return null;\n }\n\n return result.data;\n}\n\n/**\n * Writes forked-from provenance metadata into a skill's metadata.yaml.\n *\n * Reads the existing metadata.yaml (preserving any extra fields), sets the\n * `forkedFrom` block with the given skill ID, content hash, and current date,\n * then writes the file back with a YAML language server schema comment.\n *\n * Called during skill installation (by the skill copier) to record where a\n * locally-installed skill originated from.\n *\n * @param destPath - Absolute path to the skill directory containing metadata.yaml.\n * The file must already exist (created during skill copy).\n * @param skillId - Canonical skill ID from the source repository (e.g., \"cc-ts-react-hook-form\")\n * @param contentHash - SHA-256 hash of the source SKILL.md content at install time\n * @param origin - Where the bytes came from: the repository ref, and the directory inside it for\n * a skill nothing but that directory can install again. A bag rather than two\n * positional strings, because two adjacent optional strings can be swapped\n * silently and these two mean entirely different things.\n *\n * @remarks\n * **Side effect:** Overwrites `{destPath}/metadata.yaml` on disk. Existing fields\n * are preserved if the file parses successfully; if parsing fails, only `forkedFrom`\n * is written (with a warning logged).\n */\nexport async function injectForkedFromMetadata(\n destPath: string,\n skillId: SkillId,\n contentHash: string,\n origin: Pick<ForkedFromMetadata, \"source\" | \"path\"> = {},\n): Promise<void> {\n const metadataPath = path.join(destPath, STANDARD_FILES.METADATA_YAML);\n const rawContent = await readFile(metadataPath);\n const { yamlContent } = stripYamlSchemaComment(rawContent);\n\n const metadata: LocalSkillMetadata = {\n ...existingMetadataFields(yamlContent, metadataPath),\n forkedFrom: {\n skillId,\n contentHash,\n date: getCurrentDate(),\n ...(origin.source !== undefined && { source: origin.source }),\n ...(origin.path !== undefined && { path: origin.path }),\n },\n };\n\n await writeMetadataYaml(metadataPath, metadata, `${yamlSchemaComment(SCHEMA_PATHS.metadata)}\\n`);\n}\n\n/**\n * Serializes skill metadata with the standard line-width policy and writes it,\n * optionally prefixed by a yaml-language-server schema comment.\n */\nexport async function writeMetadataYaml(\n filePath: string,\n metadata: unknown,\n schemaComment = \"\",\n): Promise<void> {\n const yamlContent = stringifyYaml(metadata, { lineWidth: YAML_FORMATTING.LINE_WIDTH_NONE });\n await writeFile(filePath, schemaComment + yamlContent);\n}\n\n/** What a YAML read can answer: the document, or why no parser could produce one. */\ntype YamlRead =\n | { readonly parsed: true; readonly value: unknown }\n | { readonly parsed: false; readonly reason: string };\n\n/**\n * Parses YAML without letting a syntax error escape.\n *\n * The two ways a metadata file fails reach a reader by different routes, and only one of them was\n * ever handled here: a wrong SHAPE is caught by the schema's `safeParse`, while a file no parser\n * can read throws out of `parseYaml` BEFORE `safeParse` is called at all. Both readers below\n * promise to survive an invalid file and neither kept that promise for the second kind.\n *\n * `readSkillMetadata` in `lib/loading/loader.ts` is the same guard written out at its own call\n * site; this is that shape, shared by the two readers here rather than repeated.\n */\nfunction readYaml(content: string): YamlRead {\n try {\n return { parsed: true, value: parseYaml(content) };\n } catch (error) {\n return { parsed: false, reason: getErrorMessage(error) };\n }\n}\n\n/**\n * The fields a metadata.yaml already holds, or none of them.\n *\n * Answers empty and warns for EITHER failure — a file no parser can read, or one whose shape the\n * schema refuses. Both are the same event from the author's side: the fields they wrote are about\n * to be replaced by a file carrying only `forkedFrom`, and the warning is the only thing that says\n * so. Keeping the two apart here would mean two warnings for one consequence.\n */\nfunction existingMetadataFields(\n yamlContent: string,\n metadataPath: string,\n): Partial<LocalSkillMetadata> {\n const read = readYaml(yamlContent);\n\n if (read.parsed) {\n const result = localSkillMetadataSchema.safeParse(read.value);\n if (result.success) return result.data;\n }\n\n warn(`Malformed metadata.yaml at '${metadataPath}' — existing fields may be lost`);\n return {};\n}\n","import { createHash } from \"crypto\";\nimport path from \"path\";\nimport { getErrorMessage } from \"../utils/errors\";\nimport { readFile, readFileSafe, writeFile, glob, fileExists } from \"../utils/fs\";\nimport { warn } from \"../utils/logger\";\nimport {\n DEFAULT_VERSION,\n MAX_PLUGIN_FILE_SIZE,\n STANDARD_FILES,\n HASH_PREFIX_LENGTH,\n} from \"../consts\";\nimport { pluginManifestSchema } from \"./schemas\";\nimport { SKILL_CONTENT_FILES, SKILL_CONTENT_DIRS } from \"./metadata-keys\";\n\nconst ISO_DATE_LENGTH = 10;\n\nexport function getCurrentDate(): string {\n return new Date().toISOString().slice(0, ISO_DATE_LENGTH);\n}\n\nexport function computeStringHash(content: string): string {\n const hash = createHash(\"sha256\");\n hash.update(content);\n return hash.digest(\"hex\").slice(0, HASH_PREFIX_LENGTH);\n}\n\nexport async function computeFileHash(filePath: string): Promise<string> {\n const content = await readFile(filePath);\n return computeStringHash(content);\n}\n\nexport async function computeSkillFolderHash(skillPath: string): Promise<string> {\n const contents: string[] = [];\n\n for (const fileName of SKILL_CONTENT_FILES) {\n const filePath = path.join(skillPath, fileName);\n if (await fileExists(filePath)) {\n const content = await readFile(filePath);\n contents.push(`${fileName}:${content}`);\n }\n }\n\n for (const dirName of SKILL_CONTENT_DIRS) {\n const dirPath = path.join(skillPath, dirName);\n if (await fileExists(dirPath)) {\n const files = await glob(\"**/*\", dirPath);\n for (const file of files.sort()) {\n const filePath = path.join(dirPath, file);\n const content = await readFile(filePath);\n contents.push(`${dirName}/${file}:${content}`);\n }\n }\n }\n\n const combined = contents.join(\"\\n---\\n\");\n return computeStringHash(combined);\n}\n\n/**\n * Plugin versioning utilities shared by skill, agent, and stack plugin compilers.\n * Reads existing plugin.json + .content-hash, bumps semver major on content change.\n */\n\nconst CONTENT_HASH_FILE = \".content-hash\";\n\nexport function parseMajorVersion(version: string): number {\n const [, major] = version.match(/^(\\d+)\\./) ?? [];\n return major === undefined ? 1 : parseInt(major, 10);\n}\n\nexport function bumpMajorVersion(version: string): string {\n const major = parseMajorVersion(version);\n return `${major + 1}.0.0`;\n}\n\nasync function readExistingPluginManifest(\n pluginDir: string,\n getManifestPath: (dir: string) => string,\n): Promise<{ version: string; contentHash: string | undefined } | null> {\n const manifestPath = getManifestPath(pluginDir);\n\n if (!(await fileExists(manifestPath))) {\n return null;\n }\n\n try {\n const content = await readFileSafe(manifestPath, MAX_PLUGIN_FILE_SIZE);\n const manifest = pluginManifestSchema.parse(JSON.parse(content));\n\n const hashFilePath = manifestPath.replace(STANDARD_FILES.PLUGIN_JSON, CONTENT_HASH_FILE);\n const contentHash = (await fileExists(hashFilePath))\n ? (await readFile(hashFilePath)).trim()\n : undefined;\n\n return {\n version: manifest.version ?? DEFAULT_VERSION,\n contentHash,\n };\n } catch (error) {\n warn(`Failed to read plugin manifest at '${manifestPath}': ${getErrorMessage(error)}`);\n return null;\n }\n}\n\nexport async function determinePluginVersion(\n newHash: string,\n pluginDir: string,\n getManifestPath: (dir: string) => string,\n): Promise<{ version: string; contentHash: string }> {\n const existing = await readExistingPluginManifest(pluginDir, getManifestPath);\n\n if (!existing) {\n return {\n version: DEFAULT_VERSION,\n contentHash: newHash,\n };\n }\n\n if (existing.contentHash !== newHash) {\n return {\n version: bumpMajorVersion(existing.version),\n contentHash: newHash,\n };\n }\n\n return {\n version: existing.version,\n contentHash: newHash,\n };\n}\n\nexport async function writeContentHash(\n pluginDir: string,\n contentHash: string,\n getManifestPath: (dir: string) => string,\n): Promise<void> {\n const hashFilePath = getManifestPath(pluginDir).replace(\n STANDARD_FILES.PLUGIN_JSON,\n CONTENT_HASH_FILE,\n );\n await writeFile(hashFilePath, contentHash);\n}\n","/** Generates a yaml-language-server schema comment for the top of YAML files. */\nexport function yamlSchemaComment(schemaPath: string): string {\n return `# yaml-language-server: $schema=${schemaPath}`;\n}\n\n/**\n * Splits YAML file content into its leading yaml-language-server schema\n * comment (empty string when absent, trailing newline included when present)\n * and the parseable YAML body.\n */\nexport function stripYamlSchemaComment(content: string): {\n schemaComment: string;\n yamlContent: string;\n} {\n const lines = content.split(\"\\n\");\n if (lines[0]?.startsWith(\"# yaml-language-server:\")) {\n return { schemaComment: `${lines[0]}\\n`, yamlContent: lines.slice(1).join(\"\\n\") };\n }\n return { schemaComment: \"\", yamlContent: content };\n}\n","import path from \"path\";\n\nimport { copy, ensureDir, isPathWithin } from \"../../utils/fs\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { plural } from \"../../utils/string\";\nimport { computeFileHash } from \"../versioning\";\nimport { EJECT_SOURCE, SOURCE_SRC_DIR, STANDARD_FILES } from \"../../consts\";\nimport type { ResolvedSkill, SkillId } from \"../../types\";\nimport type { SourceLoadResult } from \"../loading\";\nimport { getSkillById } from \"../matrix/matrix-provider\";\nimport { injectForkedFromMetadata } from \"./skill-metadata\";\n\nexport type CopiedSkill = {\n skillId: SkillId;\n contentHash: string;\n sourcePath: string;\n destPath: string;\n local?: boolean;\n};\n\nconst NULL_BYTE_PATTERN = /\\0/;\n\n/**\n * Validate that a resolved path stays within the expected parent directory.\n * Prevents path traversal attacks where skill.path contains sequences like \"../../sensitive\".\n */\nexport function validateSkillPath(\n resolvedPath: string,\n expectedParent: string,\n skillPath: string,\n): void {\n if (NULL_BYTE_PATTERN.test(skillPath)) {\n throw new Error(`Invalid skill path: '${skillPath}' contains null bytes`);\n }\n\n if (!isPathWithin(resolvedPath, expectedParent)) {\n throw new Error(\n `Invalid skill path: '${skillPath}' escapes expected directory '${path.resolve(expectedParent)}'`,\n );\n }\n}\n\n/**\n * Join basePath + skillPath, validate the result stays within basePath,\n * and return the resolved path. Combines path.join + validateSkillPath\n * to eliminate repeated join-then-validate boilerplate.\n */\nfunction resolveSkillPath(basePath: string, skillPath: string): string {\n const resolved = path.join(basePath, skillPath);\n validateSkillPath(resolved, basePath, skillPath);\n return resolved;\n}\n\nfunction getSkillSourcePath(skill: ResolvedSkill, rootDir: string): string {\n const srcDir = path.join(rootDir, SOURCE_SRC_DIR);\n return resolveSkillPath(srcDir, skill.path);\n}\n\nfunction getSkillDestPath(skill: ResolvedSkill, stackDir: string): string {\n const skillRelativePath = skill.path.replace(/^skills\\//, \"\");\n const skillsDir = path.join(stackDir, \"skills\");\n return resolveSkillPath(skillsDir, skillRelativePath);\n}\n\nasync function generateSkillHash(skillSourcePath: string): Promise<string> {\n const skillMdPath = path.join(skillSourcePath, STANDARD_FILES.SKILL_MD);\n return computeFileHash(skillMdPath);\n}\n\n/** Core copy: hash the source SKILL.md, copy the directory, stamp forkedFrom provenance. */\nasync function copySkillTo(\n skill: ResolvedSkill,\n sourcePath: string,\n destPath: string,\n source?: string,\n): Promise<CopiedSkill> {\n const contentHash = await generateSkillHash(sourcePath);\n\n await ensureDir(path.dirname(destPath));\n await copy(sourcePath, destPath);\n\n // No directory: the marketplace this ref names resolves the id itself, so where inside it the\n // skill lived is not part of installing it again. Absent rather than undefined, because that is\n // the difference between \"no ref was given\" and \"the ref is the word undefined\".\n await injectForkedFromMetadata(destPath, skill.id, contentHash, {\n ...(source !== undefined && { source }),\n });\n\n return { skillId: skill.id, contentHash, sourcePath, destPath };\n}\n\nexport async function copySkill(\n skill: ResolvedSkill,\n stackDir: string,\n registryRoot: string,\n source?: string,\n): Promise<CopiedSkill> {\n return copySkillTo(\n skill,\n getSkillSourcePath(skill, registryRoot),\n getSkillDestPath(skill, stackDir),\n source,\n );\n}\n\nexport async function copySkillFromSource(\n skill: ResolvedSkill,\n stackDir: string,\n sourceResult: SourceLoadResult,\n): Promise<CopiedSkill> {\n return copySkillTo(\n skill,\n getSkillSourcePath(skill, sourceResult.sourcePath),\n getSkillDestPath(skill, stackDir),\n sourceResult.sourceConfig.source,\n );\n}\n\n/**\n * In-place CopiedSkill for a local skill left where it already lives (no copy):\n * source and destination are the skill's own local path.\n */\nasync function resolveLocalCopiedSkill(\n skill: ResolvedSkill,\n localPath: string,\n): Promise<CopiedSkill> {\n const contentHash = await generateSkillHash(localPath);\n return {\n skillId: skill.id,\n sourcePath: localPath,\n destPath: localPath,\n contentHash,\n local: true,\n };\n}\n\n/**\n * Copies every selected skill, and reports the ones that could not be copied BY ID.\n *\n * `Promise.all` alone rejects with whichever error arrived first and discards its siblings', and\n * that error is the filesystem's: an `ENOENT` naming a path inside the source cache. The reader is\n * told a file is missing at an address they did not choose, cannot place, and cannot act on — and\n * they learn about the second missing skill only by fixing the first and running again.\n *\n * The condition is ordinary rather than exotic: the copy walks the MATRIX and reads from the\n * FETCHED directory, so any disagreement between the two lands here. A user whose CLI predates a\n * marketplace change has no way to make them agree, which makes the id the only actionable thing\n * the failure can carry.\n *\n * It still throws. A partial copy would leave an installation missing skills its config records,\n * which is the orphan-entry state the plugin-install path already refuses.\n */\nasync function copyEachSkill(\n selectedSkillIds: SkillId[],\n copyOne: (skillId: SkillId) => Promise<CopiedSkill>,\n): Promise<CopiedSkill[]> {\n const outcomes = await Promise.all(\n selectedSkillIds.map(async (skillId) => attemptCopy(skillId, copyOne)),\n );\n const failures = outcomes.filter(isCopyFailure);\n\n if (failures.length > 0) throw new Error(copyFailureMessage(failures, selectedSkillIds.length));\n\n return outcomes.filter(isCopySuccess).map((outcome) => outcome.copied);\n}\n\ntype CopySuccess = { skillId: SkillId; copied: CopiedSkill };\ntype CopyFailure = { skillId: SkillId; problem: string };\ntype CopyOutcome = CopySuccess | CopyFailure;\n\nasync function attemptCopy(\n skillId: SkillId,\n copyOne: (skillId: SkillId) => Promise<CopiedSkill>,\n): Promise<CopyOutcome> {\n try {\n return { skillId, copied: await copyOne(skillId) };\n } catch (error) {\n return { skillId, problem: getErrorMessage(error) };\n }\n}\n\nfunction isCopyFailure(outcome: CopyOutcome): outcome is CopyFailure {\n return \"problem\" in outcome;\n}\n\nfunction isCopySuccess(outcome: CopyOutcome): outcome is CopySuccess {\n return \"copied\" in outcome;\n}\n\n/** One line per skill that failed, so both what failed and why are named for every one of them. */\nfunction copyFailureMessage(failures: CopyFailure[], attempted: number): string {\n const lines = failures.map((failure) => ` ${failure.skillId}: ${failure.problem}`);\n\n return `Could not copy ${failures.length} of ${plural(attempted, \"skill\")}:\\n${lines.join(\"\\n\")}`;\n}\n\nfunction getFlattenedSkillDestPath(skill: ResolvedSkill, localSkillsDir: string): string {\n return resolveSkillPath(localSkillsDir, skill.id);\n}\n\nasync function copySkillToLocalFlattened(\n skill: ResolvedSkill,\n localSkillsDir: string,\n sourceResult: SourceLoadResult,\n): Promise<CopiedSkill> {\n return copySkillTo(\n skill,\n getSkillSourcePath(skill, sourceResult.sourcePath),\n getFlattenedSkillDestPath(skill, localSkillsDir),\n sourceResult.sourceConfig.source,\n );\n}\n\nexport async function copySkillsToLocalFlattened(\n selectedSkillIds: SkillId[],\n localSkillsDir: string,\n sourceResult: SourceLoadResult,\n sourceSelections?: Partial<Record<SkillId, string>>,\n): Promise<CopiedSkill[]> {\n return copyEachSkill(selectedSkillIds, async (skillId) => {\n const skill = getSkillById(skillId);\n\n const selectedSource = sourceSelections?.[skillId];\n const userSelectedRemote = selectedSource && selectedSource !== EJECT_SOURCE;\n if (!skill.local || !skill.localPath || userSelectedRemote) {\n return copySkillToLocalFlattened(skill, localSkillsDir, sourceResult);\n }\n\n const destPath = getFlattenedSkillDestPath(skill, localSkillsDir);\n if (path.resolve(skill.localPath) === path.resolve(destPath)) {\n return resolveLocalCopiedSkill(skill, skill.localPath);\n }\n\n const contentHash = await generateSkillHash(skill.localPath);\n await ensureDir(path.dirname(destPath));\n await copy(skill.localPath, destPath);\n\n return { skillId: skill.id, sourcePath: skill.localPath, destPath, contentHash };\n });\n}\n","import path from \"path\";\nimport { parse as parseYaml } from \"yaml\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { readFile, writeFile, ensureDir, glob, fileExists, copy } from \"../../utils/fs\";\nimport { log, verbose, warn } from \"../../utils/logger\";\nimport {\n generateSkillPluginManifest,\n writePluginManifest,\n getPluginManifestPath,\n} from \"../plugins\";\nimport { parseFrontmatter } from \"../loading\";\nimport { computeSkillFolderHash, determinePluginVersion, writeContentHash } from \"../versioning\";\nimport type { PluginManifest, SkillFrontmatter } from \"../../types\";\nimport { formatZodIssues, skillMetadataLoaderSchema } from \"../schemas\";\nimport type { z } from \"zod\";\n\ntype SkillMetadata = z.infer<typeof skillMetadataLoaderSchema>;\nimport { DEFAULT_BRANDING, STANDARD_FILES } from \"../../consts\";\nimport { stripYamlSchemaComment } from \"../../utils/yaml-schema\";\nimport { plural } from \"../../utils/string\";\nimport { SKILL_CONTENT_FILES, SKILL_CONTENT_DIRS } from \"../metadata-keys\";\n\nexport type SkillPluginOptions = {\n skillPath: string;\n outputDir: string;\n skillName?: string;\n};\n\nexport type CompiledSkillPlugin = {\n pluginPath: string;\n manifest: PluginManifest;\n skillName: string;\n};\n\nexport type SkillCompilationRun = {\n compiled: CompiledSkillPlugin[];\n /** Directory basenames of skills that failed to compile this run. */\n failed: string[];\n};\n\nfunction sanitizeSkillName(name: string): string {\n return name.replace(/\\+/g, \"-\");\n}\n\n/**\n * The optional `author` and `category` a skill's metadata.yaml lends the plugin manifest.\n *\n * Not the `readSkillMetadata` exported from `loading/loader.ts` one import away, whose name this\n * carried until the two proved impossible to tell apart in prose. That one is handed the\n * metadata.yaml's own PATH and answers a verdict — the single judgment of whether a file describes\n * its skill, which `compile`, config-types generation and `doctor` all defer to — and it warns\n * about nothing. This is handed the skill DIRECTORY, answers null for a file that is absent as\n * readily as for one nothing can be read out of, and warns on the way past both, because the\n * compile it feeds runs either way with two manifest fields left off.\n */\nasync function readPluginSkillMetadata(skillPath: string): Promise<SkillMetadata | null> {\n const metadataPath = path.join(skillPath, STANDARD_FILES.METADATA_YAML);\n\n if (!(await fileExists(metadataPath))) {\n return null;\n }\n\n try {\n const content = await readFile(metadataPath);\n const { yamlContent } = stripYamlSchemaComment(content);\n\n const result = skillMetadataLoaderSchema.safeParse(parseYaml(yamlContent));\n if (!result.success) {\n warn(`Invalid metadata.yaml at '${skillPath}': ${formatZodIssues(result.error.issues)}`);\n return null;\n }\n return result.data;\n } catch (error) {\n warn(`Failed to read metadata.yaml at '${skillPath}': ${getErrorMessage(error)}`);\n return null;\n }\n}\n\nfunction generateReadme(skillName: string, frontmatter: SkillFrontmatter): string {\n return `# ${skillName}\n\n${frontmatter.description}\n\n## Installation\n\nAdd this plugin to your Claude Code configuration:\n\n\\`\\`\\`json\n{\n \"plugins\": [\"${skillName}\"]\n}\n\\`\\`\\`\n\n## Usage\n\nThis skill is automatically available when installed.\n\n---\n\n*Generated by ${DEFAULT_BRANDING.NAME} skill-plugin-compiler*\n`;\n}\n\nexport async function compileSkillPlugin(\n options: SkillPluginOptions,\n): Promise<CompiledSkillPlugin> {\n const { skillPath, outputDir, skillName: overrideName } = options;\n\n const dirBasename = path.basename(skillPath);\n\n const skillMdPath = path.join(skillPath, STANDARD_FILES.SKILL_MD);\n if (!(await fileExists(skillMdPath))) {\n throw new Error(\n `Skill '${dirBasename}' is missing required ${STANDARD_FILES.SKILL_MD} file. Expected at: ${skillMdPath}`,\n );\n }\n\n const skillMdContent = await readFile(skillMdPath);\n const frontmatter = parseFrontmatter(skillMdContent, skillMdPath);\n\n // No cause is inlined here, and that is the difference from the agent side. `parseFrontmatter`\n // has already warned the exact reason against this same `skillMdPath`, and it is shared by six\n // call sites — five of which skip the skill rather than throw, so its warn is their only report\n // and cannot be removed. Repeating the reason in this message would print it twice on every\n // path that reaches here. What is gone is the hard-coded `Required fields: 'name' and\n // 'description'`, which named two fields whatever had actually failed.\n if (!frontmatter) {\n throw new Error(\n `Skill '${dirBasename}' has invalid or missing YAML frontmatter in ${STANDARD_FILES.SKILL_MD}. ` +\n `File: ${skillMdPath}`,\n );\n }\n\n const skillName = overrideName ?? sanitizeSkillName(frontmatter.name);\n\n verbose(`Compiling skill plugin: ${skillName} from ${skillPath}`);\n\n const metadata = await readPluginSkillMetadata(skillPath);\n\n const pluginDir = path.join(outputDir, skillName);\n const skillsDir = path.join(pluginDir, \"skills\", skillName);\n\n await ensureDir(pluginDir);\n await ensureDir(skillsDir);\n\n const newHash = await computeSkillFolderHash(skillPath);\n\n const { version, contentHash } = await determinePluginVersion(\n newHash,\n pluginDir,\n getPluginManifestPath,\n );\n\n const manifest = generateSkillPluginManifest({\n skillName,\n description: frontmatter.description,\n ...(metadata?.author !== undefined && { author: metadata.author }),\n ...(metadata?.category !== undefined && { category: metadata.category }),\n version,\n });\n\n await writePluginManifest(pluginDir, manifest);\n\n await writeContentHash(pluginDir, contentHash, getPluginManifestPath);\n\n verbose(` Wrote plugin.json for ${skillName} (v${version})`);\n\n await writeFile(path.join(skillsDir, STANDARD_FILES.SKILL_MD), skillMdContent);\n verbose(` Copied ${STANDARD_FILES.SKILL_MD}`);\n\n for (const fileName of SKILL_CONTENT_FILES) {\n if (fileName === STANDARD_FILES.SKILL_MD) continue;\n\n const sourcePath = path.join(skillPath, fileName);\n if (await fileExists(sourcePath)) {\n const content = await readFile(sourcePath);\n await writeFile(path.join(skillsDir, fileName), content);\n verbose(` Copied ${fileName}`);\n }\n }\n\n for (const dirName of SKILL_CONTENT_DIRS) {\n const sourceDir = path.join(skillPath, dirName);\n if (await fileExists(sourceDir)) {\n await copy(sourceDir, path.join(skillsDir, dirName));\n verbose(` Copied ${dirName}/`);\n }\n }\n\n const readme = generateReadme(skillName, frontmatter);\n await writeFile(path.join(pluginDir, STANDARD_FILES.README_MD), readme);\n verbose(\" Generated README.md\");\n\n return {\n pluginPath: pluginDir,\n manifest,\n skillName,\n };\n}\n\nexport async function compileAllSkillPlugins(\n skillsDir: string,\n outputDir: string,\n): Promise<SkillCompilationRun> {\n const compiled: CompiledSkillPlugin[] = [];\n const failed: string[] = [];\n\n const skillMdFiles = await glob(`**/${STANDARD_FILES.SKILL_MD}`, skillsDir);\n\n for (const skillMdFile of skillMdFiles) {\n const skillPath = path.join(skillsDir, path.dirname(skillMdFile));\n\n try {\n const result = await compileSkillPlugin({\n skillPath,\n outputDir,\n });\n compiled.push(result);\n log(` [OK] ${result.skillName}`);\n } catch (error) {\n const errorMessage = getErrorMessage(error);\n const dirBasename = path.basename(skillPath);\n failed.push(dirBasename);\n warn(`Failed to compile skill from '${dirBasename}': ${errorMessage}`);\n }\n }\n\n return { compiled, failed };\n}\n\nexport function printCompilationSummary(results: CompiledSkillPlugin[]): void {\n log(`\\nCompiled ${plural(results.length, \"skill plugin\")}:`);\n for (const result of results) {\n log(` - ${result.skillName} (v${result.manifest.version})`);\n }\n}\n","import path from \"path\";\n\nimport { ensureDir, writeFile } from \"../../utils/fs\";\nimport { DEFAULT_VERSION, PLUGIN_MANIFEST_DIR, STANDARD_FILES } from \"../../consts\";\nimport type { PluginAuthor, PluginManifest } from \"../../types\";\n\nconst PLUGIN_DIR_NAME = PLUGIN_MANIFEST_DIR;\nconst PLUGIN_MANIFEST_FILE = STANDARD_FILES.PLUGIN_JSON;\nconst AGENT_PLUGIN_PREFIX = \"agent-\";\n\nexport type SkillManifestOptions = {\n skillName: string;\n description?: string;\n author?: string;\n authorEmail?: string;\n category?: string;\n version?: string;\n keywords?: string[];\n};\n\nexport type AgentManifestOptions = {\n agentName: string;\n description?: string;\n version?: string;\n};\n\nfunction buildAuthor(name?: string, email?: string): PluginAuthor | undefined {\n if (!name) {\n return undefined;\n }\n return { name, ...(email ? { email } : {}) };\n}\n\nexport function generateSkillPluginManifest(options: SkillManifestOptions): PluginManifest {\n const author = buildAuthor(options.author, options.authorEmail);\n return {\n name: options.skillName,\n version: options.version ?? DEFAULT_VERSION,\n skills: \"./skills/\",\n ...(options.description ? { description: options.description } : {}),\n ...(author ? { author } : {}),\n ...(options.category ? { category: options.category } : {}),\n ...(options.keywords?.length ? { keywords: options.keywords } : {}),\n };\n}\n\nexport function generateAgentPluginManifest(options: AgentManifestOptions): PluginManifest {\n return {\n name: `${AGENT_PLUGIN_PREFIX}${options.agentName}`,\n version: options.version ?? DEFAULT_VERSION,\n agents: \"./agents/\",\n ...(options.description ? { description: options.description } : {}),\n };\n}\n\nexport async function writePluginManifest(\n outputDir: string,\n manifest: PluginManifest,\n): Promise<string> {\n const pluginDir = path.join(outputDir, PLUGIN_DIR_NAME);\n const manifestPath = path.join(pluginDir, PLUGIN_MANIFEST_FILE);\n\n await ensureDir(pluginDir);\n\n const content = JSON.stringify(manifest, null, 2);\n await writeFile(manifestPath, content);\n\n return manifestPath;\n}\n","/**\n * Marketplace-qualified plugin reference (`{id}@{marketplace}`) — the form the\n * Claude CLI plugin registry expects. Bare ids do not match registry entries.\n */\nexport function buildMarketplacePluginRef(id: string, marketplace: string): string {\n return `${id}@${marketplace}`;\n}\n\n/**\n * Inverse of buildMarketplacePluginRef: extracts the skill id from a\n * `{id}@{marketplace}` reference. Returns the whole string when no `@` is present.\n */\nexport function parseMarketplacePluginRef(ref: string): string {\n const separator = ref.indexOf(\"@\");\n return separator === -1 ? ref : ref.slice(0, separator);\n}\n","import os from \"os\";\nimport path from \"path\";\n\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { fileExists, readFileSafe } from \"../../utils/fs\";\nimport { verbose } from \"../../utils/logger\";\nimport {\n CLAUDE_DIR,\n MAX_PLUGIN_FILE_SIZE,\n PLUGINS_SUBDIR,\n PLUGIN_MANIFEST_DIR,\n PLUGIN_MANIFEST_FILE,\n} from \"../../consts\";\nimport type { PluginManifest } from \"../../types\";\nimport { pluginManifestSchema } from \"../schemas\";\n\nexport function getUserPluginsDir(): string {\n return path.join(os.homedir(), CLAUDE_DIR, PLUGINS_SUBDIR);\n}\n\nexport function getProjectPluginsDir(projectDir?: string): string {\n const dir = projectDir ?? process.cwd();\n return path.join(dir, CLAUDE_DIR, PLUGINS_SUBDIR);\n}\n\nexport function getPluginAgentsDir(pluginDir: string): string {\n return path.join(pluginDir, \"agents\");\n}\n\nexport function getPluginManifestPath(pluginDir: string): string {\n return path.join(pluginDir, PLUGIN_MANIFEST_DIR, PLUGIN_MANIFEST_FILE);\n}\n\nexport async function readPluginManifest(pluginDir: string): Promise<PluginManifest | null> {\n const manifestPath = getPluginManifestPath(pluginDir);\n\n if (!(await fileExists(manifestPath))) {\n verbose(` No manifest at ${manifestPath}`);\n return null;\n }\n\n try {\n const content = await readFileSafe(manifestPath, MAX_PLUGIN_FILE_SIZE);\n const manifest = pluginManifestSchema.parse(JSON.parse(content));\n\n if (!manifest.name || typeof manifest.name !== \"string\") {\n verbose(` Invalid manifest at ${manifestPath}: missing name`);\n return null;\n }\n\n return manifest;\n } catch (error) {\n verbose(` Failed to parse manifest at ${manifestPath}: ${getErrorMessage(error)}`);\n return null;\n }\n}\n","import { readdir } from \"fs/promises\";\nimport type { Dirent } from \"fs\";\n\nimport { DEFAULT_PLUGIN_NAME } from \"../../consts\";\nimport { loadProjectConfig, type LoadedProjectConfig } from \"../configuration\";\nimport {\n detectInstallation,\n isHomeDirectory,\n resolveInstallPaths,\n INSTALL_MODE_LABELS,\n type Installation,\n type InstallMode,\n} from \"../installation\";\nimport type { SkillScope } from \"../../types/config\";\n\nconst AGENT_FILE_EXTENSION = \".md\";\n\nexport type InstallationInfo = {\n mode: InstallMode;\n name: string;\n skillCount: number;\n agentCount: number;\n configPath: string;\n /** Every directory that actually holds compiled agents; empty when no scope has any. */\n agentDirs: string[];\n};\n\nexport async function getInstallationInfo(): Promise<InstallationInfo | null> {\n const installation = await detectInstallation();\n if (!installation) return null;\n\n const loaded = await loadProjectConfig(installation.projectDir);\n const agentDirCounts = await countCompiledAgentsPerScope(\n installation,\n installedScopes(installation),\n );\n\n return {\n mode: installation.mode,\n name: loaded?.config.name || DEFAULT_PLUGIN_NAME,\n skillCount: countManagedSkills(loaded),\n agentCount: sumCounts(agentDirCounts),\n configPath: installation.configPath,\n agentDirs: agentDirCounts.filter(hasEntries).map((scopeCount) => scopeCount.dir),\n };\n}\n\n/**\n * The number of skills the CLI reports it manages, which is what its own configuration declares\n * and nothing else. Neither the plugin registry nor `.claude/skills/` answers that question:\n * each holds only the half of an installation its own install path writes — so a mixed install\n * read from either one reports a fraction of itself — and each also holds entries this CLI never\n * wrote, which it has no business claiming. The install mode is therefore irrelevant here.\n *\n * A tombstone (`excluded: true`) records a skill this project has switched OFF, so it is not one\n * of them; and a skill enabled under both roots is two registrations of one skill, so the entries\n * merge by id.\n */\nfunction countManagedSkills(loaded: LoadedProjectConfig | null): number {\n if (!loaded) return 0;\n\n const managed = loaded.config.skills.filter((skill) => !skill.excluded);\n return new Set(managed.map((skill) => skill.id)).size;\n}\n\n/**\n * Scopes whose compiled agents belong to this installation, in report order\n * (global first, mirroring the init success report). A project context also owns\n * everything installed globally under HOME, so both roots are counted; at the\n * home root the two resolve to the same directory and only one pass runs so\n * nothing is counted twice.\n */\nfunction installedScopes(installation: Installation): SkillScope[] {\n return isHomeDirectory(installation.projectDir) ? [\"project\"] : [\"global\", \"project\"];\n}\n\ntype ScopeCount = {\n dir: string;\n count: number;\n};\n\nfunction hasEntries(scopeCount: ScopeCount): boolean {\n return scopeCount.count > 0;\n}\n\nfunction sumCounts(scopeCounts: ScopeCount[]): number {\n return scopeCounts.reduce((total, scopeCount) => total + scopeCount.count, 0);\n}\n\n/**\n * Compiled-agent count per scope, keyed by the directory it was read from, so\n * callers can both total the counts and name the directories the agents are\n * actually in — a default install driven from a project directory compiles\n * every agent under HOME, and naming the project directory there names a\n * directory that was never written.\n */\nasync function countCompiledAgentsPerScope(\n installation: Installation,\n scopes: SkillScope[],\n): Promise<ScopeCount[]> {\n return Promise.all(\n scopes.map(async (scope) => {\n const dir = resolveInstallPaths(installation.projectDir, scope).agentsDir;\n return { dir, count: await countDirEntries(dir, isCompiledAgentFile) };\n }),\n );\n}\n\nfunction isCompiledAgentFile(entry: Dirent): boolean {\n return entry.isFile() && entry.name.endsWith(AGENT_FILE_EXTENSION);\n}\n\n/** Counts entries in `dir` matching `pred`; 0 when the directory is missing or unreadable. */\nasync function countDirEntries(dir: string, pred: (entry: Dirent) => boolean): Promise<number> {\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n return entries.filter(pred).length;\n } catch {\n return 0;\n }\n}\n\nexport function formatInstallationDisplay(info: InstallationInfo): string {\n const agentDirLines = info.agentDirs.map((dir) => `\\n Agents: ${dir}`).join(\"\");\n\n return `Installation: ${info.name}\n Mode: ${INSTALL_MODE_LABELS[info.mode]}\n Skills: ${info.skillCount}\n Agents: ${info.agentCount}\n Config: ${info.configPath}${agentDirLines}`;\n}\n","import os from \"os\";\nimport path from \"path\";\nimport { fileExists } from \"../../utils/fs\";\nimport { ConfigLoadError, loadProjectConfigFromDir } from \"../configuration/project-config\";\nimport { CLAUDE_DIR, PLUGINS_SUBDIR, EJECT_SOURCE } from \"../../consts\";\nimport { getProjectConfigPath } from \"./install-base-dir\";\nimport { agentsDir, providerInUse } from \"./install-layout\";\nimport type { ProjectConfig, SkillConfig, SkillScope } from \"../../types/config\";\nimport type { InstallMode } from \"../../types/matrix\";\n\n// Re-exported from types/matrix.ts for existing importers of the installation barrel\nexport type { InstallMode };\n\nexport const INSTALL_MODE_LABELS = {\n plugin: \"Plugin\",\n mixed: \"Mixed\",\n eject: \"Eject\",\n} as const satisfies Record<InstallMode, string>;\n\n/**\n * How a mode is described wherever a command tells the user what KIND of install is\n * about to happen — `init`'s install-plan line, and `edit`'s line for the skills it\n * is switching. One definition because it is one statement about one operation:\n * switching a skill to plugin mode installs it natively exactly as a fresh plugin\n * install does, and used to be announced in words `init` never printed.\n *\n * `mixed` is absent by construction. Nothing is switched TO mixed — it is a shape a\n * whole selection can have, described with per-mode counts only the install plan\n * holds, so `init` composes that one line itself.\n *\n * **Neither description names a DIRECTORY, and the eject one read `(copy to .claude/skills/)`\n * until 2026-09-22.** A constant cannot name one truthfully: the directory is the host's and\n * the scope's — `.claude/skills`, `$CODEX_HOME/skills`, `<repo>/.agents/skills` — and one\n * selection routinely spans two of them, so any single answer misnames at least one. It is also\n * said before anything is copied, where the run has nothing to report yet; `reportSkillsCopied`\n * in `commands/init.tsx` names the real directories afterwards, one block per non-empty scope.\n * The `COPIED_LOCAL_SKILLS_*` note in `e2e/pages/constants.ts` had already reached this\n * conclusion for `edit`'s copy count and stopped one line short of this constant.\n */\nexport const INSTALL_MODE_DESCRIPTIONS = {\n plugin: `${INSTALL_MODE_LABELS.plugin} (native install)`,\n eject: `${INSTALL_MODE_LABELS.eject} (local copy)`,\n} as const satisfies Record<Exclude<InstallMode, \"mixed\">, string>;\n\nexport type Installation = {\n mode: InstallMode;\n configPath: string;\n agentsDir: string;\n skillsDir: string;\n projectDir: string;\n};\n\n/**\n * Whether a successfully-loaded config declares nothing to install — no skills and no agents.\n *\n * Exported rather than kept private to its one caller below because two surfaces have to agree on\n * exactly which configs are content-less: this detection, which maps them to `null` so `init`\n * routes to the wizard instead of the dashboard, and `doctor`, which has to name that state rather\n * than repeat the `null` as `not found`. Two answers to that question is how one screen ended up\n * validating a file and calling it missing four lines apart.\n */\nexport function declaresNoContent(config: ProjectConfig): boolean {\n return config.skills.length === 0 && config.agents.length === 0;\n}\n\n/** Derive install mode from skills array at runtime */\nexport function deriveInstallMode(skills: SkillConfig[]): InstallMode {\n if (skills.length === 0) return \"eject\";\n const hasEject = skills.some((s) => s.origin === EJECT_SOURCE);\n const hasPlugin = skills.some((s) => s.origin !== EJECT_SOURCE);\n if (hasEject && hasPlugin) return \"mixed\";\n return hasEject ? \"eject\" : \"plugin\";\n}\n\n// Use loadProjectConfigFromDir directly (not detectInstallation) to avoid the\n// project→global fallback recursing back into this detection.\nasync function detectInstallationInDir(\n dir: string,\n scope: SkillScope,\n): Promise<Installation | null> {\n // The provider is read off the directory, because an installation's folder is the only record\n // of one — the same read the existence check and the load below both have to make, or they\n // would be asking about two different installations in one function.\n const provider = providerInUse(dir);\n const configPath = getProjectConfigPath(dir, provider);\n\n if (!(await fileExists(configPath))) {\n return null;\n }\n\n // The config file exists. loadProjectConfigFromDir throws ConfigLoadError for a\n // corrupt config, so a returned value is always a usable config — a corrupt\n // config surfaces to the caller (compile reports it) instead of silently\n // becoming a phantom eject installation that resurrects every built-in agent.\n const loaded = await loadProjectConfigFromDir(dir, provider);\n if (!loaded) {\n // The file vanished between the fileExists check and the load.\n return null;\n }\n\n // A successfully-loaded config that declares neither skills nor agents is\n // content-less and does not count as an installation — init must route to the\n // setup wizard, not the dashboard. This is the shared detection function, so\n // returning null here covers both the project-config and global-config\n // manifestations. A reporting surface must not read this `null` as \"no config\n // here\": see declaresNoContent, which doctor asks the same question of.\n if (declaresNoContent(loaded.config)) {\n return null;\n }\n\n const mode: InstallMode = deriveInstallMode(loaded.config.skills);\n\n return {\n mode,\n configPath,\n // The HOST's, per scope, and a `.claude/agents` literal until C5. `compile` hands this\n // straight to the pass as its `outputDir`, so a Codex installation compiled agent ROLE\n // definitions into `<project>/.claude/agents/` — Codex's format in Claude's directory, the\n // inverse of the defect the whole host funnel exists against, and invisible while\n // `compilesSubAgents` was short-circuiting every Codex compile before it got here.\n agentsDir: agentsDir(provider, scope, dir),\n // Mixed mode has local skills in .claude/skills/ and plugins in cache;\n // use .claude/skills/ as the primary skillsDir (same as eject mode)\n skillsDir: path.join(dir, CLAUDE_DIR, mode === \"plugin\" ? PLUGINS_SUBDIR : \"skills\"),\n projectDir: dir,\n };\n}\n\n/** Detect installation in a specific directory only (no global fallback). */\nexport async function detectProjectInstallation(projectDir: string): Promise<Installation | null> {\n return detectInstallationInDir(projectDir, \"project\");\n}\n\n/**\n * Whether `dir` holds an installation of its own, for a surface that must answer rather than\n * refuse. DEGRADE posture: a config that exists and cannot be loaded answers yes, because the file\n * is there — where {@link detectProjectInstallation} throws `ConfigLoadError` over it.\n */\nexport async function holdsItsOwnInstallation(dir: string): Promise<boolean> {\n try {\n return (await detectProjectInstallation(dir)) !== null;\n } catch (error) {\n if (error instanceof ConfigLoadError) return true;\n throw error;\n }\n}\n\n/** Detect installation in the home directory (global scope). */\nexport async function detectGlobalInstallation(): Promise<Installation | null> {\n return detectInstallationInDir(os.homedir(), \"global\");\n}\n\n/**\n * Detect installation: checks project-level first, then falls back to global (home directory).\n * Project fully overrides global (no merging).\n */\nexport async function detectInstallation(\n projectDir: string = process.cwd(),\n): Promise<Installation | null> {\n // 1. Check project-level first\n const projectInstallation = await detectProjectInstallation(projectDir);\n if (projectInstallation) return projectInstallation;\n\n // 2. Fall back to global (home directory)\n return detectGlobalInstallation();\n}\n","import os from \"os\";\nimport path from \"path\";\nimport { unique } from \"remeda\";\nimport type {\n AgentDefinition,\n AgentName,\n CompileAgentConfig,\n ProjectConfig,\n SkillId,\n SkillReference,\n Stack,\n StackAgentConfig,\n} from \"../../types\";\nimport { isHomeDirectory } from \"./is-home-directory\";\nimport type { AgentScopeConfig, SkillConfig, SkillScope } from \"../../types/config\";\nimport type { WizardResultV2 } from \"../../components/wizard/wizard\";\nimport {\n type MergeResult,\n type AuthoritativeScope,\n mergeWithExistingConfig,\n loadProjectConfig,\n loadInstalledConfig,\n} from \"../configuration\";\nimport { type SourceLoadResult } from \"../loading\";\nimport { loadStackById, stackNotOfferedMessage } from \"../stacks\";\nimport { buildSkillRefsFromConfig } from \"../resolver\";\nimport { generateProjectConfigFromSkills, buildStackProperty } from \"../configuration\";\nimport { scopeEligibilityKey, isScopePairCompatible } from \"../configuration/config-generator\";\nimport {\n isActiveAt,\n activeSkillScopeMap,\n activeAgentScopeMap,\n effectivelyExcludedSkillIds,\n} from \"../configuration/scope-predicates\";\nimport { verbose } from \"../../utils/logger\";\nimport { typedFromEntries } from \"../../utils/typed-object\";\nimport { DEFAULT_PLUGIN_NAME } from \"../../consts\";\n\n/**\n * Returns the ids of skills active in the CURRENT wizard selection that were\n * NOT active in the persisted PRIOR config. Filters `excluded: true` on both\n * sides — excluded entries don't participate in stack membership, so flipping\n * a skill from excluded back to active counts as \"newly added\".\n *\n * `priorSkills === undefined` (first init) collapses the prior active set to\n * empty — every current skill is new this session. The generator's seeding\n * branch is what actually produces useful output in that case, so treating\n * every skill as \"new\" is safe.\n */\nfunction computeNewlyAddedSkillIds(\n currentSkills: readonly SkillConfig[],\n priorSkills: readonly SkillConfig[] | undefined,\n): readonly SkillId[] {\n const priorActiveIds = new Set((priorSkills ?? []).filter((s) => !s.excluded).map((s) => s.id));\n const currentActiveIds = currentSkills.filter((s) => !s.excluded).map((s) => s.id);\n return unique(currentActiveIds.filter((id) => !priorActiveIds.has(id)));\n}\n\n/**\n * Returns `(agent, skillId)` keys whose scope-compatibility was GAINED this\n * session — the pair is scope-compatible now but was NOT scope-compatible (or\n * was absent entirely) in the persisted config. Admits pure scope-flip cases\n * that `computeNewlyAddedSkillIds` (keyed by id only) cannot express.\n *\n * Scope rule: `isScopePairCompatible` from config-generator — the single\n * definition shared with the generator's own compatibility filter.\n *\n * Keys are produced by `scopeEligibilityKey` so lookup membership matches the\n * generator's internal set-membership check.\n */\nfunction computeScopeEligibilityGained(\n currentSkills: readonly SkillConfig[],\n currentAgents: readonly AgentScopeConfig[],\n priorSkills: readonly SkillConfig[] | undefined,\n priorAgents: readonly AgentScopeConfig[] | undefined,\n): ReadonlySet<string> {\n const priorSkillScope = activeSkillScopeMap(priorSkills);\n const priorAgentScope = activeAgentScopeMap(priorAgents);\n const gainedCompatibility = (skill: SkillConfig, agent: AgentScopeConfig): boolean =>\n isScopePairCompatible(skill.scope, agent.scope) &&\n !wereScopeCompatible(priorSkillScope.get(skill.id), priorAgentScope.get(agent.name));\n\n const activeCurrentSkills = currentSkills.filter((s) => !s.excluded);\n const activeCurrentAgents = currentAgents.filter((a) => !a.excluded);\n\n const gainedKeys = activeCurrentAgents.flatMap((agent) =>\n activeCurrentSkills\n .filter((skill) => gainedCompatibility(skill, agent))\n .map((skill) => scopeEligibilityKey(agent.name, skill.id)),\n );\n return new Set(gainedKeys);\n}\n\n/**\n * Whether a pair was scope-compatible in the persisted config — which it cannot have been where\n * either half was absent from it, or excluded there.\n */\nfunction wereScopeCompatible(\n priorSkillScope: SkillScope | undefined,\n priorAgentScope: SkillScope | undefined,\n): boolean {\n return (\n priorSkillScope !== undefined &&\n priorAgentScope !== undefined &&\n isScopePairCompatible(priorSkillScope, priorAgentScope)\n );\n}\n\n/**\n * The stack the written config carries.\n *\n * A producer that knows per-`(skill, agent)` assignments has already decided what every sub-agent\n * holds and what preloads, so its stack REPLACES the ownership-derived one rather than merging\n * with it. Ownership rules hand every scope-compatible skill to every selected agent — exactly the\n * curation a shared configuration exists to carry — and inherit `preloaded` from a prior or\n * stack-YAML entry, which is silent about what the sharer chose. A stack id in such a payload\n * still names the config's description, but its own expansion is not overlaid for the same reason:\n * it would add back the skills and agents the assignments left out.\n *\n * Only a stack the generator itself built is replaced. With no agents selected there is nothing to\n * own, and the absent key is what tells the merger to leave the stack already on disk alone.\n */\nfunction resolveStackProperty(\n generated: ProjectConfig[\"stack\"],\n assigned: WizardResultV2[\"assignedStack\"],\n): ProjectConfig[\"stack\"] {\n return generated && assigned ? assigned : generated;\n}\n\n/**\n * The sentence this config records about itself, from whichever end of the install knows it.\n *\n * The two are never both present, and the two install paths are the reason. A stack loaded HERE is\n * the wizard path, where the stack object is the authority on its own description. A description\n * carried on the wizard result is the `init --from` path, where `configToSeedPayload` writes\n * `stackId: null` on purpose — so `loadedStack` is null, there is no id to resolve a description\n * out of, and before the payload carried one the line was simply dropped.\n *\n * The loaded stack is asked first anyway, so the ordering is stated rather than left to the fact\n * that the cases do not overlap: a stack the install actually read beats a sentence handed to it.\n */\nfunction resolveDescription(\n loadedStack: Stack | null,\n shared: WizardResultV2[\"description\"],\n): string | undefined {\n return loadedStack === null ? shared : loadedStack.description;\n}\n\n/**\n * The identity a freshly-written config carries.\n *\n * A project config is named for the directory it configures — the same identity\n * `eject` passes as its `fallbackName` and the loader repairs a missing `name`\n * to. At `$HOME` there is no project to name: `path.basename(os.homedir())` is\n * the OS account name, which identifies the USER rather than the installation\n * and differs per machine for one logical global install, so the global config\n * keeps the product constant instead.\n *\n * A config already on disk keeps the name it saved either way — `mergeConfigs`\n * carries identity fields over from the existing config, so this seed only ever\n * names a config being created.\n */\nfunction configNameFor(projectDir: string): string {\n return isHomeDirectory(projectDir) ? DEFAULT_PLUGIN_NAME : path.basename(projectDir);\n}\n\n/**\n * The per-agent curation this save must preserve, from every config that carries\n * any.\n *\n * A GLOBAL sub-agent's curation lives in the global config ALONE — a project\n * config's stack is filtered down to project-scoped agents on the way out, so a\n * global agent has no row of its own there. Reading the project config by itself\n * therefore makes a `s` toggle (G→P) look like an agent nobody has ever curated,\n * and the generator's seed branch rebuilds its catalogue from relevance defaults,\n * silently dropping every assignment the shared resolver would not re-derive.\n *\n * Both configs are carriers and both are merged; the project's word wins per\n * agent, since a project-scoped agent's row is the one the project owns. The\n * global config is READ here and never written — a project-context edit moves an\n * agent INTO this project, it never migrates global state out.\n */\nasync function loadCuratedStack(\n projectDir: string,\n projectStack: ProjectConfig[\"stack\"],\n): Promise<Partial<Record<AgentName, StackAgentConfig>>> {\n // At `$HOME` the config already loaded IS the global one — re-reading it would\n // merge it with itself.\n const globalStack = isHomeDirectory(projectDir) ? undefined : await loadGlobalStack();\n\n // ProjectConfig.stack types its agents as Record<string, StackAgentConfig> (it\n // comes from parsed TS/JSON); the declared return type is where those keys are\n // narrowed to AgentName, so this load boundary needs no cast of its own.\n return { ...globalStack, ...projectStack };\n}\n\n/** The global install's per-agent stack, absent until a global config exists. */\nasync function loadGlobalStack(): Promise<ProjectConfig[\"stack\"]> {\n return (await loadInstalledConfig(os.homedir()))?.config.stack;\n}\n\nasync function buildInstallConfig(\n wizardResult: WizardResultV2,\n sourceResult: SourceLoadResult,\n projectDir: string,\n): Promise<{ config: ProjectConfig; loadedStack: Stack | null }> {\n const skillIds = unique(wizardResult.skills.map((s) => s.id));\n verbose(\n `buildInstallConfig: selectedStackId='${wizardResult.selectedStackId}', ` +\n `skills=[${skillIds.join(\", \")}], ` +\n `selectedAgents=[${wizardResult.selectedAgents.join(\", \")}]`,\n );\n\n const loadedStack = await loadSelectedStack(wizardResult.selectedStackId, sourceResult);\n const existing = await loadProjectConfig(projectDir);\n const existingStack = await loadCuratedStack(projectDir, existing?.config.stack);\n\n const options = generatorOptionsFor(\n wizardResult,\n existing?.config,\n stackToPreserve(loadedStack, existingStack),\n );\n const generated = generateProjectConfigFromSkills(configNameFor(projectDir), skillIds, options);\n const stack = resolveStackProperty(generated.stack, wizardResult.assignedStack);\n const description = resolveDescription(loadedStack, wizardResult.description);\n const localConfig: ProjectConfig = {\n ...generated,\n ...(stack && { stack }),\n ...(description !== undefined && { description }),\n };\n\n verbose(\n `buildInstallConfig result: stack=${stackSizeForLog(localConfig.stack)}, ` +\n `agents=[${localConfig.agents.map((a) => a.name).join(\", \")}], skills=${localConfig.skills.length}`,\n );\n\n return { config: localConfig, loadedStack };\n}\n\n/**\n * Refuses a selected stack the source does not offer, through the lookup the install makes, so a\n * caller can ask before it writes anything. The `--from` producers do (see\n * `refuseSharedConfigBeforeAsking` on `BaseCommand`); the install's own lookup is then only the\n * backstop, since a refusal reached that late lands after the plugins are installed and the skills\n * copied.\n */\nexport async function refuseUnofferedStack(\n stackId: WizardResultV2[\"selectedStackId\"],\n sourceResult: SourceLoadResult,\n): Promise<void> {\n await loadSelectedStack(stackId, sourceResult);\n}\n\n/**\n * The stack the wizard selected, loaded from the source — `null` where none was selected, and a\n * refusal naming the source where one was selected that the source does not offer.\n */\nasync function loadSelectedStack(\n stackId: WizardResultV2[\"selectedStackId\"],\n sourceResult: SourceLoadResult,\n): Promise<Stack | null> {\n if (!stackId) return null;\n\n const { source } = sourceResult.sourceConfig;\n const loadedStack = await loadStackById(stackId, sourceResult.sourcePath, source);\n verbose(\n `buildInstallConfig: loadedStack=${loadedStack ? `found (id='${loadedStack.id}')` : \"NOT FOUND\"}`,\n );\n if (!loadedStack) throw new Error(stackNotOfferedMessage(stackId, source));\n\n return loadedStack;\n}\n\n/**\n * The per-agent stack the generator must preserve: the curated one on disk, over any stack this\n * install applies.\n *\n * With a stack, it is overlaid so its (agent, category, skill) triples reach the ownership-based\n * builder with a load already decided — the author's flag where a third-party stacks file wrote\n * one, and the shared mapping's verdict where none was written, which is every entry of a built-in\n * stack. `buildStackProperty` is where that decision is made, so applying a stack is a NEW\n * selection: it never arrives flagless and is never read as a curated lazy.\n *\n * The on-disk stack spreads LAST and wins per agent, so re-running over an installed config\n * preserves what the user saved. Ownership rules still govern which agents and categories land in\n * the final stack, so Phase A (init) and Phase B (edit) produce equivalent stacks for the same\n * selection.\n */\nfunction stackToPreserve(\n loadedStack: Stack | null,\n curatedStack: Partial<Record<AgentName, StackAgentConfig>>,\n): Partial<Record<AgentName, StackAgentConfig>> {\n if (loadedStack === null) return curatedStack;\n return { ...buildStackProperty(loadedStack), ...curatedStack };\n}\n\n/**\n * Everything the generator is told beyond the skill ids: the user's agent selection, the skill\n * and agent configs that carry each one's scope, the stack to preserve, and what this session\n * changed relative to the persisted config.\n *\n * Both `skillConfigs` and `agentConfigs` are always passed when `selectedAgents` is set — the\n * config generator enforces that invariant to prevent silent \"project\" scope defaults on missing\n * lookups.\n *\n * The two deltas are what per-agent curation turns on: the skills new to this session's selection,\n * and the `(agent, skillId)` pairs that became scope-compatible, which admits the scope-flip case a\n * skill-id-only diff would miss. With no persisted config (first init) both collapse to\n * \"everything is new this session\", which the generator's seeding branch tolerates.\n */\nfunction generatorOptionsFor(\n wizardResult: WizardResultV2,\n persisted: ProjectConfig | undefined,\n existingStack: Partial<Record<AgentName, StackAgentConfig>>,\n): {\n selectedAgents?: AgentName[];\n skillConfigs: SkillConfig[];\n agentConfigs: AgentScopeConfig[];\n existingStack: Partial<Record<AgentName, StackAgentConfig>>;\n newlyAddedSkillIds: readonly SkillId[];\n scopeEligibilityGained: ReadonlySet<string>;\n} {\n return {\n skillConfigs: wizardResult.skills,\n agentConfigs: wizardResult.agentConfigs,\n existingStack,\n newlyAddedSkillIds: computeNewlyAddedSkillIds(wizardResult.skills, persisted?.skills),\n scopeEligibilityGained: computeScopeEligibilityGained(\n wizardResult.skills,\n wizardResult.agentConfigs,\n persisted?.skills,\n persisted?.agents,\n ),\n ...(wizardResult.selectedAgents.length > 0 && {\n selectedAgents: wizardResult.selectedAgents,\n }),\n };\n}\n\n/** How many agents a stack carries, as the verbose lines spell it. */\nfunction stackSizeForLog(stack: ProjectConfig[\"stack\"]): string {\n return stack ? `${Object.keys(stack).length} agents` : \"UNDEFINED\";\n}\n\nexport function setConfigMetadata(\n config: ProjectConfig,\n wizardResult: WizardResultV2,\n sourceResult: SourceLoadResult,\n sourceFlag?: string,\n): ProjectConfig {\n const result = { ...config };\n\n // Only persist selected domains when non-empty (sparse output)\n if (wizardResult.selectedDomains.length > 0) {\n result.selectedDomains = wizardResult.selectedDomains;\n }\n\n if (sourceFlag) {\n result.marketplace = sourceFlag;\n } else if (sourceResult.sourceConfig.source) {\n result.marketplace = sourceResult.sourceConfig.source;\n }\n\n if (sourceResult.marketplace) {\n result.marketplaceName = sourceResult.marketplace;\n }\n\n return result;\n}\n\nexport async function buildAndMergeConfig(\n wizardResult: WizardResultV2,\n sourceResult: SourceLoadResult,\n projectDir: string,\n sourceFlag?: string,\n authoritativeScope?: AuthoritativeScope,\n): Promise<MergeResult> {\n const { config } = await buildInstallConfig(wizardResult, sourceResult, projectDir);\n verbose(`buildAndMergeConfig: before merge — stack=${stackSizeForLog(config.stack)}`);\n const configWithMetadata = setConfigMetadata(config, wizardResult, sourceResult, sourceFlag);\n const result = await mergeWithExistingConfig(configWithMetadata, {\n projectDir,\n ...(authoritativeScope !== undefined && { authoritativeScope }),\n });\n verbose(\n `buildAndMergeConfig: after merge — stack=${stackSizeForLog(result.config.stack)}, merged=${result.merged}`,\n );\n return result;\n}\n\nexport function buildCompileAgents(\n config: ProjectConfig,\n agents: Partial<Record<AgentName, AgentDefinition>>,\n): Partial<Record<AgentName, CompileAgentConfig>> {\n const activeAgents = config.agents.filter((a) => !a.excluded);\n const excludedSkillIds = effectivelyExcludedSkillIds(config.skills);\n const globalSkillIds = new Set(\n config.skills.filter((s) => isActiveAt(s, \"global\")).map((s) => s.id),\n );\n const sourceById = new Map<SkillId, string>(config.skills.map((s) => [s.id, s.origin]));\n\n // An effectively excluded skill compiles into no agent, and a global agent takes only the skills\n // active at global scope — the D7 cross-scope safety net.\n const compilesInto = (ref: SkillReference, agentConfig: AgentScopeConfig): boolean => {\n if (excludedSkillIds.has(ref.id)) return false;\n if (agentConfig.scope === \"global\") return globalSkillIds.has(ref.id);\n return true;\n };\n\n // The skill's `origin`, carried as `source`, is what lets the compiler choose per skill between\n // `${id}:${id}` (plugin) and a bare id (eject). A skill with no SkillConfig — a user-authored\n // local one — legitimately has none, so the ref goes through without it.\n const withItsOrigin = (ref: SkillReference): SkillReference => {\n const source = sourceById.get(ref.id);\n return { ...ref, ...(source !== undefined && { source }) };\n };\n\n const buildAgentCompileEntry = (agentConfig: AgentScopeConfig): CompileAgentConfig => {\n // Model/effort are the agent's own settings, not its skills' — a bare agent with no stack\n // entry still carries them, so they are resolved before the skill-less early-out.\n const tuning: CompileAgentConfig = {\n ...(agentConfig.model !== undefined && { model: agentConfig.model }),\n ...(agentConfig.effort !== undefined && { effort: agentConfig.effort }),\n };\n\n const agentStack = config.stack?.[agentConfig.name];\n if (!agentStack) return tuning;\n\n const filteredRefs = buildSkillRefsFromConfig(agentStack)\n .filter((ref) => compilesInto(ref, agentConfig))\n .map(withItsOrigin);\n return { ...tuning, skills: filteredRefs };\n };\n\n return typedFromEntries<AgentName, CompileAgentConfig>(\n activeAgents\n .filter((agentConfig) => agents[agentConfig.name])\n .map((agentConfig) => [agentConfig.name, buildAgentCompileEntry(agentConfig)]),\n );\n}\n\nexport function buildAgentScopeMap(config: ProjectConfig): Map<AgentName, SkillScope> {\n return activeAgentScopeMap(config.agents);\n}\n","import { parse as parseYaml } from \"yaml\";\nimport path from \"path\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { extractFrontmatter } from \"../../utils/frontmatter\";\nimport { glob, readFile, directoryExists, fileExists } from \"../../utils/fs\";\nimport { verbose, warn } from \"../../utils/logger\";\nimport {\n DIRS,\n LOCAL_PSEUDO_CATEGORY,\n STANDARD_DIRS,\n STANDARD_FILES,\n PROJECT_ROOT,\n} from \"../../consts\";\nimport { providerInUse, sourceFolderInUse } from \"../installation/install-layout\";\nimport type {\n AgentDefinition,\n AgentName,\n AgentYamlConfig,\n SkillDefinition,\n SkillDefinitionMap,\n SkillFrontmatter,\n} from \"../../types\";\nimport {\n describeMetadataSchemaFailure,\n formatZodIssues,\n localRawMetadataSchema,\n skillFrontmatterLoaderSchema,\n agentYamlConfigSchema,\n} from \"../schemas\";\nimport type { LocalRawMetadata } from \"../skills/local-skill-loader\";\nimport { METADATA_KEYS } from \"../metadata-keys\";\n\n/** A skill's metadata.yaml as the fields a skill is described by, or why it describes none. */\nexport type SkillMetadataRead =\n { usable: true; metadata: LocalRawMetadata } | { usable: false; reason: string };\n\n/**\n * Reads one skill's metadata.yaml into the fields a skill is described by — the\n * metadata.yaml counterpart of {@link parseFrontmatter}.\n *\n * This is the single judgment of whether a metadata.yaml describes its skill, and\n * every pass that meets one shares it: `compile`'s skill discovery, the local-skill\n * discovery that feeds config-types generation, and `doctor`'s content layer. What\n * each does about a file that describes nothing differs — compile refuses the run,\n * discovery skips the skill, doctor reports it — but what they CALL describing does\n * not. Compile used to check only that the file existed, and then only that it\n * parsed, so it loaded from SKILL.md a skill the same run's config-types pass had\n * already skipped.\n *\n * Both ways of describing nothing are refused here: a file nothing can be parsed\n * out of, and a file that parses without the fields `localRawMetadataSchema`\n * requires. `doctor` layers its stricter published-skill checks on top of the\n * fields this returns; it does not disagree with them.\n */\nexport async function readSkillMetadata(metadataPath: string): Promise<SkillMetadataRead> {\n let parsed: unknown;\n try {\n parsed = parseYaml(await readFile(metadataPath));\n } catch (error) {\n return { usable: false, reason: getErrorMessage(error) };\n }\n\n if (!isFieldMapping(parsed)) {\n return { usable: false, reason: `expected metadata fields, found ${nameYamlValue(parsed)}` };\n }\n\n const validated = localRawMetadataSchema.safeParse(parsed);\n if (!validated.success) {\n return { usable: false, reason: describeMetadataSchemaFailure(validated.error.issues, parsed) };\n }\n\n return { usable: true, metadata: validated.data };\n}\n\n/**\n * Whether this metadata names the `local` placeholder instead of a real category.\n *\n * `local` is a trapdoor rather than a category: it belongs to no domain, so a skill wearing it\n * joins no grid tab and is dropped from every sub-agent's stack. Both passes that read an\n * installed skill's metadata.yaml share this verdict — the local-skill discovery behind the\n * wizard's matrix, and the discovery behind `compile`'s skill count. One reader loading what the\n * other refused is what printed a discovery total beside a refusal about the same skill, in a\n * single run.\n *\n * The sibling of {@link readSkillMetadata}, one question over: that one asks whether the file\n * describes a skill at all, this one whether the skill it describes can be reached. A file can\n * pass the first and fail this, which is why the two verdicts are separate and why this one is\n * not repairable — nothing in the file is malformed.\n */\nexport function namesPlaceholderCategory(metadata: LocalRawMetadata): boolean {\n return metadata.category === LOCAL_PSEUDO_CATEGORY;\n}\n\nfunction isFieldMapping(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Names what a metadata.yaml holds when it holds no fields — for the refusal's reason. */\nfunction nameYamlValue(value: unknown): string {\n if (value === null || value === undefined) return \"an empty file\";\n if (Array.isArray(value)) return \"a list\";\n return `a ${typeof value}`;\n}\n\nexport function parseFrontmatter(content: string, filePath?: string): SkillFrontmatter | null {\n const rawFrontmatter = extractFrontmatter(content);\n if (rawFrontmatter === null) return null;\n\n const parsed = skillFrontmatterLoaderSchema.safeParse(rawFrontmatter);\n\n if (!parsed.success) {\n const location = filePath ?? \"unknown file\";\n warn(`Invalid SKILL.md frontmatter in '${location}': ${formatZodIssues(parsed.error.issues)}`);\n return null;\n }\n return parsed.data;\n}\n\ntype LoadAgentsFromDirOptions = {\n /** Relative base recorded on each definition (project agents live under the source folder's agents/). */\n agentBaseDir?: string;\n /** Propagate the `custom: true` metadata flag (source/CLI agents only). */\n includeCustomFlag?: boolean;\n /** Label for the per-agent verbose line. */\n verboseLabel: string;\n};\n\n/**\n * The one sentence a user gets about an agent `metadata.yaml` this loader would not take.\n *\n * The path is the point: this is the last boundary that still knows which file the value came\n * from. Everything downstream reports against a compiled `.md` the user never wrote.\n */\nfunction refusalOfAgentMetadata(metadataPath: string, reason: string): string {\n return `Skipping invalid ${STANDARD_FILES.AGENT_METADATA_YAML} at '${metadataPath}': ${reason}`;\n}\n\n// Boundary cast: agent keys come from agentYamlConfigSchema which types config.id as AgentName;\n// custom agents (not in the union) are accepted by the schema's z.string() base\nasync function loadAgentsFromDir(\n agentsDir: string,\n sourceRoot: string,\n options: LoadAgentsFromDirOptions,\n): Promise<Partial<Record<AgentName, AgentDefinition>>> {\n const agents: Record<string, AgentDefinition> = {};\n const files = await glob(`**/${STANDARD_FILES.AGENT_METADATA_YAML}`, agentsDir);\n\n for (const file of files) {\n const fullPath = path.join(agentsDir, file);\n try {\n const content = await readFile(fullPath);\n // safeParse rather than parse: a ZodError's own message is a JSON dump of its issues, and\n // this warning is the only place a user is told which metadata.yaml is wrong and why.\n const parsed = agentYamlConfigSchema.safeParse(parseYaml(content));\n if (!parsed.success) {\n warn(refusalOfAgentMetadata(fullPath, formatZodIssues(parsed.error.issues)));\n continue;\n }\n const config = parsed.data;\n\n agents[config.id] = toAgentDefinition(config, file, sourceRoot, options);\n verbose(`Loaded ${options.verboseLabel}: ${config.id} from ${file}`);\n } catch (error) {\n warn(refusalOfAgentMetadata(fullPath, getErrorMessage(error)));\n }\n }\n\n return agents;\n}\n\n/**\n * One parsed agent `metadata.yaml` as the definition the compiler reads, recording where it was\n * found: `file` is its path under the agents directory, whose parent becomes the agent's `path`.\n */\nfunction toAgentDefinition(\n config: AgentYamlConfig,\n file: string,\n sourceRoot: string,\n options: LoadAgentsFromDirOptions,\n): AgentDefinition {\n return {\n title: config.title,\n description: config.description,\n ...(config.model !== undefined && { model: config.model }),\n ...(config.effort !== undefined && { effort: config.effort }),\n tools: config.tools,\n // The rest of what `agent.liquid` reads. Spread conditionally, because the template\n // branches on presence — an explicit `undefined` renders as an empty frontmatter key.\n ...(config.disallowedTools !== undefined && {\n disallowedTools: config.disallowedTools,\n }),\n ...(config.permissionMode !== undefined && { permissionMode: config.permissionMode }),\n ...(config.isolation !== undefined && { isolation: config.isolation }),\n ...(config.hooks !== undefined && { hooks: config.hooks }),\n ...(config.experimental !== undefined && { experimental: config.experimental }),\n ...(config.outputFormat !== undefined && { outputFormat: config.outputFormat }),\n path: path.dirname(file),\n sourceRoot,\n ...(options.agentBaseDir ? { agentBaseDir: options.agentBaseDir } : {}),\n ...(config.domain ? { domain: config.domain } : {}),\n ...(options.includeCustomFlag && config.custom === true ? { custom: true } : {}),\n };\n}\n\nexport async function loadAllAgents(\n projectRoot: string,\n): Promise<Partial<Record<AgentName, AgentDefinition>>> {\n return loadAgentsFromDir(path.join(projectRoot, DIRS.agents), projectRoot, {\n includeCustomFlag: true,\n verboseLabel: \"agent\",\n });\n}\n\n/**\n * Loads agent definitions from the CLI repo and a skills source in parallel,\n * merged so source definitions take precedence on name collisions.\n */\nexport async function loadMergedAgents(\n sourcePath: string,\n): Promise<Partial<Record<AgentName, AgentDefinition>>> {\n const [cliAgents, sourceAgents] = await Promise.all([\n loadAllAgents(PROJECT_ROOT),\n loadAllAgents(sourcePath),\n ]);\n return { ...cliAgents, ...sourceAgents };\n}\n\nexport async function loadProjectAgents(\n projectRoot: string,\n): Promise<Partial<Record<AgentName, AgentDefinition>>> {\n const sourceFolder = sourceFolderInUse(projectRoot, providerInUse(projectRoot));\n const projectAgentsDir = path.join(sourceFolder.dir, STANDARD_DIRS.AGENTS);\n\n if (!(await directoryExists(projectAgentsDir))) {\n verbose(`No project agents directory at ${projectAgentsDir}`);\n const noAgents: Record<string, AgentDefinition> = {};\n return noAgents;\n }\n\n return loadAgentsFromDir(projectAgentsDir, projectRoot, {\n // The recorded base is the folder this scope is actually on, so an agent's `path` names a\n // directory the reader can open rather than the layout the product is moving to.\n agentBaseDir: `${sourceFolder.relName}/${STANDARD_DIRS.AGENTS}`,\n verboseLabel: \"project agent\",\n });\n}\n\nexport type LoadSkillsFromDirOptions = {\n /** Path prefix recorded on each skill's `path` (e.g. LOCAL_SKILLS_PATH or \"skills\"). */\n pathPrefix?: string;\n /**\n * When true, a SKILL.md whose sibling metadata.yaml is missing, or present but\n * describing no skill, is skipped (local-skill registration rule). Plugin\n * discovery passes false — plugin skills carry no metadata.yaml.\n */\n requireMetadata?: boolean;\n};\n\n/** One skill directory whose metadata.yaml exists but describes no skill. */\nexport type UnusableSkillMetadata = {\n /** The skill's directory name, as it appears under `.claude/skills/`. */\n skillDirName: string;\n /** Absolute path to the offending metadata.yaml. */\n metadataPath: string;\n /** The YAML parser's own message, what the file holds instead of fields, or which fields it lacks. */\n reason: string;\n};\n\nexport type LoadedSkills = {\n skills: SkillDefinitionMap;\n /**\n * Skill directories refused by {@link readSkillMetadata}. Only ever non-empty\n * under `requireMetadata` — a plugin skill carries no metadata.yaml to refuse.\n */\n unusableMetadata: UnusableSkillMetadata[];\n};\n\n/**\n * Loads SKILL.md files from a directory, parsing frontmatter for skill metadata.\n * Returns the skillId -> SkillDefinition map plus every skill directory whose\n * metadata.yaml describes no skill. Missing/invalid frontmatter and per-file read\n * errors are logged and skipped, never thrown.\n */\nexport async function loadSkillsFromDir(\n skillsDir: string,\n options: LoadSkillsFromDirOptions = {},\n): Promise<LoadedSkills> {\n const { pathPrefix = \"\", requireMetadata = false } = options;\n const skills: SkillDefinitionMap = {};\n const unusableMetadata: UnusableSkillMetadata[] = [];\n\n if (!(await directoryExists(skillsDir))) {\n return { skills, unusableMetadata };\n }\n\n const skillFiles = await glob(`**/${STANDARD_FILES.SKILL_MD}`, skillsDir);\n\n for (const skillFile of skillFiles) {\n const skill = locateSkill(skillsDir, skillFile, pathPrefix);\n\n if (requireMetadata) {\n const verdict = await judgeSkillMetadata(skill);\n if (verdict.kind === \"unusable\") unusableMetadata.push(verdict.refusal);\n if (verdict.kind !== \"admitted\") continue;\n }\n\n const definition = await readSkillDefinition(skill);\n if (definition) skills[definition.id] = definition;\n }\n\n return { skills, unusableMetadata };\n}\n\n/** One SKILL.md the glob found, in each of the forms the loader reads or reports it by. */\ntype SkillLocation = {\n /** The SKILL.md relative to the skills directory, as the glob returned it. */\n skillFile: string;\n /** Absolute path to the SKILL.md. */\n skillMdPath: string;\n /** Absolute path to the directory holding it. */\n skillDir: string;\n /** That directory's own name. */\n skillDirName: string;\n /** The `path` recorded on the skill: prefixed, relative, slash-terminated. */\n displayPath: string;\n};\n\nfunction locateSkill(skillsDir: string, skillFile: string, pathPrefix: string): SkillLocation {\n const skillMdPath = path.join(skillsDir, skillFile);\n const skillDir = path.dirname(skillMdPath);\n const relativePath = path.relative(skillsDir, skillDir);\n\n return {\n skillFile,\n skillMdPath,\n skillDir,\n skillDirName: path.basename(skillDir),\n displayPath: pathPrefix ? `${pathPrefix}/${relativePath}/` : `${relativePath}/`,\n };\n}\n\n/**\n * What a skill's metadata.yaml says about loading it, under `requireMetadata`. Only an\n * `unusable` file is the caller's to report; a `skipped` skill is logged here and left out.\n */\ntype SkillMetadataVerdict =\n { kind: \"admitted\" } | { kind: \"skipped\" } | { kind: \"unusable\"; refusal: UnusableSkillMetadata };\n\nasync function judgeSkillMetadata(skill: SkillLocation): Promise<SkillMetadataVerdict> {\n const metadataPath = path.join(skill.skillDir, STANDARD_FILES.METADATA_YAML);\n if (!(await fileExists(metadataPath))) {\n warn(\n `Skill '${skill.skillDirName}' in '${skill.displayPath}' is missing ${STANDARD_FILES.METADATA_YAML} — skipped. Add ${STANDARD_FILES.METADATA_YAML} to register it with the CLI.`,\n );\n return { kind: \"skipped\" };\n }\n\n // A metadata.yaml that describes no skill is reported to the caller rather\n // than loaded around: the local-skill discovery behind config-types\n // generation refuses the same file, and compile refuses the whole run over it.\n const read = await readSkillMetadata(metadataPath);\n if (!read.usable) {\n verbose(` Unusable ${STANDARD_FILES.METADATA_YAML} in '${skill.skillDirName}'`);\n return {\n kind: \"unusable\",\n refusal: { skillDirName: skill.skillDirName, metadataPath, reason: read.reason },\n };\n }\n\n // Skipped rather than reported, and silently: the file is intact, so there is nothing\n // here to repair or refuse a run over — and the sentence telling the user which field\n // to fix is `extractLocalSkill`'s, which every command reaching here also runs.\n if (namesPlaceholderCategory(read.metadata)) {\n verbose(` Placeholder ${METADATA_KEYS.CATEGORY} in '${skill.skillDirName}'`);\n return { kind: \"skipped\" };\n }\n\n return { kind: \"admitted\" };\n}\n\n/**\n * The skill a SKILL.md defines, keyed by its frontmatter `name`, or undefined — logged, never\n * thrown — when the file cannot be read or names no skill.\n */\nasync function readSkillDefinition(skill: SkillLocation): Promise<SkillDefinition | undefined> {\n try {\n const content = await readFile(skill.skillMdPath);\n const frontmatter = parseFrontmatter(content, skill.skillMdPath);\n\n if (!frontmatter?.name) {\n warn(`Skipping skill in '${skill.skillDirName}': missing or invalid frontmatter name`);\n return undefined;\n }\n\n const canonicalId = frontmatter.name;\n verbose(` Loaded skill: ${canonicalId}`);\n return {\n id: canonicalId,\n path: skill.displayPath,\n description: frontmatter.description || \"\",\n };\n } catch (error) {\n verbose(` Failed to load skill: ${skill.skillFile} - ${getErrorMessage(error)}`);\n return undefined;\n }\n}\n\n/**\n * Loads skills from a plugin's `skills/` subdirectory. Plugin skills carry no\n * metadata.yaml, so metadata is not required here — and nothing can be refused\n * for one, which is why only the skill map comes back.\n */\nexport async function loadPluginSkills(pluginDir: string): Promise<SkillDefinitionMap> {\n const { skills } = await loadSkillsFromDir(path.join(pluginDir, \"skills\"), {\n pathPrefix: \"skills\",\n requireMetadata: false,\n });\n return skills;\n}\n","import { parse as parseYaml } from \"yaml\";\nimport { getErrorMessage } from \"./errors\";\n\n/** The YAML between the `---` fences that open a file. */\nconst FRONTMATTER_PATTERN = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---/;\n\n/** A file's frontmatter, parsed — or why it could not be. */\ntype FrontmatterRead = { parsed: unknown } | { unreadable: string };\n\nfunction readFrontmatter(content: string): FrontmatterRead {\n const block = content.match(FRONTMATTER_PATTERN)?.[1];\n if (!block) return { unreadable: \"there is no frontmatter between --- fences at its top\" };\n\n try {\n return { parsed: parseYaml(block) };\n } catch (error) {\n return { unreadable: getErrorMessage(error) };\n }\n}\n\nexport function extractFrontmatter(content: string): unknown {\n const read = readFrontmatter(content);\n return \"parsed\" in read ? read.parsed : null;\n}\n\n/**\n * Why a file's frontmatter reads as nothing at all, or `undefined` when it reads as something.\n *\n * {@link extractFrontmatter} answers `null` for a file with no frontmatter, an empty one, and one\n * whose YAML will not parse, which is all a reader that only skips needs. A caller that names the\n * file it skipped needs to say which of the three it was, with the parser's own reason.\n */\nexport function unreadableFrontmatter(content: string): string | undefined {\n const read = readFrontmatter(content);\n if (\"unreadable\" in read) return read.unreadable;\n return read.parsed === null ? \"its frontmatter is empty\" : undefined;\n}\n","import { createHash } from \"crypto\";\nimport { isRecord } from \"../../utils/type-guards.js\";\nimport { downloadTemplate, type DownloadTemplateResult } from \"giget\";\nimport os from \"os\";\nimport path from \"path\";\nimport type { z } from \"zod\";\n\nimport {\n cacheRoot,\n CACHE_HASH_LENGTH,\n CACHE_READABLE_PREFIX_LENGTH,\n MAX_MARKETPLACE_FILE_SIZE,\n MAX_JSON_NESTING_DEPTH,\n MAX_MARKETPLACE_PLUGINS,\n MARKETPLACE_JSON,\n marketplaceManifestPath,\n} from \"../../consts\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport {\n ensureDir,\n directoryExists,\n fileExists,\n readFileOptional,\n readFileSafe,\n remove,\n writeFile,\n} from \"../../utils/fs\";\nimport { log, verbose, warn } from \"../../utils/logger\";\nimport { sourceUnreachableUsingCache, STATUS_MESSAGES } from \"../../utils/messages\";\nimport { DEFAULT_SOURCE, isLocalSource } from \"../configuration\";\nimport { validateLoadedMarketplaceName } from \"../marketplace-generator\";\nimport {\n formatZodIssues,\n marketplaceSchema,\n sourceRevalidationSchema,\n validateNestingDepth,\n warnUnknownFields,\n} from \"../schemas\";\nimport type { Marketplace, MarketplaceFetchResult } from \"../../types\";\n\n/** Safe name pattern: alphanumeric, hyphens, underscores, dots, spaces, @, / (no shell metacharacters) */\nconst SAFE_NAME_PATTERN = /^[a-zA-Z0-9@._/ -]+$/;\nconst MAX_NAME_LENGTH = 200;\n\n/** Matches giget's source protocol regex to extract provider name */\nconst SOURCE_PROTO_RE = /^([\\w-.]+):/;\n\n/**\n * Matches giget's input regex for git URI parsing.\n * Groups: repo (org/name), subdir (optional path), ref (optional #branch)\n */\nconst GIT_URI_RE = /^(?<repo>[\\w.-]+\\/[\\w.-]+)(?<subdir>[^#]+)?(?<ref>#[\\w./@-]+)?/;\n\nexport type FetchOptions = {\n subdir?: string;\n};\n\nexport type FetchResult = {\n path: string;\n fromCache: boolean;\n source: string;\n};\n\nexport function sanitizeSourceForCache(source: string): string {\n const hash = createHash(\"sha256\").update(source).digest(\"hex\").slice(0, CACHE_HASH_LENGTH);\n\n const readable = source\n .replace(/[^a-zA-Z0-9]/g, \"-\")\n .replace(/--+/g, \"-\")\n .replace(/^-|-$/g, \"\")\n .slice(0, CACHE_READABLE_PREFIX_LENGTH);\n\n return readable ? `${readable}-${hash}` : hash;\n}\n\nfunction getCacheDir(source: string): string {\n const sanitized = sanitizeSourceForCache(source) || \"unknown\";\n return path.join(cacheRoot(), \"sources\", sanitized);\n}\n\nexport async function fetchFromSource(\n source: string,\n options: FetchOptions = {},\n): Promise<FetchResult> {\n const { subdir } = options;\n\n if (isLocalSource(source)) {\n return fetchFromLocalSource(source, subdir);\n }\n\n return fetchFromRemoteSource(source, subdir);\n}\n\nasync function fetchFromLocalSource(source: string, subdir?: string): Promise<FetchResult> {\n const fullPath = subdir ? path.join(source, subdir) : source;\n const absolutePath = path.isAbsolute(fullPath) ? fullPath : path.resolve(process.cwd(), fullPath);\n\n if (!(await directoryExists(absolutePath))) {\n throw new Error(\n `Local marketplace not found: '${absolutePath}'\\n\\n` +\n `Nothing is at that path, and a local marketplace must be a directory holding skills.\\n\\n` +\n `Check it for a typo, or name a marketplace that exists:\\n` +\n ` --marketplace ${DEFAULT_SOURCE}`,\n );\n }\n\n verbose(`Using local marketplace: ${absolutePath}`);\n\n return {\n path: absolutePath,\n fromCache: false,\n source,\n };\n}\n\n/**\n * Compute the giget tarball cache directory for a source.\n *\n * Replicates giget's internal cache path logic:\n * `{gigetCacheRoot}/{providerName}/{templateName}`\n *\n * where templateName is `repo.replace(\"/\", \"-\")` sanitized to `[a-zA-Z0-9-]`.\n * Returns undefined if the source format doesn't match giget's git URI pattern.\n */\nexport function getGigetCacheDir(source: string): string | undefined {\n const protoMatch = source.match(SOURCE_PROTO_RE);\n\n // http/https providers use the full URL, not parseable as git URI\n if (protoMatch && (protoMatch[1] === \"http\" || protoMatch[1] === \"https\")) {\n return undefined;\n }\n\n const providerName = protoMatch?.[1] ?? \"github\";\n const rawSource = protoMatch ? source.slice(protoMatch[0].length) : source;\n\n const uriMatch = rawSource.match(GIT_URI_RE);\n if (!uriMatch?.groups?.repo) {\n return undefined;\n }\n\n // Replicate giget's template.name sanitization\n const templateName = uriMatch.groups.repo.replace(\"/\", \"-\").replace(/[^\\da-z-]/gi, \"-\");\n\n const gigetCacheRoot = process.env.XDG_CACHE_HOME\n ? path.resolve(process.env.XDG_CACHE_HOME, \"giget\")\n : path.resolve(os.homedir(), \".cache\", \"giget\");\n\n return path.join(gigetCacheRoot, providerName, templateName);\n}\n\n/**\n * Clear giget's tarball/ETag cache for a source so downloadTemplate()\n * performs a fresh fetch instead of short-circuiting with a stale ETag.\n */\nasync function clearGigetCache(source: string): Promise<void> {\n const gigetDir = getGigetCacheDir(source);\n if (!gigetDir) return;\n\n if (await directoryExists(gigetDir)) {\n verbose(`Clearing giget cache: ${gigetDir}`);\n await remove(gigetDir);\n }\n}\n\nasync function fetchFromRemoteSource(source: string, subdir?: string): Promise<FetchResult> {\n const cacheDir = getCacheDir(source);\n const fullSource = subdir ? `${source}/${subdir}` : source;\n\n verbose(`Fetching from remote: ${fullSource}`);\n verbose(`Cache directory: ${cacheDir}`);\n\n if (await directoryExists(cacheDir)) {\n const verdict = await revalidateCachedCopy(cacheDir, source);\n const cached: FetchResult = { path: cacheDir, fromCache: true, source: fullSource };\n\n if (verdict === \"current\" || verdict === \"unreachable\") {\n verbose(`Using cached marketplace: ${cacheDir}`);\n return cached;\n }\n\n announceRefetch(verdict);\n await clearGigetCache(source);\n await remove(cacheDir);\n }\n\n await ensureDir(path.dirname(cacheDir));\n\n try {\n const result = await downloadTemplate(fullSource, {\n dir: cacheDir,\n force: true, // Always force when downloading to avoid \"already exists\" error\n offline: false,\n });\n\n verbose(`Downloaded to: ${result.dir}`);\n await recordFetchedCopy(cacheDir, result);\n markCopyCurrentForThisRun(cacheDir);\n\n return {\n path: result.dir,\n fromCache: false,\n source: fullSource,\n };\n } catch (error) {\n throw createDetailedFetchError(error, source);\n }\n}\n\n/**\n * What a revalidation learned about the copy in the cache.\n *\n * `unrecorded` is a cache with no fetch record beside it — written before this\n * check existed, or by hand. Nothing can be asked about it, so it is re-fetched\n * once to establish a record, and that re-fetch is not a change to announce.\n */\ntype CacheVerdict = \"current\" | \"superseded\" | \"unrecorded\" | \"unreachable\";\n\ntype SourceRevalidation = z.infer<typeof sourceRevalidationSchema>;\n\n/**\n * How long a revalidation may spend asking before the cached copy is used\n * instead. Against the default marketplace the question costs ~260ms, so five\n * seconds is around twenty times a healthy answer: a link slow enough to need\n * that much is still given the chance to answer, rather than being told its copy\n * may be stale when the source was reachable all along. Being unreachable is the\n * rare case, and a longer honest wait for it is cheaper than a wrong verdict on\n * a slow one. The bound still exists — the platform's own connect timeout is\n * ~10s, which is the wait no user with a dropped connection should sit through\n * for an answer their cache already holds.\n */\nconst REVALIDATION_TIMEOUT_MS = 5000;\n\n/** Where a cache directory's fetch record sits: beside it, never inside it. */\nconst FETCH_RECORD_SUFFIX = \".etag.json\";\n\n/**\n * One question per source per process. A single command loads the same source\n * more than once — the matrix and the marketplace label are separate calls — and\n * the answer cannot change between them.\n */\nconst askedThisRun = new Map<string, Promise<CacheVerdict>>();\n\n/**\n * The one line a re-fetch nobody asked for owes the user — and silence for\n * `unrecorded`, where the CLI cannot place the copy it holds and the re-fetch is\n * housekeeping rather than news.\n *\n * The parameter is the two verdicts that reach a download, not the whole union:\n * a new verdict that must not fall through to one fails here at the call site.\n */\nfunction announceRefetch(verdict: Extract<CacheVerdict, \"superseded\" | \"unrecorded\">): void {\n if (verdict === \"superseded\") {\n log(STATUS_MESSAGES.MARKETPLACE_HAS_NEWER_CONTENT);\n }\n}\n\nfunction revalidateCachedCopy(cacheDir: string, source: string): Promise<CacheVerdict> {\n const asked = askedThisRun.get(cacheDir);\n if (asked) return asked;\n\n const verdict = classifyCachedCopy(cacheDir, source);\n askedThisRun.set(cacheDir, verdict);\n return verdict;\n}\n\n/**\n * The answer for a copy this run has just downloaded, without asking for it: the\n * record written beside it names the tarball the source served a moment ago, so\n * within this run the copy is current by construction. Without it, the later\n * loads of the same command re-read a `superseded` answer that was true when it\n * was given and has been acted on since — and download it all over again.\n */\nfunction markCopyCurrentForThisRun(cacheDir: string): void {\n askedThisRun.set(cacheDir, Promise.resolve(\"current\"));\n}\n\n/**\n * The one question a run asks about a cached copy, and everything that answer\n * owes the user.\n *\n * An unreachable source's staleness is named here rather than at the call site\n * because the verdict is memoised and the line is owed once per source per run:\n * left outside, every later load of the same run repeats a warning about a\n * question that was only asked once.\n */\nasync function classifyCachedCopy(cacheDir: string, source: string): Promise<CacheVerdict> {\n const record = await readFetchRecord(cacheDir);\n if (!record) return \"unrecorded\";\n\n if (record.etag === undefined) {\n verbose(`No ETag was recorded for ${record.tar} — keeping the cached copy`);\n return \"current\";\n }\n\n try {\n const live = await fetchEtag(record.tar);\n if (live === undefined) {\n verbose(`${record.tar} answered without an ETag — keeping the cached copy`);\n return \"current\";\n }\n return live === record.etag ? \"current\" : \"superseded\";\n } catch (error) {\n verbose(`Could not revalidate ${record.tar}: ${getErrorMessage(error)}`);\n warn(sourceUnreachableUsingCache(source));\n return \"unreachable\";\n }\n}\n\n/**\n * The tarball's ETag as the host reports it now, asked for the same way giget\n * asks — a HEAD, from the same runtime — so the two agree on what the value for\n * a given source is. A private repository needs the token giget uses; it is read\n * from the environment per request and never written into the record.\n */\nasync function fetchEtag(tar: string): Promise<string | undefined> {\n const auth = process.env.GIGET_AUTH;\n const response = await fetch(tar, {\n method: \"HEAD\",\n ...(auth && { headers: { Authorization: `Bearer ${auth}` } }),\n signal: AbortSignal.timeout(REVALIDATION_TIMEOUT_MS),\n });\n return response.headers.get(\"etag\") ?? undefined;\n}\n\n/**\n * Where the record for a cached copy lives — exported because a second surface has to agree with\n * this one on the address: `e2e/fixtures/default-source-cache.ts` seeds a copy of the DEFAULT\n * source, and a run over a seeded copy with no record here re-downloads it over the network, which\n * is the one thing that fixture exists to avoid.\n */\nexport function fetchRecordPath(cacheDir: string): string {\n return `${cacheDir}${FETCH_RECORD_SUFFIX}`;\n}\n\nasync function readFetchRecord(cacheDir: string): Promise<SourceRevalidation | undefined> {\n const raw = await readFileOptional(fetchRecordPath(cacheDir));\n if (!raw) return undefined;\n\n const parsed = sourceRevalidationSchema.safeParse(parseJsonOrUndefined(raw));\n if (!parsed.success) {\n verbose(`Unusable fetch record at ${fetchRecordPath(cacheDir)} — re-fetching the marketplace`);\n return undefined;\n }\n\n return parsed.data;\n}\n\n/**\n * Records what would prove this copy current, so the next load can ask in one\n * request.\n *\n * The tarball URL is read off giget's own result rather than rebuilt here, which\n * is what keeps this provider-agnostic — it is whatever giget resolved for the\n * source. giget's result type erases its fields to an index signature, so the\n * value arrives untyped and is narrowed rather than trusted; without one there\n * is nothing to ask about and the copy stays unrecorded.\n */\nasync function recordFetchedCopy(cacheDir: string, result: DownloadTemplateResult): Promise<void> {\n const tar: unknown = result.tar;\n if (typeof tar !== \"string\") {\n verbose(\"No tarball URL came back from the download — the copy cannot be revalidated\");\n return;\n }\n\n const etag = await fetchEtag(tar).catch(() => undefined);\n const record: SourceRevalidation = { tar, ...(etag !== undefined && { etag }) };\n await writeFile(fetchRecordPath(cacheDir), JSON.stringify(record));\n}\n\nfunction parseJsonOrUndefined(raw: string): unknown {\n try {\n return JSON.parse(raw);\n } catch {\n return undefined;\n }\n}\n\nfunction createDetailedFetchError(error: unknown, source: string): Error {\n const message = getErrorMessage(error);\n\n if (message.includes(\"404\") || message.includes(\"Not Found\")) {\n return new Error(\n `Repository not found: ${source}\\n\\n` +\n `This could mean:\\n` +\n ` - The repository doesn't exist\\n` +\n ` - The repository is private and you need to set authentication\\n` +\n ` - There's a typo in the URL\\n\\n` +\n `For private repositories, set the GIGET_AUTH environment variable:\\n` +\n ` export GIGET_AUTH=ghp_your_github_token`,\n );\n }\n\n if (message.includes(\"401\") || message.includes(\"Unauthorized\")) {\n return new Error(\n `Authentication required for: ${source}\\n\\n` +\n `Set the GIGET_AUTH environment variable with a GitHub token:\\n` +\n ` export GIGET_AUTH=ghp_your_github_token\\n\\n` +\n `Create a token at: https://github.com/settings/tokens\\n` +\n `Required scope: repo (for private repos) or public_repo (for public)`,\n );\n }\n\n if (message.includes(\"403\") || message.includes(\"Forbidden\")) {\n return new Error(\n `Access denied to: ${source}\\n\\n` +\n `Your token may not have sufficient permissions.\\n` +\n `Ensure your GIGET_AUTH token has the 'repo' scope for private repositories.`,\n );\n }\n\n if (\n message.includes(\"ENOTFOUND\") ||\n message.includes(\"ETIMEDOUT\") ||\n message.includes(\"network\")\n ) {\n return new Error(\n `Network error fetching: ${source}\\n\\n` +\n `Please check your internet connection.\\n` +\n `If you're behind a corporate proxy, you may need to set:\\n` +\n ` export HTTPS_PROXY=http://your-proxy:port\\n` +\n ` export FORCE_NODE_FETCH=true # Required for Node 20+`,\n );\n }\n\n return new Error(`Failed to fetch ${source}: ${message}`);\n}\n\n/**\n * Thrown when a marketplace has no manifest at all, which every other failure in\n * {@link fetchMarketplace} is not.\n *\n * A type rather than a sentence a caller matches on: absent and unreadable have\n * different remedies — add the file, versus repair the file that is already there —\n * and the only way a caller can report them apart is if the throw says which it is.\n * A caller that does not care still catches an ordinary `Error`.\n */\nexport class MarketplaceManifestAbsentError extends Error {}\n\n/**\n * Thrown when the manifest is there, parses, and names the marketplace something this\n * CLI refuses to publish under.\n *\n * A type of its own for the reason {@link MarketplaceManifestAbsentError} is one, and\n * one step further: this is the only manifest defect whose remedy is not \"repair the\n * file so the marketplace can be named\" but \"there is nothing to install here at all\".\n * The name is the namespace Claude Code registers every plugin under, so a name it will\n * not accept leaves a marketplace that loads and can install nothing — which is the\n * state `build marketplace` refuses to publish and this is the same rule read on load.\n * Every other refusal in {@link fetchMarketplace} is a manifest to repair or rebuild, so\n * it stays an ordinary `Error`.\n */\nexport class MarketplaceNameRefusedError extends Error {}\n\n/**\n * The manifest field whose value a load then USES, spelled against the type so a rename\n * of it fails here rather than silently stopping the refusal below from firing.\n */\nconst MANIFEST_NAME_FIELD: keyof Marketplace = \"name\";\n\n/**\n * How a reserved name is replaced on load, worded as the schema's own name refusal words it\n * (`MARKETPLACE_NAME_REFUSAL` in `schemas.ts`): the manifest is the file being read, so it is\n * the one a reader can change.\n */\nconst LOADED_NAME_WAY_OUT = \"rename the marketplace in this manifest\";\n\n/**\n * Whether a manifest's refusal is about its name.\n *\n * Read off the issue's PATH rather than its text, for the reason\n * {@link MarketplaceManifestAbsentError} is a type: a message is prose that gets\n * rewritten, and a caller matching on one is a caller that stops working silently.\n */\nfunction refusesTheName(issues: readonly z.ZodIssue[]): boolean {\n return issues.some((issue) => issue.path.length === 1 && issue.path[0] === MANIFEST_NAME_FIELD);\n}\n\n/**\n * A refused manifest as the throw its readers tell apart — see\n * {@link MarketplaceNameRefusedError} for which refusal earns which type. The message is\n * one sentence either way: what separates them is the remedy, not the wording.\n */\nfunction manifestRefusal(marketplacePath: string, issues: readonly z.ZodIssue[]): Error {\n const message =\n `Invalid ${MARKETPLACE_JSON} at: ${marketplacePath}\\n\\n` +\n `Validation errors: ${formatZodIssues([...issues])}`;\n\n return refusesTheName(issues) ? new MarketplaceNameRefusedError(message) : new Error(message);\n}\n\nexport async function fetchMarketplace(source: string): Promise<MarketplaceFetchResult> {\n const result = await fetchFromSource(source, {\n subdir: \"\", // Root of repo\n });\n\n const marketplacePath = marketplaceManifestPath(result.path);\n\n // The FILE, not its directory: a plugin repository ships `.claude-plugin/plugin.json`\n // with no marketplace beside it, and a directory check calls that manifest readable\n // and leaves the absence to surface as a read error two statements later.\n if (!(await fileExists(marketplacePath))) {\n throw new MarketplaceManifestAbsentError(\n `Marketplace not found at: ${source}\\n\\n` +\n `The .claude-plugin/marketplace.json file is missing from this repository.\\n\\n` +\n `Possible causes:\\n` +\n \" - The marketplace URL may be incorrect\\n\" +\n \" - The repository may not have a marketplace configured\\n\\n\" +\n \"To create a marketplace, add a .claude-plugin/marketplace.json file to your marketplace repository.\",\n );\n }\n\n const content = await readFileSafe(marketplacePath, MAX_MARKETPLACE_FILE_SIZE);\n const parsed: unknown = JSON.parse(content);\n\n if (!validateNestingDepth(parsed, MAX_JSON_NESTING_DEPTH)) {\n throw new Error(\n `Invalid marketplace.json at: ${marketplacePath}\\n\\n` +\n `JSON structure exceeds maximum nesting depth of ${MAX_JSON_NESTING_DEPTH}.`,\n );\n }\n\n const validation = marketplaceSchema.safeParse(parsed);\n\n if (!validation.success) {\n throw manifestRefusal(marketplacePath, validation.error.issues);\n }\n\n const marketplace = validation.data;\n\n const reservedName = validateLoadedMarketplaceName(marketplace.name, LOADED_NAME_WAY_OUT);\n if (reservedName) {\n throw new MarketplaceNameRefusedError(\n `Invalid ${MARKETPLACE_JSON} at: ${marketplacePath}\\n\\n${reservedName}`,\n );\n }\n\n const EXPECTED_MARKETPLACE_KEYS = [\n \"$schema\",\n \"name\",\n \"version\",\n \"description\",\n \"owner\",\n \"metadata\",\n \"plugins\",\n ] as const;\n if (isRecord(parsed)) {\n warnUnknownFields(parsed, EXPECTED_MARKETPLACE_KEYS, MARKETPLACE_JSON);\n }\n\n if (marketplace.plugins.length > MAX_MARKETPLACE_PLUGINS) {\n throw new Error(\n `Invalid marketplace.json at: ${marketplacePath}\\n\\n` +\n `Too many plugins: ${marketplace.plugins.length} (limit: ${MAX_MARKETPLACE_PLUGINS}).`,\n );\n }\n\n for (const plugin of marketplace.plugins) {\n if (plugin.name.length > MAX_NAME_LENGTH) {\n warn(\n `Marketplace plugin name too long (${plugin.name.length} chars): '${plugin.name.slice(0, 50)}...'`,\n );\n }\n if (!SAFE_NAME_PATTERN.test(plugin.name)) {\n warn(`Marketplace plugin name contains unsafe characters: '${plugin.name.slice(0, 50)}'`);\n }\n }\n\n verbose(`Loaded marketplace: ${marketplace.name} v${marketplace.version}`);\n\n return {\n marketplace,\n sourcePath: result.path,\n fromCache: result.fromCache,\n };\n}\n","import path from \"path\";\nimport { countBy, sortBy } from \"remeda\";\n\nimport {\n DEFAULT_PUBLIC_SOURCE_NAME,\n DEFAULT_VERSION,\n EJECT_SOURCE,\n PLUGIN_MANIFEST_DIR,\n PLUGIN_MANIFEST_FILE,\n PUBLIC_CATALOGUE_PACKAGE,\n} from \"../consts\";\nimport { writeFile, glob, ensureDir } from \"../utils/fs\";\nimport { verbose, warn } from \"../utils/logger\";\nimport type { Marketplace, MarketplacePlugin, PluginManifest } from \"../types\";\n// The module rather than the `./plugins` barrel: the loader reads this file's load-side refusal,\n// and the barrel reaches the loader back through plugin discovery.\nimport { readPluginManifest } from \"./plugins/plugin-finder\";\n\nconst PLUGIN_MANIFEST_PATH = `${PLUGIN_MANIFEST_DIR}/${PLUGIN_MANIFEST_FILE}`;\nconst MARKETPLACE_SCHEMA_URL = \"https://anthropic.com/claude-code/marketplace.schema.json\";\n\n/** Namespace a skill with no marketplace at all is given. */\nconst EXTERNAL_SKILL_NAMESPACE = \"external\";\n\n/** Namespace a skill created in place, rather than fetched from a marketplace, is given. */\nconst LOCAL_SKILL_NAMESPACE = \"local\";\n\n/**\n * Marketplace names that are not an author's to take.\n *\n * The public catalogue's skills ship unprefixed, so every bare id in the catalogue\n * already lives in `agents-inc`; `external` and `local` hold the skills that belong to\n * no marketplace. Publishing under any of those claims ids the marketplace does not own.\n * `eject` is the `origin` an installation records for a skill copied into it, so a\n * marketplace under that name has every skill it installs read back as an ejected copy —\n * a plugin install turned into a silent local one.\n */\nconst RESERVED_MARKETPLACE_NAMES: readonly string[] = [\n DEFAULT_PUBLIC_SOURCE_NAME,\n EXTERNAL_SKILL_NAMESPACE,\n LOCAL_SKILL_NAMESPACE,\n EJECT_SOURCE,\n];\n\n/** How many offending ids a namespace refusal lists before summarising the rest. */\nconst MAX_REPORTED_NAMESPACE_VIOLATIONS = 10;\n\ntype MarketplaceOptions = {\n name: string;\n version?: string;\n description?: string;\n ownerName: string;\n ownerEmail?: string;\n pluginRoot: string;\n};\n\nfunction convertManifestToMarketplacePlugin(\n manifest: PluginManifest,\n pluginRoot: string,\n pluginDirName: string,\n): MarketplacePlugin {\n return {\n name: manifest.name,\n source: `./${pluginRoot}/${pluginDirName}`,\n ...(manifest.description !== undefined && { description: manifest.description }),\n ...(manifest.version !== undefined && { version: manifest.version }),\n ...(manifest.author !== undefined && { author: manifest.author }),\n ...(manifest.category !== undefined && { category: manifest.category }),\n ...(manifest.keywords !== undefined && { keywords: manifest.keywords }),\n };\n}\n\nexport async function generateMarketplace(\n pluginsDir: string,\n options: MarketplaceOptions,\n): Promise<Marketplace> {\n verbose(`Scanning plugins directory: ${pluginsDir}`);\n\n const manifestFiles = await glob(`**/${PLUGIN_MANIFEST_PATH}`, pluginsDir);\n verbose(`Found ${manifestFiles.length} plugin manifests`);\n\n const plugins: MarketplacePlugin[] = [];\n\n for (const manifestFile of manifestFiles) {\n const pluginDirName = pluginDirNameOf(manifestFile);\n const pluginDir = path.join(pluginsDir, pluginDirName);\n\n const manifest = await readPluginManifest(pluginDir);\n if (!manifest) {\n warn(`Could not read plugin manifest: '${manifestFile}'`);\n continue;\n }\n\n const plugin = convertManifestToMarketplacePlugin(\n manifest,\n options.pluginRoot.replace(/^\\.\\//, \"\"),\n pluginDirName,\n );\n plugins.push(plugin);\n verbose(` [OK] ${plugin.name}`);\n }\n\n const sortedPlugins = sortBy(plugins, (p) => p.name);\n\n // Field order matters: the object is serialized verbatim into marketplace.json,\n // so conditional fields keep the same positions the previous emissions used.\n return {\n $schema: MARKETPLACE_SCHEMA_URL,\n name: options.name,\n version: options.version ?? DEFAULT_VERSION,\n owner: {\n name: options.ownerName,\n ...(options.ownerEmail ? { email: options.ownerEmail } : {}),\n },\n metadata: {\n pluginRoot: options.pluginRoot,\n },\n plugins: sortedPlugins,\n ...(options.description ? { description: options.description } : {}),\n };\n}\n\n/**\n * The plugin directory a manifest belongs to: the first segment of its path under the plugins\n * directory.\n */\nfunction pluginDirNameOf(manifestFile: string): string {\n const separator = manifestFile.indexOf(\"/\");\n return separator === -1 ? manifestFile : manifestFile.slice(0, separator);\n}\n\n/**\n * Refuses a marketplace name that belongs to a namespace the author does not own,\n * or returns null when the name is theirs to take.\n *\n * `packageName` is package.json's own `name`. It is read for one purpose: the public\n * catalogue publishes under a reserved name legitimately, and\n * {@link PUBLIC_CATALOGUE_PACKAGE} is what distinguishes it from a claimant.\n *\n * `wayOut` is the caller's, because how another name is chosen depends on where this one came\n * from: `build marketplace` reads it off package.json and takes `--name`, while `new marketplace`\n * takes it as its argument and has no package.json yet.\n */\nexport function validateMarketplaceName(\n marketplaceName: string,\n packageName: string,\n wayOut: string,\n): string | null {\n if (!RESERVED_MARKETPLACE_NAMES.includes(marketplaceName)) return null;\n if (isCatalogueOwnReservedName(marketplaceName, packageName)) return null;\n\n return reservedNameError(marketplaceName, wayOut);\n}\n\n/**\n * Refuses a marketplace being LOADED under a reserved name, or returns null — a manifest built\n * before the name was reserved, or written by hand, refused in the words the build uses.\n *\n * The list {@link validateMarketplaceName} refuses, less the public catalogue's own name: the\n * catalogue's manifest is called `agents-inc`, and a load has no package.json to tell the\n * catalogue from a claimant by, so that one name loads.\n */\nexport function validateLoadedMarketplaceName(\n marketplaceName: string,\n wayOut: string,\n): string | null {\n if (marketplaceName === DEFAULT_PUBLIC_SOURCE_NAME) return null;\n return RESERVED_MARKETPLACE_NAMES.includes(marketplaceName)\n ? reservedNameError(marketplaceName, wayOut)\n : null;\n}\n\n/**\n * Refuses a marketplace whose skill ids fall outside its own namespace, or returns\n * null when every id carries it.\n *\n * The public catalogue is exempt: its skills ship unprefixed by design and\n * `agents-inc` IS the namespace they occupy. Reading that exemption off the NAME is\n * only safe because {@link validateMarketplaceName} runs first and lets nothing but\n * the catalogue's own package hold it — the two checks are a pair, in that order.\n */\nexport function validateSkillIdNamespace(marketplace: Marketplace): string | null {\n if (marketplace.name === DEFAULT_PUBLIC_SOURCE_NAME) return null;\n\n const foreignIds = marketplace.plugins\n .filter((plugin) => !carriesNamespace(plugin.name, marketplace.name))\n .map((plugin) => plugin.name);\n\n if (foreignIds.length === 0) return null;\n\n return namespaceViolationError(foreignIds, marketplace.name);\n}\n\n/**\n * Whether the reserved NAME this build publishes under is the catalogue's own, which\n * takes both halves: the name claimed is the catalogue's, and the package claiming it\n * is the catalogue's package.\n *\n * The load side asks a different question of the same identity: `isPublicCatalogueCheckout`\n * in `configuration/config.ts` asks whether a DIRECTORY is a checkout of that repository,\n * and reads the package name off it rather than being handed one.\n */\nfunction isCatalogueOwnReservedName(marketplaceName: string, packageName: string): boolean {\n return marketplaceName === DEFAULT_PUBLIC_SOURCE_NAME && packageName === PUBLIC_CATALOGUE_PACKAGE;\n}\n\nfunction carriesNamespace(skillId: string, marketplaceName: string): boolean {\n return skillId.startsWith(`${marketplaceName}-`);\n}\n\nfunction reservedNameError(marketplaceName: string, wayOut: string): string {\n return (\n `Marketplace name '${marketplaceName}' is reserved. ` +\n `'${DEFAULT_PUBLIC_SOURCE_NAME}' is the public catalogue's own namespace, ` +\n `'${EXTERNAL_SKILL_NAMESPACE}' and '${LOCAL_SKILL_NAMESPACE}' hold the skills that belong to ` +\n `no marketplace, and '${EJECT_SOURCE}' is what an installation records for a skill copied ` +\n `into it rather than installed as a plugin — a marketplace under any of them is read back ` +\n `as something it is not. Choose a name of your own: ${wayOut}.`\n );\n}\n\nfunction namespaceViolationError(foreignIds: string[], marketplaceName: string): string {\n const listed = foreignIds\n .slice(0, MAX_REPORTED_NAMESPACE_VIOLATIONS)\n .map((id) => ` ${id} -> ${marketplaceName}-${id}`);\n const unlisted = foreignIds.length - listed.length;\n\n return [\n `Marketplace '${marketplaceName}' ships ${foreignIds.length} skill id(s) outside its own ` +\n `namespace. Every skill id must begin with the marketplace's name:`,\n ...listed,\n ...(unlisted > 0 ? [` ... and ${unlisted} more`] : []),\n `Rename each skill directory and the 'name' in its SKILL.md, re-run 'build plugins', then ` +\n `build the marketplace again.`,\n ].join(\"\\n\");\n}\n\nexport async function writeMarketplace(\n outputPath: string,\n marketplace: Marketplace,\n): Promise<void> {\n await ensureDir(path.dirname(outputPath));\n const content = `${JSON.stringify(marketplace, null, 2)}\\n`;\n await writeFile(outputPath, content);\n}\n\nexport function getMarketplaceStats(marketplace: Marketplace): {\n total: number;\n byCategory: Record<string, number>;\n} {\n return {\n total: marketplace.plugins.length,\n byCategory: countBy(marketplace.plugins, (p) => p.category ?? \"uncategorized\"),\n };\n}\n","import os from \"os\";\n\nimport { isHomeDirectory } from \"../installation/is-home-directory\";\nimport { DEFAULT_PUBLIC_SOURCE_NAME, EJECT_SOURCE } from \"../../consts\";\nimport type {\n MergedSkillsMatrix,\n ResolvedSkill,\n SkillId,\n SkillSource,\n SkillSourceType,\n} from \"../../types\";\nimport { verbose } from \"../../utils/logger\";\nimport { typedEntries, typedKeys } from \"../../utils/typed-object\";\nimport { isDefaultSource, type ResolvedConfig } from \"../configuration\";\nimport { discoverAllPluginSkills } from \"../plugins\";\n\n/**\n * True when the tagging pass looked at this skill and found only the copy on disk.\n *\n * The one reading of `availableSources` every surface that asks \"can this be a plugin?\"\n * must share: the Sources grid offers a cell on it and the install pipeline refuses on\n * it, and a second copy of the rule is how those two come to disagree. Asked of the\n * tagged sources rather than of `custom` — what a plugin install needs is a marketplace\n * that HAS the skill, and who wrote it decides nothing. A skill the pass never reached\n * carries no sources at all and answers `false`: absence of an answer is not an answer.\n */\nexport function isLocalOnlySkill(skill: ResolvedSkill | undefined): boolean {\n return (\n skill?.availableSources !== undefined &&\n !skill.availableSources.some((source) => source.type !== \"local\")\n );\n}\n\n/**\n * Appends a source to the skill's availableSources, initializing the array on\n * first tag. In-place mutation is this module's documented tagging contract.\n */\nfunction addAvailableSource(\n skill: { availableSources?: SkillSource[] },\n source: SkillSource,\n): void {\n skill.availableSources = skill.availableSources ?? [];\n skill.availableSources.push(source);\n}\n\n/**\n * Annotates every skill in the matrix with its install-mode availability metadata.\n *\n * Runs a four-phase tagging pipeline that mutates `primaryMatrix.skills` in place:\n * 1. **Primary** -- tags every skill the marketplace CARRIES with it (public or private),\n * skipping the ids in `unbackedSkillIds`\n * 2. **Local** -- tags skills with `local: true` as installed via local source\n * 3. **Plugin** -- detects skills in the plugins the host reports installed and enabled, at the\n * project and, from a project, at the home directory\n * 4. **Active source** -- sets `activeSource` to the installed variant, or first available\n *\n * After this function completes, each skill in the matrix has `availableSources` -- at most\n * the local copy and the one marketplace, which are the two install modes the Sources step\n * offers -- and `activeSource` (the one currently in use) populated.\n *\n * @param primaryMatrix - The merged skills matrix to annotate. Mutated in place --\n * `availableSources` and `activeSource` are set on each skill.\n * @param sourceConfig - Resolved source configuration, used to determine whether the\n * marketplace is a private one or the default public source\n * @param projectDir - Absolute path to the project root, used to locate plugin directories\n * @param marketplace - Optional marketplace name resolved from the source's marketplace.json.\n * Takes precedence over `sourceConfig.marketplace` when provided.\n * @param unbackedSkillIds - Ids the matrix holds that the marketplace does NOT carry. They are\n * left out of the primary tag, because a marketplace entry on a skill\n * no marketplace has is a plugin install that cannot happen. Defaults\n * to empty.\n *\n * @remarks\n * **Side effects:** Mutates `primaryMatrix` in place.\n */\nexport async function loadSkillsFromAllSources(\n primaryMatrix: MergedSkillsMatrix,\n sourceConfig: ResolvedConfig,\n projectDir: string,\n marketplace?: string,\n unbackedSkillIds: ReadonlySet<SkillId> = new Set(),\n): Promise<void> {\n const { name: primarySourceName, type: primarySourceType } = marketplaceSource(\n sourceConfig,\n marketplace,\n );\n\n tagPrimarySourceSkills(primaryMatrix, sourceConfig, marketplace, unbackedSkillIds);\n tagLocalSkills(primaryMatrix);\n await tagPluginSkills(primaryMatrix, projectDir, primarySourceName, primarySourceType);\n setActiveSources(primaryMatrix);\n}\n\n/**\n * The entry naming the marketplace a skill is carried by, as the primary pass writes it: the\n * marketplace's resolved name — `marketplace`, read from its manifest, over the name its config\n * stored — public or private, and not yet known to be installed.\n *\n * Exported for the one other catalogue a load reads: the global installation's own, whose skills\n * `source-loader.ts` seats beside a project's when that project's marketplace does not carry them.\n * A fresh object per call, because the tagging pass mutates the entry it is handed.\n */\nexport function marketplaceSource(sourceConfig: ResolvedConfig, marketplace?: string): SkillSource {\n return {\n name: marketplace ?? sourceConfig.marketplace ?? DEFAULT_PUBLIC_SOURCE_NAME,\n type: isDefaultSource(sourceConfig.source) ? \"public\" : \"private\",\n installed: false,\n primary: true,\n };\n}\n\nfunction tagPrimarySourceSkills(\n matrix: MergedSkillsMatrix,\n sourceConfig: ResolvedConfig,\n marketplace: string | undefined,\n unbackedSkillIds: ReadonlySet<SkillId>,\n): void {\n for (const [id, skill] of typedEntries(matrix.skills)) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- typedEntries/Object.entries launders the `| undefined` a Partial<Record> admits out of its result type, so this guard reads as dead while still covering an explicitly-undefined slot\n if (!skill) continue;\n if (unbackedSkillIds.has(id)) continue;\n\n addAvailableSource(skill, marketplaceSource(sourceConfig, marketplace));\n }\n}\n\nfunction tagLocalSkills(matrix: MergedSkillsMatrix): void {\n let count = 0;\n for (const [, skill] of typedEntries(matrix.skills)) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- typedEntries/Object.entries launders the `| undefined` a Partial<Record> admits out of its result type, so this guard reads as dead while still covering an explicitly-undefined slot\n if (!skill) continue;\n if (!skill.local) continue;\n\n const source: SkillSource = {\n name: EJECT_SOURCE,\n type: \"local\",\n installed: true,\n installMode: \"eject\",\n };\n\n addAvailableSource(skill, source);\n count++;\n }\n\n verbose(`Tagged ${count} local skills with local source`);\n}\n\nasync function tagPluginSkills(\n matrix: MergedSkillsMatrix,\n projectDir: string,\n primarySourceName: string,\n primarySourceType: SkillSourceType,\n): Promise<void> {\n const allPluginSkillIds = await collectPluginSkillIds(projectDir);\n\n if (allPluginSkillIds.length === 0) {\n return;\n }\n\n for (const skillId of allPluginSkillIds) {\n const skill = matrix.skills[skillId];\n if (!skill) continue;\n\n markInstalledAsPlugin(skill, primarySourceName, primarySourceType);\n }\n\n verbose(`Tagged ${allPluginSkillIds.length} plugin-installed skills`);\n}\n\n/**\n * Records that a skill is installed as a plugin. The skill's own marketplace entry, where one was\n * written with no install mode yet, becomes the installed plugin; otherwise a plugin entry is\n * added under the primary source — unless the skill already carries one.\n *\n * Its OWN entry rather than the loaded marketplace's: a global installation's skill seated from\n * the marketplace that installation was made from is carried under that marketplace's name, and\n * labelling its plugin with the loaded one's would name a marketplace that never shipped it.\n */\nfunction markInstalledAsPlugin(\n skill: ResolvedSkill,\n primarySourceName: string,\n primarySourceType: SkillSourceType,\n): void {\n skill.availableSources = skill.availableSources ?? [];\n\n const existingSource = skill.availableSources.find((s) => s.primary === true);\n if (existingSource && !existingSource.installMode) {\n existingSource.installed = true;\n existingSource.installMode = \"plugin\";\n return;\n }\n if (skill.availableSources.some((s) => s.installMode === \"plugin\")) return;\n\n addAvailableSource(skill, {\n name: primarySourceName,\n type: primarySourceType,\n installed: true,\n installMode: \"plugin\",\n primary: true,\n });\n}\n\n/**\n * Collects skill IDs from every plugin the host reports installed and enabled, at the project and,\n * from a project, at the home directory. Uses {@link discoverAllPluginSkills}, which reads each\n * plugin's cache directory.\n */\nasync function collectPluginSkillIds(projectDir: string): Promise<SkillId[]> {\n const pluginSkills = await discoverAllPluginSkills(projectDir);\n const skillIds = typedKeys<SkillId>(pluginSkills);\n\n // Also discover global plugins when editing from a project directory.\n // Follows the same global+project merge pattern as local skills in source-loader.ts.\n const homeDir = os.homedir();\n if (!isHomeDirectory(projectDir)) {\n const globalPluginSkills = await discoverAllPluginSkills(homeDir);\n const globalSkillIds = typedKeys<SkillId>(globalPluginSkills);\n if (globalSkillIds.length > 0) {\n verbose(`Found ${globalSkillIds.length} global plugin skill(s)`);\n const merged = new Set([...skillIds, ...globalSkillIds]);\n return [...merged];\n }\n }\n\n if (skillIds.length === 0) {\n verbose(\"No plugin skills discovered from settings.json\");\n }\n\n return skillIds;\n}\n\n/** Prefers installed source so the wizard shows current state; falls back to first available */\nfunction setActiveSources(matrix: MergedSkillsMatrix): void {\n for (const [, skill] of typedEntries(matrix.skills)) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- typedEntries/Object.entries launders the `| undefined` a Partial<Record> admits out of its result type, so this guard reads as dead while still covering an explicitly-undefined slot\n if (!skill) continue;\n if (!skill.availableSources || skill.availableSources.length === 0) continue;\n\n // Prefer installed source, then fall back to first available\n const [firstSource] = skill.availableSources;\n if (!firstSource) continue;\n skill.activeSource = skill.availableSources.find((s) => s.installed) ?? firstSource;\n }\n}\n","import type {\n AgentConfig,\n AgentDefinition,\n AgentName,\n CompileAgentConfig,\n CompileConfig,\n Skill,\n SkillDefinitionMap,\n SkillReference,\n StackAgentConfig,\n} from \"../types\";\nimport { verbose } from \"../utils/logger\";\nimport { typedEntries, typedFromEntries, typedKeys } from \"../utils/typed-object\";\nimport { resolveAgentConfigToSkills } from \"./stacks/stacks-loader\";\n\nexport function resolveSkillReference(\n ref: SkillReference,\n skills: SkillDefinitionMap,\n): Skill | null {\n const definition = skills[ref.id];\n if (!definition) {\n verbose(`Skill '${ref.id}' not found in available skills, skipping`);\n return null;\n }\n return {\n ...definition,\n usage: ref.usage,\n preloaded: ref.preloaded ?? false,\n ...(ref.source !== undefined && { source: ref.source }),\n };\n}\n\nexport function resolveSkillReferences(\n skillRefs: SkillReference[],\n skills: SkillDefinitionMap,\n): Skill[] {\n return skillRefs\n .map((ref) => resolveSkillReference(ref, skills))\n .filter((skill): skill is Skill => skill !== null);\n}\n\n/**\n * Builds skill references from a ProjectConfig stack mapping (agent -> category -> SkillAssignment[]).\n *\n * Values are normalized to SkillAssignment[] at load time (by normalizeStackRecord in project-config.ts).\n * Preserves preloaded flags from skill assignments.\n *\n * @param agentStack - Category-to-SkillAssignment[] mapping from ProjectConfig.stack for one agent\n * @returns Skill references with usage hints derived from category names\n */\nexport function buildSkillRefsFromConfig(agentStack: StackAgentConfig): SkillReference[] {\n return resolveAgentConfigToSkills(agentStack);\n}\n\n/**\n * Resolves the skill references an agent compiles with.\n *\n * The compile config is the only source: `buildCompileAgents` has already expanded\n * the project config's stack into `skills` by the time this runs.\n *\n * @param agentConfig - Compile-time agent config\n * @returns The agent's explicit skill references, or an empty array when it names none\n */\nexport function resolveAgentSkillRefs(agentConfig: CompileAgentConfig): SkillReference[] {\n return agentConfig.skills ?? [];\n}\n\n/**\n * Resolves all agents referenced in a compile config into fully populated AgentConfigs\n * with their skill lists materialized from definitions.\n *\n * For each agent in `compileConfig.agents`, this function:\n * 1. Validates the agent exists in the scanned agent definitions\n * 2. Resolves skill references from the agent's compile config\n * 3. Materializes skill references into full Skill objects using the skill definitions map\n * 4. Merges the agent definition with its resolved skills into an AgentConfig\n *\n * @param agents - Available agent definitions keyed by name (from scanning agent directories)\n * @param skills - Available skill definitions keyed by ID (from scanning skill directories)\n * @param compileConfig - Compilation config specifying which agents to compile and their overrides\n * @param _projectRoot - Project root directory (currently unused, reserved for future use)\n * @returns Map of agent names to fully resolved AgentConfig objects ready for compilation\n * @throws When an agent referenced in compileConfig is not found in scanned agents\n */\n// Nothing below is asynchronous any more: `resolveAgentSkillRefs` never was, and\n// dropping its `async` emptied this one too. The `Promise` stays because it is the\n// published shape — two production callers await it and local-installer.test.ts\n// doubles it with `mockResolvedValue`, so unwinding it is a change to the compile\n// pipeline rather than to this line.\n// eslint-disable-next-line @typescript-eslint/require-await -- published shape, see above\nexport async function resolveAgents(\n agents: Partial<Record<AgentName, AgentDefinition>>,\n skills: SkillDefinitionMap,\n compileConfig: CompileConfig,\n _projectRoot: string,\n): Promise<Partial<Record<AgentName, AgentConfig>>> {\n const entries = typedEntries<AgentName, CompileAgentConfig>(compileConfig.agents).map(\n ([agentName, agentConfig]) => {\n const definition = agents[agentName];\n if (!definition) throw new Error(agentNotFoundError(agentName, agents));\n\n const skillRefs = resolveAgentSkillRefs(agentConfig);\n const resolvedSkills = resolveSkillReferences(skillRefs, skills);\n\n return [\n agentName,\n assembleAgentConfig(agentName, definition, agentConfig, resolvedSkills),\n ] as const;\n },\n );\n\n return typedFromEntries(entries);\n}\n\n/** How many scanned agents a not-found refusal names before summarising the rest. */\nconst MAX_LISTED_AVAILABLE_AGENTS = 5;\n\n/** The refusal for an agent the compile config names and no scanned directory defines. */\nfunction agentNotFoundError(\n agentName: AgentName,\n agents: Partial<Record<AgentName, AgentDefinition>>,\n): string {\n const availableAgents = describeAvailableAgents(typedKeys<AgentName>(agents));\n return `Agent '${agentName}' referenced in compile config but not found in scanned agents. ${availableAgents}. Check that src/agents/${agentName}/metadata.yaml exists.`;\n}\n\n/** The agents that WERE scanned, capped at {@link MAX_LISTED_AVAILABLE_AGENTS} names. */\nfunction describeAvailableAgents(availableAgents: AgentName[]): string {\n if (availableAgents.length === 0) return \"No agents found in scanned directories\";\n\n const listed = availableAgents.slice(0, MAX_LISTED_AVAILABLE_AGENTS).join(\", \");\n const unlisted = availableAgents.length - MAX_LISTED_AVAILABLE_AGENTS;\n return unlisted > 0\n ? `Available agents: ${listed} (and ${unlisted} more)`\n : `Available agents: ${listed}`;\n}\n\n/**\n * One agent as the compiler takes it: the definition's frontmatter, the compile config's\n * overrides on top of it, and the skills already resolved.\n */\nfunction assembleAgentConfig(\n agentName: AgentName,\n definition: AgentDefinition,\n agentConfig: CompileAgentConfig,\n resolvedSkills: Skill[],\n): AgentConfig {\n // The project config carries the user's deliberate choice; the agent's own metadata\n // carries the default. Config wins, silently — warning on every compile for a setting\n // someone made on purpose is noise. Neither present leaves the key off entirely.\n const model = agentConfig.model ?? definition.model;\n const effort = agentConfig.effort ?? definition.effort;\n\n return {\n name: agentName,\n title: definition.title,\n description: definition.description,\n ...(model !== undefined && { model }),\n ...(effort !== undefined && { effort }),\n tools: definition.tools,\n // Every optional frontmatter field `agent.liquid` reads. Spread conditionally rather\n // than unconditionally, because the template branches on presence — an explicit\n // `undefined` renders as an empty key.\n ...(definition.disallowedTools !== undefined && {\n disallowedTools: definition.disallowedTools,\n }),\n ...(definition.permissionMode !== undefined && {\n permissionMode: definition.permissionMode,\n }),\n ...(definition.isolation !== undefined && { isolation: definition.isolation }),\n ...(definition.hooks !== undefined && { hooks: definition.hooks }),\n ...(definition.experimental !== undefined && {\n experimental: definition.experimental,\n }),\n skills: resolvedSkills,\n ...(definition.path !== undefined && { path: definition.path }),\n ...(definition.sourceRoot !== undefined && { sourceRoot: definition.sourceRoot }),\n ...(definition.agentBaseDir !== undefined && { agentBaseDir: definition.agentBaseDir }),\n };\n}\n","import os from \"os\";\n\nimport type { Provider } from \"../../consts.js\";\nimport { isHomeDirectory } from \"./is-home-directory.js\";\nimport {\n plannedSourceFolderMove,\n providerInUse,\n resolveSourceDir,\n type SourceFolderMove,\n} from \"./install-layout.js\";\nimport { directoryExists } from \"../../utils/fs.js\";\n\n/**\n * The scopes `doctor`'s Layout row and the write commands' rival-folder refusal both answer for,\n * and which layout each one is on.\n *\n * One list, shared, because the two surfaces have to agree: a scope `doctor` calls a collision is\n * a scope a write must refuse, and two enumerations of \"the scopes in play\" are two things that\n * can disagree about whether the home directory counts twice.\n *\n * Nothing here moves a folder. An installation on the name every pre-rename install carries is\n * read AND written where it is, indefinitely; moving one is a manual step, documented in\n * `.ai-docs/reference/concepts/source-folder-layout.md`.\n */\n\n/** Which of a run's two scopes this is — the directory the command was run in, or the machine's. */\nexport type ScopeKind = \"project\" | \"global\";\n\n/** One scope a run reads, and the directory it is rooted at. */\nexport type ScopeRoot = { kind: ScopeKind; root: string };\n\n/** A scope with a source folder on disk, and the state that folder is in. */\nexport type SourceScope = {\n kind: ScopeKind;\n /** The directory the source folder sits under: a project root, or the home directory. */\n root: string;\n /**\n * Which installation this scope holds, read off the folder.\n *\n * Carried rather than re-derived by each reader: `legacy`, `both` and `move` are all answers\n * ABOUT one provider — the retired name is Claude's — so a reader resolving its own provider\n * could describe a different installation from the one these three fields describe.\n */\n provider: Provider;\n /** Whether this scope is still on the folder every pre-rename installation carries. */\n legacy: boolean;\n /** Whether this provider's two folders are both on disk as rivals. */\n both: boolean;\n /**\n * The folder this scope is read from, as a user writes it — `.agents-inc/codex`, `.claude-src`.\n *\n * Carried for {@link SourceScope.provider}'s reason and answering the question\n * {@link SourceScope.move} cannot: a provider that never had a legacy folder has no move to\n * describe — the retired name is Claude's — and doctor's\n * Layout row still owes a sentence saying which folder the scope is on. Read off the same\n * `resolveSourceDir` call that decided `legacy` and `both`, so the three cannot describe\n * different folders.\n */\n relName: string;\n /** Where the source is, and the folder it belongs under. `null` for a provider with no legacy folder. */\n move: SourceFolderMove | null;\n};\n\n/**\n * The folder this scope is actually READ from, as a message spells it.\n *\n * Every sentence that names two folders has to say which one is live, and the answer is not the\n * current name: the preference order takes whichever folder holds a `config.ts` before it looks\n * at content, so a scope whose config has not been moved by hand is read from the OLD name\n * however much sits under the new one. That is the exact arrangement the refusal is read in, so a\n * sentence hard-wired to the new name was wrong in the one state it is read in.\n */\nexport function folderBeingRead(scope: SourceScope, move: SourceFolderMove): string {\n return scope.legacy ? move.from.relName : move.to.relName;\n}\n\n/**\n * Every scope of this run that holds an installation, global first.\n *\n * A scope with NEITHER folder on disk is left out rather than reported as already on the current\n * name: there is nothing there, and a command that congratulated an empty directory on its layout\n * would say it of every directory anyone ever ran it in.\n *\n * Run from the home directory, the project scope and the global scope are the same directory and\n * one entry is returned — the global one, because that is what the installation IS.\n */\nexport async function sourceScopesInPlay(cwd: string): Promise<SourceScope[]> {\n const scopes = await Promise.all(\n scopeRootsInPlay(cwd).map(async ({ kind, root }) =>\n describeScope(kind, root, providerInUse(root)),\n ),\n );\n return scopes.filter((scope): scope is SourceScope => scope !== null);\n}\n\n/**\n * The directories a run from `cwd` looks in, global first.\n *\n * Run from the home directory the project scope and the global scope are the same directory, and\n * an installation counted twice is a second installation that does not exist — so the two collapse\n * into the global one. Exported because installation discovery enumerates the same scopes, and\n * this module's own rule is that two enumerations are two things that can disagree.\n */\nexport function scopeRootsInPlay(cwd: string): ScopeRoot[] {\n const global: ScopeRoot = { kind: \"global\", root: os.homedir() };\n if (isHomeDirectory(cwd)) return [global];\n return [global, { kind: \"project\", root: cwd }];\n}\n\n/** One scope's layout, or `null` when nothing of this product is in that directory at all. */\nexport async function describeScope(\n kind: ScopeKind,\n root: string,\n provider: Provider,\n): Promise<SourceScope | null> {\n const resolved = resolveSourceDir(root, provider);\n const present = resolved.legacy || (await directoryExists(resolved.dir));\n if (!present) return null;\n\n return {\n kind,\n root,\n provider,\n legacy: resolved.legacy,\n both: resolved.both,\n relName: resolved.relName,\n move: plannedSourceFolderMove(root, provider),\n };\n}\n","import type { Provider } from \"../../consts.js\";\nimport { PROVIDERS } from \"../../consts.js\";\nimport { fileExists } from \"../../utils/fs.js\";\nimport { getProjectConfigPath } from \"./install-base-dir.js\";\nimport { scopeRootsInPlay, type ScopeKind, type ScopeRoot } from \"./source-scopes.js\";\n\n/**\n * What a run finds when it asks the disk which installations are there.\n *\n * The folder is the only record of a provider — there is no field in `config.ts`, and a shared\n * payload carries none either, so one saved setup installs on either provider. Discovery reading\n * the folder is therefore the whole of \"the provider is derivable after the install\", and it is\n * what lets `compile`, `edit`, `update`, `uninstall`, `share`, `eject` and `doctor` need no flag.\n *\n * **One installation is exactly one provider, and a root holding two folders holds TWO of them.**\n * `.agents-inc/` is a parent rather than an installation, so `.agents-inc/claude/` beside\n * `.agents-inc/codex/` is a pair of single-provider installations. The answer is a LIST, nothing\n * in it is mixed, and a root holding both is never collapsed into whichever the preference order\n * reaches first — that collapse is exactly what `getProjectConfigPath` did before C2 gave it a\n * provider, silently and with a path that exists and parses.\n */\n\n/** One installation on disk: which provider it belongs to, which scope it is, and its config. */\nexport type DetectedInstallation = {\n provider: Provider;\n scope: ScopeKind;\n /** The config file as it is actually read — a pre-rename installation names `.claude-src/`. */\n configPath: string;\n};\n\n/**\n * Every installation a run from `cwd` can see, global before project and, within a scope, in the\n * provider roster's own order.\n *\n * An installation is a source folder holding a `config.ts`, never a folder that merely exists: a\n * consuming repository keeps its own state under `.agents-inc/` — the benchmark's hand gate writes\n * `baseline.json` and an `attempts/` directory there — and an empty or half-built provider folder\n * beside a live installation must not be reported as a second one.\n *\n * A pre-rename scope answers `claude` at `.claude-src/config.ts`. The provider names the\n * installation rather than the folder it was found under: a discovery that asked only which\n * `.agents-inc/<provider>/` directories exist would answer nothing at all on every machine that\n * has not moved its folder by hand, and tell those users they have nothing installed.\n */\nexport async function detectInstallations(cwd: string): Promise<DetectedInstallation[]> {\n const everywhereOneCouldBe = scopeRootsInPlay(cwd).flatMap(everyProviderUnder);\n const found = await Promise.all(everywhereOneCouldBe.map(installationIfPresent));\n\n return found.filter(\n (installation): installation is DetectedInstallation => installation !== null,\n );\n}\n\n/** Where each provider's installation WOULD be under one scope root, whatever is on disk. */\nfunction everyProviderUnder({ kind, root }: ScopeRoot): DetectedInstallation[] {\n return PROVIDERS.map((provider) => ({\n provider,\n scope: kind,\n configPath: getProjectConfigPath(root, provider),\n }));\n}\n\n/** The same entry back when its config file is really there, and `null` when it is not. */\nasync function installationIfPresent(\n candidate: DetectedInstallation,\n): Promise<DetectedInstallation | null> {\n return (await fileExists(candidate.configPath)) ? candidate : null;\n}\n","/**\n * Claude Code's plugin machinery, behind {@link PluginHost}.\n *\n * `exec.ts` keeps `execCommand` and the argument validators, which are every host's and not this\n * one's.\n *\n * **Two vocabularies meet in this file and nowhere else.** Above the line, the seam speaks this\n * product's words — {@link SkillScope}'s `global` and `project`. Below it, `claude plugin` takes\n * {@link ClaudePluginScope}'s `user` and `project`, and routes a user-scoped call by the working\n * directory as well as by the flag. {@link toClaudePluginScope} is the whole of the translation,\n * and it belongs here because it is a fact about one binary.\n *\n * **Removal is classified from Claude's own message**, not from its exit code: `claude plugin\n * uninstall` exits 1 both for \"there was no such plugin\" and for a real failure, and the CLI has\n * always swallowed the first by matching the text. What C3 adds is that the caller can now see\n * which of the two happened. `e2e/smoke/plugin-host-contract.smoke.test.ts` is what holds that\n * against the real binary — a recorded string is a claim about software that ships on its own\n * schedule.\n */\n\nimport os from \"os\";\nimport path from \"path\";\nimport { z } from \"zod\";\n\nimport { PLUGINS_SUBDIR } from \"../../consts.js\";\nimport type { ClaudePluginScope, SkillScope } from \"../../types/config.js\";\nimport { getErrorMessage } from \"../../utils/errors.js\";\nimport {\n execCommand,\n validateMarketplaceSource,\n validatePluginName,\n validatePluginPath,\n type ExecResult,\n} from \"../../utils/exec.js\";\nimport { fileExists } from \"../../utils/fs.js\";\nimport { warn } from \"../../utils/logger.js\";\nimport { pluginsDir } from \"../installation/install-layout.js\";\nimport {\n getEnabledPluginKeys,\n getInstalledPluginsRegistryPath,\n listPluginInstallsForProject,\n} from \"../plugins/plugin-settings.js\";\nimport type {\n HostCallOptions,\n HostPlugin,\n InstallPlacement,\n PluginHost,\n PluginRemovalOutcome,\n} from \"./plugin-host.js\";\n\n/** The provider this module is the host for, named once so no member spells it again. */\nconst CLAUDE: PluginHost[\"provider\"] = \"claude\";\n\n/**\n * Both spellings Claude uses for a plugin it does not have, as `claude 2.1.278` prints them.\n *\n * `✘ Failed to uninstall plugin \"x@y\": Plugin \"x@y\" not found in installed plugins` is the one a\n * user meets; the other arm has been swallowed here since before the messages were recorded, and\n * dropping either turns an ordinary second uninstall into a thrown error. The exit code says 1\n * for both this and a real failure, which is why the reading is of the message.\n */\nconst NOT_INSTALLED_MESSAGES = [\"not installed\", \"not found\"];\n\n/**\n * Every mode/scope cell Claude offers, which is all four of them.\n *\n * Four rather than three is the whole of what separates this host from Codex's at the seam: a\n * plugin can be installed for one project here, and cannot be there. Rebuilt per call by\n * {@link claudeHost} so no two callers hold one array.\n */\nfunction claudeOfferedPlacements(): InstallPlacement[] {\n return [\n { mode: \"plugin\", scope: \"global\" },\n { mode: \"plugin\", scope: \"project\" },\n { mode: \"eject\", scope: \"global\" },\n { mode: \"eject\", scope: \"project\" },\n ];\n}\n\n/**\n * Maps a cc scope to the Claude CLI plugin scope: `\"global\"` installs are\n * user-scoped in Claude (registered in `~/.claude/settings.json`); anything\n * else — including an absent scope — is project-scoped.\n */\nexport function toClaudePluginScope(scope: SkillScope | undefined): ClaudePluginScope {\n return scope === \"global\" ? \"user\" : \"project\";\n}\n\n/** User-scoped plugins run from home dir so Claude CLI only writes to ~/.claude/settings.json */\nfunction resolvePluginCwd(scope: ClaudePluginScope, projectDir: string): string {\n return scope === \"user\" ? os.homedir() : projectDir;\n}\n\n/**\n * Which Claude installation a `claude plugin` call reads and writes.\n *\n * The host's own spelling of {@link HostCallOptions}, kept as a name of its\n * own because the e2e harness drives these functions directly.\n */\nexport type ClaudeConfigOptions = HostCallOptions;\n\n/**\n * The `execCommand` options fragment that pins the config dir — empty when there\n * is none, so the call inherits its process's environment untouched.\n *\n * `CLAUDE_CONFIG_DIR` takes precedence over `HOME` in the Claude CLI, so passing\n * it also overrides an exported one rather than merely competing with it.\n */\nfunction configDirEnv(options: ClaudeConfigOptions | undefined): { env?: NodeJS.ProcessEnv } {\n if (options?.configDir === undefined) return {};\n return { env: { CLAUDE_CONFIG_DIR: options.configDir } };\n}\n\nexport async function claudePluginInstall(\n pluginPath: string,\n scope: ClaudePluginScope,\n projectDir: string,\n options?: ClaudeConfigOptions,\n): Promise<void> {\n validatePluginPath(pluginPath);\n\n const cwd = resolvePluginCwd(scope, projectDir);\n const args = [\"plugin\", \"install\", pluginPath, \"--scope\", scope];\n const result = await execCommand(\"claude\", args, { cwd, ...configDirEnv(options) });\n\n if (result.exitCode !== 0) {\n throw new Error(`Plugin installation failed: ${whyClaudeFailed(result)}`);\n }\n}\n\n/**\n * Whether the `claude` binary is there and runnable.\n *\n * It takes the config directory like every other member, and passes it for the seam's reason\n * rather than for one of its own: measured on 2026-09-21, `claude --version` under a pinned\n * scratch `HOME` and `CLAUDE_CONFIG_DIR` wrote nothing at all, so for THIS host the option\n * changes no file. The seam carries it because the next host's probe is a write — Codex links\n * helper binaries under `$CODEX_HOME/tmp/arg0/` before it reads an argument — and a member whose\n * Claude implementation quietly dropped the option would send every spawned probe at whichever\n * installation the process happened to point at.\n */\nexport async function isClaudeCLIAvailable(options?: ClaudeConfigOptions): Promise<boolean> {\n try {\n const result = await execCommand(\"claude\", [\"--version\"], configDirEnv(options));\n return result.exitCode === 0;\n } catch {\n return false;\n }\n}\n\nexport type MarketplaceInfo = {\n name: string;\n source: string;\n repo?: string;\n path?: string;\n};\n\nconst marketplaceInfoListSchema: z.ZodType<MarketplaceInfo[]> = z.array(\n z.object({\n name: z.string(),\n source: z.string(),\n repo: z.string().exactOptional(),\n path: z.string().exactOptional(),\n }),\n);\n\nexport async function claudePluginMarketplaceList(\n options?: ClaudeConfigOptions,\n): Promise<MarketplaceInfo[]> {\n try {\n const result = await execCommand(\n \"claude\",\n [\"plugin\", \"marketplace\", \"list\", \"--json\"],\n configDirEnv(options),\n );\n\n if (result.exitCode !== 0) return [];\n return marketplacesListedIn(result.stdout);\n } catch {\n return [];\n }\n}\n\n/** The marketplaces a `--json` listing names, or none, after a warning, where it is unreadable. */\nfunction marketplacesListedIn(stdout: string): MarketplaceInfo[] {\n let parsed: unknown;\n try {\n parsed = JSON.parse(stdout);\n } catch {\n warn(\"Failed to parse marketplace list output as JSON\");\n return [];\n }\n\n const listResult = marketplaceInfoListSchema.safeParse(parsed);\n if (!listResult.success) {\n warn(\"Unexpected marketplace list format — expected an array of marketplace entries\");\n return [];\n }\n\n return listResult.data;\n}\n\nexport async function claudePluginMarketplaceExists(\n name: string,\n options?: ClaudeConfigOptions,\n): Promise<boolean> {\n const marketplaces = await claudePluginMarketplaceList(options);\n return marketplaces.some((m) => m.name === name);\n}\n\nexport async function claudePluginMarketplaceAdd(\n source: string,\n options?: ClaudeConfigOptions,\n): Promise<void> {\n validateMarketplaceSource(source);\n\n const args = [\"plugin\", \"marketplace\", \"add\", source];\n const result = await runClaude(args, options, \"add marketplace\");\n if (result.exitCode === 0) return;\n\n const said = whyClaudeFailed(result);\n if (said.includes(\"already installed\")) return;\n throw new Error(`Failed to add marketplace: ${said}`);\n}\n\nexport async function claudePluginMarketplaceRemove(\n name: string,\n options?: ClaudeConfigOptions,\n): Promise<void> {\n validatePluginName(name);\n\n const args = [\"plugin\", \"marketplace\", \"remove\", name];\n const result = await runClaude(args, options, \"remove marketplace\");\n if (result.exitCode === 0) return;\n\n const said = whyClaudeFailed(result);\n if (said.includes(\"not found\") || said.includes(\"not installed\")) return;\n throw new Error(`Failed to remove marketplace: ${said}`);\n}\n\nexport async function claudePluginMarketplaceUpdate(\n name: string,\n options?: ClaudeConfigOptions,\n): Promise<void> {\n validatePluginName(name);\n\n const args = [\"plugin\", \"marketplace\", \"update\", name];\n const result = await runClaude(args, options, \"update marketplace\");\n if (result.exitCode === 0) return;\n\n throw new Error(`Failed to update marketplace: ${whyClaudeFailed(result)}`);\n}\n\n/**\n * One `claude` call against the installation `options` names, where a binary that could not be\n * spawned at all is reported as `Failed to <attempt>` — the words each marketplace verb's own\n * refusal uses. A call that ran and exited non-zero is returned for the caller to read, because\n * `add` and `remove` each treat one refusal as success.\n */\nasync function runClaude(\n args: string[],\n options: ClaudeConfigOptions | undefined,\n attempt: string,\n): Promise<ExecResult> {\n try {\n return await execCommand(\"claude\", args, configDirEnv(options));\n } catch (err) {\n throw new Error(`Failed to ${attempt}: ${getErrorMessage(err)}`, { cause: err });\n }\n}\n\n/** Whichever stream carried the reason a call failed, ready to quote. */\nfunction whyClaudeFailed(result: ExecResult): string {\n return (result.stderr || result.stdout || \"Unknown error\").trim();\n}\n\n/**\n * Removes a plugin, and says which of the two ordinary outcomes it was.\n *\n * The classification is a widening rather than a change: `claudePluginUninstall` returned `void`\n * and swallowed the same two spellings of \"there was no such plugin\", so every caller that was\n * told nothing goes on being told nothing. Both spellings stay in the list — dropping either turns\n * an ordinary uninstall into a thrown error.\n */\nexport async function claudePluginUninstall(\n pluginName: string,\n scope: ClaudePluginScope,\n projectDir: string,\n options?: ClaudeConfigOptions,\n): Promise<PluginRemovalOutcome> {\n validatePluginName(pluginName);\n\n const cwd = resolvePluginCwd(scope, projectDir);\n const args = [\"plugin\", \"uninstall\", pluginName, \"--scope\", scope];\n const result = await execCommand(\"claude\", args, { cwd, ...configDirEnv(options) });\n\n if (result.exitCode === 0) return \"removed\";\n\n const said = whyClaudeFailed(result);\n if (namesAMissingPlugin(said)) return \"absent\";\n throw new Error(`Plugin uninstall failed: ${said}`);\n}\n\n/** Whether Claude's refusal says there was no such plugin, rather than that it could not go. */\nfunction namesAMissingPlugin(message: string): boolean {\n return NOT_INSTALLED_MESSAGES.some((phrase) => message.includes(phrase));\n}\n\n/**\n * Which plugins directory a listing reads, given the installation the caller pinned.\n *\n * `CLAUDE_CONFIG_DIR` names the `.claude` tree itself, so the plugins directory hangs off it\n * directly. Unpinned, the answer is the layout's — the user's own tree, under whichever root\n * `installBaseDir` gives a global scope. `null` is a cell that has no plugins directory at all,\n * which `pluginsDir` answers for a host that installs plugins for a machine rather than a\n * project; Claude has one at both scopes, and the branch is the layout's shape rather than this\n * host's.\n */\nfunction claudePluginsRoot(\n projectDir: string,\n options: ClaudeConfigOptions | undefined,\n): string | null {\n if (options?.configDir !== undefined) return path.join(options.configDir, PLUGINS_SUBDIR);\n return pluginsDir(CLAUDE, \"global\", projectDir);\n}\n\n/**\n * What Claude has installed, as seen from one project.\n *\n * Two files rather than a command: Claude has no `plugin list --json`, so the installs come from\n * `installed_plugins.json` under {@link claudePluginsRoot} and the switch comes from the project's\n * own settings. A host that shelled out for this would read a non-zero exit as an empty listing.\n * An absent registry is an installation with no plugins, which is why it answers `[]` where\n * {@link listPluginInstallsForProject} throws for one that is present and unreadable.\n *\n * **\"As seen from one project\" is the pick, not just the switch.** A plugin key the registry\n * carries more than once is answered with this project's OWN record where there is one and the\n * user-scoped record otherwise, which is what {@link listPluginInstallsForProject} does. Returning\n * every recorded install instead would hand a reader another project's install path for a key\n * this project merely has switched on — the reading that was live in `plugin-discovery.ts` before\n * this member existed, and the one it now takes from here.\n */\nasync function claudeListPlugins(\n projectDir: string,\n options?: ClaudeConfigOptions,\n): Promise<HostPlugin[]> {\n const pluginsRoot = claudePluginsRoot(projectDir, options);\n if (pluginsRoot === null) return [];\n if (!(await fileExists(getInstalledPluginsRegistryPath(pluginsRoot)))) return [];\n\n const [installs, enabled] = await Promise.all([\n listPluginInstallsForProject(pluginsRoot, projectDir),\n getEnabledPluginKeys(projectDir),\n ]);\n const enabledKeys = new Set(enabled);\n\n return installs.map(({ pluginKey, installPath }) => ({\n pluginKey,\n installPath,\n enabled: enabledKeys.has(pluginKey),\n }));\n}\n\n/**\n * Claude Code as a {@link PluginHost}.\n *\n * A factory rather than a shared constant, so no caller holds another's `offeredPlacements` array\n * by identity — the rule `validResult()` in `lib/validation-result.ts` states and `agentCodec` in\n * `install-layout.ts` already follows.\n */\nexport function claudeHost(): PluginHost {\n return {\n provider: CLAUDE,\n offeredPlacements: claudeOfferedPlacements(),\n installsProjectScopedPlugins: true,\n isAvailable: isClaudeCLIAvailable,\n marketplaceExists: claudePluginMarketplaceExists,\n addMarketplace: claudePluginMarketplaceAdd,\n refreshMarketplace: claudePluginMarketplaceUpdate,\n installPlugin: (pluginRef, scope, projectDir, options) =>\n claudePluginInstall(pluginRef, toClaudePluginScope(scope), projectDir, options),\n uninstallPlugin: (pluginRef, scope, projectDir, options) =>\n claudePluginUninstall(pluginRef, toClaudePluginScope(scope), projectDir, options),\n listPlugins: claudeListPlugins,\n };\n}\n","/**\n * Spawning a child process, and the argument checks every host's plugin commands owe.\n *\n * The `claude*` functions this module used to carry moved into `lib/hosts/claude-host.ts` in C3,\n * where one host's vocabulary belongs. What stays is what is not any one host's: the `spawn`\n * wrapper itself, and three validators that refuse a name, a path or a marketplace source before\n * it reaches an argument vector. Codex's plugin verbs differ from Claude's word for word, so a\n * shared argv builder was never on offer — these checks are the part both hosts do share.\n */\n\nimport { spawn } from \"child_process\";\nimport path from \"path\";\n\n// Argument length limits to prevent oversized CLI arguments\nconst MAX_PLUGIN_PATH_LENGTH = 1024;\nconst MAX_PLUGIN_NAME_LENGTH = 256;\nconst MAX_MARKETPLACE_SOURCE_LENGTH = 1024;\n\n// Marketplace/plugin names: alphanumeric, dashes, underscores, dots, @\nconst SAFE_NAME_PATTERN = /^[a-zA-Z0-9._@/-]+$/;\n\n// Plugin path/ref: alphanumeric, dashes, underscores, dots, slashes, @, colons (for marketplace refs like skill@marketplace)\nconst SAFE_PLUGIN_PATH_PATTERN = /^[a-zA-Z0-9._@/:~-]+$/;\n\n/** A source that opens with `./` or `../` — the relative half of a directory on this machine. */\nconst OPENS_A_RELATIVE_PATH = /^\\.\\.?[/\\\\]/;\n\n/**\n * Whether a marketplace source names a DIRECTORY on this machine rather than a reference to fetch.\n *\n * The same split `isLocalSource` in `lib/configuration/config.ts` makes for the fetcher, spelled\n * again here rather than imported: `utils/` sits under `lib/`, and that function THROWS on a\n * traversal pattern, which is a refusal this check has no standing to make on another program's\n * behalf.\n */\nfunction namesADirectoryOnThisMachine(source: string): boolean {\n return path.isAbsolute(source) || OPENS_A_RELATIVE_PATH.test(source);\n}\n\n// eslint-disable-next-line no-control-regex\nconst CONTROL_CHAR_PATTERN = /[\\x00-\\x08\\x0E-\\x1F\\x7F]/u;\n\nexport function validatePluginPath(pluginPath: string): void {\n if (!pluginPath || pluginPath.trim().length === 0) {\n throw new Error(\"Plugin path must not be empty.\");\n }\n\n if (pluginPath.length > MAX_PLUGIN_PATH_LENGTH) {\n throw new Error(\n `Plugin path is too long (${pluginPath.length} characters, max ${MAX_PLUGIN_PATH_LENGTH}).`,\n );\n }\n\n if (CONTROL_CHAR_PATTERN.test(pluginPath)) {\n throw new Error(\"Plugin path contains invalid control characters.\");\n }\n\n if (!SAFE_PLUGIN_PATH_PATTERN.test(pluginPath)) {\n throw new Error(\n `Plugin path contains invalid characters: \"${pluginPath}\"\\n` +\n \"Plugin paths may only contain alphanumeric characters, dashes, underscores, dots, slashes, @, and colons.\",\n );\n }\n}\n\n/**\n * Refuses a marketplace source before it reaches an argument vector — a reference by its shape, a\n * directory by nothing but its length and its bytes.\n *\n * **A DIRECTORY'S NAME IS THE FILESYSTEM'S TO DECIDE, and holding one to the reference pattern\n * refused a directory the host accepts.** A marketplace named as a directory on this machine — an\n * absolute path, or one opening `./` or `../` — carries whatever the filesystem called it, and\n * under `/Users/My Name` that includes a space the reference pattern has no room for. Codex itself\n * has no objection: measured on the pinned 0.155.1, 2026-09-23, with `HOME` and `CODEX_HOME`\n * pinned to a scratch tree whose path contains a space and the global `config.toml` deleted first,\n * `codex plugin marketplace add '<…>/My Home/…' --json` exits 0 and `plugin add` then installs a\n * plugin from it.\n *\n * **What the pattern was ever protecting against is not reachable from here.** {@link execCommand}\n * spawns with an argv array and never passes `shell`, so a source is handed to the binary as data\n * and there is no shell to re-read it. The pattern stays on for a REFERENCE, where it does real\n * work — it refuses a value that is not a reference at all — and\n * `hosts/__tests__/a-marketplace-directory-with-a-space-reaches-the-host.test.ts` pins both halves\n * together, because an admitted directory on its own reads exactly like a check that was deleted.\n *\n * The length bound and the control-character refusal apply to both: a NUL byte is not a filename\n * on any host this runs on, and `spawn` throws on one rather than saying which argument it was.\n */\nexport function validateMarketplaceSource(source: string): void {\n if (!source || source.trim().length === 0) {\n throw new Error(\"Marketplace must not be empty.\");\n }\n\n if (source.length > MAX_MARKETPLACE_SOURCE_LENGTH) {\n throw new Error(\n `Marketplace is too long (${source.length} characters, max ${MAX_MARKETPLACE_SOURCE_LENGTH}).`,\n );\n }\n\n if (CONTROL_CHAR_PATTERN.test(source)) {\n throw new Error(\"Marketplace contains invalid control characters.\");\n }\n\n if (namesADirectoryOnThisMachine(source)) return;\n\n if (!SAFE_PLUGIN_PATH_PATTERN.test(source)) {\n throw new Error(\n `Marketplace contains invalid characters: \"${source}\"\\n` +\n \"Marketplaces may only contain alphanumeric characters, dashes, underscores, dots, slashes, @, and colons.\",\n );\n }\n}\n\nexport function validatePluginName(pluginName: string): void {\n if (!pluginName || pluginName.trim().length === 0) {\n throw new Error(\"Plugin name must not be empty.\");\n }\n\n if (pluginName.length > MAX_PLUGIN_NAME_LENGTH) {\n throw new Error(\n `Plugin name is too long (${pluginName.length} characters, max ${MAX_PLUGIN_NAME_LENGTH}).`,\n );\n }\n\n if (CONTROL_CHAR_PATTERN.test(pluginName)) {\n throw new Error(\"Plugin name contains invalid control characters.\");\n }\n\n if (!SAFE_NAME_PATTERN.test(pluginName)) {\n throw new Error(\n `Plugin name contains invalid characters: \"${pluginName}\"\\n` +\n \"Names may only contain alphanumeric characters, dashes, underscores, dots, @, and slashes.\",\n );\n }\n}\n\nexport type ExecResult = {\n stdout: string;\n stderr: string;\n exitCode: number;\n};\n\n/**\n * One child process run to completion, with the environment forwarded and `options.env` over it.\n *\n * **This module is the one place in the package that forwards the whole environment**, and\n * `__tests__/e2e-runner-environment.test.ts` is what holds it to exactly one: a spread anywhere\n * else hands every variable to a child that nothing named it for.\n */\nexport async function execCommand(\n command: string,\n args: string[],\n options?: { cwd?: string; env?: NodeJS.ProcessEnv },\n): Promise<ExecResult> {\n return new Promise((resolve, reject) => {\n const proc = spawn(command, args, {\n cwd: options?.cwd,\n env: { ...process.env, ...options?.env },\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n let stdout = \"\";\n let stderr = \"\";\n\n proc.stdout.on(\"data\", (data: Buffer) => {\n stdout += data.toString();\n });\n\n proc.stderr.on(\"data\", (data: Buffer) => {\n stderr += data.toString();\n });\n\n proc.on(\"close\", (code) => {\n resolve({\n stdout,\n stderr,\n exitCode: code ?? 1,\n });\n });\n\n proc.on(\"error\", (err) => {\n reject(err);\n });\n });\n}\n","import path from \"path\";\nimport { z } from \"zod\";\nimport { fileExists, readFileSafe } from \"../../utils/fs\";\nimport { verbose } from \"../../utils/logger\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { typedEntries } from \"../../utils/typed-object\";\nimport { CLAUDE_DIR, MAX_CONFIG_FILE_SIZE, STANDARD_FILES } from \"../../consts\";\nimport { formatZodErrors } from \"../schema-validator\";\nimport { INSTALLED_PLUGINS_FILE } from \"../installation/install-layout\";\n\n/**\n * Plugin key format: \"plugin-name@marketplace\"\n * e.g., \"web-framework-react@acme-marketplace\"\n *\n * Kept as string — user-extensible identifiers (plugin names and marketplace names).\n */\nexport type PluginKey = string;\n\n/**\n * Resolved plugin with its install path\n */\nexport type ResolvedPlugin = {\n pluginKey: PluginKey;\n installPath: string;\n};\n\n// Zod schemas for JSON parse boundaries\n\nconst pluginSettingsSchema = z\n .object({\n // The one genuine optional here: a settings.json with no plugin enabled omits the\n // key entirely, and `getEnabledPluginKeys` says so in its own diagnostic rather than\n // defaulting it away. `lastUpdated` and `gitCommitSha` used to sit beside the fields\n // below on the same footing and were decoration — declared, never read, and stripped\n // by `z.object` either way.\n enabledPlugins: z.record(z.string(), z.unknown()).exactOptional(),\n })\n .passthrough();\n\n/** The fields every installation record carries, whatever scope it was registered at. */\nconst installationFields = {\n installPath: z.string(),\n version: z.string(),\n installedAt: z.string(),\n};\n\n/**\n * Discriminated on `scope` rather than carrying an optional `projectPath`, because which\n * project a record belongs to is a question only a project-scoped record has: a\n * user-scoped one has no answer, and a project-scoped one without a path is a malformed\n * record that `pickInstallation` would silently decline to match.\n */\nconst pluginInstallationSchema = z.discriminatedUnion(\"scope\", [\n z.object({ scope: z.literal(\"project\"), projectPath: z.string(), ...installationFields }),\n z.object({ scope: z.literal(\"user\"), ...installationFields }),\n z.object({ scope: z.literal(\"local\"), ...installationFields }),\n]);\n\nconst installedPluginsSchema = z\n .object({\n version: z.number(),\n plugins: z.record(z.string(), z.array(pluginInstallationSchema)),\n })\n .passthrough();\n\nconst SETTINGS_FILE = STANDARD_FILES.SETTINGS_JSON;\n\n/** Absolute path of the claude CLI install registry inside a plugins directory. */\nexport function getInstalledPluginsRegistryPath(pluginsDir: string): string {\n return path.join(pluginsDir, INSTALLED_PLUGINS_FILE);\n}\n\n/**\n * The registry, parsed, keyed by plugin. The one read the two listings below share.\n *\n * Throws when the registry is unreadable or fails schema validation — callers\n * treat the registry as the source of truth for installed plugins, so a broken\n * registry must surface as an error rather than an empty result.\n */\nasync function readRegisteredInstallations(\n pluginsDir: string,\n): Promise<Record<PluginKey, RegisteredInstallation[]>> {\n const registryPath = getInstalledPluginsRegistryPath(pluginsDir);\n const content = await readFileSafe(registryPath, MAX_CONFIG_FILE_SIZE);\n const raw: unknown = JSON.parse(content);\n const result = installedPluginsSchema.safeParse(raw);\n\n if (!result.success) {\n throw new Error(\n `Invalid ${INSTALLED_PLUGINS_FILE}: ${formatZodErrors(result.error).join(\"; \")}`,\n );\n }\n\n return result.data.plugins;\n}\n\n/**\n * Lists every install recorded in a plugins directory's `installed_plugins.json`\n * (v2 registry — claude CLI >=2.1.220 installs under `cache/<marketplace>/<plugin>/<version>/`),\n * flattened to unique (pluginKey, installPath) pairs across all scopes.\n *\n * The listing for a reader whose subject is the REGISTRY — `content-validator.ts` validates what\n * is recorded there, and a record it skipped would be a record it never reported on. A reader\n * whose subject is a project takes {@link listPluginInstallsForProject} instead.\n */\nexport async function listRegisteredPluginInstalls(pluginsDir: string): Promise<ResolvedPlugin[]> {\n const installations = await readRegisteredInstallations(pluginsDir);\n\n return typedEntries(installations).flatMap(([pluginKey, forKey]) => {\n const uniquePaths = [...new Set(forKey.map((i) => i.installPath))];\n return uniquePaths.map((installPath) => ({ pluginKey, installPath }));\n });\n}\n\n/**\n * The same registry read as ONE install per plugin, as seen from `projectDir`.\n *\n * A plugin key the registry carries more than once has to be resolved to a single directory\n * before anything loads a skill out of it, and which one that is depends on who is asking:\n * this project's own record where there is one, the user-scoped record otherwise, and nothing at\n * all for a key recorded only under a different project's path. Returning every record instead\n * would hand a reader another project's install path for a key this project merely has switched\n * on.\n *\n * Throws for a present-but-unreadable registry, like its sibling and for its sibling's reason.\n */\nexport async function listPluginInstallsForProject(\n pluginsDir: string,\n projectDir: string,\n): Promise<ResolvedPlugin[]> {\n const installations = await readRegisteredInstallations(pluginsDir);\n\n return typedEntries(installations).flatMap(([pluginKey, forKey]) => {\n const picked = pickInstallation(forKey, projectDir);\n if (!picked) {\n verbose(`No installation of '${pluginKey}' belongs to '${projectDir}'`);\n return [];\n }\n return [{ pluginKey, installPath: picked.installPath }];\n });\n}\n\n/**\n * Read enabled plugin keys from project's .claude/settings.json\n */\nexport async function getEnabledPluginKeys(projectDir: string): Promise<PluginKey[]> {\n const settingsPath = path.join(projectDir, CLAUDE_DIR, SETTINGS_FILE);\n\n if (!(await fileExists(settingsPath))) {\n verbose(`No settings.json found at '${settingsPath}'`);\n return [];\n }\n\n try {\n const content = await readFileSafe(settingsPath, MAX_CONFIG_FILE_SIZE);\n const raw: unknown = JSON.parse(content);\n const result = pluginSettingsSchema.safeParse(raw);\n\n if (!result.success) {\n verbose(`Invalid settings.json structure: ${getErrorMessage(result.error)}`);\n return [];\n }\n\n const settings = result.data;\n\n if (!settings.enabledPlugins) {\n verbose(`No enabledPlugins found in '${settingsPath}'`);\n return [];\n }\n\n const enabledKeys = typedEntries(settings.enabledPlugins)\n .filter(([, enabled]) => enabled === true)\n .map(([key]) => key);\n\n verbose(`Found ${enabledKeys.length} enabled plugins in settings.json`);\n return enabledKeys;\n } catch (error) {\n verbose(`Failed to read settings.json: ${getErrorMessage(error)}`);\n return [];\n }\n}\n\ntype RegisteredInstallation = z.infer<typeof pluginInstallationSchema>;\n\n/** This project's own project-scoped installation wins; otherwise the user-scoped one. */\nfunction pickInstallation(\n installations: RegisteredInstallation[],\n projectDir: string,\n): RegisteredInstallation | undefined {\n return (\n installations.find((i) => i.scope === \"project\" && i.projectPath === projectDir) ??\n installations.find((i) => i.scope === \"user\")\n );\n}\n","/**\n * Codex's plugin machinery, behind {@link PluginHost}.\n *\n * The second implementation of the seam, and the first one that proves the seam was worth having:\n * nothing above it changes shape, and almost nothing below it is spelled the way Claude's is.\n *\n * **Every difference here is a measured fact about `@openai/codex` 0.155.1, not a preference.**\n * Each was re-derived with `HOME` and `CODEX_HOME` pinned to a scratch tree and the global\n * `config.toml` deleted between runs — the reset matters because `--sandbox workspace-write` and\n * `danger-full-access` make Codex WRITE a trust entry into that very file, so a later run answers\n * for a reason the measurement never set:\n *\n * | What differs from Claude | What this module does about it |\n * | ---------------------------------------------------------- | ----------------------------------------- |\n * | the verbs are `add` / `remove` / `marketplace upgrade` | its own argv per member — no shared builder |\n * | no subcommand takes a scope, and the cwd routes a WRITE nowhere | {@link codexPluginCwd}, pinned for every write verb |\n * | a LISTING does answer per directory, once the project is trusted | {@link codexListPlugins} asks from the project |\n * | `plugin marketplace list --json` answers an OBJECT | {@link marketplaceRegistrySchema} |\n * | `plugin remove` exits 0 whatever happened | the outcome comes from the listing BEFORE it |\n * | `marketplace upgrade` exits 1 on a local source | {@link refreshCodexMarketplace} branches on `sourceType` |\n * | every run prints a PATH-alias WARNING on stderr, exit 0 too | {@link withoutTheStandingWarning} |\n * | one unreadable marketplace fails BOTH listings outright | {@link namesAnUnreadableMarketplace}, on the two members that ask a question |\n *\n * **The scope argument is a lie this host cannot tell.** `codex plugin` has no `--scope`, and a\n * `plugin add` run from inside a project writes `[plugins.\"<id>@<mkt>\"] enabled = true` into the\n * GLOBAL `config.toml` and creates no project file at all. So a project-scoped plugin is not a\n * thing that can be installed here, and `installsProjectScopedPlugins` is `false` with\n * `offeredPlacements` saying the same thing in the vocabulary a refusal can print. The refusal\n * itself is `hostFor`'s, applied at the door to every host — see `offered-placements.ts` for why\n * it is not re-implemented in each of them.\n */\n\nimport os from \"os\";\nimport path from \"path\";\nimport { z } from \"zod\";\n\nimport { PLUGINS_SUBDIR } from \"../../consts.js\";\nimport type { SkillScope } from \"../../types/config.js\";\nimport { getErrorMessage } from \"../../utils/errors.js\";\nimport {\n execCommand,\n validateMarketplaceSource,\n validatePluginName,\n validatePluginPath,\n type ExecResult,\n} from \"../../utils/exec.js\";\nimport { verbose, warnOnce } from \"../../utils/logger.js\";\nimport { ensureDir } from \"../../utils/fs.js\";\nimport { pluginsDir, userConfigRoot } from \"../installation/install-layout.js\";\nimport type {\n HostCallOptions,\n HostPlugin,\n InstallPlacement,\n PluginHost,\n PluginRemovalOutcome,\n} from \"./plugin-host.js\";\n\n/** The provider this module is the host for, named once so no member spells it again. */\nconst CODEX: PluginHost[\"provider\"] = \"codex\";\n\n/**\n * The staged copy of a plugin lives under this directory of the Codex state root.\n *\n * `plugin list --json` prints no install path, so the path is COMPOSED from the shape\n * `plugin add --json` reports back — `<CODEX_HOME>/plugins/cache/<marketplace>/<name>/<version>`,\n * measured. Two segments rather than one because the cache is nested by marketplace, and a caller\n * listing the cache root can never see a plugin's own name in it.\n */\nconst PLUGIN_CACHE_SUBDIR = \"cache\";\n\n/**\n * The line Codex prints on stderr for every run whose `CODEX_HOME` sits under the temp directory,\n * including the ones that exit 0.\n *\n * It is not an error and quoting it into one names a cause that is not the cause. Recognised by\n * its own words rather than by its position, because it is emitted before anything this CLI asked\n * for and interleaves with whatever the command itself says.\n */\nconst STANDING_WARNING = /could not create PATH aliases/;\n\n/**\n * Where every `codex plugin` call that WRITES is made from, and why it is not the project.\n *\n * Claude routes a user-scoped install by the working directory as well as by a flag, so its host\n * picks a cwd per scope. A Codex WRITE routes nothing by it: there is no scope flag, and `plugin\n * add` run inside a project silently writes the machine-wide switch. A host that let the cwd\n * follow the project would read as project work in every call site and be global work in every\n * effect, which is the one failure in this step that changes another project's installation.\n *\n * **It is not where a LISTING is asked from**, and the first draft of this host used it for every\n * call alike — see {@link codexListPlugins} for the measurement that separates the two.\n *\n * A function rather than a constant for the reason `installBaseDir` gives one file over: a home\n * directory frozen at import answers from whichever HOME the first import saw, and every later\n * call spawns against a directory that may since have been removed.\n */\nfunction codexPluginCwd(): string {\n return os.homedir();\n}\n\n/**\n * Every mode/scope cell a Codex installation offers, which is three of the four.\n *\n * `plugin + project` is the cell Codex has no way to fill and the one a shared configuration is\n * refused for by name. Rebuilt per call by {@link codexHost} so no two callers hold one array.\n */\nfunction codexOfferedPlacements(): InstallPlacement[] {\n return [\n { mode: \"plugin\", scope: \"global\" },\n { mode: \"eject\", scope: \"global\" },\n { mode: \"eject\", scope: \"project\" },\n ];\n}\n\n/**\n * Which Codex installation a call reads and writes.\n *\n * The host's own spelling of {@link HostCallOptions}, kept as a name of its own because the e2e\n * harness drives these functions directly. `CODEX_HOME` relocates everything Codex keeps for a\n * user and is inherited by every process spawned below.\n */\nexport type CodexConfigOptions = HostCallOptions;\n\n/**\n * The `execCommand` options fragment that pins the state tree — empty when there is none, so the\n * call inherits its process's environment untouched.\n */\nfunction codexHomeEnv(options: CodexConfigOptions | undefined): { env?: NodeJS.ProcessEnv } {\n if (options?.configDir === undefined) return {};\n return { env: { CODEX_HOME: options.configDir } };\n}\n\n/**\n * The state tree this call is about: the one the caller pinned, or the one the layout answers.\n *\n * The layout's own `codexUserRoot` reads `CODEX_HOME` from the environment, which is the same\n * variable {@link codexHomeEnv} writes — so both branches name one directory and the unpinned one\n * is simply the variable this process already carries.\n */\nfunction codexStateRoot(options: CodexConfigOptions | undefined, askedFrom: string): string {\n return options?.configDir ?? userConfigRoot(CODEX, \"global\", askedFrom);\n}\n\n/**\n * One `codex` invocation, from `askedFrom` and against the pinned state tree.\n *\n * The directory is a required argument rather than a constant inside this function, which is the\n * whole of {@link codexListPlugins}'s fix: while it was pinned here, every member asked from the\n * home directory and no call site said so, so the one member whose answer DEPENDS on the\n * directory was wrong in a way no reader of a call site could see.\n *\n * **The state tree is CREATED first, and the reason is measured rather than defensive.** On\n * 0.155.1, with `CODEX_HOME` naming a directory that does not exist:\n *\n * ```\n * $ codex --version # exit 0, \"codex-cli 0.155.1\", a WARNING on stderr\n * $ codex plugin marketplace list --json # exit 1, \"Error: failed to resolve CODEX_HOME\"\n * $ codex plugin list --json # exit 1, the same\n * ```\n *\n * So the probe succeeds and every verb fails — `isAvailable` answers `true` for a host on which\n * nothing this module does can work, which is the silent-in-the-direction-that-looks-fine failure\n * the rest of this file is written against. A user who has installed Codex and never run it is in\n * exactly that state, and so is every pinned HOME a spec hands us. The directory is Codex's own\n * and it creates it itself on first run; making it here is what lets the FIRST thing that ever\n * touches this home be an install.\n */\nasync function runCodex(\n args: string[],\n options: CodexConfigOptions | undefined,\n askedFrom: string,\n): Promise<ExecResult> {\n await makeTheStateRoot(codexStateRoot(options, askedFrom));\n return execCommand(\"codex\", args, { cwd: askedFrom, ...codexHomeEnv(options) });\n}\n\n/**\n * Creates the state tree, and DEGRADES where it cannot — which is a posture, not a swallow.\n *\n * The authority on whether a `CODEX_HOME` is usable is Codex, and its refusal names the path:\n * `Error: failed to resolve CODEX_HOME … but that path does not exist`. Turning a filesystem error\n * here into a thrown host failure would replace that sentence with one about a directory the user\n * did not ask us to make — and turning it into `isAvailable: false` would say the binary is\n * missing when it is not. So the reason is recorded where diagnostics go and the call proceeds to\n * the program that owns the answer.\n */\nasync function makeTheStateRoot(root: string): Promise<void> {\n try {\n await ensureDir(root);\n } catch (error) {\n verbose(`Could not create the codex state directory at ${root}: ${getErrorMessage(error)}`);\n }\n}\n\n/**\n * The same invocation, where anything but a clean exit is this host's failure to report.\n *\n * Two shapes of failure meet here and a member that handled one of them would let the other reach\n * a caller as something else entirely: a binary that ran and refused arrives as an exit code, and\n * a binary that is not on PATH arrives as a rejected spawn. `attempt` is the verb phrase the\n * message is built on — \"add marketplace\", \"install plugin\" — so every failure on this host reads\n * as one sentence about what was being done.\n */\nasync function runCodexOrThrow(\n args: string[],\n options: CodexConfigOptions | undefined,\n attempt: string,\n askedFrom: string,\n): Promise<ExecResult> {\n let result;\n try {\n result = await runCodex(args, options, askedFrom);\n } catch (error) {\n throw new Error(`Failed to ${attempt}: ${getErrorMessage(error)}`, { cause: error });\n }\n\n if (result.exitCode !== 0) throw new Error(`Failed to ${attempt}: ${whyItFailed(result)}`);\n return result;\n}\n\n/**\n * What a failing `codex` call said, with the standing warning taken out of it.\n *\n * Line by line rather than by a replacement over the whole string: the warning arrives on its own\n * line and what follows it is the cause a user needs, so removing the line keeps the cause's own\n * formatting intact.\n */\nfunction withoutTheStandingWarning(stream: string): string {\n return stream\n .split(\"\\n\")\n .filter((line) => !STANDING_WARNING.test(line))\n .join(\"\\n\")\n .trim();\n}\n\n/** Whichever stream carried the reason a call failed, ready to quote. */\nfunction whyItFailed(result: ExecResult): string {\n const said = withoutTheStandingWarning(result.stderr) || withoutTheStandingWarning(result.stdout);\n return said || \"Unknown error\";\n}\n\n/**\n * The JSON one `--json` call printed, or a throw naming what was being read.\n *\n * **A parse failure is loud here, where Claude's marketplace reader answers `[]` after a warning.**\n * That reader's silence is survivable on a host whose shape it was written for and is not on this\n * one: an unreadable listing read as \"nothing is registered\" makes `marketplaceExists` answer\n * false forever, so the marketplace is re-added on every run and the doctor row that reports it\n * can never go green — with nothing failing anywhere to say so.\n */\nasync function readJsonFromCodex<T>(\n schema: z.ZodType<T>,\n args: string[],\n options: CodexConfigOptions | undefined,\n attempt: string,\n askedFrom: string,\n): Promise<T> {\n const result = await runCodexOrThrow(args, options, attempt, askedFrom);\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(result.stdout);\n } catch (error) {\n throw new Error(`Failed to ${attempt}: codex answered no JSON at all`, { cause: error });\n }\n\n const validated = schema.safeParse(parsed);\n if (!validated.success) {\n throw new Error(`Failed to ${attempt}: codex answered a document this release cannot read`);\n }\n return validated.data;\n}\n\n/**\n * Codex's marketplace registry, which is an OBJECT with the array inside it.\n *\n * Claude answers `[{name, source, …}]`; this answers `{\"marketplaces\":[{name, root,\n * marketplaceSource:{sourceType, source}}]}`. There is no top-level `source` at all, which is why\n * a reader written for the other shape parses nothing and reports an empty registry.\n */\nconst marketplaceRegistrySchema = z.object({\n marketplaces: z.array(\n z.object({\n name: z.string(),\n marketplaceSource: z.object({ sourceType: z.string(), source: z.string() }),\n }),\n ),\n});\n\n/** One marketplace as Codex's registry reports it. */\ntype CodexMarketplace = z.infer<typeof marketplaceRegistrySchema>[\"marketplaces\"][number];\n\n/**\n * Codex's own listing of what is installed, disabled plugins included.\n *\n * `available` comes back beside `installed` and is deliberately not read: it is the catalogue of\n * what COULD be installed, and a reader that merged the two would report a plugin as installed\n * for being on offer.\n */\nconst pluginListingSchema = z.object({\n installed: z.array(\n z.object({\n pluginId: z.string(),\n name: z.string(),\n marketplaceName: z.string(),\n version: z.string(),\n enabled: z.boolean(),\n }),\n ),\n});\n\ntype CodexInstalledPlugin = z.infer<typeof pluginListingSchema>[\"installed\"][number];\n\n/**\n * Which plugins directory a listing composes its paths under, given the installation the caller\n * pinned.\n *\n * `CODEX_HOME` names the state tree itself, so the plugins directory hangs off it directly.\n * Unpinned, the answer is the layout's — which reads the same variable, from the environment this\n * process is actually in. `null` is a cell with no plugins directory at all, which `pluginsDir`\n * answers for Codex at PROJECT scope, where plugins are a machine's and not a project's; the\n * global scope asked for here always has one, and the branch is the layout's shape rather than a\n * state this host can reach.\n */\nfunction codexPluginsRoot(\n projectDir: string,\n options: CodexConfigOptions | undefined,\n): string | null {\n if (options?.configDir !== undefined) return path.join(options.configDir, PLUGINS_SUBDIR);\n return pluginsDir(CODEX, \"global\", projectDir);\n}\n\n/**\n * Whether the `codex` binary is there and runnable at all.\n *\n * The state tree is pinned even though nothing is being installed, because on this host the probe\n * is a WRITE: `codex --version` links its helper binaries under `$CODEX_HOME/tmp/arg0/` before it\n * reads an argument. A probe with no way to name an installation writes the developer's own on\n * every run, which is what made the option part of the seam rather than of one member.\n */\nexport async function isCodexCLIAvailable(options?: CodexConfigOptions): Promise<boolean> {\n try {\n const result = await runCodex([\"--version\"], options, codexPluginCwd());\n return result.exitCode === 0;\n } catch {\n return false;\n }\n}\n\n/**\n * Codex's own refusal when a marketplace it has RECORDED can no longer be read.\n *\n * Both listing verbs answer it, in their own words — `failed to load marketplace(s)` from\n * `plugin marketplace list` and `failed to load configured marketplace snapshot(s)` from `plugin\n * list` — and both exit 1 having printed no JSON at all. Recorded 2026-09-22 on the pinned\n * 0.155.1 by adding a local marketplace and then moving its directory away:\n *\n * ```\n * $ codex plugin marketplace list --json # exit 1\n * Error: failed to load marketplace(s):\n * - `c4-measure-marketplace` at <gone>: marketplace root does not contain a supported manifest\n * $ codex plugin list --json # exit 1\n * Error: failed to load configured marketplace snapshot(s):\n * - `c4-measure-marketplace` at <gone>: marketplace root does not contain a supported manifest\n * ```\n *\n * **It is total, and it is not about us.** One unreadable entry fails the whole listing, so a\n * marketplace a user added by hand and later deleted takes down every read this host makes — while\n * `plugin marketplace add` and `plugin remove` go on working in the same state, measured. That is\n * why the degrade is at the two members that ask a QUESTION and nowhere else: a write whose\n * correctness is decided by a listing must not be told the listing was empty.\n */\nconst UNREADABLE_MARKETPLACE = /failed to load (?:configured )?marketplace/i;\n\n/** Whether a failure from a listing verb is that refusal rather than a failure of this host's. */\nfunction namesAnUnreadableMarketplace(error: unknown): boolean {\n return UNREADABLE_MARKETPLACE.test(getErrorMessage(error));\n}\n\n/** Every marketplace this Codex installation knows, in its own shape. */\nasync function codexMarketplaces(\n options: CodexConfigOptions | undefined,\n): Promise<CodexMarketplace[]> {\n const registry = await readJsonFromCodex(\n marketplaceRegistrySchema,\n [\"plugin\", \"marketplace\", \"list\", \"--json\"],\n options,\n \"read the marketplaces codex knows\",\n codexPluginCwd(),\n );\n return registry.marketplaces;\n}\n\n/**\n * Whether this Codex installation knows a marketplace by that NAME.\n *\n * **By name and never by count.** A Codex home holds whatever marketplaces its user has added\n * beside ours, so a predicate answering \"the registry is not empty\" is green on somebody else's\n * entry — and one answering \"the registry holds exactly ours\" is red the moment they add one.\n *\n * *Correction, 2026-09-22.* This paragraph used to give a different reason: that Codex ships its\n * own `openai-api-curated` rooted at `$CODEX_HOME/.tmp/plugins`, so ours is never the only entry.\n * That does not reproduce offline. Against the pinned 0.155.1 with a virgin `CODEX_HOME`,\n * `plugin marketplace list --json` answers `{\"marketplaces\":[]}` and `plugin list --json` answers\n * `{\"installed\":[],\"available\":[]}`. The names `openai-api-curated`, `openai-curated` and\n * `openai-bundled` are all in the shipped binary, so something registers them — an account, a\n * fetch, a feature — and nothing this rig can reach does. The RULE is unchanged; only its reason\n * was a claim that cannot be re-run, and the condition that produces the bundled entry is an open\n * question for the owner's real-Codex hand check rather than a fact this file may assert.\n *\n * **An unreadable marketplace is not an answer to this question, and it is not this host's\n * failure either** — see {@link namesAnUnreadableMarketplace}. Answering `false` is what Claude's\n * twin does for a registry it cannot parse, and it is the survivable direction here: the caller\n * adds our marketplace again, which `plugin marketplace add` performs in exactly this state.\n */\nasync function codexMarketplaceExists(\n name: string,\n options?: CodexConfigOptions,\n): Promise<boolean> {\n return (await codexRegisteredMarketplace(name, options)) !== null;\n}\n\n/**\n * The registration Codex holds under one marketplace NAME, with the source it was added from.\n *\n * `null` for a name nothing is registered under, and for a registry Codex could not read at all —\n * which is the posture {@link codexMarketplaceExists} had when it owned this read, and it is the\n * survivable direction for the same reason: the caller goes on to ADD, which `plugin marketplace\n * add` performs in exactly that state.\n *\n * {@link codexMarketplaceExists} is expressed over this rather than beside it, so the two cannot\n * answer differently about one registry.\n */\nasync function codexRegisteredMarketplace(\n name: string,\n options?: CodexConfigOptions,\n): Promise<CodexMarketplace | null> {\n let registered;\n try {\n registered = await codexMarketplaces(options);\n } catch (error) {\n if (!namesAnUnreadableMarketplace(error)) throw error;\n warnOnce(sayWhatCodexRefused(\"list the marketplaces it knows\", getErrorMessage(error)));\n return null;\n }\n\n return registered.find((marketplace) => marketplace.name === name) ?? null;\n}\n\n/**\n * Codex's own words for the refusal, quoted rather than summarised.\n *\n * The refusal names the marketplace and the path it could not read there, and neither is\n * derivable from anything this CLI holds — so a warning that said \"codex could not read its\n * marketplaces\" would leave a user with a degraded answer and no way to find the entry that\n * caused it.\n */\nfunction sayWhatCodexRefused(attempt: string, said: string): string {\n return `Codex could not ${attempt}, so this run is treating it as having none. It said: ${said}`;\n}\n\n/** Registers a marketplace from its SOURCE — the one verb here that does not take a name. */\nexport async function codexMarketplaceAdd(\n source: string,\n options?: CodexConfigOptions,\n): Promise<void> {\n validateMarketplaceSource(source);\n await runCodexOrThrow(\n [\"plugin\", \"marketplace\", \"add\", source, \"--json\"],\n options,\n \"add marketplace\",\n codexPluginCwd(),\n );\n}\n\n/**\n * Pulls a registered marketplace's current contents — two different commands behind one member.\n *\n * `marketplace upgrade` is git-only: against a local source it exits 1 with ``marketplace `…` is\n * not configured as a Git marketplace``, measured. This CLI's own generated marketplace IS local,\n * so a refresh that reached for `upgrade` unconditionally would report a failed update for the\n * one marketplace that is working exactly as designed. A local marketplace is refreshed by\n * installing its plugins again over the top, which is what `plugin add` does to an installed one.\n *\n * A name nothing registered is a throw rather than a silent no-op: `update` collects the failure\n * and names the marketplace, where a quiet return would report every marketplace refreshed.\n *\n * **The name is validated before anything is spawned**, which this member did not do until\n * 2026-09-22 while its Claude twin `claudePluginMarketplaceUpdate` always has. It is the one value\n * on this host that reached an argument vector unchecked: `add` checks its source and both plugin\n * verbs check their reference, so the gap was invisible beside three neighbours that read as the\n * rule. Checked here rather than in {@link upgradeGitMarketplace}, because the refusal is owed\n * whichever branch a caller's name would have taken.\n */\nasync function refreshCodexMarketplace(name: string, options?: CodexConfigOptions): Promise<void> {\n validatePluginName(name);\n\n const registered = (await codexMarketplaces(options)).find(\n (marketplace) => marketplace.name === name,\n );\n if (registered === undefined) {\n throw new Error(`Failed to refresh marketplace: codex has no marketplace named '${name}'`);\n }\n\n if (isGitSourced(registered)) return upgradeGitMarketplace(name, options);\n return reinstallEachPluginOf(name, options);\n}\n\n/** Whether Codex recorded this marketplace as a git checkout, which is what `upgrade` needs. */\nfunction isGitSourced(marketplace: CodexMarketplace): boolean {\n return marketplace.marketplaceSource.sourceType === \"git\";\n}\n\n/** The one verb that refreshes a git marketplace in place. */\nasync function upgradeGitMarketplace(\n name: string,\n options: CodexConfigOptions | undefined,\n): Promise<void> {\n await runCodexOrThrow(\n [\"plugin\", \"marketplace\", \"upgrade\", name, \"--json\"],\n options,\n \"refresh marketplace\",\n codexPluginCwd(),\n );\n}\n\n/** Every installed plugin of one local marketplace, installed again over the top of itself. */\nasync function reinstallEachPluginOf(\n name: string,\n options: CodexConfigOptions | undefined,\n): Promise<void> {\n // From the home directory: what is INSTALLED is a function of `CODEX_HOME` alone, and this\n // listing decides what gets written rather than what one project sees.\n const installed = await codexPluginListing(options, codexPluginCwd());\n\n // In sequence rather than through `Promise.all`: every one of these writes the same\n // `config.toml` and the same cache, and a host that raced them would interleave writes to one\n // file for no gain a user could see.\n for (const plugin of installed.filter((entry) => entry.marketplaceName === name)) {\n await installCodexPlugin(plugin.pluginId, options);\n }\n}\n\n/**\n * Installs a marketplace-qualified plugin.\n *\n * The scope and the project directory are the seam's, and this host has no use for either: no\n * Codex subcommand takes a scope, and the working directory is pinned for {@link codexPluginCwd}'s\n * reason. A `plugin + project` placement never reaches here at all — `hostFor` binds the roster on\n * this verb, so the refusal happens before anything is spawned.\n */\nasync function codexInstallPlugin(\n pluginRef: string,\n _scope: SkillScope,\n _projectDir: string,\n options?: CodexConfigOptions,\n): Promise<void> {\n await installCodexPlugin(pluginRef, options);\n}\n\n/** One `plugin add`, which is the whole of an install on this host. */\nasync function installCodexPlugin(\n pluginRef: string,\n options: CodexConfigOptions | undefined,\n): Promise<void> {\n validatePluginPath(pluginRef);\n await runCodexOrThrow(\n [\"plugin\", \"add\", pluginRef, \"--json\"],\n options,\n `install ${pluginRef}`,\n codexPluginCwd(),\n );\n}\n\n/**\n * Removes a plugin, and says which of the two ordinary outcomes it was.\n *\n * **The answer cannot come from the command that does it.** Measured three times on 0.155.1: a\n * plugin that was never installed, one that really went, and one removed a second time all exit 0\n * and print the same three fields on stdout. So the classification is the listing taken BEFORE the\n * removal, and the listing taken after is what turns a failed removal into a throw rather than\n * into a cheerful count — `uninstall` reports what it observed, which is D11(b).\n *\n * The scope and the project directory are the seam's; a Codex removal is machine-wide whichever\n * scope asks for it, and `uninstall` decides which scopes sweep at all.\n *\n * **The reference is held to the same check its Claude twin uses**, which is `validatePluginName`\n * and not the looser `validatePluginPath` this member reached for until 2026-09-22. A plugin\n * reference is `<name>@<marketplace>` and needs neither the colon nor the tilde the path check\n * admits, so the two hosts were refusing different values for one argument.\n */\nasync function codexUninstallPlugin(\n pluginRef: string,\n _scope: SkillScope,\n _projectDir: string,\n options?: CodexConfigOptions,\n): Promise<PluginRemovalOutcome> {\n validatePluginName(pluginRef);\n\n const wasInstalled = await isListed(pluginRef, options);\n await runCodexOrThrow(\n [\"plugin\", \"remove\", pluginRef, \"--json\"],\n options,\n `remove ${pluginRef}`,\n codexPluginCwd(),\n );\n\n if (await isListed(pluginRef, options)) {\n throw new Error(\n `Failed to remove ${pluginRef}: codex still lists it after removing it. ` +\n `Nothing else has been changed.`,\n );\n }\n\n return wasInstalled ? \"removed\" : \"absent\";\n}\n\n/**\n * Whether this Codex installation currently lists that plugin, switched on or off.\n *\n * Asked from the home directory, because the question is about the machine-wide registry a\n * removal acts on. The membership of that listing does not move with the directory — only the\n * `enabled` switch does, which this predicate never reads.\n */\nasync function isListed(\n pluginRef: string,\n options: CodexConfigOptions | undefined,\n): Promise<boolean> {\n const installed = await codexPluginListing(options, codexPluginCwd());\n return installed.some((plugin) => plugin.pluginId === pluginRef);\n}\n\n/** The `installed` array of one `plugin list --json`, parsed, as seen from `askedFrom`. */\nasync function codexPluginListing(\n options: CodexConfigOptions | undefined,\n askedFrom: string,\n): Promise<CodexInstalledPlugin[]> {\n const listing = await readJsonFromCodex(\n pluginListingSchema,\n [\"plugin\", \"list\", \"--json\"],\n options,\n \"read the plugins codex has installed\",\n askedFrom,\n );\n return listing.installed;\n}\n\n/**\n * What Codex has installed, as seen from one project — and it is ASKED from that project.\n *\n * **This is the one member whose answer the working directory decides, and it asked from the home\n * directory until 2026-09-22.** `codex plugin list` takes no project or scope argument at all\n * (`-m/--marketplace`, `--available` and `--json` are the whole of it), which is what the first\n * draft read as \"the directory cannot matter\" — and the membership of the listing really is a\n * function of `CODEX_HOME` alone. The `enabled` switch is not. Re-derived on the pinned 0.155.1,\n * one `CODEX_HOME` whose global `config.toml` says `[plugins.\"<id>\"] enabled = true`, one project\n * whose own `.codex/config.toml` says `enabled = false`, and the global `[projects.\"<abs path>\"]\n * trust_level = \"trusted\"` entry added between the second run and the first:\n *\n * ```\n * untrusted, asked from the project -> \"enabled\": true # the project file is ignored\n * TRUSTED, asked from the project -> \"enabled\": false # the project file wins\n * TRUSTED, asked from the home dir -> \"enabled\": true # the project is not in play\n * TRUSTED, asked from ANOTHER project -> \"enabled\": true # nor is its file\n * ```\n *\n * So a host pinned to the home directory answers the global switch to every caller, and the field\n * the seam was widened to carry — \"installed but disabled for THIS project\" — has no state it can\n * ever report. The doctor row that reads it would be green over a plugin the project has switched\n * off.\n *\n * **`projectDir` is the project ROOT, and on this host that matters.** From a SUBDIRECTORY of the\n * same trusted project the answer went back to `true` — unless the project is a git repository,\n * in which case the subdirectory answers `false` like the root. Measured both ways in the same\n * rig, the repository written as files rather than by running `git`. The seam passes a resolved\n * project root, so this host is on the safe side of it either way; it is recorded because a\n * caller that ever passes a cwd instead would get the global switch back with nothing to say so.\n *\n * A WRITE is still made from the home directory, and that asymmetry is the measurement rather\n * than an inconsistency: `plugin add` run inside a project writes the machine-wide switch and\n * creates no project file, so following the project there changes another project's installation.\n * See {@link codexPluginCwd}.\n *\n * No caller may read `enabled: true` as \"this project has it switched on\" even now: an untrusted\n * project's own file is ignored in silence, and the listing does not say which of the two\n * answered. That is the same trust gate `codexProjectRoles` in `installation/install-layout.ts`\n * carries for a compiled sub-agent.\n *\n * **An unreadable marketplace answers an empty listing rather than throwing**, which is Claude's\n * posture for a registry it cannot read — see {@link namesAnUnreadableMarketplace} for why the\n * failure is not about this installation at all.\n */\nasync function codexListPlugins(\n projectDir: string,\n options?: CodexConfigOptions,\n): Promise<HostPlugin[]> {\n const listing = await codexPluginsOrUnreadable(projectDir, options);\n if (listing.kind === \"listed\") return [...listing.plugins];\n\n warnOnce(sayWhatCodexRefused(\"list the plugins it has installed\", listing.reason));\n return [];\n}\n\n/**\n * What Codex has installed, or the reason it could not say — the same read with the degrade left\n * visible.\n *\n * `reason` is Codex's OWN words and nothing else — the refusal names the marketplace and the path\n * it could not read there, neither of which anything in this CLI holds. The caller wraps them in\n * its own sentence.\n */\ntype CodexPluginListing =\n | { readonly kind: \"listed\"; readonly plugins: readonly HostPlugin[] }\n | { readonly kind: \"unreadable\"; readonly reason: string };\n\nasync function codexPluginsOrUnreadable(\n projectDir: string,\n options?: CodexConfigOptions,\n): Promise<CodexPluginListing> {\n const pluginsRoot = codexPluginsRoot(projectDir, options);\n if (pluginsRoot === null) return { kind: \"listed\", plugins: [] };\n const cacheRoot = path.join(pluginsRoot, PLUGIN_CACHE_SUBDIR);\n\n let installed;\n try {\n installed = await codexPluginListing(options, projectDir);\n } catch (error) {\n if (!namesAnUnreadableMarketplace(error)) throw error;\n return { kind: \"unreadable\", reason: getErrorMessage(error) };\n }\n\n return {\n kind: \"listed\",\n plugins: installed.map((plugin) => ({\n pluginKey: plugin.pluginId,\n installPath: path.join(cacheRoot, plugin.marketplaceName, plugin.name, plugin.version),\n enabled: plugin.enabled,\n })),\n };\n}\n\n/**\n * Codex as a {@link PluginHost}.\n *\n * A factory rather than a shared constant, so no caller holds another's `offeredPlacements` array\n * by identity — the rule `validResult()` in `lib/validation-result.ts` states and `claudeHost`\n * follows one file over.\n */\nexport function codexHost(): PluginHost {\n return {\n provider: CODEX,\n offeredPlacements: codexOfferedPlacements(),\n installsProjectScopedPlugins: false,\n isAvailable: isCodexCLIAvailable,\n marketplaceExists: codexMarketplaceExists,\n addMarketplace: codexMarketplaceAdd,\n refreshMarketplace: refreshCodexMarketplace,\n installPlugin: codexInstallPlugin,\n uninstallPlugin: codexUninstallPlugin,\n listPlugins: codexListPlugins,\n };\n}\n","/**\n * What makes {@link PluginHost.offeredPlacements} binding rather than decorative.\n *\n * The roster exists so that a refusal reads data off the host instead of being written as\n * `if (provider === \"codex\")` in the installer. A roster nothing consults is neither: it reads as\n * the rule while the installer goes on trying whatever it was asked for. So the seam enforces it\n * at the one verb that CHOOSES a placement, and it does so once — a rule each host re-implements\n * is a rule the next host forgets, and the forgetting is silent in the direction that looks fine.\n *\n * **The enforcement is at the DOOR, not inside a host.** `hostFor` wraps whatever host it answers\n * with {@link bindsItsOfferedPlacements}, so a host written in a later step is bound before its\n * author has read this file. Putting the same guard inside `claude-host.ts` would leave a branch\n * no Claude test can reach — Claude offers all four cells — and would have to be remembered again\n * for every host after it.\n *\n * **The refusal names the cells it read**, because a message that says only \"not supported\" leaves\n * the user to guess which of the remaining ones to ask for. `unbackedPluginInstallError` in\n * `operations/skills/install-plugin-skills.ts` is the precedent for a refusal that advises.\n */\n\nimport { EJECT_SOURCE } from \"../../consts.js\";\nimport type { SkillConfig } from \"../../types/config.js\";\nimport type { InstallPlacement, PluginHost } from \"./plugin-host.js\";\n\n/** A placement as one comparable name. Nothing is parsed out of it — it is a spelling. */\nfunction placementName(placement: InstallPlacement): string {\n return `${placement.mode}+${placement.scope}`;\n}\n\nfunction offersPlacement(host: PluginHost, placement: InstallPlacement): boolean {\n return host.offeredPlacements.some(\n (offered) => offered.mode === placement.mode && offered.scope === placement.scope,\n );\n}\n\n/**\n * Refuses a placement the host's own roster does not carry, naming the ones it does.\n *\n * Exported because the install pre-flight refuses the same thing earlier and from a config rather\n * than from one call — a user is owed the refusal before anything is written, not after the first\n * skill has been installed. Both readings come off the same roster, so they cannot disagree.\n */\nexport function refuseUnofferedPlacement(\n host: PluginHost,\n placement: InstallPlacement,\n subject: string,\n): void {\n if (offersPlacement(host, placement)) return;\n\n throw new Error(\n `Refusing to install ${subject} as ${placementName(placement)}: the ${host.provider} host ` +\n `offers ${host.offeredPlacements.map(placementName).join(\", \")}. Nothing has been changed.`,\n );\n}\n\n/**\n * The placement one configured skill asks for, in the product's own two words.\n *\n * `origin` carries the marketplace a plugin skill came from, so anything that is not\n * {@link EJECT_SOURCE} is a plugin row. Nothing is parsed out of the name — which marketplace it\n * was is a question for the installer, not for whether the cell exists at all.\n */\nfunction placementAskedFor(skill: SkillConfig): InstallPlacement {\n return { mode: skill.origin === EJECT_SOURCE ? \"eject\" : \"plugin\", scope: skill.scope };\n}\n\n/**\n * Refuses a CONFIGURATION asking for a cell its host does not offer, naming the first such skill.\n *\n * **The read path needs this as much as the install path does, and nothing ties a folder's\n * contents to its name.** There is no `provider` field in `config.ts` and the ruling forbids one,\n * so a user who reads \"the folder says the provider\" and copies `.agents-inc/claude/` to\n * `.agents-inc/codex/` has a Codex installation holding a configuration that never passed through\n * `init --from --provider codex` and never met its pre-flight. Every later command reads that\n * file.\n *\n * It comes off the same roster {@link refuseUnofferedPlacement} reads, so the message a user gets\n * from `compile` names the same cells the one from `init` does. A second spelling written at the\n * read path would be a second thing to keep true.\n *\n * **Excluded rows are skipped**, because an excluded skill is one this installation is NOT\n * placing anywhere: refusing on one would make a configuration unreadable over a row whose whole\n * meaning is that nothing is installed for it.\n *\n * The FIRST offending row rather than all of them: the refusal is a stop, and a user fixing a\n * configuration reruns the command, so a list would be a list of guesses about rows the first fix\n * may well have been.\n */\nexport function refuseUnofferedPlacements(skills: readonly SkillConfig[], host: PluginHost): void {\n for (const skill of skills) {\n if (skill.excluded === true) continue;\n refuseUnofferedPlacement(host, placementAskedFor(skill), skill.id);\n }\n}\n\n/**\n * The same host, with its roster binding on the verb that picks a placement.\n *\n * `installPlugin` only: `uninstallPlugin` at a scope the host never installs at is an ordinary\n * no-op sweep, and `pluginScopesToSweep` in `commands/uninstall.tsx` already reads the roster to\n * decide how wide that sweep is.\n */\nexport function bindsItsOfferedPlacements(host: PluginHost): PluginHost {\n return {\n ...host,\n // `async` so a refused placement arrives as a rejected promise rather than as a synchronous\n // throw: `installPluginSkills` collects per-skill failures around an `await`, and a member\n // that threw before returning one would escape that collection and abort the whole install.\n installPlugin: async (pluginRef, scope, projectDir, options) => {\n refuseUnofferedPlacement(host, { mode: \"plugin\", scope }, pluginRef);\n return host.installPlugin(pluginRef, scope, projectDir, options);\n },\n };\n}\n","/**\n * The door every caller goes through to reach a host's plugin machinery.\n *\n * Two doors, because there are two ways a run knows which provider it is about and they are not\n * the same question:\n *\n * - {@link hostAt} — a caller holding a DIRECTORY and nothing else. The folder is the only record\n * of a provider (there is no field in `config.ts` and nothing in a shared payload carries one),\n * so this is C2's `providerInUse` with a host on the end of it. Almost every caller is this one.\n * - {@link hostFor} — a caller that has been TOLD the provider. `--provider` on a greenfield\n * `init --from` is the case that exists, and it is the one no folder can answer, because the\n * folder has not been created yet.\n *\n * **Both providers answer a host from C4, and the refusal that stood here until then is gone.**\n * It read \"this release has a host for claude only\", and its twin at the paths —\n * `refuseAProviderWithNoHost` in `install-layout.ts` — is deleted in the same step. Neither was\n * widened: a refusal that names one provider and a roster that names two cannot both be the rule,\n * and the switch below is now total over {@link Provider}, so the next provider is a compiler\n * error here rather than a silent fall-through into Claude's machinery.\n *\n * **Every host leaves here with its offered placements binding.** {@link bindsItsOfferedPlacements}\n * is applied once, at the door, rather than inside each host: a rule each host re-implements is a\n * rule the next host forgets, and for the one host this release ships every cell is offered, so\n * the omission would never have shown up.\n */\n\nimport type { Provider } from \"../../consts.js\";\nimport { providerInUse } from \"../installation/install-layout.js\";\nimport { claudeHost } from \"./claude-host.js\";\nimport { codexHost } from \"./codex-host.js\";\nimport { bindsItsOfferedPlacements } from \"./offered-placements.js\";\nimport type { PluginHost } from \"./plugin-host.js\";\n\n/** The host for a provider this run has been told, rather than one it read off a folder. */\nexport function hostFor(provider: Provider): PluginHost {\n switch (provider) {\n case \"claude\":\n return bindsItsOfferedPlacements(claudeHost());\n case \"codex\":\n return bindsItsOfferedPlacements(codexHost());\n default: {\n const _exhaustive: never = provider;\n return _exhaustive;\n }\n }\n}\n\n/**\n * The host the installation under `root` belongs to.\n *\n * @throws where the folder names a provider this release has no host for — the refusal is\n * `providerInUse`'s, raised before this module is reached.\n */\nexport function hostAt(root: string): PluginHost {\n return hostFor(providerInUse(root));\n}\n","import type { SkillId } from \"../../types\";\nimport type { SkillConfig, SkillScope } from \"../../types/config\";\nimport type { SourceLoadResult } from \"../loading\";\n// Type-only, so no module edge is created: the operations layer imports back into\n// this one, and the shape a plugin install reports is defined where installs live.\nimport type { PluginInstallResult } from \"../operations/skills/install-plugin-skills\";\nimport { deleteLocalSkill, copySkillsToLocalFlattened } from \"../skills\";\nimport { hostAt } from \"../hosts/host-for\";\nimport type { PluginHost } from \"../hosts/plugin-host\";\nimport { buildMarketplacePluginRef } from \"../plugins/plugin-ref\";\nimport { resolveInstallPaths } from \"./install-base-dir\";\nimport { verbose } from \"../../utils/logger\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { CLI_INVOKE_COMMAND, EJECT_SOURCE } from \"../../consts\";\n\nexport type SkillMigration = {\n id: SkillId;\n oldSource: string;\n newSource: string;\n oldScope: SkillScope;\n newScope: SkillScope;\n};\n\nexport type MigrationPlan = {\n toEject: SkillMigration[];\n toPlugin: SkillMigration[];\n scopeChanges: SkillMigration[];\n};\n\n/**\n * What the plugin→eject half copied, in the shape {@link PluginInstallResult} reports the\n * opposite direction, so one command surface reports both and neither can drift into a\n * private idea of what a failure looks like.\n *\n * A non-empty `failed` means this run could NOT honor the user's eject intent for those\n * skills, so the caller MUST hard-error before writing any config — otherwise config.ts\n * records `origin: \"eject\"` for a skill that has no local copy. The asymmetry this\n * replaces is what let that ship: the plugin half returned its failures structurally\n * while the eject half turned them into a warning string nobody could act on.\n */\nexport type EjectCopyResult = {\n copied: SkillId[];\n failed: Array<{ id: SkillId; error: string }>;\n};\n\nexport type MigrationResult = {\n ejectCopies: EjectCopyResult;\n /**\n * What the eject→plugin half installed, in the shape a fresh install returns, so\n * one command surface reports both. The refs are built here because this is where\n * each migration's own scope and marketplace are already resolved.\n *\n * A non-empty `failed` means this run could NOT honor the user's plugin intent for\n * those skills, so the caller MUST hard-error before writing any config — otherwise\n * config.ts records a marketplace `origin` for a skill that has no plugin\n * registration.\n */\n pluginInstalls: PluginInstallResult;\n warnings: string[];\n};\n\n/**\n * Hard-error message for failed eject copies — the twin of `pluginInstallFailureError` in\n * `operations/skills/install-plugin-skills.ts`, worded from the same rule: an install intent\n * this run could not honor must stop the run BEFORE any config records it.\n */\nexport function ejectCopyFailureError(failedCount: number): string {\n return `Failed to copy ${failedCount} skill(s) for eject. Eject intent could not be honored. Check that the destination skills directory is writable, then run '${CLI_INVOKE_COMMAND} edit' again — or switch the affected skills back to plugin mode.`;\n}\n\n/**\n * Detect which skills changed source or scope between old and new configs\n * by comparing SkillConfig[] entries by ID.\n */\nexport function detectMigrations(\n oldSkills: SkillConfig[],\n newSkills: SkillConfig[],\n): MigrationPlan {\n const oldById = new Map(oldSkills.map((s) => [s.id, s]));\n const migrations = newSkills.flatMap((newSkill) => {\n const oldSkill = oldById.get(newSkill.id);\n return oldSkill ? [migrationBetween(oldSkill, newSkill)] : [];\n });\n\n return {\n toEject: migrations.filter(switchesToEject),\n toPlugin: migrations.filter(switchesToPlugin),\n scopeChanges: migrations.filter(movesScopeWithoutSwitchingMode),\n };\n}\n\n/** One skill's before and after, as the migration that takes it from one to the other. */\nfunction migrationBetween(oldSkill: SkillConfig, newSkill: SkillConfig): SkillMigration {\n return {\n id: newSkill.id,\n oldSource: oldSkill.origin,\n newSource: newSkill.origin,\n oldScope: oldSkill.scope,\n newScope: newSkill.scope,\n };\n}\n\nfunction wasEjected(migration: SkillMigration): boolean {\n return migration.oldSource === EJECT_SOURCE;\n}\n\nfunction isEjected(migration: SkillMigration): boolean {\n return migration.newSource === EJECT_SOURCE;\n}\n\nfunction switchesToEject(migration: SkillMigration): boolean {\n return !wasEjected(migration) && isEjected(migration);\n}\n\nfunction switchesToPlugin(migration: SkillMigration): boolean {\n return wasEjected(migration) && !isEjected(migration);\n}\n\n/**\n * A scope change on a skill that stays in its mode. A skill that switches mode is planned as\n * `toEject` or `toPlugin` instead, and never as a scope change as well.\n */\nfunction movesScopeWithoutSwitchingMode(migration: SkillMigration): boolean {\n return (\n migration.oldScope !== migration.newScope && wasEjected(migration) === isEjected(migration)\n );\n}\n\n/**\n * Execute per-skill migration: delete locals that switch to plugin,\n * copy to local for skills that switch from plugin.\n * Uses per-skill scope from the migration plan.\n */\nexport async function executeMigration(\n plan: MigrationPlan,\n projectDir: string,\n sourceResult: SourceLoadResult,\n): Promise<MigrationResult> {\n const host = hostAt(projectDir);\n\n const ejectCopies = await copyMigratedSkillsToLocal(plan.toEject, projectDir, sourceResult);\n // Only the skills whose copy LANDED, which is `installMigratedPlugins`' rule read the other way\n // round. Dropping the plugin registration of a skill that has no local copy would leave it\n // installed nowhere, so a working install must survive a failed migration exactly as the\n // ejected working copy survives a failed plugin install.\n const warnings = await uninstallMigratedPlugins(\n migrationsWhoseCopyLanded(plan.toEject, ejectCopies),\n projectDir,\n sourceResult,\n host,\n );\n const pluginInstalls = await installMigratedPlugins(\n plan.toPlugin,\n projectDir,\n sourceResult,\n host,\n );\n\n return { ejectCopies, pluginInstalls, warnings };\n}\n\n/**\n * Installs the plugin each newly-pluginized skill becomes, and names every one it could not\n * install.\n *\n * Plugin install intent is inviolable: without a marketplace NO migration in this list can be\n * installed, so the whole list fails before anything is deleted. Deleting first and downgrading\n * to a warning destroys the user's editable working copy and leaves config entries claiming a\n * plugin that was never installed.\n *\n * The same rule applies per skill: install FIRST and delete the ejected working copy only once\n * THAT skill's plugin is registered. A failed install then leaves the skill exactly as it was,\n * and the caller hard-errors on `pluginInstalls.failed` before any config claims the plugin\n * source.\n */\nasync function installMigratedPlugins(\n migrations: SkillMigration[],\n projectDir: string,\n sourceResult: SourceLoadResult,\n host: PluginHost,\n): Promise<PluginInstallResult> {\n const installs: PluginInstallResult = { installed: [], failed: [] };\n if (migrations.length === 0) return installs;\n\n if (!sourceResult.marketplace) {\n throw new Error(\n `Cannot install skills as plugins: marketplace could not be resolved from ` +\n `'${sourceResult.sourceConfig.source}'. Plugin install mode requires a marketplace — ` +\n `fix the marketplace or switch the affected skills to eject mode.`,\n );\n }\n\n for (const migration of migrations) {\n const pluginRef = buildMarketplacePluginRef(migration.id, sourceResult.marketplace);\n try {\n await host.installPlugin(pluginRef, migration.newScope, projectDir);\n } catch (error) {\n installs.failed.push({ id: migration.id, error: getErrorMessage(error) });\n continue;\n }\n installs.installed.push({ id: migration.id, ref: pluginRef });\n verbose(`Installed plugin for ${migration.id}`);\n await deleteEjectedWorkingCopy(migration, projectDir);\n }\n\n return installs;\n}\n\n/**\n * Writes the local copy each newly-ejected skill becomes, and names every one it could not\n * write.\n *\n * The mirror of {@link installMigratedPlugins}, and per-skill for the same reasons. Each\n * migration resolves its OWN destination from its own scope, so the two scopes are independent\n * by construction rather than by pass ordering — a refused write under $HOME says nothing about\n * the project tree, and one batched `try` around both once let a single project-scope failure\n * cancel every global copy behind one warning line.\n *\n * Failures are COLLECTED rather than aborted on. The caller hard-errors on any of them before\n * writing config, so stopping at the first buys no safety and costs the user the rest of the\n * list — they would learn about the second unwritable destination only by fixing the first and\n * running again. That is the reasoning `copyEachSkill` already gives for reporting its own\n * failures by id rather than throwing on the first.\n */\nasync function copyMigratedSkillsToLocal(\n migrations: SkillMigration[],\n projectDir: string,\n sourceResult: SourceLoadResult,\n): Promise<EjectCopyResult> {\n const copies: EjectCopyResult = { copied: [], failed: [] };\n\n for (const migration of migrations) {\n const { skillsDir } = resolveInstallPaths(projectDir, migration.newScope);\n try {\n const copied = await copySkillsToLocalFlattened([migration.id], skillsDir, sourceResult);\n copies.copied.push(...copied.map((skill) => skill.skillId));\n } catch (error) {\n copies.failed.push({ id: migration.id, error: getErrorMessage(error) });\n }\n }\n\n return copies;\n}\n\n/** The migrations that now have a local copy on disk, and so no longer need their plugin. */\nfunction migrationsWhoseCopyLanded(\n migrations: SkillMigration[],\n copies: EjectCopyResult,\n): SkillMigration[] {\n const landed = new Set(copies.copied);\n return migrations.filter((migration) => landed.has(migration.id));\n}\n\n/**\n * True when a migration must LEAVE the plugin registered: a skill moving from the global\n * install to a project-local copy keeps the global plugin for every other project, and this\n * project's config tombstone (`excluded: true`) is what keeps this project off it.\n */\nfunction keepsGlobalPluginRegistration(migration: SkillMigration): boolean {\n return migration.oldScope === \"global\" && migration.newScope === \"project\";\n}\n\n/**\n * Drops the plugin registration each newly-ejected skill no longer needs, and names every one\n * it could not drop.\n *\n * Diagnostic-only: the local copy IS the install now, so a stale registration is untidy rather\n * than wrong and must not fail the migration. What it must not do is borrow the copy pass's\n * words — this loop lived inside the copy's `try`, so a `claude plugin uninstall` that threw\n * was reported to the user as `Could not copy skills for eject`, naming work that had in fact\n * succeeded one line above the count proving it.\n */\nasync function uninstallMigratedPlugins(\n migrations: SkillMigration[],\n projectDir: string,\n sourceResult: SourceLoadResult,\n host: PluginHost,\n): Promise<string[]> {\n const warnings: string[] = [];\n\n for (const migration of migrations) {\n if (keepsGlobalPluginRegistration(migration)) {\n verbose(`Keeping global plugin for ${migration.id} (migrated to project-eject)`);\n continue;\n }\n if (!sourceResult.marketplace) {\n warnings.push(`Could not uninstall plugin for ${migration.id}: no marketplace configured`);\n continue;\n }\n\n // Scope-precise uninstall keyed to this migration's own scope. A best-effort\n // both-scopes sweep would also drop a same-id plugin registered at the OTHER Claude\n // scope (e.g. a project→eject switch uninstalling the still-needed global/user-scope\n // plugin). The registered scope is unambiguous here, so target it exactly.\n // A removal still answers `absent` rather than throwing for a plugin the host does not\n // have, so an already-gone registration is not a warning.\n const pluginRef = buildMarketplacePluginRef(migration.id, sourceResult.marketplace);\n try {\n await host.uninstallPlugin(pluginRef, migration.oldScope, projectDir);\n } catch (error) {\n warnings.push(`Could not uninstall plugin for ${migration.id}: ${getErrorMessage(error)}`);\n continue;\n }\n verbose(`Uninstalled plugin for ${migration.id}`);\n }\n\n return warnings;\n}\n\n/**\n * Removes the local copy a now-pluginized skill no longer needs, from the scope it was\n * ejected at. A global copy is kept when the skill moves to project scope — the global\n * copy must remain for other projects.\n */\nasync function deleteEjectedWorkingCopy(\n migration: SkillMigration,\n projectDir: string,\n): Promise<void> {\n if (migration.oldScope === \"global\" && migration.newScope === \"project\") {\n verbose(`Keeping global local skill for ${migration.id} (migrated to project-plugin)`);\n return;\n }\n await deleteLocalSkill(projectDir, migration.id, migration.oldScope);\n}\n","import { isRecord } from \"../../utils/type-guards.js\";\nimport path from \"path\";\nimport fg from \"fast-glob\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport {\n fileExists,\n readFile,\n readFileSafe,\n directoryExists,\n listDirectories,\n} from \"../../utils/fs\";\nimport type { ValidationResult } from \"../../types\";\nimport { validResult, invalidResult, mergeValidationResults } from \"../validation-result\";\nimport { extractFrontmatter } from \"../../utils/frontmatter\";\nimport { log } from \"../../utils/logger\";\nimport { formatZodErrors } from \"../schema-validator\";\nimport {\n pluginManifestValidationSchema,\n skillFrontmatterValidationSchema,\n agentFrontmatterValidationSchema,\n} from \"../schemas\";\nimport {\n KEBAB_CASE_PATTERN,\n MAX_PLUGIN_FILE_SIZE,\n PLUGIN_MANIFEST_DIR,\n STANDARD_FILES,\n} from \"../../consts\";\nimport { getPluginManifestPath } from \"./plugin-finder\";\n\nconst PLUGIN_DIR = PLUGIN_MANIFEST_DIR;\nconst PLUGIN_MANIFEST = STANDARD_FILES.PLUGIN_JSON;\nconst SEMVER_REGEX =\n /^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$/;\n\nfunction isKebabCase(str: string): boolean {\n return KEBAB_CASE_PATTERN.test(str);\n}\n\nfunction isValidSemver(str: string): boolean {\n return SEMVER_REGEX.test(str);\n}\n\n/**\n * Validates the directory structure of a plugin.\n *\n * Checks for the required `.claude-plugin/` directory and `plugin.json` manifest file.\n * Warns if README.md is missing (recommended but not required).\n *\n * @param pluginPath - Absolute path to the plugin root directory\n * @returns Validation result with errors for missing required structure\n */\nexport async function validatePluginStructure(pluginPath: string): Promise<ValidationResult> {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!(await directoryExists(pluginPath))) {\n return invalidResult(`Plugin directory does not exist: ${pluginPath}`);\n }\n\n const pluginDir = path.join(pluginPath, PLUGIN_DIR);\n if (!(await directoryExists(pluginDir))) {\n errors.push(`Missing ${PLUGIN_DIR}/ directory`);\n }\n\n const manifestPath = path.join(pluginDir, PLUGIN_MANIFEST);\n if (!(await fileExists(manifestPath))) {\n errors.push(`Missing ${PLUGIN_DIR}/${PLUGIN_MANIFEST}`);\n }\n\n const readmePath = path.join(pluginPath, STANDARD_FILES.README_MD);\n if (!(await fileExists(readmePath))) {\n warnings.push(\"Missing README.md (recommended for documentation)\");\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\n/**\n * Validates a plugin manifest file (plugin.json) for correctness and completeness.\n *\n * Performs the following validation checks:\n * 1. File existence and readability\n * 2. Valid JSON syntax (with file size limit via readFileSafe)\n * 3. Zod schema validation (strict mode rejects unrecognized keys)\n * 4. Plugin name is kebab-case\n * 5. Version string is valid semver\n * 6. Description field is present (warning if missing)\n * 7. Skills directory path exists on disk (if specified as string)\n * 8. Agents directory path exists on disk (if specified as string)\n *\n * @param manifestPath - Absolute path to the plugin.json file\n * @returns Validation result with errors for invalid/missing data and warnings for recommendations\n */\nexport async function validatePluginManifest(manifestPath: string): Promise<ValidationResult> {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!(await fileExists(manifestPath))) {\n return invalidResult(`Manifest file not found: ${manifestPath}`);\n }\n\n // `JSON.parse` returns `any`, and every field read below trusts what it\n // returns. Landing it in `unknown` and narrowing with `isRecord` first is what\n // makes `manifest.name` a checked read of a record rather than a property\n // fetched off `any` — and it names the array/string/null cases the schema\n // would otherwise report as a shape mismatch several lines later.\n let manifest: Record<string, unknown>;\n try {\n const content = await readFileSafe(manifestPath, MAX_PLUGIN_FILE_SIZE);\n const parsed: unknown = JSON.parse(content);\n if (!isRecord(parsed)) return invalidResult(`${PLUGIN_MANIFEST} must contain a JSON object`);\n manifest = parsed;\n } catch (err) {\n return invalidResult(`Invalid JSON in ${PLUGIN_MANIFEST}: ${getErrorMessage(err)}`);\n }\n\n const result = pluginManifestValidationSchema.safeParse(manifest);\n\n if (!result.success) {\n errors.push(...formatZodErrors(result.error));\n }\n\n if (manifest.name && typeof manifest.name === \"string\") {\n if (!isKebabCase(manifest.name)) {\n errors.push(`name must be kebab-case: \"${manifest.name}\"`);\n }\n }\n\n if (manifest.version && typeof manifest.version === \"string\") {\n if (!isValidSemver(manifest.version)) {\n errors.push(\n `version \"${manifest.version}\" is not valid semver (expected: major.minor.patch)`,\n );\n }\n }\n\n if (!manifest.description) {\n warnings.push(\"Missing description field (recommended for discoverability)\");\n }\n\n const pluginDir = path.dirname(path.dirname(manifestPath));\n\n if (manifest.skills && typeof manifest.skills === \"string\") {\n const skillsPath = path.join(pluginDir, manifest.skills);\n if (!(await directoryExists(skillsPath))) {\n errors.push(`Skills path does not exist: ${manifest.skills}`);\n }\n }\n\n if (manifest.agents && typeof manifest.agents === \"string\") {\n const agentsPath = path.join(pluginDir, manifest.agents);\n if (!(await directoryExists(agentsPath))) {\n errors.push(`Agents path does not exist: ${manifest.agents}`);\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\nexport async function validateSkillFrontmatter(skillPath: string): Promise<ValidationResult> {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!(await fileExists(skillPath))) {\n return invalidResult(`Skill file not found: ${skillPath}`);\n }\n\n const content = await readFile(skillPath);\n const frontmatter = extractFrontmatter(content);\n\n if (frontmatter === null) {\n return invalidResult(\"Missing or invalid YAML frontmatter\");\n }\n\n const result = skillFrontmatterValidationSchema.safeParse(frontmatter);\n\n if (!result.success) {\n errors.push(...formatZodErrors(result.error));\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\nexport async function validateAgentFrontmatter(agentPath: string): Promise<ValidationResult> {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!(await fileExists(agentPath))) {\n return invalidResult(`Agent file not found: ${agentPath}`);\n }\n\n const content = await readFile(agentPath);\n const frontmatter = extractFrontmatter(content);\n\n if (frontmatter === null) {\n return invalidResult(\"Missing or invalid YAML frontmatter\");\n }\n\n const result = agentFrontmatterValidationSchema.safeParse(frontmatter);\n\n if (!result.success) {\n errors.push(...formatZodErrors(result.error));\n }\n\n // Boundary cast: YAML frontmatter parsed as unknown, narrow to record for field access\n const fm = frontmatter as Record<string, unknown>;\n\n if (fm.name && typeof fm.name === \"string\") {\n if (!isKebabCase(fm.name)) {\n errors.push(`name must be kebab-case: \"${fm.name}\"`);\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\nfunction prefixResult(result: ValidationResult, prefix: string): ValidationResult {\n return {\n valid: result.valid,\n errors: result.valid ? [] : result.errors.map((e) => `${prefix}: ${e}`),\n warnings: result.warnings.map((w) => `${prefix}: ${w}`),\n };\n}\n\nasync function validatePluginSkillFiles(\n pluginPath: string,\n skillsRelPath: string,\n): Promise<ValidationResult> {\n const skillsDir = path.join(pluginPath, skillsRelPath);\n if (!(await directoryExists(skillsDir))) return validResult();\n\n const files = await fg(`**/${STANDARD_FILES.SKILL_MD}`, { cwd: skillsDir, absolute: true });\n if (files.length === 0) {\n return {\n valid: true,\n errors: [],\n warnings: [`Skills directory exists but contains no SKILL.md files: ${skillsRelPath}`],\n };\n }\n\n const results = await Promise.all(\n files.map(async (f) =>\n prefixResult(await validateSkillFrontmatter(f), path.relative(pluginPath, f)),\n ),\n );\n return mergeValidationResults(results);\n}\n\nasync function validatePluginAgentFiles(\n pluginPath: string,\n agentsRelPath: string,\n): Promise<ValidationResult> {\n const agentsDir = path.join(pluginPath, agentsRelPath);\n if (!(await directoryExists(agentsDir))) return validResult();\n\n const files = await fg(\"*.md\", { cwd: agentsDir, absolute: true });\n if (files.length === 0) {\n return {\n valid: true,\n errors: [],\n warnings: [`Agents directory exists but contains no .md files: ${agentsRelPath}`],\n };\n }\n\n const results = await Promise.all(\n files.map(async (f) =>\n prefixResult(await validateAgentFrontmatter(f), path.relative(pluginPath, f)),\n ),\n );\n return mergeValidationResults(results);\n}\n\nasync function loadManifestForValidation(\n manifestPath: string,\n): Promise<Record<string, unknown> | null> {\n try {\n const content = await readFileSafe(manifestPath, MAX_PLUGIN_FILE_SIZE);\n const parsed: unknown = JSON.parse(content);\n return isRecord(parsed) ? parsed : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Runs comprehensive validation on a plugin: structure, manifest, skill files, and agent files.\n *\n * Short-circuits on structure validation failure (no point checking manifest if\n * the directory structure is wrong). For valid structures, validates the manifest\n * and then checks all SKILL.md and agent .md files for valid frontmatter.\n *\n * @param pluginPath - Absolute path to the plugin root directory\n * @returns Merged validation result from all validation passes\n */\nexport async function validatePlugin(pluginPath: string): Promise<ValidationResult> {\n const structureResult = await validatePluginStructure(pluginPath);\n if (!structureResult.valid) return structureResult;\n\n const manifestPath = getPluginManifestPath(pluginPath);\n const manifestResult = await validatePluginManifest(manifestPath);\n const manifest = await loadManifestForValidation(manifestPath);\n\n const skillsResult =\n manifest?.skills && typeof manifest.skills === \"string\"\n ? await validatePluginSkillFiles(pluginPath, manifest.skills)\n : validResult();\n\n const agentsResult =\n manifest?.agents && typeof manifest.agents === \"string\"\n ? await validatePluginAgentFiles(pluginPath, manifest.agents)\n : validResult();\n\n return mergeValidationResults([structureResult, manifestResult, skillsResult, agentsResult]);\n}\n\n/**\n * Validates all plugins found in a directory, returning individual results and an aggregate summary.\n *\n * Scans subdirectories for `.claude-plugin/` markers to identify plugins, then validates\n * each one. Returns early with an error if the directory doesn't exist or contains no plugins.\n *\n * @param pluginsDir - Absolute path to the directory containing plugin subdirectories\n * @returns Object with overall validity, per-plugin results, and counts summary\n */\nexport async function validateAllPlugins(pluginsDir: string): Promise<{\n valid: boolean;\n results: Array<{ name: string; result: ValidationResult }>;\n summary: {\n total: number;\n valid: number;\n invalid: number;\n withWarnings: number;\n };\n}> {\n const results: Array<{ name: string; result: ValidationResult }> = [];\n\n if (!(await directoryExists(pluginsDir))) {\n return {\n valid: false,\n results: [\n {\n name: pluginsDir,\n result: invalidResult(`Directory does not exist: ${pluginsDir}`),\n },\n ],\n summary: { total: 0, valid: 0, invalid: 1, withWarnings: 0 },\n };\n }\n\n const allDirs = await listDirectories(pluginsDir);\n const dirChecks = await Promise.all(\n allDirs.map(async (dirName) => ({\n dirName,\n isPlugin: await directoryExists(path.join(pluginsDir, dirName, PLUGIN_DIR)),\n })),\n );\n const pluginDirs = dirChecks.filter((c) => c.isPlugin).map((c) => c.dirName);\n\n if (pluginDirs.length === 0) {\n return {\n valid: false,\n results: [\n {\n name: pluginsDir,\n result: invalidResult(\n `No plugins found in directory: ${pluginsDir}. Plugins must contain a ${PLUGIN_DIR}/ directory.`,\n ),\n },\n ],\n summary: { total: 0, valid: 0, invalid: 1, withWarnings: 0 },\n };\n }\n\n for (const pluginName of pluginDirs) {\n const pluginPath = path.join(pluginsDir, pluginName);\n const result = await validatePlugin(pluginPath);\n results.push({ name: pluginName, result });\n }\n\n const validCount = results.filter((r) => r.result.valid).length;\n const summary = {\n total: results.length,\n valid: validCount,\n invalid: results.length - validCount,\n withWarnings: results.filter((r) => r.result.warnings.length > 0).length,\n };\n\n return {\n valid: summary.invalid === 0,\n results,\n summary,\n };\n}\n\nexport function printPluginValidationResult(name: string, result: ValidationResult): void {\n const status = result.valid ? \"\\u2713\" : \"\\u2717\";\n\n if (result.valid && result.warnings.length === 0) {\n return;\n }\n\n log(`\\n ${status} ${name}`);\n\n if (result.errors.length > 0) {\n log(\" Errors:\");\n result.errors.forEach((e) => log(` - ${e}`));\n }\n\n if (result.warnings.length > 0) {\n log(\" Warnings:\");\n result.warnings.forEach((w) => log(` - ${w}`));\n }\n}\n","import type { ValidationResult } from \"../types\";\n\n/**\n * A passing validation result with no errors or warnings. A factory rather than a\n * shared constant so each caller owns its arrays — callers merge and prefix results,\n * and a shared instance would let one mutation leak into every other holder.\n */\nexport function validResult(): ValidationResult {\n return { valid: true, errors: [], warnings: [] };\n}\n\n/** A failing validation result carrying a single error message. */\nexport function invalidResult(message: string): ValidationResult {\n return { valid: false, errors: [message], warnings: [] };\n}\n\n/**\n * Flattens several validation partials into one result. `valid` is derived from\n * whether any errors were collected. Generic over the error/warning element type\n * so it can serve any {errors, warnings} partial, string-based ValidationResult\n * included.\n */\nexport function mergeValidationResults<E, W>(\n results: ReadonlyArray<{ errors: E[]; warnings: W[] }>,\n): { valid: boolean; errors: E[]; warnings: W[] } {\n const errors = results.flatMap((r) => r.errors);\n const warnings = results.flatMap((r) => r.warnings);\n return { valid: errors.length === 0, errors, warnings };\n}\n","/**\n * The plugin READ path: what is installed and switched on for one project, and the skills in it.\n *\n * **It goes through {@link hostAt}, which is the half C3 left out.** The seam declared\n * `PluginHost.listPlugins` and then wired nobody to it, so the module that actually answers \"what\n * plugins does this project have\" went on reading Claude's `installed_plugins.json` and Claude's\n * `settings.json` by hand. A seam with a hole in it is worse than no seam: every caller below —\n * the multi-source loader, the agent recompiler, `edit`, `uninstall` and `doctor` — reads as\n * host-agnostic while being wired to one host.\n *\n * The verbs above it are unchanged and so are their signatures; what moved is where the two files\n * are read, which is now the host's own business.\n */\n\nimport type { SkillDefinitionMap } from \"../../types\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { fileExists } from \"../../utils/fs\";\nimport { verbose } from \"../../utils/logger\";\nimport { typedEntries } from \"../../utils/typed-object\";\nimport { hostAt } from \"../hosts/host-for.js\";\nimport { loadPluginSkills } from \"../loading\";\nimport { getPluginManifestPath } from \"./plugin-finder\";\nimport type { ResolvedPlugin } from \"./plugin-settings\";\n\n/**\n * The enabled plugins of the installation under `projectDir` that are really on disk.\n *\n * Three questions, and the host answers the first two: what it has installed, and which of those\n * this project has switched on. The third — whether the recorded directory still holds a plugin\n * manifest — stays here, because a cache directory that has been deleted underneath a registry is\n * a fact about the filesystem rather than about the host.\n *\n * **It answers `[]` rather than throwing, and that is deliberate, not an oversight.** `doctor`\n * reads it to say which configured skills are missing, and a registry it cannot parse must\n * surface as that row's own finding rather than as an aborted check; the discovery verbs below\n * degrade the same way. The host throws for a registry that is present and unreadable, so the\n * swallow lives here, at the one place that has decided to degrade.\n */\nexport async function getVerifiedPluginInstallPaths(projectDir: string): Promise<ResolvedPlugin[]> {\n let enabled: ResolvedPlugin[];\n try {\n const installed = await hostAt(projectDir).listPlugins(projectDir);\n enabled = installed\n .filter((plugin) => plugin.enabled)\n .map(({ pluginKey, installPath }) => ({ pluginKey, installPath }));\n } catch (error) {\n verbose(`Failed to list installed plugins: ${getErrorMessage(error)}`);\n return [];\n }\n\n const onDisk = await Promise.all(enabled.map(hasManifestOnDisk));\n const verified = enabled.filter((_, index) => onDisk[index] === true);\n\n verbose(`Verified ${verified.length} plugin install paths`);\n return verified;\n}\n\n/** Whether the plugin's recorded directory still holds its manifest, with the miss logged. */\nasync function hasManifestOnDisk({ pluginKey, installPath }: ResolvedPlugin): Promise<boolean> {\n const pluginJsonPath = getPluginManifestPath(installPath);\n const manifestExists = await fileExists(pluginJsonPath);\n if (!manifestExists) {\n verbose(`Plugin '${pluginKey}' manifest does not exist at: '${pluginJsonPath}'`);\n }\n return manifestExists;\n}\n\n/**\n * Discovers all plugin-installed skills from enabled plugins.\n *\n * Asks the host under `projectDir` what it has installed and switched on, then loads skills from\n * each plugin's cache directory.\n *\n * @param projectDir - Absolute path to the project root\n * @returns Merged map of all discovered plugin skills (later plugins override earlier)\n */\nexport async function discoverAllPluginSkills(projectDir: string): Promise<SkillDefinitionMap> {\n try {\n const pluginPaths = await getVerifiedPluginInstallPaths(projectDir);\n\n if (pluginPaths.length === 0) {\n verbose(`No enabled plugins found for '${projectDir}'`);\n return {};\n }\n\n const perPluginSkills = await Promise.all(pluginPaths.map(loadSkillsOfPlugin));\n return mergeInPluginOrder(perPluginSkills);\n } catch (error) {\n verbose(`Plugin discovery failed: ${getErrorMessage(error)}`);\n return {};\n }\n}\n\n/** One plugin's skills, or none — with the reason logged — when its cache cannot be read. */\nasync function loadSkillsOfPlugin({\n pluginKey,\n installPath,\n}: ResolvedPlugin): Promise<SkillDefinitionMap> {\n verbose(`Discovering skills from plugin: '${pluginKey}'`);\n try {\n return await loadPluginSkills(installPath);\n } catch (error) {\n verbose(`Failed to load skills from '${pluginKey}': ${getErrorMessage(error)}`);\n return {};\n }\n}\n\n/**\n * Every plugin's skills in one map. A later plugin overrides an earlier one on the same id — the\n * merge follows `pluginPaths` order — and an absent entry is skipped.\n */\nfunction mergeInPluginOrder(perPluginSkills: readonly SkillDefinitionMap[]): SkillDefinitionMap {\n const allSkills: SkillDefinitionMap = {};\n for (const pluginSkills of perPluginSkills) {\n for (const [id, skill] of typedEntries(pluginSkills)) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- typedEntries/Object.entries launders the `| undefined` a Partial<Record> admits out of its result type, so this guard reads as dead while still covering an explicitly-undefined slot\n if (skill) allSkills[id] = skill;\n }\n }\n return allSkills;\n}\n\n/**\n * Lists the keys of all enabled plugins.\n *\n * @param projectDir - Absolute path to the project root\n * @returns Array of plugin keys (e.g., [\"web-framework-react@acme-marketplace\"])\n */\nexport async function listPluginNames(projectDir: string): Promise<string[]> {\n try {\n const pluginPaths = await getVerifiedPluginInstallPaths(projectDir);\n return pluginPaths.map(({ pluginKey }) => pluginKey);\n } catch (error) {\n verbose(`Failed to list plugin names: ${getErrorMessage(error)}`);\n return [];\n }\n}\n","import path from \"path\";\nimport { directoryExists, listDirectories, fileExists, readFile } from \"../../utils/fs\";\nimport { verbose, warn } from \"../../utils/logger\";\nimport { plural } from \"../../utils/string\";\nimport { LOCAL_PSEUDO_CATEGORY, LOCAL_SKILLS_PATH, STANDARD_FILES } from \"../../consts\";\nimport { namesPlaceholderCategory, parseFrontmatter, readSkillMetadata } from \"../loading\";\nimport type { CategoryPath, Domain, ExtractedSkillMetadata, SkillSlug } from \"../../types\";\nimport { LOCAL_DEFAULTS, METADATA_KEYS } from \"../metadata-keys\";\n\nexport type LocalRawMetadata = {\n displayName: string;\n /** Kebab-case short key for alias resolution */\n slug: SkillSlug;\n cliDescription?: string;\n /** Skill category (e.g., \"web-framework\", \"web-styling\", \"api-api\") */\n category: CategoryPath;\n usageGuidance?: string;\n tags?: string[];\n /** Domain this skill belongs to (e.g., \"web\", \"api\", \"cli\") */\n domain: Domain;\n /** True if this skill was created outside the CLI's built-in vocabulary */\n custom?: boolean;\n};\n\nexport type LocalSkillDiscoveryResult = {\n skills: ExtractedSkillMetadata[];\n localSkillsPath: string;\n};\n\nexport async function discoverLocalSkills(\n projectDir: string,\n): Promise<LocalSkillDiscoveryResult | null> {\n const localSkillsPath = path.join(projectDir, LOCAL_SKILLS_PATH);\n\n if (!(await directoryExists(localSkillsPath))) {\n verbose(`Local skills directory not found: ${localSkillsPath}`);\n return null;\n }\n\n const skillDirs = await listDirectories(localSkillsPath);\n const extracted = await Promise.all(\n skillDirs.map((skillDirName) => extractLocalSkill(localSkillsPath, skillDirName)),\n );\n const skills = extracted.filter((skill) => skill !== null);\n\n verbose(`Discovered ${plural(skills.length, \"local skill\")} from ${localSkillsPath}`);\n\n return {\n skills,\n localSkillsPath,\n };\n}\n\nasync function extractLocalSkill(\n localSkillsPath: string,\n skillDirName: string,\n): Promise<ExtractedSkillMetadata | null> {\n const skillDir = path.join(localSkillsPath, skillDirName);\n const metadataPath = path.join(skillDir, STANDARD_FILES.METADATA_YAML);\n const skillMdPath = path.join(skillDir, STANDARD_FILES.SKILL_MD);\n\n if (!(await fileExists(metadataPath))) {\n verbose(`Skipping local skill '${skillDirName}': No metadata.yaml found`);\n return null;\n }\n\n if (!(await fileExists(skillMdPath))) {\n verbose(`Skipping local skill '${skillDirName}': No SKILL.md found`);\n return null;\n }\n\n // One file that describes no skill must skip its own skill, not abort discovery\n // for every command that loads the catalog. `compile` refuses the same judgment's\n // verdict outright, which is what keeps the two passes from disagreeing.\n const read = await readSkillMetadata(metadataPath);\n if (!read.usable) {\n warn(\n `Skipping local skill '${skillDirName}': ${STANDARD_FILES.METADATA_YAML} at ${metadataPath} does not describe it — ${read.reason}`,\n );\n return null;\n }\n\n const metadata = read.metadata;\n\n // The verdict is `namesPlaceholderCategory`'s and is shared with the discovery behind\n // `compile`'s skill count, so neither pass can load what the other refuses. The SENTENCE\n // is this pass's alone: it is the one that reaches every command, so saying it here says\n // it once per run rather than once per reader.\n if (namesPlaceholderCategory(metadata)) {\n warn(\n `Skipping local skill '${skillDirName}': ${METADATA_KEYS.CATEGORY} '${LOCAL_PSEUDO_CATEGORY}' is a placeholder, not a real category, so no sub-agent can be given this skill. Set ${METADATA_KEYS.CATEGORY} in ${metadataPath} to a real one.`,\n );\n return null;\n }\n\n const skillMdContent = await readFile(skillMdPath);\n const frontmatter = parseFrontmatter(skillMdContent, skillMdPath);\n\n if (!frontmatter) {\n verbose(`Skipping local skill '${skillDirName}': invalid SKILL.md frontmatter`);\n return null;\n }\n\n const relativePath = `${LOCAL_SKILLS_PATH}/${skillDirName}/`;\n const absolutePath = path.join(localSkillsPath, skillDirName) + path.sep;\n const skillId = frontmatter.name;\n\n const extracted: ExtractedSkillMetadata = {\n id: skillId,\n directoryPath: skillDirName,\n description: metadata.cliDescription || frontmatter.description,\n ...(frontmatter.description && { activationDescription: frontmatter.description }),\n ...(metadata.usageGuidance !== undefined && { usageGuidance: metadata.usageGuidance }),\n category: metadata.category,\n author: LOCAL_DEFAULTS.AUTHOR,\n path: relativePath,\n local: true,\n localPath: absolutePath,\n domain: metadata.domain,\n ...(metadata.custom !== undefined && { custom: metadata.custom }),\n slug: metadata.slug,\n displayName: metadata.displayName,\n };\n\n verbose(`Extracted local skill: ${skillId}`);\n return extracted;\n}\n","import path from \"path\";\n\nimport { EJECT_SOURCE, STANDARD_FILES } from \"../../consts\";\nimport type { SkillConfig, SkillId } from \"../../types\";\nimport { directoryExists, fileExists, readFile } from \"../../utils/fs\";\nimport { resolveInstallPaths } from \"../installation/install-base-dir\";\nimport { parseFrontmatter, readSkillMetadata, type UnusableSkillMetadata } from \"../loading\";\n\n/**\n * What became of the skill a saved config entry names, when the loaded catalogue does not\n * carry it.\n *\n * The wizard resolves an installed roster against the catalogue, and an id it cannot find is\n * an id it cannot put on any screen — so the merge drops that entry and `edit` reports a\n * removal the user never asked for. Reporting it is right; reporting all of them the same way\n * was not. A marketplace entry the source no longer carries is gone from the CATALOGUE. A\n * local entry is gone from the DISK — or is not gone at all, and its metadata.yaml simply\n * stopped describing it, which is a file to repair rather than a reason to lose the entry.\n *\n * Told apart at the entry's own install path. A local skill lives at\n * `<skillsDir>/<id>` — the one address `copySkillsToLocalFlattened`, `deleteLocalSkill` and\n * `migrateLocalSkillScope` all write to — so the entry names exactly where to look. What is\n * asked there is borrowed rather than invented: {@link readSkillMetadata} gives the same verdict\n * local-skill discovery, `compile` and `doctor` already share about that file, and\n * {@link parseFrontmatter}'s `name` is the same identity discovery registers the skill under.\n */\ntype SavedSkillFate =\n /** No local copy is claimed: the marketplace this entry names no longer carries the skill. */\n | { kind: \"dropped-by-source\" }\n /** Its local install is gone from the disk — nothing is left at the path it was ejected to. */\n | { kind: \"files-gone\"; skillDir: string }\n /** The directory is there but registers no skill by that name (no metadata.yaml, or a SKILL.md naming another). */\n | { kind: \"not-installed-there\"; skillDir: string }\n /** The skill is installed and intact — its declared category is one no domain in this source claims. */\n | { kind: \"unplaceable-category\"; skillDir: string; category: string }\n /** The directory is there and its metadata.yaml describes no skill — repairable, so the run refuses instead. */\n | { kind: \"unusable-metadata\"; detail: UnusableSkillMetadata };\n\ntype ClassifiedSkill = { id: SkillId; fate: SavedSkillFate };\n\n/**\n * The saved entries whose local skill is installed but whose metadata.yaml describes no skill.\n *\n * A run that meets one must stop rather than drop the entry: the file can be repaired, and\n * `compile` already refuses the whole run over the same verdict about the same file. Dropping\n * the entry instead would spend a config record on a YAML typo, and say the marketplace did it.\n */\nexport async function findUnusableSavedSkillMetadata(\n unresolvedIds: readonly SkillId[],\n savedSkills: readonly SkillConfig[],\n projectDir: string,\n): Promise<UnusableSkillMetadata[]> {\n const classified = await classifyUnresolvedSkills(unresolvedIds, savedSkills, projectDir);\n return classified.flatMap(({ fate }) => (fate.kind === \"unusable-metadata\" ? [fate.detail] : []));\n}\n\n/**\n * Why each unresolvable entry went, for `edit`'s Changes block.\n *\n * These removals are the only ones the user did not ask for: the wizard could not represent\n * the skill, so it never appeared on any screen to be deselected, and the merge drops it.\n * Reporting the id alone would read as \"we removed something you chose to remove\"; the reason\n * says which of the things below happened. Every other removal is a deselection the user\n * watched themselves make and needs no reason.\n *\n * An entry {@link findUnusableSavedSkillMetadata} would name is deliberately absent from the\n * map — that run refuses before any of this is printed, so a sentence for it would only ever\n * be a wrong one.\n */\nexport async function unresolvedSkillRemovalReasons(\n unresolvedIds: readonly SkillId[],\n savedSkills: readonly SkillConfig[],\n projectDir: string,\n sourceLabel: string,\n): Promise<ReadonlyMap<SkillId, string>> {\n const classified = await classifyUnresolvedSkills(unresolvedIds, savedSkills, projectDir);\n return new Map(\n classified.flatMap(({ id, fate }) => {\n const reason = removalReason(id, fate, sourceLabel);\n return reason === null ? [] : [[id, reason] as const];\n }),\n );\n}\n\nasync function classifyUnresolvedSkills(\n unresolvedIds: readonly SkillId[],\n savedSkills: readonly SkillConfig[],\n projectDir: string,\n): Promise<ClassifiedSkill[]> {\n return Promise.all(\n unresolvedIds.map(async (id) => {\n const saved = savedSkills.find((entry) => entry.id === id);\n return { id, fate: await classifySavedSkill(id, saved, projectDir) };\n }),\n );\n}\n\n/**\n * An id with no saved entry behind it — a plugin-discovered skill the config never recorded —\n * is read as the marketplace's: there is no local copy claimed for it to have lost.\n */\nasync function classifySavedSkill(\n id: SkillId,\n saved: SkillConfig | undefined,\n projectDir: string,\n): Promise<SavedSkillFate> {\n if (saved?.origin !== EJECT_SOURCE) return { kind: \"dropped-by-source\" };\n\n const skillDir = path.join(resolveInstallPaths(projectDir, saved.scope).skillsDir, id);\n if (!(await directoryExists(skillDir))) return { kind: \"files-gone\", skillDir };\n\n const metadataPath = path.join(skillDir, STANDARD_FILES.METADATA_YAML);\n // A directory with no metadata.yaml at all is not registered with the CLI, and `compile`\n // skips rather than refuses it — so this one is reported and removed, not stopped over.\n if (!(await fileExists(metadataPath))) return { kind: \"not-installed-there\", skillDir };\n\n const read = await readSkillMetadata(metadataPath);\n if (!read.usable) {\n return {\n kind: \"unusable-metadata\",\n detail: { skillDirName: id, metadataPath, reason: read.reason },\n };\n }\n\n // The metadata describes SOME skill. Whether it describes THIS one is SKILL.md's answer — a\n // local skill is identified by its frontmatter name — so a SKILL.md deleted out from under a\n // live metadata.yaml, or renamed under a directory that was not, lands here.\n if (!(await skillMdNames(skillDir, id))) return { kind: \"not-installed-there\", skillDir };\n\n // Everything about the install is intact, so what could not be placed is the category this\n // metadata.yaml declares — whichever arm brought the id here. `resolveSkillForPopulation` in\n // `stores/wizard-store.ts` returns null both for a skill the catalogue does not carry and for\n // one it carries under a category no domain claims, and an intact install arrives by either:\n // local discovery refuses the placeholder category before the catalogue is built.\n return { kind: \"unplaceable-category\", skillDir, category: read.metadata.category };\n}\n\n/** Whether the SKILL.md installed here names this skill — a local skill's identity is that name. */\nasync function skillMdNames(skillDir: string, id: SkillId): Promise<boolean> {\n const skillMdPath = path.join(skillDir, STANDARD_FILES.SKILL_MD);\n if (!(await fileExists(skillMdPath))) return false;\n\n const frontmatter = parseFrontmatter(await readFile(skillMdPath), skillMdPath);\n return frontmatter?.name === id;\n}\n\n/** The sentence the Changes block puts after the removed row, or null when there is none to give. */\nfunction removalReason(id: SkillId, fate: SavedSkillFate, sourceLabel: string): string | null {\n switch (fate.kind) {\n case \"dropped-by-source\":\n return `not present in ${sourceLabel}`;\n case \"files-gone\":\n return `skill files no longer exist at ${fate.skillDir}`;\n case \"not-installed-there\":\n return `no skill named '${id}' is installed at ${fate.skillDir}`;\n case \"unplaceable-category\":\n return `installed at ${fate.skillDir}, but its category '${fate.category}' is not one this source knows`;\n case \"unusable-metadata\":\n return null;\n default: {\n const exhaustive: never = fate;\n return exhaustive;\n }\n }\n}\n","import path from \"path\";\n\nimport {\n copy,\n directoryExists,\n ensureDir,\n isPathWithin,\n remove,\n removeDirIfEmpty,\n} from \"../../utils/fs\";\nimport { verbose, warn } from \"../../utils/logger\";\nimport { resolveInstallPaths } from \"../installation/install-base-dir\";\nimport type { SkillId, SkillScope } from \"../../types\";\n\n/**\n * Validates a skill ID is safe for use in filesystem paths.\n * Blocks null bytes and path traversal sequences at runtime\n * since TypeScript template literal types don't prevent malformed data from YAML/JSON.\n */\nfunction validateSkillId(skillId: SkillId): boolean {\n return !(\n skillId.length === 0 ||\n skillId.includes(\"\\0\") ||\n skillId.includes(\"..\") ||\n skillId.includes(\"/\") ||\n skillId.includes(\"\\\\\")\n );\n}\n\n/**\n * Delete an ejected skill's directory at `<skillsDir>/<skill-id>/`, where `skillsDir` is the one the\n * installation at `projectDir` keeps ejected skills in at `scope` — `.claude/skills` on Claude,\n * `$CODEX_HOME/skills` or `<repo>/.agents/skills` on Codex.\n *\n * **Resolved per host, as the copy side resolves it** (`resolveInstallPaths(...).skillsDir`).\n * _Corrected 2026-09-26 (CLI-895):_ this joined Claude's `.claude/skills` to the base directory\n * whatever the host, so on Codex a switch to plugin mode and a deselected ejected skill both left\n * the copy where Codex reads skills — and Codex then read the skill twice.\n */\nexport async function deleteLocalSkill(\n projectDir: string,\n skillId: SkillId,\n scope: SkillScope = \"project\",\n): Promise<void> {\n if (!validateSkillId(skillId)) {\n warn(`Invalid skill ID for deletion: '${skillId}'`);\n return;\n }\n\n const skillsDir = path.resolve(resolveInstallPaths(projectDir, scope).skillsDir);\n const skillPath = path.resolve(skillsDir, skillId);\n\n if (!isPathWithin(skillPath, skillsDir)) {\n warn(`Skill ID '${skillId}' resolves outside the skills directory.`);\n return;\n }\n\n try {\n await remove(skillPath);\n } catch {\n // Skill may not exist — silently ignore\n }\n\n // The skills directory only — the host's directory above it stays whatever happens here.\n // Removing that one is uninstall's decision, not the edit path's.\n await removeDirIfEmpty(skillsDir);\n\n verbose(`Deleted local skill '${skillId}'`);\n}\n\n/**\n * Migrate a local skill's files between project and global directories.\n * Used when a skill's scope changes during edit (e.g., [P] → [G] or [G] → [P]).\n *\n * Copies the skill directory to the new location.\n * For P→G, removes the old project copy. For G→P (override model), the global copy stays untouched.\n * No-op if the source directory doesn't exist (skill may be plugin-mode).\n */\nexport async function migrateLocalSkillScope(\n skillId: SkillId,\n fromScope: SkillScope,\n projectDir: string,\n): Promise<void> {\n if (!validateSkillId(skillId)) {\n warn(`Invalid skill ID for scope migration: '${skillId}'`);\n return;\n }\n\n const toScope: SkillScope = fromScope === \"global\" ? \"project\" : \"global\";\n // Each scope's skills directory as its host keeps it — see `deleteLocalSkill` (CLI-895). It\n // resolves `os.homedir()` at call time, so test home-dir mocks apply.\n const fromSkillsDir = path.resolve(resolveInstallPaths(projectDir, fromScope).skillsDir);\n const toSkillsDir = path.resolve(resolveInstallPaths(projectDir, toScope).skillsDir);\n\n const fromPath = path.resolve(fromSkillsDir, skillId);\n const toPath = path.resolve(toSkillsDir, skillId);\n\n if (!isPathWithin(fromPath, fromSkillsDir)) {\n warn(`Skill ID '${skillId}' resolves outside the source skills directory.`);\n return;\n }\n if (!isPathWithin(toPath, toSkillsDir)) {\n warn(`Skill ID '${skillId}' resolves outside the destination skills directory.`);\n return;\n }\n\n if (!(await directoryExists(fromPath))) {\n if (await directoryExists(toPath)) {\n verbose(`Skill '${skillId}' already at ${toScope} scope — no migration needed`);\n return;\n }\n warn(`Could not migrate skill '${skillId}' — not found at either scope`);\n return;\n }\n\n await ensureDir(toSkillsDir);\n await copy(fromPath, toPath);\n\n // G→P is an override — the global copy stays untouched; the project copy overrides it.\n // Only P→G should delete the old directory.\n if (fromScope === \"project\") {\n await remove(fromPath);\n }\n\n verbose(`Migrated skill '${skillId}' from ${fromScope} to ${toScope}`);\n}\n\n/**\n * Moves a project's ejected copy of a skill into the global install, in place of the global copy\n * it masked: what `s` does to a `[P][G]` pair whose halves are both Local. Every project reads the\n * global copy, so the project's edits reach them all.\n *\n * The global copy is removed first rather than copied over, because a copy merges into what is\n * there: a file the project's copy deleted would survive in the global install.\n */\nexport async function foldLocalSkillIntoGlobal(\n projectDir: string,\n skillId: SkillId,\n): Promise<void> {\n await deleteLocalSkill(projectDir, skillId, \"global\");\n await migrateLocalSkillScope(skillId, \"project\", projectDir);\n}\n","import { parse as parseYaml } from \"yaml\";\nimport path from \"path\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { unreadableFrontmatter } from \"../../utils/frontmatter\";\nimport { glob, readFile, fileExists } from \"../../utils/fs\";\nimport { verbose, warn } from \"../../utils/logger\";\nimport { STANDARD_FILES } from \"../../consts\";\nimport { loadConfig } from \"../configuration/config-loader\";\nimport { METADATA_KEYS } from \"../metadata-keys\";\nimport { parseFrontmatter } from \"../loading\";\nimport {\n skillCategoriesFileSchema,\n skillRulesFileSchema,\n formatZodIssues,\n matrixRawMetadataSchema,\n} from \"../schemas\";\nimport type { CategoryMap, ExtractedSkillMetadata, SkillRulesConfig } from \"../../types\";\n\n/**\n * Loads and validates a skill-categories.ts configuration file.\n *\n * @param configPath - Absolute path to the skill-categories.ts file\n * @returns Parsed and validated categories map\n * @throws When the file cannot be read or fails Zod schema validation\n */\nexport async function loadSkillCategories(configPath: string): Promise<CategoryMap> {\n const data = await loadConfig(configPath, skillCategoriesFileSchema);\n\n if (!data) {\n throw new Error(`Invalid skill categories at '${configPath}': failed to load or validate`);\n }\n\n verbose(`Loaded skill categories: ${configPath}`);\n return data.categories;\n}\n\n/**\n * Loads and validates a skill-rules.ts configuration file.\n *\n * @param configPath - Absolute path to the skill-rules.ts file\n * @returns Parsed and validated skill rules config\n * @throws When the file cannot be read or fails Zod schema validation\n */\nexport async function loadSkillRules(configPath: string): Promise<SkillRulesConfig> {\n const data = await loadConfig(configPath, skillRulesFileSchema);\n\n if (!data) {\n throw new Error(`Invalid skill rules at '${configPath}': failed to load or validate`);\n }\n\n const config: SkillRulesConfig = {\n version: data.version,\n relationships: data.relationships ?? {\n conflicts: [],\n discourages: [],\n requires: [],\n alternatives: [],\n },\n };\n\n verbose(`Loaded skill rules: ${configPath}`);\n return config;\n}\n\n/**\n * Scans a skills directory and extracts metadata from all valid skills.\n *\n * Discovers skills by globbing for `metadata.yaml` files, then for each:\n * 1. Validates a corresponding SKILL.md exists (skips if missing)\n * 2. Parses metadata.yaml and validates it against the raw metadata schema\n * 3. Parses SKILL.md frontmatter for the canonical skill ID\n * 4. Merges metadata fields into an ExtractedSkillMetadata object\n *\n * A metadata.yaml that describes no skill — unparseable, or parseable without the\n * fields the schema requires — is warned by path and skips its own skill, and so is a\n * SKILL.md whose frontmatter does not read; one bad file does not take the scan down\n * with it. Skills missing the required\n * `displayName` field in metadata.yaml cause a hard error.\n *\n * @param skillsDir - Absolute path to the skills root directory (e.g., `{root}/src/skills`)\n * @returns Array of extracted skill metadata, one per valid skill found\n * @throws When a skill's metadata.yaml is missing the required `displayName` field\n */\nexport async function extractAllSkills(skillsDir: string): Promise<ExtractedSkillMetadata[]> {\n const skills: ExtractedSkillMetadata[] = [];\n const metadataFiles = await glob(`**/${STANDARD_FILES.METADATA_YAML}`, skillsDir);\n\n for (const metadataFile of metadataFiles) {\n const skillDir = path.dirname(metadataFile);\n const skillMdPath = path.join(skillsDir, skillDir, STANDARD_FILES.SKILL_MD);\n const metadataPath = path.join(skillsDir, metadataFile);\n\n if (!(await fileExists(skillMdPath))) {\n verbose(`Skipping ${metadataFile}: No ${STANDARD_FILES.SKILL_MD} found`);\n continue;\n }\n\n const metadataContent = await readFile(metadataPath);\n\n // The safeParse below catches a file that parses without the fields a skill is\n // described by, and cannot catch a file nothing parses out of at all. Both refuse\n // the same way readSkillMetadata does: skip this skill, not the whole scan.\n let rawMetadata: unknown;\n try {\n rawMetadata = parseYaml(metadataContent);\n } catch (error) {\n warn(\n `Skipping '${metadataFile}': unparseable ${STANDARD_FILES.METADATA_YAML} at ${metadataPath} — ${getErrorMessage(error)}`,\n );\n continue;\n }\n\n const metadataResult = matrixRawMetadataSchema.safeParse(rawMetadata);\n\n if (!metadataResult.success) {\n warn(\n `Skipping '${metadataFile}': invalid metadata.yaml — ${formatZodIssues(metadataResult.error.issues)}`,\n );\n continue;\n }\n\n const metadata = metadataResult.data;\n const skillMdContent = await readFile(skillMdPath);\n const frontmatter = parseFrontmatter(skillMdContent, skillMdPath);\n\n // Named as an unparseable metadata.yaml is above, so the skill does not simply go missing. A\n // frontmatter that READ and failed its schema has already been named by `parseFrontmatter`.\n if (!frontmatter) {\n const unreadable = unreadableFrontmatter(skillMdContent);\n if (unreadable !== undefined) {\n warn(\n `Skipping '${path.join(skillDir, STANDARD_FILES.SKILL_MD)}': unparseable ${STANDARD_FILES.SKILL_MD} frontmatter at ${skillMdPath} — ${unreadable}`,\n );\n }\n continue;\n }\n\n if (!metadata.displayName) {\n throw new Error(\n `Skill at ${metadataFile} is missing required '${METADATA_KEYS.DISPLAY_NAME}' field in metadata.yaml`,\n );\n }\n\n const skillId = frontmatter.name;\n\n const extracted: ExtractedSkillMetadata = {\n id: skillId,\n directoryPath: skillDir,\n description: metadata.cliDescription || frontmatter.description,\n ...(frontmatter.description && { activationDescription: frontmatter.description }),\n ...(metadata.usageGuidance !== undefined && { usageGuidance: metadata.usageGuidance }),\n category: metadata.category,\n author: metadata.author,\n path: `skills/${skillDir}/`,\n domain: metadata.domain,\n displayName: metadata.displayName,\n slug: metadata.slug,\n ...(metadata.custom === true ? { custom: true } : {}),\n };\n\n skills.push(extracted);\n verbose(`Extracted skill: ${skillId}`);\n }\n\n return skills;\n}\n","import { verbose, warn } from \"../../utils/logger\";\nimport { unique, uniqueBy } from \"remeda\";\nimport { toTitleCase } from \"../../utils/string\";\nimport { DEFAULT_VERSION, LOCAL_PSEUDO_CATEGORY } from \"../../consts\";\nimport { defaultRules } from \"../configuration/default-rules\";\nimport type {\n CategoryDefinition,\n CategoryMap,\n Domain,\n ExtractedSkillMetadata,\n MergedSkillsMatrix,\n RelationshipDefinitions,\n RequireRule,\n ResolvedSkill,\n SkillAlternative,\n SkillId,\n SkillRelation,\n SkillRequirement,\n SkillRulesConfig,\n SkillSlug,\n SkillSlugMap,\n Category,\n} from \"../../types\";\n\n/** Resolves a slug to a canonical SkillId, or null if unresolvable */\ntype ResolveId = (slug: SkillSlug, context?: string) => SkillId | null;\n\nconst AUTO_SYNTH_ORDER = 999;\n\n/**\n * Synthesizes a basic CategoryDefinition for a category not defined in any\n * skill-categories.ts. This is a safety net — the preferred path is for\n * skill authors to maintain proper skill-categories.ts entries.\n */\n/**\n * Warns when a second skill files an undeclared category under a different domain from the first.\n *\n * A synthesized category takes its domain from **whichever skill the glob reached first**, and the\n * order a directory walk returns is not a decision anybody made. Two skills sharing an undeclared\n * category while declaring different domains therefore file the second under a domain its own\n * `metadata.yaml` contradicts — silently, until now. The value feeds six product readers of\n * `getCategoryDomain`, `config-generator.ts` and `wizard-store.ts` among them, so it shapes both\n * the emitted `config.ts` and where the wizard puts the skill.\n *\n * **Reported, not resolved.** Picking a winner would need a rule the catalogue does not state, and\n * the author is the only one who can say which domain they meant. `checkCategoryDomains` does not\n * cover this — it reports a category with NO domain, and this one has two.\n */\nfunction warnOnDomainDisagreement(\n skill: ExtractedSkillMetadata,\n decidedBy: ExtractedSkillMetadata,\n): void {\n if (skill.domain === decidedBy.domain) return;\n\n warn(\n `Category '${skill.category}' has no definition, so its domain was taken from the first skill ` +\n `naming it — '${decidedBy.id}' (${decidedBy.domain}). '${skill.id}' declares ` +\n `'${skill.domain}' and will be filed under '${decidedBy.domain}'. Declare the category in ` +\n `the marketplace's own config, or make the two skills agree.`,\n );\n}\n\nexport function synthesizeCategory(category: Category, domain: Domain): CategoryDefinition {\n verbose(\n `Category '${category}' has no definition in skill-categories.ts — using auto-generated placeholder`,\n );\n const displayName = toTitleCase(category);\n\n return {\n id: category,\n displayName,\n description: `Auto-generated category for ${category}`,\n domain,\n exclusive: false,\n order: AUTO_SYNTH_ORDER,\n };\n}\n\n/**\n * Claims a slug for a skill merged in after a marketplace's map was built — an installed copy, or\n * a skill a shared configuration carries — unless a skill already holds it.\n *\n * A held slug keeps its holder, and nothing is said. Ids carry their marketplace's namespace and\n * slugs do not, so a skill installed from one marketplace may share its slug with one the loaded\n * marketplace ships — every `new marketplace` scaffold gives its example skill the same one. Both\n * are installed and both work, so there is no collision to report and nothing is ignored.\n * Exported because the merge is not the only writer: `source-loader` and `external-skills` both\n * seat skills into an already-built map, and two writers deciding a held slug differently is how\n * a slug comes to mean one skill here and another there.\n */\nexport function claimSlug(slugMap: SkillSlugMap, slug: SkillSlug, id: SkillId): void {\n slugMap.slugToId[slug] ??= id;\n}\n\n/**\n * Builds the slug -> ID map from one marketplace's extracted skill metadata, first claim winning\n * and every later one named. Inside ONE marketplace two skills sharing a slug is that author's\n * defect: the rules that marketplace writes name its skills by slug, so one of the two is no\n * longer reachable by them. A skill re-stating a claim it already holds is not a collision.\n */\nfunction buildSlugMap(skills: ExtractedSkillMetadata[]): SkillSlugMap {\n const slugMap: SkillSlugMap = { slugToId: {} };\n\n for (const { slug, id } of skills) {\n const incumbent = slugMap.slugToId[slug];\n if (incumbent !== undefined && incumbent !== id) {\n warn(`Duplicate slug '${slug}': already mapped to '${incumbent}', ignoring '${id}'`);\n }\n claimSlug(slugMap, slug, id);\n }\n\n return slugMap;\n}\n\n/**\n * Resolves every skill into the map the matrix is read through, keyed by id.\n * Warns on duplicate ids (first one wins) — the identity axis {@link buildSlugMap}\n * guards for slugs. Two directories whose SKILL.md declares the same name would\n * otherwise resolve in glob order, and the loser would leave no trace.\n */\nfunction buildResolvedSkillMap(\n skills: ExtractedSkillMetadata[],\n categories: CategoryMap,\n relationships: RelationshipDefinitions,\n slugMap: SkillSlugMap,\n): Partial<Record<SkillId, ResolvedSkill>> {\n const resolvedSkills: Partial<Record<SkillId, ResolvedSkill>> = {};\n\n for (const skill of skills) {\n const existing = resolvedSkills[skill.id];\n if (existing) {\n warn(\n `Duplicate skill id '${skill.id}': already resolved from '${existing.path}', ignoring '${skill.path}'`,\n );\n continue;\n }\n\n resolvedSkills[skill.id] = buildResolvedSkill(skill, categories, relationships, slugMap);\n }\n\n return resolvedSkills;\n}\n\nfunction resolveToCanonicalId(\n slug: SkillSlug,\n slugToId: SkillSlugMap[\"slugToId\"],\n context?: string,\n): SkillId | null {\n const slugResult = slugToId[slug];\n if (slugResult) {\n return slugResult;\n }\n const location = context ? ` in ${context}` : \"\";\n warn(`Unresolved slug '${slug}'${location} — skipping`);\n return null;\n}\n\n/** Every slug the rules name, in the order the four rule kinds declare them. */\nfunction slugsNamedByRules(relationships: RelationshipDefinitions): SkillSlug[] {\n return [\n ...relationships.conflicts.flatMap((rule) => rule.skills),\n ...relationships.discourages.flatMap((rule) => rule.skills),\n ...relationships.requires.flatMap((rule) => [rule.skill, ...rule.needs]),\n ...relationships.alternatives.flatMap((rule) => rule.skills),\n ];\n}\n\n/**\n * The slugs the rules name that no skill carries, deduplicated.\n *\n * Asked of the rules rather than counted off the resolution pass, because that\n * pass walks every rule once per skill: one typo would otherwise be reported as\n * many findings as the source has skills, which is the noise this removed.\n */\nfunction collectUnresolvedSlugs(\n relationships: RelationshipDefinitions,\n slugToId: SkillSlugMap[\"slugToId\"],\n): SkillSlug[] {\n return unique(slugsNamedByRules(relationships).filter((slug) => slugToId[slug] === undefined));\n}\n\n/** Merges relationship rule sets: source rules first, so they win first-match lookups. */\nfunction mergeRelationships(\n source: RelationshipDefinitions,\n defaults: RelationshipDefinitions,\n): RelationshipDefinitions {\n return {\n conflicts: [...source.conflicts, ...defaults.conflicts],\n discourages: [...source.discourages, ...defaults.discourages],\n requires: [...source.requires, ...defaults.requires],\n alternatives: [...source.alternatives, ...defaults.alternatives],\n };\n}\n\n/** Below two present members a group rule relates nothing, so it is dropped whole. */\nconst MIN_RELATABLE_GROUP_MEMBERS = 2;\n\n/** Group rules — conflicts, discourages, alternatives — keeping only present slugs. */\nfunction narrowGroupsToSlugs<Rule extends { skills: SkillSlug[] }>(\n rules: Rule[],\n shipped: ReadonlySet<SkillSlug>,\n): Rule[] {\n return rules\n .map((rule) => ({ ...rule, skills: rule.skills.filter((slug) => shipped.has(slug)) }))\n .filter((rule) => rule.skills.length >= MIN_RELATABLE_GROUP_MEMBERS);\n}\n\n/**\n * Requirements, keeping only those a present skill declares over present skills.\n * A rule left needing nothing states no requirement — resolution already treats it\n * that way — so it goes rather than resolving to an empty `needs`.\n */\nfunction narrowRequirementsToSlugs(\n rules: RequireRule[],\n shipped: ReadonlySet<SkillSlug>,\n): RequireRule[] {\n return rules\n .filter((rule) => shipped.has(rule.skill))\n .map((rule) => ({ ...rule, needs: rule.needs.filter((slug) => shipped.has(slug)) }))\n .filter((rule) => rule.needs.length > 0);\n}\n\nfunction narrowToShippedSlugs(\n rules: RelationshipDefinitions,\n shipped: ReadonlySet<SkillSlug>,\n): RelationshipDefinitions {\n return {\n conflicts: narrowGroupsToSlugs(rules.conflicts, shipped),\n discourages: narrowGroupsToSlugs(rules.discourages, shipped),\n requires: narrowRequirementsToSlugs(rules.requires, shipped),\n alternatives: narrowGroupsToSlugs(rules.alternatives, shipped),\n };\n}\n\n/**\n * The relationships a source's skills can actually express: the source's own rules\n * verbatim, plus the built-ins narrowed to the slugs this source ships.\n *\n * The built-in rules are written against the whole public catalogue — 176 slugs — so\n * a source shipping ten of them left the rest dangling. Resolution dropped those\n * references either way; what it ALSO did was warn once per reference per skill, and\n * since the startup band those warnings are painted over the wizard's step. Narrowing\n * first removes the noise and nothing else: a member that resolves to no skill\n * contributed nothing to the resolved matrix to begin with.\n *\n * A source's OWN rules are never narrowed. A slug its author typed and its skills do\n * not carry is that source's defect, and the warning is the only place it is reported.\n */\nexport function relationshipsForSource(\n skills: ExtractedSkillMetadata[],\n sourceRules?: SkillRulesConfig,\n): RelationshipDefinitions {\n const shipped = new Set(skills.map((skill) => skill.slug));\n const builtIn = narrowToShippedSlugs(defaultRules.relationships, shipped);\n return sourceRules ? mergeRelationships(sourceRules.relationships, builtIn) : builtIn;\n}\n\n/**\n * Merges category definitions, relationship rules, and extracted skill metadata\n * into a fully resolved MergedSkillsMatrix.\n *\n * This is the core resolution step that combines:\n * - Category definitions from skill-categories.ts\n * - Slug-based alias maps derived from metadata\n * - Relationship rules from skill-rules.ts\n * - Extracted skill metadata (from scanning skill directories)\n *\n * Each skill's raw relationship references are resolved to canonical SkillIds.\n * The result is the complete data structure consumed by the wizard UI and validation logic.\n */\nexport function mergeMatrixWithSkills(\n categories: CategoryMap,\n relationships: RelationshipDefinitions,\n skills: ExtractedSkillMetadata[],\n): MergedSkillsMatrix {\n const slugMap = buildSlugMap(skills);\n const resolvedSkills = buildResolvedSkillMap(skills, categories, relationships, slugMap);\n\n // Auto-synthesize missing categories for skills that reference undefined categories\n const synthesizedCategories = { ...categories };\n const synthesizedFrom = new Map<string, ExtractedSkillMetadata>();\n for (const skill of skills) {\n // Skip \"local\" pseudo-category — it's not a real Category union member\n if (skill.category === LOCAL_PSEUDO_CATEGORY) continue;\n\n // A category the catalogue DECLARES is not ours to synthesize, and not ours to judge either:\n // its domain is stated rather than inferred, so two skills disagreeing about it is a different\n // defect that `checkCategoryDomains` owns. Read from the input map rather than the one being\n // built, so a synthesized entry cannot be mistaken for a declared one.\n if (categories[skill.category]) continue;\n\n const already = synthesizedFrom.get(skill.category);\n if (already === undefined) {\n synthesizedCategories[skill.category] = synthesizeCategory(skill.category, skill.domain);\n synthesizedFrom.set(skill.category, skill);\n verbose(`Auto-synthesized category '${skill.category}' for skill '${skill.id}'`);\n continue;\n }\n\n warnOnDomainDisagreement(skill, already);\n }\n\n const unresolvedSlugs = collectUnresolvedSlugs(relationships, slugMap.slugToId);\n\n const merged: MergedSkillsMatrix = {\n version: DEFAULT_VERSION,\n categories: synthesizedCategories,\n skills: resolvedSkills,\n suggestedStacks: [],\n slugMap,\n ...(unresolvedSlugs.length > 0 && { unresolvedSlugs }),\n generatedAt: new Date().toISOString(),\n };\n\n return merged;\n}\n\n/** All resolved relationship data for a single skill */\ntype ResolvedRelationships = {\n conflictsWith: SkillRelation[];\n discourages: SkillRelation[];\n requires: SkillRequirement[];\n alternatives: SkillAlternative[];\n};\n\n/** Resolves a rule's slugs to canonical ids, warning and skipping any that don't resolve. */\nfunction resolveSlugsOrSkip(slugs: SkillSlug[], resolve: ResolveId, context: string): SkillId[] {\n return slugs.map((slug) => resolve(slug, context)).filter((id): id is SkillId => id !== null);\n}\n\n/**\n * A requirement's needs, or null when any one of them names no skill.\n *\n * Keeping what resolved would apply a requirement nobody wrote: under AND an\n * unresolved need narrows the rule to the survivors, under OR it takes an\n * alternative away — and either is presented to the user under the author's own\n * `reason`. A source's rules are its own (the CLI's built-ins are narrowed to\n * what a source ships, and the source's are left untouched), so they are taken\n * whole or not at all. The slug is warned here and reported by\n * `checkMatrixHealth`, which is where the author reads it.\n */\nfunction resolveEveryNeed(needs: SkillSlug[], resolve: ResolveId): SkillId[] | null {\n // A rule needing nothing states no requirement, as it did before any of its\n // members could fail to resolve.\n if (needs.length === 0) return null;\n\n const resolved = resolveSlugsOrSkip(needs, resolve, \"requires.needs\");\n return resolved.length === needs.length ? resolved : null;\n}\n\n/**\n * Members of the symmetric groups containing `skillId` (excluding itself),\n * deduplicated on first occurrence, each paired with its group's rule so the\n * caller can lift the annotation (reason/purpose).\n */\nfunction collectSymmetricGroupMembers<Rule extends { skills: SkillSlug[] }>(\n rules: readonly Rule[],\n skillId: SkillId,\n resolve: ResolveId,\n context: string,\n): Array<{ memberId: SkillId; rule: Rule }> {\n const members = rules.flatMap((rule) => {\n const resolved = resolveSlugsOrSkip(rule.skills, resolve, context);\n if (!resolved.includes(skillId)) return [];\n return resolved.filter((id) => id !== skillId).map((memberId) => ({ memberId, rule }));\n });\n return uniqueBy(members, (m) => m.memberId);\n}\n\n/**\n * Resolves all relationship data for a single skill in one pass across all\n * relationship rule types (conflicts, discourages, compatibility, requirements, alternatives).\n */\nfunction resolveRelationships(\n skillId: SkillId,\n relationships: RelationshipDefinitions,\n resolve: ResolveId,\n): ResolvedRelationships {\n // Symmetric groups: members of every group containing this skill, first-occurrence deduped\n const conflictsWith: SkillRelation[] = collectSymmetricGroupMembers(\n relationships.conflicts,\n skillId,\n resolve,\n \"conflicts\",\n ).map(({ memberId, rule }) => ({ skillId: memberId, reason: rule.reason }));\n\n const discourages: SkillRelation[] = collectSymmetricGroupMembers(\n relationships.discourages,\n skillId,\n resolve,\n \"discourages\",\n ).map(({ memberId, rule }) => ({ skillId: memberId, reason: rule.reason }));\n\n const alternatives: SkillAlternative[] = collectSymmetricGroupMembers(\n relationships.alternatives,\n skillId,\n resolve,\n \"alternatives\",\n ).map(({ memberId, rule }) => ({ skillId: memberId, purpose: rule.purpose }));\n\n // Requirements — directional, skill field identifies the dependent\n const requires: SkillRequirement[] = [];\n for (const rule of relationships.requires) {\n const ruleSkillId = resolve(rule.skill, \"requires.skill\");\n if (ruleSkillId !== skillId) continue;\n const resolvedNeeds = resolveEveryNeed(rule.needs, resolve);\n if (!resolvedNeeds) continue;\n requires.push({\n skillIds: resolvedNeeds,\n needsAny: rule.needsAny ?? false,\n reason: rule.reason,\n });\n }\n\n return {\n conflictsWith,\n discourages,\n requires,\n alternatives,\n };\n}\n\nfunction buildResolvedSkill(\n skill: ExtractedSkillMetadata,\n _categories: CategoryMap,\n relationships: RelationshipDefinitions,\n slugMap: SkillSlugMap,\n): ResolvedSkill {\n const resolve: ResolveId = (slug, context) =>\n resolveToCanonicalId(slug, slugMap.slugToId, context ? `${skill.id} ${context}` : undefined);\n\n const slug = skill.slug;\n\n const resolved = resolveRelationships(skill.id, relationships, resolve);\n\n return {\n id: skill.id,\n slug,\n displayName: skill.displayName,\n description: skill.description,\n ...(skill.activationDescription !== undefined && {\n activationDescription: skill.activationDescription,\n }),\n ...(skill.usageGuidance !== undefined && { usageGuidance: skill.usageGuidance }),\n category: skill.category,\n author: skill.author,\n ...resolved,\n path: skill.path,\n ...(skill.custom === true ? { custom: true } : {}),\n };\n}\n","import { stripTerminalControls, truncateText } from \"../../utils/string\";\nimport {\n createSelectionSemantics,\n type IncompatibilityCause,\n type SelectionCatalogFacts,\n type SelectionJudgement,\n type SelectionSemantics,\n} from \"@workspace/matrix\";\nimport { groupBy } from \"remeda\";\nimport { LOCAL_PSEUDO_CATEGORY } from \"../../consts\";\nimport type {\n CategoryPath,\n MergedSkillsMatrix,\n OptionState,\n ResolvedSkill,\n SelectionValidation,\n SkillId,\n SkillOption,\n ValidationError,\n} from \"../../types\";\nimport { typedEntries, typedValues } from \"../../utils/typed-object\";\nimport { matrix, getSkillById, allSkills } from \"./matrix-provider\";\n\n/**\n * A skill's name as a message may carry it, which is every route a display name takes out of this\n * module — the validation errors below, the grid cell's incompatibility text, and the names in an\n * unmet-requirements sentence.\n *\n * `displayName` is written in a marketplace's own `metadata.yaml`, so it is a stranger's string\n * arriving by the product's advertised route rather than by an attack. Sanitised HERE rather than\n * at each of the five messages that render it, because a sixth message is the likely next thing\n * anyone writes and it should be safe without being told to be.\n */\nfunction getLabel(skill: Pick<ResolvedSkill, \"displayName\">): string {\n return stripTerminalControls(skill.displayName);\n}\n\nfunction joinWithConjunction(items: string[], conjunction: \"or\" | \"and\"): string {\n if (items.length <= 1) return items[0] ?? \"\";\n if (items.length === 2) return `${items[0]} ${conjunction} ${items[1]}`;\n return `${items.slice(0, -1).join(\", \")} ${conjunction} ${items[items.length - 1]}`;\n}\n\ntype SelectionContext = {\n resolvedSelections: SkillId[];\n selectedSet: Set<SkillId>;\n};\n\nfunction initializeSelectionContext(currentSelections: SkillId[]): SelectionContext {\n const resolvedSelections = currentSelections.map((s) => getSkillById(s).id);\n const selectedSet = new Set<SkillId>(resolvedSelections);\n return { resolvedSelections, selectedSet };\n}\n\n/**\n * The relationship facts the shared selection semantics judge — id, category,\n * conflicts, discourages and requires. Exclusivity defaults to true for a\n * category that does not say, matching the wizard grid's own reading; the\n * `local` pseudo-category is never listed, so it stays non-exclusive here as it\n * does in `validateExclusivity`.\n */\nfunction toSelectionFacts(source: MergedSkillsMatrix): SelectionCatalogFacts {\n return {\n skills: typedValues(source.skills).map((skill) => ({\n id: skill.id,\n categoryId: skill.category,\n conflictsWith: skill.conflictsWith.map((relation) => relation.skillId),\n discourages: skill.discourages.map((relation) => ({\n skillId: relation.skillId,\n // The one author string that leaves this module without being re-rendered: the shared\n // semantics carry it through and `getCellState` hands the verdict back whole, so a\n // discouraged cell prints exactly what was put in here. Made inert on the way in, which\n // is the only point on that route this package owns.\n reason: stripTerminalControls(relation.reason),\n })),\n requires: skill.requires.map((requirement) => ({\n skillIds: requirement.skillIds,\n needsAny: requirement.needsAny,\n })),\n })),\n exclusiveCategoryIds: new Set(\n typedValues(source.categories)\n .filter((category) => category.exclusive !== false)\n .map((category) => category.id),\n ),\n };\n}\n\n// Rebound whenever `initializeMatrix` swaps the matrix, so the semantics\n// always judge the catalogue currently loaded — merged local skills included.\nlet boundSemantics: SelectionSemantics | undefined;\nlet boundTo: MergedSkillsMatrix | undefined;\n\nfunction judgeSelections(resolvedSelections: SkillId[]): SelectionJudgement {\n if (!boundSemantics || boundTo !== matrix) {\n boundSemantics = createSelectionSemantics(toSelectionFacts(matrix));\n boundTo = matrix;\n }\n return boundSemantics(resolvedSelections);\n}\n\n// The judgement speaks in ids; this surface answers in the wizard's words.\nfunction renderIncompatibility(cause: IncompatibilityCause): string {\n switch (cause.kind) {\n case \"conflict\":\n return `conflicts with ${labelOf(cause.skillId)}`;\n case \"unreachableRequirement\": {\n if (cause.requirement.needsAny) {\n const labels = cause.requirement.skillIds.map(labelOf);\n return `requires ${joinWithConjunction(labels, \"or\")} (all conflict with current selection)`;\n }\n const lostLabels = cause.lostIds.map(labelOf);\n return `requires ${joinWithConjunction(lostLabels, \"and\")} which conflicts with current selection`;\n }\n }\n}\n\nfunction labelOf(skillId: string): string {\n // Boundary cast: every id inside a cause was read out of the matrix's own\n // relationship tables, so it names a skill the matrix holds.\n return getLabel(getSkillById(skillId as SkillId));\n}\n\ntype SkillRequirement = ResolvedSkill[\"requires\"][number];\n\n/** OR (`needsAny`): met when ANY option is selected. AND: met when EVERY id is selected. */\nfunction isRequirementMet(req: SkillRequirement, selectedSet: ReadonlySet<SkillId>): boolean {\n return req.needsAny\n ? req.skillIds.some((id) => selectedSet.has(id))\n : req.skillIds.every((id) => selectedSet.has(id));\n}\n\n/** Ids blocking the requirement: every option for an unmet OR, the absent ids for an AND. */\nfunction missingRequirementIds(\n req: SkillRequirement,\n selectedSet: ReadonlySet<SkillId>,\n): SkillId[] {\n if (isRequirementMet(req, selectedSet)) return [];\n return req.needsAny ? [...req.skillIds] : req.skillIds.filter((id) => !selectedSet.has(id));\n}\n\n/**\n * For an unselected skill, finds the first selected skill that needs it\n * and whose requirement is currently unmet. Returns the dependent's display name,\n * or undefined if no selected skill has an unmet need for this skill.\n */\nexport function getUnmetRequiredBy(\n skillId: SkillId,\n currentSelections: SkillId[],\n): string | undefined {\n getSkillById(skillId); // assert the id exists in the matrix\n const { resolvedSelections, selectedSet } = initializeSelectionContext(currentSelections);\n\n if (selectedSet.has(skillId)) return undefined;\n\n for (const selectedId of resolvedSelections) {\n const selectedSkill = matrix.skills[selectedId];\n if (!selectedSkill) continue;\n\n for (const req of selectedSkill.requires) {\n if (!req.skillIds.includes(skillId)) continue;\n\n if (req.needsAny) {\n // OR: unmet only if NONE of the options are selected\n if (!req.skillIds.some((id) => selectedSet.has(id))) {\n return getLabel(selectedSkill);\n }\n } else {\n // AND: unmet if this specific skill isn't selected\n return getLabel(selectedSkill);\n }\n }\n }\n\n return undefined;\n}\n\n/**\n * Checks if a selected skill has unmet dependency requirements.\n * Only meaningful for skills that are currently selected.\n */\nexport function hasUnmetRequirements(skillId: SkillId, currentSelections: SkillId[]): boolean {\n return getUnmetRequirementsReason(skillId, currentSelections) !== undefined;\n}\n\n/**\n * The verdict a grid cell renders, judged against the selection a click on it\n * would produce. A pick-one category is a radio group: the click drops every\n * same-category member — selected or implied — so a conflict the swap\n * resolves is forgiven, and an impossibility it leaves standing (a requirement\n * the rest of the selection has ruled out) keeps its verdict and its reason,\n * exactly as a multi-select category renders it.\n */\nexport function getCellState(skillId: SkillId, currentSelections: SkillId[]): OptionState {\n const skill = getSkillById(skillId);\n const { resolvedSelections } = initializeSelectionContext(currentSelections);\n\n const verdict = judgeSelections(resolvedSelections).verdictOf(skill.id);\n return verdict.status === \"incompatible\"\n ? { status: \"incompatible\", reason: renderIncompatibility(verdict.cause) }\n : verdict;\n}\n\n/**\n * Returns a human-readable reason for unmet requirements, or undefined if all are met.\n */\nexport function getUnmetRequirementsReason(\n skillId: SkillId,\n currentSelections: SkillId[],\n): string | undefined {\n const skill = getSkillById(skillId);\n\n const { selectedSet } = initializeSelectionContext(currentSelections);\n\n for (const requirement of skill.requires) {\n const missing = missingRequirementIds(requirement, selectedSet);\n if (missing.length === 0) continue;\n const names = missing.map((id) => {\n const s = matrix.skills[id];\n return s ? getLabel(s) : stripTerminalControls(id);\n });\n return withAuthorsReason(namesTheMissing(names, requirement.needsAny), requirement.reason);\n }\n\n return undefined;\n}\n\n/** What is missing, which only the current selection can say. */\nfunction namesTheMissing(names: string[], needsAny: boolean | undefined): string {\n return `requires ${joinWithConjunction(names, needsAny ? \"or\" : \"and\")}`;\n}\n\n/**\n * How much of a rule author's `reason` a grid cell carries.\n *\n * The cell wraps rather than elides, so an unbounded reason grows the tag, grows the frame, and\n * pushes the top of the wizard off the terminal — measured against the shipped catalogue, whose\n * longest reason is 242 characters and whose React Router entry alone cost four lines. A budget is\n * what keeps a variable-length authored string out of a fixed-height layout.\n *\n * 60 covers the median (46) and every reason under it untouched; 24 of 110 shipped rules are\n * clipped. Chosen against the catalogue as it stands rather than derived from the terminal, so a\n * much narrower window can still wrap one line — the frame-fit specs are what would catch that.\n */\nconst REASON_BUDGET = 60;\n\n/**\n * The rule author's own sentence, appended to the synthesised one and clipped to fit.\n *\n * The two halves say different things and neither replaces the other: the synthesis names WHAT is\n * missing, which static prose cannot know, and the author's `reason` says WHY, which the synthesis\n * cannot infer. `reason` is required by `requireRuleSchema` and enforced across the built-ins, so\n * it is a sentence every marketplace author is already made to write — and nothing read it until\n * 2026-08-23. Both siblings render theirs: `discourages[].reason` in the grid,\n * `conflicts[].reason` through `reportValidationErrors`.\n *\n * Guarded on emptiness rather than assumed present: the schema requires the KEY, not a non-empty\n * string, so a rule carrying `reason: \"\"` must not produce a dangling separator.\n */\nfunction withAuthorsReason(synthesised: string, reason: string): string {\n const stated = reason.trim();\n if (stated === \"\") return synthesised;\n\n return `${synthesised} — ${truncateText(stated, REASON_BUDGET)}`;\n}\n\n/**\n * `{ unmetRequirementsReason }` only when there is one to state — an unselected skill,\n * or a selected skill whose requirements are all met, carries no key at all.\n */\nfunction unmetRequirementsReasonFor(\n isSelected: boolean,\n skillId: SkillId,\n currentSelections: SkillId[],\n): { unmetRequirementsReason?: string } {\n if (!isSelected) return {};\n const reason = getUnmetRequirementsReason(skillId, currentSelections);\n return reason === undefined ? {} : { unmetRequirementsReason: reason };\n}\n\nexport function validateConflicts(resolvedSelections: SkillId[]): ValidationError[] {\n const errors: ValidationError[] = [];\n\n for (const [index, skillAId] of resolvedSelections.entries()) {\n const skillA = matrix.skills[skillAId];\n if (!skillA) continue;\n\n for (const skillBId of resolvedSelections.slice(index + 1)) {\n const conflict = skillA.conflictsWith.find((c) => c.skillId === skillBId);\n if (conflict) {\n errors.push({\n type: \"conflict\",\n // The author's own sentence, made inert but not shortened: this message is reported on\n // its own line rather than into a fixed-height cell, so it needs no budget the way\n // `withAuthorsReason` does — only the guarantee that a terminal will print it.\n message: `${getLabel(skillA)} conflicts with ${getLabel(getSkillById(skillBId))}: ${stripTerminalControls(conflict.reason)}`,\n skills: [skillA.id, skillBId],\n });\n }\n }\n }\n\n return errors;\n}\n\nexport function validateRequirements(\n resolvedSelections: SkillId[],\n selectedSet: Set<SkillId>,\n): ValidationError[] {\n const errors: ValidationError[] = [];\n\n for (const skillId of resolvedSelections) {\n const skill = matrix.skills[skillId];\n if (!skill) continue;\n\n for (const requirement of skill.requires) {\n if (requirement.needsAny) {\n const hasAny = requirement.skillIds.some((reqId) => selectedSet.has(reqId));\n if (!hasAny) {\n errors.push({\n type: \"missingRequirement\",\n message: `${getLabel(skill)} requires one of: ${requirement.skillIds.map((id) => getLabel(getSkillById(id))).join(\", \")}`,\n skills: [skillId, ...requirement.skillIds],\n });\n }\n } else {\n const missingIds = requirement.skillIds.filter((reqId) => !selectedSet.has(reqId));\n if (missingIds.length > 0) {\n errors.push({\n type: \"missingRequirement\",\n message: `${getLabel(skill)} requires: ${missingIds.map((id) => getLabel(getSkillById(id))).join(\", \")}`,\n skills: [skillId, ...missingIds],\n });\n }\n }\n }\n }\n\n return errors;\n}\n\nexport function validateExclusivity(resolvedSelections: SkillId[]): ValidationError[] {\n const errors: ValidationError[] = [];\n\n const validSkills = resolvedSelections\n .map((skillId) => ({ skillId, skill: matrix.skills[skillId] }))\n .filter((entry): entry is { skillId: SkillId; skill: ResolvedSkill } => entry.skill != null);\n const categorySelections = groupBy(validSkills, (entry) => entry.skill.category);\n\n for (const [categoryId, entries] of typedEntries(categorySelections)) {\n if (entries.length > 1) {\n const skillIds = entries.map((e) => e.skillId);\n // \"local\" is a pseudo-category without exclusivity rules\n if (categoryId === LOCAL_PSEUDO_CATEGORY) continue;\n const category = matrix.categories[categoryId];\n if (category?.exclusive) {\n errors.push({\n type: \"categoryExclusive\",\n message: `Category \"${stripTerminalControls(category.displayName)}\" only allows one selection, but multiple selected: ${skillIds.map((id) => getLabel(getSkillById(id))).join(\", \")}`,\n skills: skillIds,\n });\n }\n }\n }\n\n return errors;\n}\n\n/**\n * Validates a complete set of skill selections against all matrix constraints.\n *\n * Runs three validation passes:\n * 1. **Conflicts** - Checks for mutually exclusive skill pairs (errors)\n * 2. **Requirements** - Checks that all required dependencies are selected (errors)\n * 3. **Exclusivity** - Checks that exclusive categories have at most one selection (errors)\n *\n * `valid` is derived from `errors` rather than asserted: a literal `true` beside a populated\n * `errors` array is a comment with a type annotation, and the first `if (validation.valid)`\n * written against it would pass on every rejected selection there is.\n *\n * @param selections - Complete list of selected skill IDs to validate\n * @returns Validation result with `valid` flag and error list\n */\nexport function validateSelection(selections: SkillId[]): SelectionValidation {\n const { resolvedSelections, selectedSet } = initializeSelectionContext(selections);\n\n const errors = [\n ...validateConflicts(resolvedSelections),\n ...validateRequirements(resolvedSelections, selectedSet),\n ...validateExclusivity(resolvedSelections),\n ];\n\n return {\n valid: errors.length === 0,\n errors,\n };\n}\n\n/**\n * Builds a list of skill options for a category: which are selected, and which of\n * those are still waiting on a requirement.\n *\n * It deliberately states no advisory verdict. {@link getCellState} is the one that\n * does, because a cell is judged against the selection a click on it would produce\n * — inside a pick-one category the swap forgives a conflict that a raw per-option\n * advisory would still report. The raw advisory this function used to carry was\n * therefore not merely unread but the wrong answer for its only caller,\n * `buildCategoriesForDomain` in `lib/wizard/build-step-logic.ts`, which has always\n * called `getCellState` instead.\n *\n * @param categoryId - Category path to filter skills by\n * @param currentSelections - Currently selected skill IDs\n * @returns Array of skill options with their selection state\n */\nexport function getAvailableSkills(\n categoryId: CategoryPath,\n currentSelections: SkillId[],\n): SkillOption[] {\n const { selectedSet } = initializeSelectionContext(currentSelections);\n\n return getSkillsByCategory(categoryId).map((skill) => {\n const isSelected = selectedSet.has(skill.id);\n return {\n id: skill.id,\n selected: isSelected,\n hasUnmetRequirements: isSelected && hasUnmetRequirements(skill.id, currentSelections),\n ...unmetRequirementsReasonFor(isSelected, skill.id, currentSelections),\n };\n });\n}\n\n/** Returns all resolved skills belonging to the given category. */\nexport function getSkillsByCategory(categoryId: CategoryPath): ResolvedSkill[] {\n return allSkills().filter((skill) => skill.category === categoryId);\n}\n","import type { SkillId, SkillSlug } from \"../../types\";\n\n/**\n * Post-decision-2 vocabulary: conflict groups no longer exist as a mechanism, so a skill is\n * fenced by category exclusivity, by a `requires` rule, or not at all.\n */\nexport type AuditVerdict = \"constrained-via-exclusivity-or-requires\" | \"universal\";\n\n/** The framework-adapter classification rides this manifest — one audit, two products. */\nexport type SkillClass = \"A\" | \"B\" | \"C\";\n\n/** Worksheet batch that produced a verdict — provenance for the adversarial pass. */\nexport type BatchId =\n | \"web-core\"\n | \"web-state\"\n | \"web-ui\"\n | \"web-platform\"\n | \"api-core\"\n | \"api-data\"\n | \"api-services\"\n | \"ai\"\n | \"mobile\"\n | \"desktop\"\n | \"infra-cli\"\n | \"shared-meta\";\n\nexport type SkillAuditEntry = {\n /** ISO date the verdict was established or last re-confirmed. */\n audited: `${number}-${number}-${number}`;\n verdict: AuditVerdict;\n batch: BatchId;\n /**\n * Framework-adapter classification. Omitted for the framework skills themselves\n * (react, nextjs, react-native, electron, tauri, …) which are the binding targets.\n * class A → frameworks: []; class B → exactly one; class C → the adapter set.\n */\n classification?: { class: SkillClass; frameworks: SkillSlug[] };\n /** Cited sources — recorded wherever the entry changed a rule. */\n sources?: string[];\n /** Anything the current vocabulary cannot express, deferred rather than invented here. */\n deferredToD306?: string;\n};\n\n/**\n * Every catalog skill's audit verdict, one entry per skill.\n *\n * Total record, not `Partial`: the type checker enforces \"every SkillId appears\" at compile\n * time, so the \"empty = unaudited, or nobody looked?\" ambiguity is unrepresentable for\n * built-ins. Source-provided skills cannot be covered that way — `checkMatrixHealth` carries\n * the runtime assertion for those.\n *\n * Verdicts were recorded as of the audit, assuming the batches' category dispositions would\n * land; they have, so every row is backed by the live rules and\n * `auditVerdictsPendingApply` below — the exemption list for rows the tree has not caught up\n * with — is empty.\n */\nexport const skillAudit: Record<SkillId, SkillAuditEntry> = {\n // ── B1 — web core: frameworks, meta-frameworks, routing, server state (20) ──\n \"web-framework-react\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-core\",\n },\n \"web-framework-vue-composition-api\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-core\",\n },\n \"web-framework-angular-standalone\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-core\",\n },\n \"web-framework-solidjs\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-core\",\n },\n \"web-framework-svelte\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-core\",\n },\n \"web-meta-framework-nextjs\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-core\",\n },\n \"web-meta-framework-remix\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-core\",\n },\n \"web-meta-framework-nuxt\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-core\",\n },\n \"web-meta-framework-sveltekit\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-core\",\n },\n \"web-meta-framework-astro\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-core\",\n },\n \"web-meta-framework-qwik\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-core\",\n },\n \"web-meta-framework-docusaurus\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-core\",\n classification: { class: \"A\", frameworks: [] },\n sources: [\"https://docusaurus.io\"],\n },\n \"web-meta-framework-vitepress\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-core\",\n classification: { class: \"A\", frameworks: [] },\n sources: [\"https://github.com/honojs/website\", \"https://vitepress.dev\"],\n },\n \"web-routing-react-router\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-core\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n sources: [\"https://reactrouter.com\"],\n },\n \"web-routing-tanstack-router\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-core\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n deferredToD306:\n \"Solid trigger: widen to needsAny [react, solidjs] if Solid content lands in the body (the official @tanstack/solid-router adapter already shipped upstream).\",\n },\n \"web-server-state-react-query\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-core\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n deferredToD306:\n \"The hey-api MUST beside tRPC: the MUST reads literally (generated query options from hey-api — never write custom React Query hooks) and sits in tension beside tRPC-generated options in a hybrid stack; if that MUST is ever re-cut to claim ALL server data, the coexistence rationale reopens.\",\n },\n \"web-data-fetching-swr\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-core\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n },\n \"web-data-fetching-trpc\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-core\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n },\n \"web-data-fetching-graphql-apollo\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-core\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n },\n \"web-data-fetching-graphql-urql\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-core\",\n classification: {\n class: \"C\",\n frameworks: [\"react\", \"vue-composition-api\", \"solidjs\", \"svelte\"],\n },\n },\n\n // ── B2 — web state, forms, i18n, utilities (19) ──\n \"web-state-jotai\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-state\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n deferredToD306:\n \"Jotai beside a store library is a real pattern (atomic UI atoms beside a domain store) with an official bridge extension (jotai-zustand / atomWithStore) but no vendor-documented two-peers steady state; unrepresentable while the zustand skill's MUST is territorial. Reopen trigger: the zustand MUST being re-cut to store-shaped state.\",\n },\n \"web-state-mobx\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-state\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n },\n \"web-state-redux-toolkit\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-state\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n },\n \"web-state-zustand\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-state\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n },\n \"web-state-pinia\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-state\",\n classification: { class: \"B\", frameworks: [\"vue-composition-api\"] },\n },\n \"web-state-ngrx-signalstore\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-state\",\n classification: { class: \"B\", frameworks: [\"angular-standalone\"] },\n },\n \"web-forms-react-hook-form\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-state\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n },\n \"web-forms-tanstack-form\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-state\",\n classification: {\n class: \"C\",\n frameworks: [\"react\", \"vue-composition-api\", \"angular-standalone\", \"solidjs\"],\n },\n deferredToD306:\n \"Svelte-widening trigger: widen the needsAny to svelte/sveltekit when Svelte content lands in the body (@tanstack/svelte-form is stable upstream; the skill claims React/Vue/Solid/Angular/Lit only).\",\n },\n \"web-forms-vee-validate\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-state\",\n classification: { class: \"B\", frameworks: [\"vue-composition-api\"] },\n },\n \"web-forms-zod-validation\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"web-state\",\n classification: { class: \"A\", frameworks: [] },\n sources: [\"https://zod.dev\"],\n },\n \"web-error-handling-error-boundaries\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-state\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n },\n \"web-error-handling-result-types\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"web-state\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"web-i18n-next-intl\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-state\",\n classification: { class: \"B\", frameworks: [\"nextjs\"] },\n },\n \"web-i18n-react-intl\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-state\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n },\n \"web-i18n-vue-i18n\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-state\",\n classification: { class: \"B\", frameworks: [\"vue-composition-api\"] },\n },\n \"web-utilities-rxjs\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"web-state\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"web-utilities-date-fns\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"web-state\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"web-utilities-vueuse\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-state\",\n classification: { class: \"B\", frameworks: [\"vue-composition-api\"] },\n },\n \"web-utilities-native-js\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"web-state\",\n classification: { class: \"A\", frameworks: [] },\n },\n\n // ── B3 — web UI, styling, animation, editors (22) ──\n \"web-ui-shadcn-ui\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-ui\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n },\n \"web-ui-mui\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-ui\",\n classification: { class: \"C\", frameworks: [\"react\", \"nextjs\"] },\n },\n \"web-ui-chakra-ui\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-ui\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n },\n \"web-ui-mantine\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-ui\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n },\n \"web-ui-ant-design\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-ui\",\n classification: { class: \"C\", frameworks: [\"react\", \"nextjs\"] },\n },\n \"web-ui-vuetify\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-ui\",\n classification: { class: \"B\", frameworks: [\"vue-composition-api\"] },\n },\n \"web-ui-radix-ui\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-ui\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n },\n \"web-ui-headless-ui\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-ui\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n },\n \"web-ui-base-ui\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-ui\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n sources: [\"https://base-ui.com\"],\n },\n \"web-ui-tanstack-table\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-ui\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n },\n \"web-styling-tailwind\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"web-ui\",\n classification: { class: \"C\", frameworks: [] },\n },\n \"web-styling-scss-modules\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"web-ui\",\n classification: { class: \"A\", frameworks: [] },\n deferredToD306:\n \"tailwind <-> scss-modules coexistence is documented (Tailwind's own compatibility page allows but discourages it) — a discourages-shaped pair, no fence today.\",\n },\n \"web-styling-cva\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"web-ui\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"web-styling-theming\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"web-ui\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"web-styling-design-tokens\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"web-ui\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"web-animation-framer-motion\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-ui\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n },\n \"web-animation-css-animations\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"web-ui\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"web-animation-view-transitions\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"web-ui\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"web-editor-lexical\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-ui\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n sources: [\"https://lexical.dev\"],\n },\n \"web-editor-tiptap\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-ui\",\n classification: { class: \"C\", frameworks: [\"react\", \"vue-composition-api\"] },\n },\n \"web-3d-react-three-fiber\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-ui\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n sources: [\"https://r3f.docs.pmnd.rs\"],\n },\n \"web-dnd-dnd-kit\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-ui\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n sources: [\n \"skill body (DndContext/useDraggable/useDroppable/useSortable; every import a @dnd-kit/* React package)\",\n 'npm @dnd-kit/core (\"a lightweight React library\")',\n ],\n },\n\n // ── B4 — web platform, testing, tooling (23) ──\n \"web-testing-playwright-e2e\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-platform\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"web-testing-cypress-e2e\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-platform\",\n classification: { class: \"A\", frameworks: [] },\n deferredToD306:\n \"Cypress component testing beside Playwright E2E is unrepresentable — carried by the cy.mount slice; 2026 guidance keys the CT tool to the incumbent E2E runner, so the radio holds.\",\n },\n \"web-testing-react-testing-library\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-platform\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n },\n \"web-testing-vue-test-utils\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-platform\",\n classification: { class: \"B\", frameworks: [\"vue-composition-api\"] },\n },\n \"web-testing-vitest\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"web-platform\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"web-testing-visual-regression\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"web-platform\",\n classification: { class: \"A\", frameworks: [] },\n deferredToD306:\n \"Pairs with a capture harness (playwright / cypress / storybook) — advice only; enumerating the harnesses would misstate BackstopJS/Percy-class setups.\",\n },\n \"web-tooling-storybook\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-platform\",\n classification: {\n class: \"C\",\n frameworks: [\n \"react\",\n \"vue-composition-api\",\n \"angular-standalone\",\n \"solidjs\",\n \"svelte\",\n \"qwik\",\n ],\n },\n sources: [\"https://storybook.js.org/docs/configure/integration/frameworks\"],\n deferredToD306:\n \"A community Astro framework exists (storybook-astro.org) but is not official — astro stays fenced out today. Package-health watch: storybook-framework-qwik 0.6.1, personal repo, trails Storybook 10.x.\",\n },\n \"web-tooling-vite\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"web-platform\",\n classification: { class: \"A\", frameworks: [] },\n deferredToD306:\n \"vite <-> nextjs and vite <-> docusaurus are dubious combos (discourages-shaped, advice not fence) — with the 6-of-15 vite-carrying default-stack rosters that also pin nextjs named as curation debt for the stack owner.\",\n },\n \"web-tooling-component-library\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-platform\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n sources: [\n 'skill body (self-scope on all three surfaces; 3 of 5 MUSTs React/RSC-keyed; the \"use client\" contract)',\n ],\n },\n \"web-realtime-websockets\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-platform\",\n classification: { class: \"C\", frameworks: [\"react\"] },\n },\n \"web-realtime-socket-io\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-platform\",\n classification: { class: \"C\", frameworks: [\"react\"] },\n deferredToD306:\n \"A native-WebSocket third-party feed beside Socket.IO-to-own-server (the external service dictates the protocol) is a scope split the radio cannot express.\",\n },\n \"web-realtime-sse\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"web-platform\",\n classification: { class: \"C\", frameworks: [\"react\"] },\n },\n \"web-pwa-service-workers\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"web-platform\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"web-pwa-offline-first\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"web-platform\",\n classification: { class: \"C\", frameworks: [\"react\"] },\n },\n \"web-dataviz-d3\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"web-platform\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"web-dataviz-recharts\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-platform\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n sources: [\"https://recharts.org\"],\n },\n \"web-maps-leaflet\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-platform\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"web-maps-mapbox\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-platform\",\n classification: { class: \"A\", frameworks: [] },\n deferredToD306:\n \"mapbox-gl-leaflet embedding (the Leaflet API drives a non-interactive GL layer, so half the mapbox skill applies and half must not be followed); Mapbox-as-tile-service needs no skill pairing at all.\",\n },\n \"web-mocks-msw\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"web-platform\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"web-files-file-upload-patterns\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-platform\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n },\n \"web-files-image-handling\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"web-platform\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n },\n \"web-performance-web-performance\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"web-platform\",\n classification: { class: \"C\", frameworks: [\"react\"] },\n },\n \"web-accessibility-web-accessibility\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"web-platform\",\n classification: { class: \"A\", frameworks: [] },\n },\n\n // ── B5 — api core: frameworks, GraphQL, auth, cross-cutting (17) ──\n \"api-framework-hono\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-core\",\n },\n \"api-framework-express\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-core\",\n },\n \"api-framework-fastify\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-core\",\n },\n \"api-framework-nestjs\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-core\",\n },\n \"api-framework-elysia\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-core\",\n },\n \"api-graphql-apollo-server\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-core\",\n classification: { class: \"C\", frameworks: [\"express\", \"fastify\"] },\n },\n \"api-graphql-yoga\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-core\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-graphql-mercurius\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-core\",\n classification: { class: \"B\", frameworks: [\"fastify\"] },\n sources: [\n 'skill body (\"When NOT to use: Not using Fastify (Mercurius is Fastify-only)\")',\n \"mercurius README (npm i fastify mercurius graphql; app.register(mercurius))\",\n ],\n },\n \"api-auth-better-auth-drizzle-hono\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-core\",\n classification: { class: \"B\", frameworks: [\"hono\"] },\n sources: [\n 'skill body (app.on([\"POST\",\"GET\"], \"/auth/*\", …); createMiddleware<{ Variables: AuthVariables }>; c.req.raw)',\n \"https://better-auth.com\",\n ],\n },\n \"api-auth-nextauth\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-core\",\n classification: { class: \"B\", frameworks: [\"nextjs\"] },\n sources: [\"https://authjs.dev\"],\n },\n \"api-auth-clerk\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-core\",\n classification: { class: \"B\", frameworks: [\"nextjs\"] },\n },\n \"api-specs-openapi\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"api-core\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-messaging-webhooks\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"api-core\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-caching-strategies\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"api-core\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-queue-bullmq\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-core\",\n classification: { class: \"A\", frameworks: [] },\n sources: [\n \"https://docs.bullmq.io/guide/redis-tm-compatibility\",\n \"https://upstash.com/docs/redis/integrations/bullmq\",\n ],\n deferredToD306:\n \"BullMQ polls Redis even when idle, so Upstash's per-request Pay-As-You-Go pricing balloons (Upstash recommends a Fixed plan) — curation advice, not a fence.\",\n },\n \"api-performance-api-performance\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"api-core\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-commerce-stripe\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"api-core\",\n classification: { class: \"A\", frameworks: [] },\n },\n\n // ── B6 — api data: databases and BaaS (22) ──\n \"api-database-postgresql\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-data\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-database-mysql\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-data\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-database-cockroachdb\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-data\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-database-drizzle\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-data\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-database-prisma\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-data\",\n classification: { class: \"A\", frameworks: [] },\n deferredToD306:\n \"Prisma-on-Mongo overlaps mongoose as a full Mongo data layer; the pair is deliberately unfenced across the sql-engine/document radios (accepted over-permissiveness).\",\n },\n \"api-database-sequelize\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-data\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-database-typeorm\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-data\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-database-knex\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-data\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-database-mongodb\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-data\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-database-mongoose\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-data\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-database-edgedb\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-data\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-database-surrealdb\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-data\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-database-redis\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-data\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-database-upstash\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-data\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-database-vercel-kv\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-data\",\n classification: { class: \"A\", frameworks: [] },\n deferredToD306:\n \"vercel-kv -> requires [vercel] deferred, not adopted: product-true (only provisionable on Vercel) but the product is discontinued (Dec 2024) and retirement is the better disposition.\",\n },\n \"api-database-vercel-postgres\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-data\",\n classification: { class: \"A\", frameworks: [] },\n deferredToD306:\n \"vercel-postgres -> requires [vercel] deferred, not adopted: product-true but the product is discontinued (auto-migrated to Neon) and retirement is the better disposition.\",\n },\n \"api-baas-supabase\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-data\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-baas-firebase\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-data\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-baas-appwrite\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-data\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-baas-neon\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-data\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-baas-planetscale\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-data\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-baas-turso\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-data\",\n classification: { class: \"A\", frameworks: [] },\n deferredToD306:\n \"turso as an edge-replica secondary beside a primary Postgres host is a real minority pattern the api-db-host radio over-restricts — accepted.\",\n },\n\n // ── B7 — api services: vector, search, CMS, analytics, observability, email (16) ──\n \"api-vector-db-pinecone\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-services\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-vector-db-qdrant\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-services\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-vector-db-chroma\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-services\",\n classification: { class: \"A\", frameworks: [] },\n deferredToD306:\n \"chroma <-> pinecone dev/prod graduation split is the one real minority pattern the vector-db radio blocks.\",\n },\n \"api-vector-db-weaviate\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-services\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-search-elasticsearch\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-services\",\n classification: { class: \"A\", frameworks: [] },\n deferredToD306:\n \"Elasticsearch-for-logs beside Meilisearch-for-product-search is a real dual-role coexistence the api-search radio blocks.\",\n },\n \"api-search-meilisearch\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-services\",\n classification: { class: \"A\", frameworks: [] },\n },\n // Landed by external PR (agents-inc/skills#2) after the B7 batch closed; verdict follows\n // its api-search siblings — the category radio is the constraint, no rules of its own.\n \"api-search-xquik\": {\n audited: \"2026-08-09\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-services\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-cms-payload\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-services\",\n classification: { class: \"C\", frameworks: [\"nextjs\"] },\n deferredToD306:\n \"payload's full surface (admin panel, mounted REST/GraphQL) is Next-hosted today; the taught surface (config, collections, access control, hooks, Local API) is the documented headless mode and host-neutral — the nextjs pairing is recommends-shaped. Re-derive if the body grows Next mounting content, or when the 4.0 framework adapters land.\",\n },\n \"api-cms-sanity\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-services\",\n classification: { class: \"C\", frameworks: [\"react\"] },\n },\n \"api-cms-strapi\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-services\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"api-analytics-setup-posthog\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"api-services\",\n classification: { class: \"C\", frameworks: [\"react\"] },\n },\n \"api-flags-posthog-flags\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"api-services\",\n classification: { class: \"C\", frameworks: [\"react\"] },\n },\n \"api-analytics-posthog-analytics\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"api-services\",\n classification: { class: \"C\", frameworks: [\"react\"] },\n },\n \"api-observability-setup-axiom-pino-sentry\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-services\",\n classification: { class: \"C\", frameworks: [\"nextjs\"] },\n sources: [\n \"skill body (next-axiom, @sentry/nextjs, next.config.ts wrapped withAxiom(withSentryConfig(...)), instrumentation.ts, sentry.{client,server,edge}.config.ts)\",\n 'todo/skills.md — \"Next-only in all but name\"',\n ],\n },\n \"api-observability-axiom-pino-sentry\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"api-services\",\n classification: { class: \"C\", frameworks: [\"react\"] },\n },\n \"api-email-setup-resend\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-services\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n sources: [\"https://react.email/docs\"],\n },\n \"api-email-resend-react-email\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"api-services\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n deferredToD306:\n \"React-as-template-renderer is not React-as-app-framework: React Email runs in any Node backend, but because react sits in the exclusive web-framework radio the rule fences every Vue/Svelte/Angular project out of the catalog's only email-usage skill.\",\n },\n\n // ── B8 — ai (20) ──\n \"ai-provider-anthropic-sdk\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"ai\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"ai-provider-openai-sdk\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"ai\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"ai-provider-google-gemini-sdk\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"ai\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"ai-provider-mistral-sdk\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"ai\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"ai-provider-cohere-sdk\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"ai\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"ai-provider-elevenlabs\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"ai\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"ai-provider-claude-vision\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"ai\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"ai-provider-openai-whisper\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"ai\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"ai-infrastructure-huggingface-inference\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"ai\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"ai-infrastructure-together-ai\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"ai\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"ai-infrastructure-litellm\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"ai\",\n classification: { class: \"A\", frameworks: [] },\n deferredToD306:\n \"Wire-protocol reuse is not a skill dependency: litellm's TypeScript client literally is new OpenAI({ baseURL }), but the body carries its own complete client pointed away from OpenAI, so it derives no requires [openai-sdk].\",\n },\n \"ai-infrastructure-replicate\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"ai\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"ai-infrastructure-modal\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"ai\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"ai-infrastructure-ollama\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"ai\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"ai-orchestration-langchain\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"ai\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"ai-orchestration-llamaindex\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"ai\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"ai-orchestration-vercel-ai-sdk\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"ai\",\n classification: { class: \"C\", frameworks: [\"react\"] },\n },\n \"ai-observability-langfuse\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"ai\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"ai-observability-promptfoo\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"ai\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"ai-patterns-tool-use-patterns\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"ai\",\n classification: { class: \"A\", frameworks: [] },\n },\n\n // ── B9 — mobile (24) ──\n \"mobile-framework-react-native\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"mobile\",\n },\n \"mobile-framework-expo\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"mobile\",\n },\n \"mobile-navigation-react-navigation\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"mobile\",\n classification: { class: \"B\", frameworks: [\"react-native\"] },\n sources: [\"https://reactnavigation.org\"],\n },\n \"mobile-navigation-expo-router\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"mobile\",\n classification: { class: \"B\", frameworks: [\"expo\"] },\n sources: [\"https://docs.expo.dev/router/installation/\"],\n },\n \"mobile-styling-nativewind\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"mobile\",\n classification: { class: \"B\", frameworks: [\"react-native\"] },\n sources: [\"https://www.nativewind.dev\"],\n },\n \"mobile-styling-unistyles\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"mobile\",\n classification: { class: \"B\", frameworks: [\"react-native\"] },\n sources: [\"https://www.unistyl.es\"],\n },\n \"mobile-testing-detox\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"mobile\",\n classification: { class: \"B\", frameworks: [\"react-native\"] },\n sources: [\"https://github.com/wix/Detox\"],\n },\n \"mobile-testing-maestro\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"mobile\",\n classification: { class: \"A\", frameworks: [] },\n sources: [\"https://docs.maestro.dev/get-started/supported-platform\"],\n deferredToD306:\n \"Needs an app Maestro can drive; the needsAny enumerates the catalog's current mobile-app producers (react-native, expo, tauri-mobile) — re-derive when that set changes.\",\n },\n \"mobile-ui-components-tamagui\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"mobile\",\n classification: { class: \"C\", frameworks: [\"react-native\", \"react\"] },\n sources: [\"https://tamagui.dev/docs/intro/installation\", \"https://github.com/tamagui/tamagui\"],\n deferredToD306:\n \"Surfaces a mobile-domain UI kit in web-only stacks — a curation question for the web-ui-kit split (group #14), advice-level only.\",\n },\n \"mobile-ui-components-react-native-paper\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"mobile\",\n classification: { class: \"B\", frameworks: [\"react-native\"] },\n sources: [\"https://callstack.github.io/react-native-paper/\"],\n },\n \"mobile-animation-reanimated\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"mobile\",\n classification: { class: \"B\", frameworks: [\"react-native\"] },\n sources: [\"https://docs.swmansion.com/react-native-reanimated/\"],\n },\n \"mobile-animation-gesture-handler\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"mobile\",\n classification: { class: \"B\", frameworks: [\"react-native\"] },\n sources: [\"https://docs.swmansion.com/react-native-gesture-handler/\"],\n },\n \"mobile-animation-skia\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"mobile\",\n classification: { class: \"B\", frameworks: [\"react-native\"] },\n sources: [\"https://shopify.github.io/react-native-skia/\"],\n },\n \"mobile-storage-mmkv\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"mobile\",\n classification: { class: \"B\", frameworks: [\"react-native\"] },\n sources: [\"https://github.com/mrousavy/react-native-mmkv\"],\n },\n \"mobile-storage-sqlite-powersync\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"mobile\",\n classification: { class: \"B\", frameworks: [\"react-native\"] },\n sources: [\"https://docs.powersync.com/resources/supported-platforms\"],\n },\n \"mobile-storage-watermelondb\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"mobile\",\n classification: { class: \"B\", frameworks: [\"react-native\"] },\n sources: [\"https://watermelondb.dev/docs/Implementation/DatabaseAdapters\"],\n deferredToD306:\n \"Upstream runs on React web via the LokiJS adapter; widen the binding if and only if the skill body ever covers it.\",\n },\n \"mobile-deployment-eas\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"mobile\",\n classification: { class: \"B\", frameworks: [\"expo\"] },\n sources: [\"https://docs.expo.dev/build/introduction/\"],\n },\n \"mobile-camera-vision-camera\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"mobile\",\n classification: { class: \"B\", frameworks: [\"react-native\"] },\n sources: [\"https://react-native-vision-camera.com\"],\n },\n \"mobile-hardware-ble-nfc\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"mobile\",\n classification: { class: \"B\", frameworks: [\"react-native\"] },\n sources: [\n \"https://github.com/dotintent/react-native-ble-plx\",\n \"https://github.com/revtel/react-native-nfc-manager\",\n ],\n },\n \"mobile-notifications-push\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"mobile\",\n classification: { class: \"B\", frameworks: [\"react-native\"] },\n sources: [\n \"https://docs.expo.dev/push-notifications/overview/\",\n \"https://rnfirebase.io/messaging/usage\",\n ],\n },\n \"mobile-background-tasks\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"mobile\",\n classification: { class: \"B\", frameworks: [\"react-native\"] },\n sources: [\n \"https://docs.expo.dev/versions/latest/sdk/background-task/\",\n \"https://github.com/transistorsoft/react-native-background-fetch\",\n ],\n },\n \"mobile-deep-linking-app-links\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"mobile\",\n classification: { class: \"B\", frameworks: [\"react-native\"] },\n sources: [\n \"https://docs.expo.dev/linking/overview/\",\n \"https://reactnavigation.org/docs/deep-linking/\",\n ],\n },\n \"mobile-performance-react-native\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"mobile\",\n classification: { class: \"B\", frameworks: [\"react-native\"] },\n sources: [\"https://reactnative.dev/docs/performance\"],\n },\n \"mobile-security-react-native\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"mobile\",\n classification: { class: \"B\", frameworks: [\"react-native\"] },\n sources: [\n \"https://docs.expo.dev/versions/latest/sdk/securestore/\",\n \"https://github.com/oblador/react-native-keychain\",\n ],\n },\n\n // ── B10 — desktop (16) ──\n \"desktop-framework-electron\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"desktop\",\n },\n \"desktop-framework-tauri\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"desktop\",\n },\n \"desktop-ipc-electron\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"desktop\",\n classification: { class: \"B\", frameworks: [\"electron\"] },\n sources: [\"https://www.electronjs.org/docs/latest/tutorial/ipc\"],\n },\n \"desktop-storage-electron\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"desktop\",\n classification: { class: \"B\", frameworks: [\"electron\"] },\n sources: [\n \"https://www.electronjs.org/docs/latest/api/safe-storage\",\n \"https://github.com/sindresorhus/electron-store\",\n ],\n },\n \"desktop-ui-electron\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"desktop\",\n classification: { class: \"B\", frameworks: [\"electron\"] },\n sources: [\"https://www.electronjs.org/docs/latest/api/tray\"],\n },\n \"desktop-testing-electron\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"desktop\",\n classification: { class: \"B\", frameworks: [\"electron\"] },\n sources: [\"https://playwright.dev/docs/api/class-electron\"],\n },\n \"desktop-updates-electron-updater\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"desktop\",\n classification: { class: \"B\", frameworks: [\"electron\"] },\n sources: [\n \"https://github.com/electron-userland/electron-builder\",\n \"https://www.electron.build/auto-update\",\n ],\n deferredToD306:\n \"Defaults to the electron-builder pipeline (reads app-update.yml, written only by electron-builder's PublishManager); Forge apps using the Squirrel maker use Electron's built-in autoUpdater instead; Forge without Squirrel, and custom distributions, can still run electron-updater with custom config / generic provider.\",\n },\n \"desktop-multiwindow-electron\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"desktop\",\n classification: { class: \"B\", frameworks: [\"electron\"] },\n sources: [\"https://www.electronjs.org/docs/latest/api/base-window\"],\n },\n \"desktop-security-electron\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"desktop\",\n classification: { class: \"B\", frameworks: [\"electron\"] },\n sources: [\"https://www.electronjs.org/docs/latest/tutorial/fuses\"],\n },\n \"desktop-packaging-electron-forge\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"desktop\",\n classification: { class: \"B\", frameworks: [\"electron\"] },\n sources: [\"https://www.electronforge.io\"],\n },\n \"desktop-backend-tauri\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"desktop\",\n classification: { class: \"B\", frameworks: [\"tauri\"] },\n sources: [\"https://v2.tauri.app/develop/calling-rust/\"],\n },\n \"desktop-packaging-tauri\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"desktop\",\n classification: { class: \"B\", frameworks: [\"tauri\"] },\n sources: [\"https://v2.tauri.app/distribute/\"],\n },\n \"desktop-plugins-tauri\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"desktop\",\n classification: { class: \"B\", frameworks: [\"tauri\"] },\n sources: [\"https://v2.tauri.app/plugin/\"],\n },\n \"desktop-multiwindow-tauri\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"desktop\",\n classification: { class: \"B\", frameworks: [\"tauri\"] },\n sources: [\"https://v2.tauri.app/develop/calling-frontend/\"],\n },\n \"desktop-security-tauri\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"desktop\",\n classification: { class: \"B\", frameworks: [\"tauri\"] },\n sources: [\"https://v2.tauri.app/security/capabilities/\"],\n },\n \"desktop-mobile-tauri\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"desktop\",\n classification: { class: \"B\", frameworks: [\"tauri\"] },\n sources: [\n \"https://v2.tauri.app/reference/cli\",\n \"https://v2.tauri.app/blog/roadmap-to-tauri-2-0\",\n ],\n },\n\n // ── B11 — infra + CLI (15) ──\n \"infra-ci-cd-github-actions\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"infra-cli\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"infra-ci-cd-docker\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"infra-cli\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"infra-ci-cd-turborepo-ci\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"infra-cli\",\n classification: { class: \"B\", frameworks: [\"turborepo\"] },\n sources: [\"https://turborepo.dev/docs\"],\n },\n \"infra-config-setup-env\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"infra-cli\",\n classification: { class: \"C\", frameworks: [\"nextjs\", \"vite\"] },\n },\n \"infra-containers-kubernetes\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"infra-cli\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"infra-iac-terraform\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"infra-cli\",\n classification: { class: \"A\", frameworks: [] },\n deferredToD306:\n \"Layered terraform + pulumi coexistence via Pulumi's RemoteStateReference (a Pulumi program consuming the outputs of a Terraform-managed layer) is real at org scope; the radio models one engine per project.\",\n },\n \"infra-iac-pulumi\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"infra-cli\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"infra-iac-sst\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"infra-cli\",\n classification: { class: \"A\", frameworks: [] },\n deferredToD306:\n \"sst's typical data plane is @aws-sdk/client-* — the sst skill's own handlers import it; the pairing is recommended, not required, and platform-boundness (SST needs AWS-the-platform, which has no catalog anchor) is unrepresentable in the current vocabulary.\",\n },\n \"infra-platform-vercel\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"infra-cli\",\n classification: { class: \"A\", frameworks: [] },\n deferredToD306:\n \"vercel <-> netlify is a same-slot tension (one primary Git-centric host per app; monorepo split-hosting and migrations are the minority) and vercel <-> cloudflare-workers-as-host is the same shape — dubious combos, declined as fences.\",\n },\n \"infra-platform-netlify\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"infra-cli\",\n classification: { class: \"A\", frameworks: [] },\n deferredToD306:\n \"Carries the same dubious-combo record as vercel: vercel <-> netlify is a same-slot tension declined as a fence.\",\n },\n \"infra-platform-cloudflare-workers\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"infra-cli\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"infra-platform-aws-sdk\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"infra-cli\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"cli-framework-cli-commander\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"infra-cli\",\n },\n \"cli-framework-oclif-ink\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"infra-cli\",\n },\n \"cli-prompts-clack\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"infra-cli\",\n classification: { class: \"A\", frameworks: [] },\n },\n\n // ── B12 — shared + meta (23) ──\n \"shared-monorepo-turborepo\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"shared-meta\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"shared-monorepo-nx\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"shared-meta\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"shared-monorepo-pnpm-workspaces\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"shared-meta\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"shared-tooling-biome\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"shared-meta\",\n classification: { class: \"A\", frameworks: [] },\n deferredToD306:\n \"The steady-state Biome-as-formatter plus bare-ESLint-for-plugin-gaps hybrid is real; it is unrepresentable while the catalog's ESLint skill bundles Prettier. A future bare eslint skill reopens this radio's rationale.\",\n },\n \"shared-tooling-eslint-prettier\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"shared-meta\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"shared-tooling-typescript-config\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"shared-meta\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"shared-tooling-git-hooks\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"shared-meta\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"shared-tooling-changesets\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"shared-meta\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"meta-config-stack-detect\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"shared-meta\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"shared-security-auth-security\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"shared-meta\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"meta-design-expressive-typescript\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"shared-meta\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"meta-design-composable-components\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"shared-meta\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n sources: [\n 'skill body and all four example files (imports from \"react\"; @base-ui/react/use-render; @base-ui/react/merge-props; forwardRef; JSX-part composition)',\n ],\n },\n \"meta-methodology-research-methodology\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"shared-meta\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"meta-planning-web-planning\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"shared-meta\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"meta-planning-api-planning\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"shared-meta\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"meta-planning-cli-planning\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"shared-meta\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"meta-planning-ai-planning\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"shared-meta\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"meta-reviewing-reviewing\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"shared-meta\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"meta-reviewing-web-reviewing\": {\n audited: \"2026-08-07\",\n verdict: \"constrained-via-exclusivity-or-requires\",\n batch: \"shared-meta\",\n classification: { class: \"B\", frameworks: [\"react\"] },\n sources: [\n 'skill body self-scope (description \"Use when reviewing React components\"; When-to-use \".tsx/.jsx with JSX\"; \"React PR review\" auto-detection) plus a React-keyed majority (4 of 5 MUSTs, 6 of 7 patterns)',\n ],\n },\n \"meta-reviewing-api-reviewing\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"shared-meta\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"meta-reviewing-cli-reviewing\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"shared-meta\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"meta-reviewing-ai-reviewing\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"shared-meta\",\n classification: { class: \"A\", frameworks: [] },\n },\n \"meta-reviewing-infra-reviewing\": {\n audited: \"2026-08-07\",\n verdict: \"universal\",\n batch: \"shared-meta\",\n classification: { class: \"A\", frameworks: [] },\n },\n};\n\n/**\n * Rows whose verdict was recorded ahead of the category disposition that backs it, with the\n * batch that owns the change. Both audit checks skip exactly these and nothing else, so any\n * other divergence between the manifest and the rules fails immediately.\n *\n * Empty since every disposition the fan-out ruled on landed: the live rules now back all 238\n * verdicts on their own. It stays as the mechanism for the next audit that runs ahead of its\n * taxonomy — add an entry with the batch that owns it, and delete it when that lands. The\n * consistency test asserts this set matches the live gap exactly, so a stale entry fails just\n * as loudly as a missing one.\n */\nexport const auditVerdictsPendingApply: Partial<Record<SkillId, string>> = {};\n","import { warn } from \"../../utils/logger\";\nimport { LOCAL_PSEUDO_CATEGORY } from \"../../consts\";\nimport type {\n CategoryDefinition,\n CategoryPath,\n MergedSkillsMatrix,\n ResolvedSkill,\n SkillId,\n Category,\n} from \"../../types\";\nimport { isSkillId } from \"../../utils/type-guards\";\nimport { typedEntries } from \"../../utils/typed-object\";\nimport { skillAudit, auditVerdictsPendingApply } from \"../configuration/skill-audit\";\nimport type { SkillAuditEntry } from \"../configuration/skill-audit\";\n\n/**\n * Which check produced an issue. A closed union rather than a free string because a caller may\n * branch on one kind — `source-validator` weighs `rule-unresolved-slug` differently for the\n * author of a marketplace than for someone consuming it — and a misspelled branch there must be\n * a compile error rather than a condition that is quietly never true.\n */\ntype MatrixHealthFinding =\n | \"category-missing-domain\"\n | \"skill-unknown-category\"\n | \"skill-unresolved-relation-ref\"\n | \"rule-unresolved-slug\"\n | \"audit-verdict-contradiction\"\n | \"skill-unaudited\";\n\nexport type MatrixHealthIssue = {\n severity: \"warning\" | \"error\";\n finding: MatrixHealthFinding;\n details: string;\n};\n\nexport function checkMatrixHealth(matrix: MergedSkillsMatrix): MatrixHealthIssue[] {\n const issues = [\n ...checkCategoryDomains(matrix),\n ...checkSkillCategories(matrix),\n ...checkSkillRelationRefs(matrix),\n ...checkUnresolvedRuleSlugs(matrix),\n ...checkAuditVerdictContradictions(matrix),\n ...checkUnauditedSkills(matrix),\n ];\n\n for (const issue of issues) {\n warn(`[matrix] ${issue.details}`);\n }\n\n return issues;\n}\n\n// Categories without a domain won't appear in any wizard domain view\nfunction checkCategoryDomains(matrix: MergedSkillsMatrix): MatrixHealthIssue[] {\n return (\n typedEntries<Category, CategoryDefinition>(matrix.categories)\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- typedEntries/Object.entries launders the `| undefined` a Partial<Record> admits out of its result type, so this guard reads as dead while still covering an explicitly-undefined slot\n .filter(([, cat]) => cat !== undefined && !cat.domain)\n .map(([catId]) => ({\n severity: \"warning\" as const,\n finding: \"category-missing-domain\",\n details: `Category '${catId}' has no domain — it won't appear in any wizard domain view`,\n }))\n );\n}\n\nfunction checkSkillCategories(matrix: MergedSkillsMatrix): MatrixHealthIssue[] {\n return typedEntries<SkillId, ResolvedSkill>(matrix.skills)\n .filter(\n ([, skill]) =>\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- typedEntries/Object.entries launders the `| undefined` a Partial<Record> admits out of its result type, so this guard reads as dead while still covering an explicitly-undefined slot\n skill !== undefined &&\n // \"local\" is a pseudo-category that won't exist in matrix.categories — skip it\n skill.category !== LOCAL_PSEUDO_CATEGORY &&\n !matrix.categories[skill.category],\n )\n .map(([skillId, skill]) => ({\n severity: \"warning\" as const,\n finding: \"skill-unknown-category\",\n details: `Skill '${skillId}' references category '${skill.category}' which does not exist in the matrix`,\n }));\n}\n\n/** Every outgoing relation reference on a skill, tagged with the field it came from. */\nfunction relationRefs(skill: ResolvedSkill): Array<{ field: string; ref: SkillId }> {\n return [\n ...skill.conflictsWith.map((relation) => ({ field: \"conflictsWith\", ref: relation.skillId })),\n ...skill.requires.flatMap((requirement) =>\n requirement.skillIds.map((ref) => ({ field: \"requires\", ref })),\n ),\n ];\n}\n\nfunction checkSkillRelationRefs(matrix: MergedSkillsMatrix): MatrixHealthIssue[] {\n return typedEntries<SkillId, ResolvedSkill>(matrix.skills).flatMap(([skillId, skill]) =>\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- typedEntries/Object.entries launders the `| undefined` a Partial<Record> admits out of its result type, so this guard reads as dead while still covering an explicitly-undefined slot\n skill === undefined\n ? []\n : relationRefs(skill)\n .filter(({ ref }) => !matrix.skills[ref])\n .map(({ field, ref }) => ({\n severity: \"warning\" as const,\n finding: \"skill-unresolved-relation-ref\",\n details: `Skill '${skillId}' has unresolved reference '${ref}' in '${field}'`,\n })),\n );\n}\n\n/**\n * A slug a relationship rule names that no skill carries. The rule containing it\n * states nothing — resolution drops the reference — so the source shipped a rule\n * that cannot act, which is a defect in the source rather than an advisory about\n * it. The CLI's own built-in rules are narrowed to the slugs a source ships\n * before resolution, so nothing here can be the CLI's doing.\n *\n * `error` is the AUTHOR's verdict, and it is the only one this module can reach: a matrix says\n * what is wrong with it and cannot say who is reading. Someone who merely installed from the\n * marketplace can neither open the file nor be harmed by it, and `source-validator` — the one\n * layer that knows which of the two is asking — serves them the same finding as a warning.\n */\nfunction checkUnresolvedRuleSlugs(matrix: MergedSkillsMatrix): MatrixHealthIssue[] {\n return (matrix.unresolvedSlugs ?? []).map((slug) => ({\n severity: \"error\" as const,\n finding: \"rule-unresolved-slug\",\n details: `Unresolved slug '${slug}' in the relationship rules — no skill carries it, so every rule naming it states nothing`,\n }));\n}\n\nfunction isExclusiveCategory(matrix: MergedSkillsMatrix, category: CategoryPath): boolean {\n // \"local\" is a pseudo-category with no definition in matrix.categories — never a fence\n if (category === LOCAL_PSEUDO_CATEGORY) return false;\n\n const definition = matrix.categories[category];\n return definition !== undefined && definition.exclusive;\n}\n\n/**\n * The one definition of \"this skill is fenced\" that the audit's two enforcement points — the\n * runtime contradiction check below and the manifest consistency test — must agree on. Post\n * decision 2 the only fences left are category exclusivity and `requires`.\n */\nexport function isFencedByMatrix(matrix: MergedSkillsMatrix, skillId: SkillId): boolean {\n const skill = matrix.skills[skillId];\n if (skill === undefined) return false;\n\n return skill.requires.length > 0 || isExclusiveCategory(matrix, skill.category);\n}\n\n/** Runtime lookup: the manifest is total over built-ins, but a matrix may carry source skills. */\nfunction auditEntryFor(skillId: SkillId): SkillAuditEntry | undefined {\n return Object.hasOwn(skillAudit, skillId) ? skillAudit[skillId] : undefined;\n}\n\nfunction fenceDescription(matrix: MergedSkillsMatrix, skill: ResolvedSkill): string {\n if (skill.requires.length > 0) return \"it carries a 'requires' rule\";\n return `its category '${skill.category}' is exclusive`;\n}\n\n/**\n * A `universal` verdict claims the skill is selectable beside anything; a `requires` rule or an\n * exclusive category says the opposite. Both cannot be true, so the pair is a contradiction and\n * the audit trail would be lying. Rows in `auditVerdictsPendingApply` are exempt — their verdict\n * was recorded ahead of a category disposition that has not landed yet.\n */\nfunction checkAuditVerdictContradictions(matrix: MergedSkillsMatrix): MatrixHealthIssue[] {\n return typedEntries<SkillId, ResolvedSkill>(matrix.skills)\n .filter(([skillId, skill]) => {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- typedEntries/Object.entries launders the `| undefined` a Partial<Record> admits out of its result type, so this guard reads as dead while still covering an explicitly-undefined slot\n if (skill === undefined || auditVerdictsPendingApply[skillId]) return false;\n const audit = auditEntryFor(skillId);\n\n return audit?.verdict === \"universal\" && isFencedByMatrix(matrix, skillId);\n })\n .map(([skillId, skill]) => ({\n severity: \"error\" as const,\n finding: \"audit-verdict-contradiction\",\n details: `Skill '${skillId}' is audited 'universal' but ${fenceDescription(matrix, skill)}`,\n }));\n}\n\n/**\n * \"Unaudited\" means the manifest was expected to carry a verdict and does not, so the population\n * is the ids the manifest is keyed by: the built-in catalog's. A marketplace's skills carry that\n * marketplace's namespace and are outside the manifest by construction, not unaudited — warning\n * per skill for every one of them would cost a screen of noise and put a clean bill of health out\n * of reach for anyone not on the public catalog. Local skills are the user's own and were already\n * out of scope.\n *\n * `Record<SkillId, SkillAuditEntry>` covers the built-ins exhaustively at compile time, so what\n * remains here is that same totality asserted against a matrix whose keys are open strings at\n * runtime.\n */\nfunction checkUnauditedSkills(matrix: MergedSkillsMatrix): MatrixHealthIssue[] {\n return typedEntries<SkillId, ResolvedSkill>(matrix.skills)\n .filter(\n ([skillId, skill]) =>\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- typedEntries/Object.entries launders the `| undefined` a Partial<Record> admits out of its result type, so this guard reads as dead while still covering an explicitly-undefined slot\n skill !== undefined &&\n !skill.local &&\n isSkillId(skillId) &&\n auditEntryFor(skillId) === undefined,\n )\n .map(([skillId]) => ({\n severity: \"warning\" as const,\n finding: \"skill-unaudited\",\n details: `Skill '${skillId}' has no audit verdict — the built-in audit manifest is missing an entry it is meant to carry`,\n }));\n}\n"],"mappings":"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,cAAc;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,IAAME,aAAY;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAIO,IAAM,aAAa;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAMO,IAAM,UAAU;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAMO,IAAMC,eAAc;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;;;AC71BO,SAAS,SAAS,OAAkD;AACzE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAQO,SAAS,SAAS,OAAgC;AACvD,SAAQ,QAA8B,SAAS,KAAK;AACtD;AAGO,SAAS,YAAY,OAAmC;AAC7D,SAAQC,aAAkC,SAAS,KAAK;AAC1D;AAQO,SAAS,UAAU,OAAiC;AACzD,SAAQC,WAAgC,SAAS,KAAK;AACxD;AAYO,SAAS,kBAAkB,OAA0C;AAC1E,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AAExD,SAAO,OAAQ,MAA2B,OAAO;AACnD;;;AC7DA,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,SAAS,KAAAC,UAAS;;;ACFlB,SAAS,KAAAC,UAAS;AAClB,SAAS,iBAAiB;;;ACD1B,OAAkB;AAkBX,SAAS,eAAe,OAA2B;AACxD,QAAMC,SAAO,sBAAsB,MAAM,KAAK,KAAK,GAAG,CAAC;AACvD,MAAI,MAAM,SAAS,qBAAqB;AACtC,WAAO,sBAAsB,sBAAsB,MAAM,KAAK,KAAK,MAAM,CAAC,CAAC;AAAA,EAC7E;AACA,SAAOA,SACH,GAAGA,MAAI,KAAK,sBAAsB,MAAM,OAAO,CAAC,KAChD,sBAAsB,MAAM,OAAO;AACzC;AAEO,SAAS,gBAAgB,OAA6B;AAC3D,SAAO,MAAM,OAAO,IAAI,cAAc;AACxC;;;AChBO,IAAMC,eAAc,CAAC,UAAU,QAAQ,SAAS,SAAS,SAAS;AAIlE,IAAMC,gBAAe,CAAC,OAAO,UAAU,QAAQ,SAAS,KAAK;AAI7D,IAAM,mBAAmB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAaO,IAAM,mBAAmB,CAAC,UAAU;AAkBpC,IAAM,aAAa,CAAC,MAAM,IAAI;;;AFN9B,IAAM,kBAAkBC,GAAE,KAAKC,YAAW;AAE1C,IAAM,oBAAoBD,GAAE,KAAKE,aAAY;AAE7C,IAAM,uBAAuBF,GAAE,KAAK,gBAAgB;AAEpD,IAAM,kBAAkBA,GAAE,KAAK,WAAW;AAG1C,IAAM,qBAAqBA,GAAE,OAAO,EAAE;AAAA,EAC3C,CAAC,QAA6B;AAC5B,QAAI,QAAQ,sBAAuB,QAAO;AAC1C,QAAK,WAAiC,SAAS,GAAG,EAAG,QAAO;AAE5D,WAAO,mBAAmB,KAAK,GAAG;AAAA,EACpC;AAAA,EACA;AAAA,IACE,SAAS;AAAA,EACX;AACF;AAEO,IAAM,wBAAoDA,GAAE,OAAO;AAAA,EACxE,MAAMA,GAAE,KAAK,CAAC,WAAW,UAAU,QAAQ,CAAC;AAAA,EAC5C,SAASA,GAAE,OAAO,EAAE,cAAc;AAAA,EAClC,QAAQA,GAAE,OAAO,EAAE,cAAc;AAAA,EACjC,QAAQA,GAAE,OAAO,EAAE,cAAc;AACnC,CAAC;AAYM,IAAM,4BAAqEA,GAAE,OAAO;AAAA,EACzF,SAASA,GAAE,OAAO,EAAE,cAAc;AAAA,EAClC,OAAOA,GAAE,MAAM,qBAAqB,EAAE,cAAc;AACtD,CAAC;AAGM,IAAM,oBAAoBA,GAAE,OAAOA,GAAE,OAAO,GAAGA,GAAE,MAAM,yBAAyB,CAAC;AAWjF,IAAM,uBAAuBA,GAAE,KAAK,gBAAgB;AAWpD,IAAM,0BAA0BA,GACpC,OAAO;AAAA,EACN,UAAUA,GAAE,KAAK,UAAU,EAAE,cAAc;AAC7C,CAAC,EACA,OAAO;AAGV,IAAM,kCAAkCA,GAAE,OAAO;AAAA,EAC/C,SAASA,GAAE,OAAO,EAAE,cAAc;AAAA,EAClC,OAAOA,GAAE,MAAM,qBAAqB,EAAE,IAAI,CAAC;AAC7C,CAAC;AAGM,IAAM,0BAA0BA,GAAE;AAAA,EACvCA,GAAE,OAAO;AAAA,EACTA,GAAE,MAAM,+BAA+B;AACzC;AAEO,IAAM,wBAAoDA,GAAE,OAAO;AAAA,EACxE,IAAIA,GAAE,OAAO;AAAA,EACb,WAAWA,GAAE,QAAQ,EAAE,cAAc;AAAA,EACrC,OAAOA,GAAE,QAAQ,EAAE,cAAc;AAAA,EACjC,MAAMA,GAAE,OAAO,EAAE,cAAc;AACjC,CAAC;AAGM,IAAM,+BAA+BA,GAAE,OAAO;AAAA;AAAA,EAEnD,MAAMA,GAAE,OAAO;AAAA,EACf,aAAaA,GAAE,OAAO;AAAA,EACtB,OAAO,gBAAgB,cAAc;AACvC,CAAC;AAaM,IAAM,4BAA4BA,GACtC,OAAO;AAAA,EACN,UAAU,mBAAmB,cAAc;AAAA,EAC3C,QAAQA,GAAE,OAAO,EAAE,cAAc;AAAA,EACjC,QAAQA,GAAE,OAAO;AAAA,EACjB,QAAQA,GAAE,QAAQ,EAAE,cAAc;AACpC,CAAC,EACA,YAAY;AAMR,IAAM,0BAA0BA,GAAE,OAAO;AAAA,EAC9C,UAAU;AAAA,EACV,QAAQA,GAAE,OAAO;AAAA,EACjB,aAAaA,GAAE,OAAO,EAAE,cAAc;AAAA,EACtC,MAAMA,GAAE,OAAO;AAAA,EACf,gBAAgBA,GAAE,OAAO,EAAE,cAAc;AAAA,EACzC,eAAeA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAExC,QAAQA,GAAE,OAAO;AAAA,EACjB,QAAQA,GAAE,QAAQ,EAAE,cAAc;AACpC,CAAC;AAEM,IAAM,qBAA8CA,GAAE,OAAO;AAAA,EAClE,MAAMA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACtB,OAAOA,GAAE,OAAO,EAAE,cAAc;AAClC,CAAC;AAGD,IAAM,6BAA6BA,GAAE,OAAO;AAAA,EAC1C,MAAMA,GAAE,OAAO;AAAA,EACf,SAASA,GAAE,OAAO,EAAE,cAAc;AAAA,EAClC,aAAaA,GAAE,OAAO,EAAE,cAAc;AAAA,EACtC,QAAQ,mBAAmB,cAAc;AAAA;AAAA,EAEzC,UAAUA,GAAE,OAAO,EAAE,cAAc;AAAA,EACnC,UAAUA,GAAE,MAAMA,GAAE,OAAO,CAAC,EAAE,cAAc;AAAA,EAC5C,UAAUA,GAAE,MAAM,CAACA,GAAE,OAAO,GAAGA,GAAE,MAAMA,GAAE,OAAO,CAAC,CAAC,CAAC,EAAE,cAAc;AAAA,EACnE,QAAQA,GAAE,MAAM,CAACA,GAAE,OAAO,GAAGA,GAAE,MAAMA,GAAE,OAAO,CAAC,CAAC,CAAC,EAAE,cAAc;AAAA,EACjE,QAAQA,GAAE,MAAM,CAACA,GAAE,OAAO,GAAGA,GAAE,MAAMA,GAAE,OAAO,CAAC,CAAC,CAAC,EAAE,cAAc;AAAA,EACjE,OAAOA,GAAE,MAAM,CAACA,GAAE,OAAO,GAAG,iBAAiB,CAAC,EAAE,cAAc;AAChE,CAAC;AAGM,IAAM,uBAAkD;AAGxD,IAAM,iCAAiC,2BAA2B,OAAO;AAEzE,IAAM,wBAAoDA,GAAE,OAAO;AAAA,EACxE,IAAIA,GAAE,OAAO;AAAA,EACb,OAAOA,GAAE,OAAO;AAAA,EAChB,aAAaA,GAAE,OAAO;AAAA,EACtB,OAAO,gBAAgB,cAAc;AAAA,EACrC,QAAQ,kBAAkB,cAAc;AAAA,EACxC,OAAOA,GAAE,MAAMA,GAAE,OAAO,CAAC;AAAA,EACzB,iBAAiBA,GAAE,MAAMA,GAAE,OAAO,CAAC,EAAE,cAAc;AAAA,EACnD,gBAAgB,qBAAqB,cAAc;AAAA,EACnD,WAAW,qBAAqB,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAS9C,OAAO,wBAAwB,cAAc;AAAA,EAC7C,cAAc,wBAAwB,cAAc;AAAA,EACpD,cAAcA,GAAE,OAAO,EAAE,cAAc;AAAA,EACvC,QAASA,GAAE,OAAO,EAAwB,cAAc;AAAA,EACxD,QAAQA,GAAE,QAAQ,EAAE,cAAc;AACpC,CAAC;AAID,IAAM,+BAA+BA,GAAE,MAAM;AAAA,EAC3CA,GAAE,OAAO;AAAA,EACT;AACF,CAAC;AAOM,IAAM,yBAAyBA,GAAE;AAAA,EACtCA,GAAE,OAAO;AAAA,EACTA,GAAE,MAAM,CAAC,8BAA8BA,GAAE,MAAM,4BAA4B,CAAC,CAAC;AAC/E;AAQA,IAAM,wBAAwB,EAAE,QAAQ,cAAc;AAMtD,IAAM,6BAA6B,EAAE,QAAQ,SAAS;AAKtD,SAAS,oBAAoB,QAAgB,QAAwB;AACnE,SAAO,IAAI,MAAM,qBAAqB,MAAM,kEAA6D,MAAM;AACjH;AAEA,SAAS,kBACP,QACA,SACAG,QACA,KACM;AACN,aAAW,CAAC,QAAQ,MAAM,KAAK,OAAO,QAAQ,OAAO,GAAG;AACtD,QAAI,EAAE,UAAU,QAAS;AACzB,QAAI,SAAS;AAAA,MACX,MAAM;AAAA,MACN,MAAM,CAAC,GAAGA,QAAM,MAAM;AAAA,MACtB,SAAS,oBAAoB,QAAQ,MAAM;AAAA,IAC7C,CAAC;AAAA,EACH;AACF;AAWA,SAAS,oBAAoB,QAAiB,KAA4B;AACxE,MAAI,CAAC,SAAS,MAAM,EAAG;AAEvB,oBAAkB,QAAQ,uBAAuB,CAAC,GAAG,GAAG;AAExD,QAAM,EAAE,OAAO,IAAI;AACnB,MAAI,CAAC,MAAM,QAAQ,MAAM,EAAG;AAC5B,aAAW,CAAC,OAAO,KAAK,KAAK,OAAO,QAAQ,GAAG;AAC7C,QAAI,CAAC,SAAS,KAAK,EAAG;AACtB,sBAAkB,OAAO,4BAA4B,CAAC,UAAU,KAAK,GAAG,GAAG;AAAA,EAC7E;AACF;AAOA,IAAM,oBAAoBH,GAAE,QAAQ,EAAE,YAAY,mBAAmB;AAGrE,IAAM,sBAAsBA,GACzB,OAAO;AAAA;AAAA,EAEN,MAAMA,GAAE,OAAO,EAAE,cAAc;AAAA,EAC/B,aAAaA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAEtC,QAAQA,GACL;AAAA,IACCA,GAAE,OAAO;AAAA,MACP,MAAMA,GAAE,OAAO;AAAA,MACf,OAAOA,GAAE,KAAK,CAAC,WAAW,QAAQ,CAAC;AAAA;AAAA,MAEnC,OAAO,gBAAgB,cAAc;AAAA,MACrC,QAAQ,kBAAkB,cAAc;AAAA,MACxC,UAAUA,GAAE,QAAQ,EAAE,cAAc;AAAA,IACtC,CAAC;AAAA,EACH,EACC,cAAc;AAAA;AAAA,EAEjB,QAAQA,GACL;AAAA,IACCA,GAAE,OAAO;AAAA,MACP,IAAIA,GAAE,OAAO;AAAA,MACb,OAAOA,GAAE,KAAK,CAAC,WAAW,QAAQ,CAAC;AAAA,MACnC,QAAQA,GAAE,OAAO;AAAA,MACjB,UAAUA,GAAE,QAAQ,EAAE,cAAc;AAAA,IACtC,CAAC;AAAA,EACH,EACC,cAAc;AAAA;AAAA,EAGjB,QAAQA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAEjC,iBAAiBA,GAAE,MAAMA,GAAE,OAAO,CAAsB,EAAE,cAAc;AAAA;AAAA,EAExE,OAAOA,GAAE,OAAOA,GAAE,OAAO,GAAG,sBAAsB,EAAE,cAAc;AAAA;AAAA,EAElE,aAAaA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAEtC,iBAAiBA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAE1C,cAAcA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAEvC,UAAUA,GAAE,MAAMA,GAAE,OAAO,CAAC,EAAE,cAAc;AAC9C,CAAC,EACA,YAAY;AAOR,IAAM,4BAA4B,kBAAkB,KAAK,mBAAmB;AAEnF,IAAM,2BAA0DA,GAAE,OAAO;AAAA,EACvE,IAAIA,GAAE,OAAO;AAAA,EACb,aAAaA,GAAE,OAAO;AAAA,EACtB,aAAaA,GAAE,OAAO;AAAA,EACtB,QAASA,GAAE,OAAO,EAAwB,cAAc;AAAA,EACxD,WAAWA,GAAE,QAAQ;AAAA,EACrB,OAAOA,GAAE,OAAO;AAAA,EAChB,MAAMA,GAAE,OAAO,EAAE,cAAc;AACjC,CAAC;AAiBD,SAAS,wBAAwB,OAAwB;AACvD,QAAM,QAAQ,OAAO,UAAU,WAAW,IAAI,KAAK,MAAM;AACzD,SACE,GAAG,KAAK;AAKZ;AAGA,IAAM,kBAAkBA,GAAE,KAAK,aAAa;AAAA,EAC1C,OAAO,CAAC,UAAU,wBAAwB,MAAM,KAAK;AACvD,CAAC;AAGD,IAAM,uBAAuBA,GAAE,OAAO;AAAA,EACpC,QAAQA,GAAE,MAAM,eAAe,EAAE,IAAI,CAAC;AAAA,EACtC,QAAQA,GAAE,OAAO;AACnB,CAAC;AAED,IAAM,qBAA8C;AAEpD,IAAM,uBAAkD;AAExD,IAAM,oBAA4CA,GAAE,OAAO;AAAA,EACzD,OAAO;AAAA,EACP,OAAOA,GAAE,MAAM,eAAe,EAAE,IAAI,CAAC;AAAA,EACrC,UAAUA,GAAE,QAAQ,EAAE,cAAc;AAAA,EACpC,QAAQA,GAAE,OAAO;AACnB,CAAC;AAED,IAAM,yBAAsDA,GAAE,OAAO;AAAA,EACnE,SAASA,GAAE,OAAO;AAAA,EAClB,QAAQA,GAAE,MAAM,eAAe,EAAE,IAAI,CAAC;AACxC,CAAC;AAED,IAAM,gCAAoEA,GAAE,OAAO;AAAA,EACjF,WAAWA,GAAE,MAAM,kBAAkB;AAAA,EACrC,aAAaA,GAAE,MAAM,oBAAoB;AAAA,EACzC,UAAUA,GAAE,MAAM,iBAAiB;AAAA,EACnC,cAAcA,GAAE,MAAM,sBAAsB;AAC9C,CAAC;AAMM,IAAM,4BAA4BA,GAAE,OAAO;AAAA,EAChD,SAASA,GAAE,OAAO;AAAA,EAClB,YAAYA,GAAE,OAAOA,GAAE,OAAO,GAAG,wBAAwB;AAC3D,CAAC;AAMM,IAAM,uBAAuBA,GAAE,OAAO;AAAA,EAC3C,SAASA,GAAE,OAAO;AAAA,EAClB,eAAe,8BAA8B,cAAc;AAC7D,CAAC;AAMM,IAAM,yBAAyBA,GACnC,OAAO;AAAA;AAAA,EAEN,aAAaA,GAAE,OAAO;AAAA;AAAA,EAEtB,MAAMA,GAAE,OAAO;AAAA;AAAA,EAEf,gBAAgBA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAEzC,UAAU;AAAA;AAAA,EAEV,eAAeA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAExC,QAAQA,GAAE,OAAO;AAAA;AAAA,EAEjB,QAAQA,GAAE,QAAQ,EAAE,cAAc;AACpC,CAAC,EAGA,YAAY;AAGR,IAAM,2BAA2BA,GACrC,OAAO;AAAA,EACN,YAAYA,GACT,OAAO;AAAA;AAAA,IAEN,SAASA,GAAE,OAAO;AAAA;AAAA,IAElB,aAAaA,GAAE,OAAO;AAAA;AAAA,IAEtB,MAAMA,GAAE,OAAO;AAAA;AAAA,IAEf,QAAQA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,IAEjC,MAAMA,GAAE,OAAO,EAAE,cAAc;AAAA,EACjC,CAAC,EACA,cAAc;AACnB,CAAC,EAGA,YAAY;AAEf,IAAM,cAAcA,GAAE,OAAO;AAAA,EAC3B,IAAIA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACpB,MAAMA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACtB,aAAaA,GAAE,OAAO;AAAA;AAAA,EAEtB,QAAQA,GAAE,OAAOA,GAAE,OAAO,GAAG,sBAAsB;AAAA;AAAA,EAEnD,YAAYA,GAAE,OAAO,EAAE,cAAc;AACvC,CAAC;AAIM,IAAM,qBAAqBA,GAAE,OAAO;AAAA,EACzC,QAAQA,GAAE,MAAM,WAAW,EAAE,IAAI,CAAC;AACpC,CAAC;AAED,IAAM,gCAAoEA,GAAE,OAAO;AAAA,EACjF,QAAQA,GAAE,KAAK,CAAC,UAAU,KAAK,CAAC;AAAA,EAChC,MAAMA,GAAE,OAAO,EAAE,cAAc;AAAA,EAC/B,KAAKA,GAAE,OAAO,EAAE,cAAc;AAAA,EAC9B,KAAKA,GAAE,OAAO,EAAE,cAAc;AAChC,CAAC;AAED,IAAM,0BAAwDA,GAAE,OAAO;AAAA,EACrE,MAAMA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA,EAEtB,QAAQA,GAAE,MAAM,CAACA,GAAE,OAAO,GAAG,6BAA6B,CAAC;AAAA,EAC3D,aAAaA,GAAE,OAAO,EAAE,cAAc;AAAA,EACtC,SAASA,GAAE,OAAO,EAAE,cAAc;AAAA,EAClC,QAAQ,mBAAmB,cAAc;AAAA;AAAA,EAEzC,UAAUA,GAAE,OAAO,EAAE,cAAc;AAAA,EACnC,UAAUA,GAAE,MAAMA,GAAE,OAAO,CAAC,EAAE,cAAc;AAC9C,CAAC;AAGD,IAAM,yBAAsD;AAE5D,IAAM,4BAA4DA,GAAE,OAAO;AAAA;AAAA,EAEzE,YAAYA,GAAE,OAAO,EAAE,cAAc;AACvC,CAAC;AAcD,IAAM,2BACJ;AAEK,IAAM,oBAA4CA,GAAE,OAAO;AAAA,EAChE,SAASA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMlC,MAAMA,GAAE,OAAO,EAAE,IAAI,CAAC,EAAE,MAAM,oBAAoB,EAAE,SAAS,yBAAyB,CAAC;AAAA,EACvF,SAASA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACzB,aAAaA,GAAE,OAAO,EAAE,cAAc;AAAA,EACtC,OAAO;AAAA,EACP,UAAU,0BAA0B,cAAc;AAAA,EAClD,SAASA,GAAE,MAAM,uBAAuB,EAAE,IAAI,CAAC;AACjD,CAAC;AAUM,IAAM,2BAA2BA,GAAE,OAAO;AAAA;AAAA,EAE/C,KAAKA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACrB,MAAMA,GAAE,OAAO,EAAE,IAAI,CAAC,EAAE,cAAc;AACxC,CAAC;AAGD,IAAM,yBAAyBA,GAAE,OAAO;AAAA;AAAA,EAEtC,OAAOA,GAAE,MAAMA,GAAE,OAAO,CAAC,EAAE,cAAc;AAAA;AAAA,EAEzC,MAAMA,GAAE,MAAMA,GAAE,OAAO,CAAC,EAAE,cAAc;AAC1C,CAAC;AAGM,IAAM,qBAAqBA,GAC/B,OAAO;AAAA,EACN,aAAa,uBAAuB,cAAc;AACpD,CAAC,EACA,YAAY;AAGf,IAAM,uBAAuBA,GAAE,OAAO;AAAA;AAAA,EAEpC,MAAMA,GAAE,OAAO,EAAE,cAAc;AACjC,CAAC;AAGD,IAAM,4BAA4BA,GAC/B,OAAO;AAAA;AAAA,EAEN,aAAaA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAEtC,QAAQA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAEjC,iBAAiBA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAE1C,cAAcA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAEvC,UAAU,qBAAqB,cAAc;AAAA;AAAA,EAE7C,WAAWA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAEpC,WAAWA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAEpC,YAAYA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAErC,gBAAgBA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAEzC,WAAWA,GAAE,OAAO,EAAE,cAAc;AACtC,CAAC,EACA,YAAY;AAMR,IAAM,4BAA4B,kBAAkB,KAAK,yBAAyB;AAclF,IAAM,4BAA4BA,GACtC,OAAO;AAAA,EACN,SAASA,GAAE,OAAO,EAAE,cAAc;AAAA,EAClC,IAAIA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACpB,OAAOA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACvB,aAAaA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC7B,OAAO,gBAAgB,cAAc;AAAA,EACrC,QAAQ,kBAAkB,cAAc;AAAA,EACxC,OAAOA,GAAE,MAAMA,GAAE,OAAO,CAAC,EAAE,IAAI,CAAC;AAAA,EAChC,iBAAiBA,GAAE,MAAMA,GAAE,OAAO,CAAC,EAAE,cAAc;AAAA,EACnD,gBAAgB,qBAAqB,cAAc;AAAA,EACnD,WAAW,qBAAqB,cAAc;AAAA,EAC9C,OAAO,wBAAwB,cAAc;AAAA,EAC7C,cAAc,wBAAwB,cAAc;AAAA,EACpD,cAAcA,GAAE,OAAO,EAAE,cAAc;AAAA,EACvC,QAASA,GAAE,OAAO,EAAwB,cAAc;AAAA,EACxD,QAAQA,GAAE,QAAQ,EAAE,cAAc;AACpC,CAAC,EACA,OAAO;AAeH,IAAM,mCAAmCA,GAC7C,OAAO;AAAA;AAAA,EAEN,MAAMA,GAAE,OAAO,EAAE,MAAM,kBAAkB,EAAE,IAAI,CAAC;AAAA,EAChD,aAAaA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA,EAE7B,OAAOA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAEhC,iBAAiBA,GAAE,OAAO,EAAE,cAAc;AAAA,EAC1C,OAAO,gBAAgB,cAAc;AAAA,EACrC,QAAQ,kBAAkB,cAAc;AAAA,EACxC,gBAAgB,qBAAqB,cAAc;AAAA,EACnD,WAAW,qBAAqB,cAAc;AAAA,EAC9C,cAAc,wBAAwB,cAAc;AAAA;AAAA,EAEpD,QAAQA,GAAE,MAAMA,GAAE,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,cAAc;AAAA,EACjD,OAAO,wBAAwB,cAAc;AAC/C,CAAC,EACA,OAAO;AAGH,IAAM,mCAAmCA,GAC7C,OAAO;AAAA,EACN,MAAMA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACtB,aAAaA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA,EAE7B,4BAA4BA,GAAE,QAAQ,EAAE,cAAc;AAAA;AAAA,EAEtD,kBAAkBA,GAAE,QAAQ,EAAE,cAAc;AAAA;AAAA,EAE5C,iBAAiBA,GAAE,OAAO,EAAE,cAAc;AAAA,EAC1C,OAAO,gBAAgB,cAAc;AAAA;AAAA,EAErC,SAASA,GAAE,KAAK,CAAC,MAAM,CAAC,EAAE,cAAc;AAAA;AAAA,EAExC,OAAOA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAEhC,iBAAiBA,GAAE,OAAO,EAAE,cAAc;AAC5C,CAAC,EACA,OAAO;AAQV,IAAM,mBAAmBA,GAAE,OAAO;AAAA;AAAA,EAEhC,SAASA,GAAE,OAAO;AAAA;AAAA,EAElB,SAASA,GAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,cAAc;AAAA;AAAA,EAE/C,aAAaA,GAAE,OAAO;AAAA;AAAA,EAEtB,QAAQA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAEjC,MAAMA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAE/B,MAAMA,GAAE,OAAO;AACjB,CAAC;AAQD,IAAM,6BAA6B;AAOnC,IAAM,0BAA0BA,GAAE,OAAO;AAAA;AAAA,EAEvC,QAAQA,GAAE,OAAO,EAAE,MAAM,qBAAqB;AAAA;AAAA,EAE9C,aAAaA,GAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA;AAAA,EAErC,gBAAgBA,GAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,0BAA0B;AAAA;AAAA,EAEhE,eAAeA,GAAE,OAAO,EAAE,IAAI,EAAE;AAAA;AAAA,EAEhC,aAAaA,GACV,OAAO,EACP,MAAM,eAAe,EACrB,cAAc;AAAA;AAAA,EAEjB,SAASA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAElC,YAAY,iBAAiB,cAAc;AAAA;AAAA,EAE3C,QAASA,GAAE,OAAO,EAAwB,cAAc;AAAA;AAAA,EAExD,QAAQA,GAAE,QAAQ,EAAE,cAAc;AACpC,CAAC;AAkBD,SAAS,2BAA2B,OAAwB;AAC1D,QAAM,QAAQ,OAAO,UAAU,WAAW,IAAI,KAAK,MAAM;AACzD,SACE,GAAG,KAAK,2JAC6D,cAAc,MAAM,6BACpE,eAAe,aAAa;AAIrD;AAGO,IAAM,2BAA2B,wBACrC,OAAO;AAAA;AAAA,EAEN,UAAUA,GAAE,KAAK,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA,EAK3B,MAAMA,GAAE,KAAK,aAAa;AAAA,IACxB,OAAO,CAAC,UAAU,2BAA2B,MAAM,KAAK;AAAA,EAC1D,CAAC;AACH,CAAC,EACA,OAAO;AAGH,IAAM,iCAAiC,wBAAwB,OAAO;AAAA;AAAA,EAE3E,UAAUA,GAAE,OAAO;AAAA;AAAA,EAEnB,MAAMA,GAAE,OAAO,EAAE,MAAM,kBAAkB,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAC1D,CAAC;AAED,IAAM,6BAA6BA,GAChC,OAAO;AAAA,EACN,IAAIA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA,EAEpB,WAAWA,GAAE,QAAQ,EAAE,cAAc;AACvC,CAAC,EACA,OAAO;AAGH,IAAM,8BAA8BA,GACxC,OAAO;AAAA;AAAA,EAEN,IAAIA,GAAE,OAAO,EAAE,MAAM,kBAAkB,EAAE,cAAc;AAAA,EACvD,MAAMA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACtB,SAASA,GAAE,OAAO;AAAA,EAClB,QAAQA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACxB,aAAaA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAEtC,SAASA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAElC,SAASA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAElC,WAAWA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAEpC,QAAQA,GAAE,MAAM,0BAA0B,EAAE,IAAI,CAAC;AAAA;AAAA,EAEjD,QAAQA,GAAE,MAAMA,GAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC,EAAE,IAAI,CAAC;AAAA;AAAA,EAE3D,aAAaA,GACV,OAAOA,GAAE,OAAO,GAAGA,GAAE,OAAOA,GAAE,OAAO,GAAGA,GAAE,MAAM,0BAA0B,CAAC,CAAC,EAC5E,cAAc;AAAA;AAAA,EAEjB,YAAYA,GAAE,OAAO,EAAE,cAAc;AAAA;AAAA,EAErC,YAAYA,GAAE,MAAMA,GAAE,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,cAAc;AAAA,EACrD,MAAMA,GAAE,MAAMA,GAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC,EAAE,cAAc;AAAA;AAAA,EAElE,WAAWA,GACR;AAAA,IACCA,GAAE,OAAO;AAAA,IACTA,GACG,OAAO;AAAA;AAAA,MAEN,cAAcA,GAAE,MAAMA,GAAE,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,cAAc;AAAA;AAAA,MAEvD,QAAQA,GAAE,QAAQ,EAAE,cAAc;AAAA,IACpC,CAAC,EACA,OAAO;AAAA,EACZ,EACC,cAAc;AAAA;AAAA,EAEjB,SAASA,GACN,OAAO;AAAA,IACN,SAASA,GAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,cAAc;AAAA,IAC/C,WAAWA,GAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,cAAc;AAAA,EACnD,CAAC,EACA,OAAO,EACP,cAAc;AAAA;AAAA,EAEjB,OAAO,wBAAwB,cAAc;AAC/C,CAAC,EACA,OAAO;AAGH,SAAS,gBAAgB,QAA8B;AAC5D,SAAO,OAAO,IAAI,cAAc,EAAE,KAAK,IAAI;AAC7C;AAOO,SAAS,sBAAsB,aAAsB;AAC1D,QAAM,SAAS,iBAAiB,WAAW,IACvC,iCACA;AACJ,SAAO,OAAO,UAAU,WAAW;AACrC;AAQO,SAAS,8BACd,QACA,aACQ;AACR,QAAM,CAAC,QAAQ,SAAS,IAAI,UAAU,QAAQ,CAAC,UAAU,cAAc,OAAO,WAAW,CAAC;AAC1F,SAAO;AAAA,IACL,GAAI,OAAO,SAAS,IAAI,CAAC,kBAAkB,MAAM,CAAC,IAAI,CAAC;AAAA,IACvD,GAAG,UAAU,IAAI,cAAc;AAAA,EACjC,EAAE,KAAK,IAAI;AACb;AAGA,SAAS,cAAc,OAAmB,aAA+C;AACvF,QAAM,CAAC,OAAO,GAAG,MAAM,IAAI,MAAM;AACjC,SAAO,OAAO,WAAW,KAAK,OAAO,UAAU,YAAY,YAAY,KAAK,MAAM;AACpF;AAEA,SAAS,kBAAkB,QAA8B;AACvD,QAAM,SAAS,OAAO,IAAI,CAAC,UAAU,MAAM,KAAK,KAAK,GAAG,CAAC;AACzD,SAAO,oBAAoB,OAAO,WAAW,IAAI,UAAU,QAAQ,KAAK,OAAO,KAAK,IAAI,CAAC;AAC3F;AAUA,SAAS,2BAA2B,OAA4B;AAC9D,SAAO,MAAM,SAAS,aAAa,MAAM,KAAK,WAAW,KAAK,MAAM,KAAK,CAAC,MAAM;AAClF;AAGA,SAAS,mBAAmB,KAAkC;AAC5D,MAAI,OAAO,QAAQ,OAAO,QAAQ,SAAU,QAAO;AAEnD,QAAM,QAAS,IAAqC;AACpD,SAAO,OAAO,UAAU,WAAW,QAAQ;AAC7C;AAOA,SAAS,wBAAwB,OAAmB,gBAA4C;AAC9F,MAAI,mBAAmB,OAAW,QAAO,eAAe,KAAK;AAC7D,SAAO,qBAAqB,eAAe,MAAM,yDAAoD,0BAA0B;AACjI;AAUO,SAAS,8BACd,OACA,aACoB;AACpB,QAAM,CAAC,YAAY,YAAY,IAAI,UAAU,MAAM,QAAQ,0BAA0B;AAErF,QAAM,iBAAiB,mBAAmB,WAAW;AACrD,QAAM,WAAW,WAAW,IAAI,CAAC,UAAU,wBAAwB,OAAO,cAAc,CAAC;AAEzF,SAAO,EAAE,QAAQ,aAAa,IAAI,cAAc,GAAG,SAAS;AAC9D;AAMO,SAAS,qBAAqB,OAAgB,UAA2B;AAC9E,WAAS,MAAM,KAAc,OAAwB;AACnD,QAAI,QAAQ,SAAU,QAAO;AAC7B,QAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,aAAO,IAAI,MAAM,CAAC,SAAS,MAAM,MAAM,QAAQ,CAAC,CAAC;AAAA,IACnD;AACA,QAAI,QAAQ,QAAQ,OAAO,QAAQ,UAAU;AAC3C,aAAO,OAAO,OAAO,GAAG,EAAE,MAAM,CAAC,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC;AAAA,IAC5D;AACA,WAAO;AAAA,EACT;AACA,SAAO,MAAM,OAAO,CAAC;AACvB;AAMO,SAAS,iBAAiB,KAAuB;AACtD,MAAI,OAAO,QAAQ,OAAO,QAAQ,SAAU,QAAO;AACnD,MAAI,EAAE,YAAY,KAAM,QAAO;AAC/B,SAAO,IAAI,WAAW;AACxB;AASO,SAAS,kBACd,QACA,cACA,SACM;AACN,QAAM,cAAc,IAAI,IAAI,YAAY;AACxC,QAAM,cAAc,OAAO,KAAK,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,YAAY,IAAI,CAAC,CAAC;AACzE,MAAI,YAAY,SAAS,GAAG;AAC1B,SAAK,qBAAqB,OAAO,KAAK,YAAY,KAAK,IAAI,CAAC,EAAE;AAAA,EAChE;AACF;;;AGzhCA,OAAOI,WAAU;AACjB,SAAS,qBAAqB;AAC9B,SAAS,kBAAkB;AAS3B,IAAM,sBAAsBC,MAAK;AAAA,EAC/BA,MAAK,QAAQ,cAAc,YAAY,GAAG,CAAC;AAAA,EAC3C;AACF;AAWO,IAAM,oBAAN,cAAgC,MAAM;AAAA,EAC3C,YACW,YACA,QACT;AACA,UAAM,gCAAgC,UAAU,MAAM,MAAM,EAAE;AAHrD;AACA;AAGT,SAAK,OAAO;AAAA,EACd;AAAA,EALW;AAAA,EACA;AAKb;AAYO,IAAM,2BAAN,cAAuC,MAAM;AAAA,EAClD,YAAqB,YAAoB;AACvC,UAAM,cAAc,UAAU,yBAAyB;AADpC;AAEnB,SAAK,OAAO;AAAA,EACd;AAAA,EAHqB;AAIvB;AAQA,IAAM,mBAAmB;AAOzB,SAAS,oBAAoB,WAA6B;AACxD,MAAI,SAAS,SAAS,KAAK,UAAU,YAAY,OAAW,QAAO,UAAU;AAC7E,SAAO;AACT;AAGA,SAAS,wBAAwB,WAA6B;AAC5D,SAAO,SAAS,SAAS,KAAK,oBAAoB,aAAa,EAAE,aAAa;AAChF;AAOO,IAAM,0BAA0B;AAGvC,SAAS,eAAe,OAAyB;AAC/C,SAAO,SAAS,QAAS,OAAO,UAAU,YAAY,OAAO,KAAK,KAAK,EAAE,WAAW;AACtF;AAWA,eAAsB,WAAc,YAAoB,QAA0C;AAChG,MAAI,CAAE,MAAM,WAAW,UAAU,GAAI;AACnC,YAAQ,uBAAuB,UAAU,EAAE;AAC3C,WAAO;AAAA,EACT;AAEA,MAAI;AACJ,MAAI;AASF,UAAM,OAAO,WAAW,YAAY,KAAK;AAAA,MACvC,aAAa;AAAA,MACb,gBAAgB;AAAA,MAChB,OAAO,EAAE,qBAAqB,oBAAoB;AAAA,IACpD,CAAC;AAED,gBAAY,MAAM,KAAK,OAAO,UAAU;AAAA,EAC1C,SAAS,OAAO;AACd,UAAM,IAAI,MAAM,+BAA+B,UAAU,MAAM,gBAAgB,KAAK,CAAC,IAAI;AAAA,MACvF,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,QAAM,MAAM,oBAAoB,SAAS;AAKzC,MAAI,eAAe,GAAG,GAAG;AACvB,YAAQ,aAAa,UAAU,kBAAkB;AACjD,WAAO;AAAA,EACT;AAEA,MAAI,wBAAwB,SAAS,GAAG;AACtC,UAAM,IAAI,yBAAyB,UAAU;AAAA,EAC/C;AAEA,MAAI,QAAQ;AACV,UAAM,SAAS,OAAO,UAAU,GAAG;AACnC,QAAI,CAAC,OAAO,SAAS;AACnB,YAAM,IAAI,kBAAkB,YAAY,gBAAgB,OAAO,MAAM,MAAM,CAAC;AAAA,IAC9E;AACA,WAAO,OAAO;AAAA,EAChB;AAGA,SAAO;AACT;;;ACrJA,OAAOC,WAAU;AAsCV,SAAS,qBAAqB,KAAa,UAA4B;AAC5E,SAAOC,MAAK,KAAK,kBAAkB,KAAK,QAAQ,EAAE,KAAK,eAAe,SAAS;AACjF;AAUO,SAAS,uBAAuB,KAAqB;AAC1D,SAAO,qBAAqB,KAAK,cAAc,GAAG,CAAC;AACrD;AA6BO,SAAS,oBACd,YACA,QAAoB,WACN;AACd,QAAM,UAAU,eAAe,YAAY,KAAK;AAIhD,QAAM,WAAW,cAAc,OAAO;AAEtC,SAAO;AAAA,IACL,WAAW,UAAU,UAAU,OAAO,UAAU;AAAA,IAChD,WAAW,UAAU,UAAU,OAAO,UAAU;AAAA,IAChD,YAAY,qBAAqB,SAAS,QAAQ;AAAA,EACpD;AACF;;;ALjEO,IAAM,iBAAiB;AAuE9B,eAAe,iBACb,KACA,OACwC;AACxC,QAAMC,cAAa,UAAU,YAAY,YAAY;AACrD,QAAM,aAAa,uBAAuB,GAAG;AAE7C,MAAI,CAAE,MAAM,WAAW,UAAU,GAAI;AACnC,YAAQ,GAAGA,WAAU,wBAAwB,UAAU,EAAE;AACzD,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,yBAAyB,YAAY,OAAO,GAAG;AAClE,QAAM,eAAe,MAAM,mBAAmB,YAAY,2BAA2B,UAAU;AAC/F,MAAI,iBAAiB,KAAM,OAAM,WAAW,uBAAuB;AACnE,QAAM,WAAW,aAAa,YAAY,YAAY;AAEtD,UAAQ,UAAU,KAAK,gBAAgB,GAAG,EAAE;AAC5C,SAAO;AACT;AASA,SAAS,yBACP,YACA,OACA,WACkB;AAClB,SAAO,CAAC,QAAQ,UACd,IAAI,MAAM,8BAA8B,CAAC,EAAE,YAAY,QAAQ,OAAO,UAAU,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC;AAClG;AAWA,eAAe,mBACb,YACA,QACA,YACmB;AACnB,MAAI;AACF,WAAO,MAAM,WAAW,YAAY,MAAM;AAAA,EAC5C,SAAS,OAAO;AACd,QAAI,qBAAqB,KAAK,EAAG,OAAM;AACvC,UAAM,WAAW,gBAAgB,KAAK,GAAG,KAAK;AAAA,EAChD;AACF;AAUA,SAAS,aAAa,YAAoB,cAA+C;AACvF,QAAM,WAAW,0BAA0B,UAAU,YAAY;AACjE,MAAI,CAAC,SAAS,SAAS;AACrB,UAAM,IAAI,kBAAkB,YAAY,gBAAgB,SAAS,MAAM,MAAM,CAAC;AAAA,EAChF;AACA,SAAO,SAAS;AAClB;AAUA,SAAS,qBAAqB,OAAyB;AACrD,SAAO,iBAAiB,qBAAqB,iBAAiB;AAChE;AAUA,IAAM,6BAA+C,CAAC,QAAQ,UAC5D,IAAI,MAAM,sBAAsB,MAAM,GAAG,EAAE,MAAM,CAAC;AAkBpD,eAAsB,qBACpB,UACwC;AACxC,aAAW,UAAU,4BAA4B;AAC/C,UAAM,WAAW,MAAM,mBAAmBC,MAAK,KAAK,UAAU,MAAM,CAAC;AACrE,QAAI,SAAU,QAAO;AAAA,EACvB;AACA,SAAO;AACT;AAGA,IAAM,6BAA6B,CAAC,iBAAiB,iBAAiB;AAGtE,eAAe,mBAAmB,KAAqD;AACrF,QAAM,aAAaA,MAAK,KAAK,KAAK,eAAe,SAAS;AAC1D,MAAI,CAAE,MAAM,WAAW,UAAU,GAAI;AACnC,YAAQ,8BAA8B,UAAU,EAAE;AAClD,WAAO;AAAA,EACT;AACA,SAAO,mBAAmB,YAAY,2BAA2B,0BAA0B;AAC7F;AAUA,eAAsB,wBACpB,YACwC;AACxC,SAAO,iBAAiB,YAAY,gBAAgB,UAAU,IAAI,WAAW,SAAS;AACxF;AAGA,eAAsB,yBAAiE;AACrF,SAAO,iBAAiBC,IAAG,QAAQ,GAAG,QAAQ;AAChD;AASA,eAAe,0BACb,YACuC;AACvC,QAAM,SAAS,cAAc,UAAU;AACvC,QAAM,MAAM,WAAW,OAAO,OAAO,MAAM,eAAe,QAAQ,SAAS;AAC3E,SAAO,OAAQ,MAAM,eAAeA,IAAG,QAAQ,GAAG,QAAQ;AAC5D;AAGA,eAAe,eACb,KACA,QACuC;AACvC,QAAM,SAAS,MAAM,iBAAiB,KAAK,MAAM;AACjD,SAAO,UAAU,EAAE,QAAQ,QAAQ,YAAY,uBAAuB,GAAG,EAAE;AAC7E;AAGA,SAAS,cAAc,YAA+C;AACpE,SAAO,eAAe,UAAa,gBAAgB,UAAU,IAAI,OAAO;AAC1E;AAWA,eAAe,2BACb,YACwC;AACxC,QAAM,SAAS,cAAc,UAAU;AACvC,SAAO,WAAW,OAAO,OAAO,wBAAwB,MAAM;AAChE;AAGA,SAAS,wBACP,WACqC;AACrC,MAAI,WAAW,OAAO,oBAAoB,OAAW,QAAO;AAC5D,SAAO;AAAA,IACL,aAAa,UAAU,OAAO;AAAA,IAC9B,uBAAuB,UAAU;AAAA,EACnC;AACF;AAMA,eAAsB,cAAc,SAAwD;AAC1F,QAAM,EAAE,QAAQ,MAAM,WAAW,IAAI;AACrC,QAAM,YAAY,MAAM,0BAA0B,UAAU;AAC5D,QAAM,eAAe,WAAW,OAAO,eAAe;AAKtD,QAAM,WAAW,wBAAwB,SAAS;AAClD,QAAM,WAAW,CAAC,WAAmB,WAAW,gBAAgB;AAEhE,MAAI,SAAS,QAAW;AACtB,4BAAwB,IAAI;AAC5B,YAAQ,kCAAkC,IAAI,EAAE;AAChD,WAAO,EAAE,QAAQ,MAAM,cAAc,QAAQ,GAAG,SAAS,IAAI,EAAE;AAAA,EACjE;AAEA,QAAM,YAAY,WAAW,SAAS,cAAc,IAAI;AACxD,MAAI,cAAc,QAAW;AAC3B,WAAO,EAAE,QAAQ,WAAW,cAAc,OAAO,GAAG,SAAS,SAAS,EAAE;AAAA,EAC1E;AAEA,MAAI,WAAW,OAAO,aAAa;AACjC,YAAQ,oBAAoB,UAAU,MAAM,YAAY,UAAU,OAAO,WAAW,EAAE;AACtF,WAAO;AAAA,MACL,QAAQ,UAAU,OAAO;AAAA,MACzB,cAAc,UAAU;AAAA,MACxB,GAAG,SAAS,UAAU,OAAO,WAAW;AAAA,IAC1C;AAAA,EACF;AAEA,UAAQ,8BAA8B,cAAc,EAAE;AACtD,SAAO,EAAE,QAAQ,gBAAgB,cAAc,WAAW,GAAG,SAAS,cAAc,EAAE;AACxF;AAUA,IAAM,qBAAqB;AAM3B,SAAS,wBAAwB,MAAoB;AACnD,MAAI,KAAK,KAAK,MAAM,IAAI;AACtB,UAAM,IAAI;AAAA,MACR,GAAG,kBAAkB;AAAA,IACvB;AAAA,EACF;AACA,uBAAqB,KAAK,KAAK,GAAG,kBAAkB;AACtD;AAUA,SAAS,gBAAoC;AAC3C,QAAM,WAAW,QAAQ,IAAI,cAAc;AAC3C,MAAI,CAAC,SAAU,QAAO;AAEtB,QAAM,UAAU,SAAS,KAAK;AAC9B,MAAI,YAAY,IAAI;AAClB,SAAK,GAAG,cAAc,sEAAiE;AACvF,WAAO;AAAA,EACT;AAEA,MAAI;AACF,yBAAqB,SAAS,cAAc;AAAA,EAC9C,SAAS,OAAO;AACd;AAAA,MACE,GAAG,cAAc;AAAA,EAAwE,gBAAgB,KAAK,CAAC;AAAA,IACjH;AACA,WAAO;AAAA,EACT;AAEA,UAAQ,oBAAoB,cAAc,aAAa,OAAO,EAAE;AAChE,SAAO;AACT;AA2BA,eAAsB,gBAAgB,YAAgD;AACpF,QAAM,CAAC,KAAK,MAAM,IAAI,MAAM,QAAQ,IAAI;AAAA,IACtC,2BAA2B,UAAU;AAAA,IACrC,uBAAuB;AAAA,EACzB,CAAC;AAED,SAAO;AAAA,IACL,MAAM,KAAK,UAAU,QAAQ,QAAQ,UAAU,QAAQ,iBAAiB;AAAA,EAC1E;AACF;AAWA,eAAsB,0BAA0B,YAA2C;AACzF,QAAM,iBAAiB,MAAM,cAAc,EAAE,QAAQ,UAAU,WAAW,CAAC;AAC3E,SAAO;AAAA,IACL,MAAM;AAAA,IACN,KAAK,eAAe;AAAA,IACpB,aAAa;AAAA,EACf;AACF;AAEA,IAAM,mBAAmB;AAAA,EACvB,cAAc;AAAA;AAAA,EACd,cAAc;AAAA;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGA,IAAM,yBAAyB;AAC/B,IAAM,oBAAoB;AAG1B,IAAM,oBAAoB;AAG1B,IAAM,yBAAyB;AAI/B,IAAM,mBAAmB;AAIzB,IAAM,uBACJ;AAGF,IAAM,uBACJ;AAUK,SAAS,qBAAqB,QAAgB,UAAwB;AAE3E,MAAI,kBAAkB,KAAK,MAAM,GAAG;AAClC,UAAM,IAAI;AAAA,MACR,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA,IAGJ,QAAQ;AAAA,IACR,QAAQ;AAAA,IACjB;AAAA,EACF;AAEA,MAAI,OAAO,SAAS,mBAAmB;AACrC,UAAM,IAAI;AAAA,MACR,GAAG,QAAQ,uBAAuB,OAAO,MAAM,oBAAoB,iBAAiB;AAAA;AAAA;AAAA;AAAA,IAG7E,QAAQ;AAAA,IACR,QAAQ;AAAA,IACjB;AAAA,EACF;AAEA,QAAM,kBAAkB,iBAAiB,KAAK,CAAC,WAAW,OAAO,WAAW,MAAM,CAAC;AAEnF,MAAI,iBAAiB;AACnB,yBAAqB,QAAQ,iBAAiB,QAAQ;AAAA,EACxD,OAAO;AACL,sBAAkB,QAAQ,QAAQ;AAAA,EACpC;AACF;AAEA,SAAS,qBAAqB,QAAgB,UAAkB,UAAwB;AACtF,QAAM,oBAAoB,OAAO,MAAM,SAAS,MAAM,EAAE,KAAK;AAE7D,MAAI,kBAAkB,SAAS,wBAAwB;AACrD,UAAM,IAAI;AAAA,MACR,GAAG,QAAQ,4BAA4B,MAAM;AAAA;AAAA;AAAA;AAAA,IAGtC,QAAQ;AAAA,IACR,QAAQ;AAAA,IACjB;AAAA,EACF;AAGA,MAAI,uBAAuB,KAAK,iBAAiB,GAAG;AAClD,UAAM,IAAI;AAAA,MACR,GAAG,QAAQ,qCAAqC,MAAM;AAAA;AAAA;AAAA;AAAA,IAG/C,QAAQ;AAAA,IACR,QAAQ;AAAA,IACjB;AAAA,EACF;AAGA,MAAI,aAAa,cAAc,aAAa,WAAW;AACrD,oBAAgB,QAAQ,QAAQ;AAChC;AAAA,EACF;AAGA,uBAAqB,QAAQ,mBAAmB,QAAQ;AAC1D;AAEA,SAAS,gBAAgB,QAAgB,UAAwB;AAE/D,QAAM,gBAAgB,OAAO,QAAQ,gBAAgB,EAAE;AAEvD,QAAM,mBAAmB,cAAc,MAAM,GAAG,EAAE,CAAC,KAAK;AACxD,QAAM,WAAW,iBAAiB,MAAM,GAAG,EAAE,CAAC,KAAK;AAEnD,MAAI,CAAC,kBAAkB,UAAU,gBAAgB,GAAG;AAClD,UAAM,IAAI;AAAA,MACR,GAAG,QAAQ,yBAAyB,MAAM;AAAA;AAAA;AAAA;AAAA,IAGnC,QAAQ;AAAA,IACR,QAAQ;AAAA,IACjB;AAAA,EACF;AAGA,MAAI,qBAAqB,KAAK,QAAQ,KAAK,qBAAqB,KAAK,gBAAgB,GAAG;AACtF,UAAM,IAAI;AAAA,MACR,GAAG,QAAQ,iDAAiD,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,IAI3D,QAAQ;AAAA,IACR,QAAQ;AAAA,IACjB;AAAA,EACF;AACF;AAMA,SAAS,kBAAkB,UAAkB,kBAAmC;AAC9E,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,kBAAkB,iBAAiB,WAAW,GAAG,KAAK,iBAAiB,SAAS,GAAG;AACzF,SAAO,SAAS,SAAS,GAAG,KAAK,aAAa,eAAe;AAC/D;AAEA,SAAS,qBAAqB,QAAgB,UAAkB,UAAwB;AAEtF,MAAI,CAAC,SAAS,SAAS,GAAG,GAAG;AAC3B,UAAM,IAAI;AAAA,MACR,GAAG,QAAQ,0CAA0C,MAAM;AAAA;AAAA;AAAA;AAAA,IAGpD,QAAQ;AAAA,IACR,QAAQ;AAAA,IACjB;AAAA,EACF;AACF;AAEA,SAAS,kBAAkB,QAAgB,UAAwB;AAGjE,QAAMC,wBAAuB;AAC7B,MAAIA,sBAAqB,KAAK,MAAM,GAAG;AACrC,UAAM,IAAI;AAAA,MACR,GAAG,QAAQ,kCAAkC,MAAM;AAAA;AAAA;AAAA;AAAA,IAG5C,QAAQ;AAAA,IACR,QAAQ;AAAA,IACjB;AAAA,EACF;AAIA,MAAI,iBAAiB,KAAK,MAAM,GAAG;AACjC,UAAM,IAAI;AAAA,MACR,GAAG,QAAQ,kCAAkC,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,IAI5C,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACjB;AAAA,EACF;AACF;AAgBO,SAAS,gBAAgB,QAAyB;AACvD,SAAO,WAAW;AACpB;AAGA,IAAM,wBAAwBC,GAAE,OAAO,EAAE,MAAMA,GAAE,OAAO,EAAE,CAAC;AAiB3D,eAAsB,0BAA0B,UAAoC;AAClF,QAAM,MAAM,MAAM,iBAAiBC,MAAK,KAAK,UAAU,eAAe,YAAY,CAAC;AACnF,SAAO,oBAAoB,GAAG,MAAM;AACtC;AAGA,SAAS,oBAAoB,KAA4B;AACvD,MAAI;AACJ,MAAI;AACF,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,sBAAsB,UAAU,IAAI;AACnD,SAAO,OAAO,UAAU,OAAO,KAAK,OAAO;AAC7C;AAeA,eAAsB,oBAAoB,UAAkB,QAAkC;AAC5F,SAAO,gBAAgB,MAAM,KAAM,MAAM,0BAA0B,QAAQ;AAC7E;AAEO,SAAS,cAAc,QAAyB;AACrD,MAAI,OAAO,WAAW,GAAG,KAAK,OAAO,WAAW,GAAG,GAAG;AACpD,WAAO;AAAA,EACT;AAEA,QAAM,oBAAoB,iBAAiB,KAAK,CAAC,WAAW,OAAO,WAAW,MAAM,CAAC;AACrF,MAAI,kBAAmB,QAAO;AAE9B,MAAI,OAAO,SAAS,IAAI,KAAK,OAAO,SAAS,GAAG,GAAG;AACjD,UAAM,IAAI;AAAA,MACR,6BAA6B,MAAM;AAAA,IACrC;AAAA,EACF;AACA,SAAO;AACT;AASO,SAAS,kBAAkB,GAAW,GAAW,SAA0B;AAChF,MAAI,cAAc,CAAC,KAAK,cAAc,CAAC,GAAG;AACxC,WAAOA,MAAK,QAAQ,SAAS,CAAC,MAAMA,MAAK,QAAQ,SAAS,CAAC;AAAA,EAC7D;AACA,SAAO,MAAM;AACf;;;AM/tBA,SAAS,SAAS,SAAS,QAAAC,OAAM,aAAAC,kBAAiB;;;ACblD,SAAS,YAAY;;;AC6Bd,IAAM,cAAc;AAGpB,IAAM,cAAc;AAG3B,IAAM,kBAAkB;AACxB,IAAM,iBAAiB;AAGvB,IAAM,WAAW;AAGjB,IAAM,cAAc;AACpB,IAAM,eAAe;AAGd,SAAS,cACd,OACkC;AAClC,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAOO,SAAS,UAAU,OAAuB;AAC/C,QAAM,YAAY,YAAY,OAAO,eAAe;AACpD,QAAM,WAAW,YAAY,OAAO,cAAc;AAClD,QAAM,QAAQ,YAAY,WAAW,iBAAiB;AAEtD,SAAO,GAAG,KAAK,GAAG,WAAW,OAAO,KAAK,CAAC,GAAG,KAAK;AACpD;AAGO,SAAS,UAAU,KAAqB;AAC7C,SAAO,SAAS,KAAK,GAAG,IAAI,MAAM,UAAU,GAAG;AACjD;AAgBO,SAAS,aAAa,QAA0C;AACrE,SAAO,OAAO,IAAI,CAAC,WAAW,EAAE,MAAM,SAAS,MAAM,EAAE;AACzD;AAGO,SAAS,aAAa,MAA0B;AACrD,SAAO,EAAE,MAAM,WAAW,KAAK;AACjC;AAGO,SAAS,YAAY,QAA4B;AACtD,SAAO,EAAE,MAAM,UAAU,OAAO;AAClC;AAeO,SAAS,gBACd,OACA,UACQ;AACR,SAAO;AAAA,IACL,YAAY,OAAO,QAAQ;AAAA,IAC3B,oBAAoB,KAAK;AAAA,IACzB;AAAA,EACF;AACF;AAGO,SAAS,gBACd,SACA,UACQ;AACR,SAAO,KAAK,YAAY,SAAS,QAAQ,GAAG,QAAQ,WAAW,GAAG,QAAQ;AAC5E;AAuBO,SAAS,YACd,SACA,UACa;AACb,QAAM,OAAO,UAAU,OAAO;AAC9B,QAAM,cAAc,SAAS,YAAY,KAAK,SAAS,SAAS;AAEhE,SAAO,eAAe,cAClB,WACA,kBAAkB,SAAS,SAAS,UAAU;AACpD;AAMO,SAAS,kBACd,SACA,YACmB;AACnB,SAAO,aAAa,UAAU,OAAO,EAAE,UAAU,cAC7C,aACA;AACN;AAGO,SAAS,gBACd,SACA,QACA,YACQ;AACR,QAAM,UAAU,OAAO,UAAU;AAEjC,SAAO,WAAW,aACd,GAAG,OAAO,GAAG,UAAU,OAAO,CAAC,KAC/B,QAAQ,IAAI,CAAC,WAAW,GAAG,OAAO,KAAK,MAAM,EAAE,EAAE,KAAK,IAAI;AAChE;AAGO,SAAS,UAAU,SAAoC;AAC5D,SAAO,QAAQ,KAAK,KAAK;AAC3B;AAMO,SAAS,qBACd,YACA,YACQ;AACR,QAAM,OAAO,SAAS,UAAU,UAAU,CAAC;AAC3C,QAAM,SAAS,iBAAiB,WAAW,KAAK,IAAI,CAAC,KAAK,IAAI;AAC9D,MAAI,OAAO,UAAU,YAAa,QAAO;AAEzC,QAAM,QAAQ,WAAW;AAAA,IACvB,CAAC,cAAc,GAAG,OAAO,WAAW,CAAC,GAAG,SAAS;AAAA,EACnD;AACA,SAAO,CAAC,iBAAiB,GAAG,OAAO,IAAI,IAAI,EAAE,EAAE,KAAK,IAAI;AAC1D;AASA,SAAS,KACP,UACA,oBACA,UACQ;AACR,QAAM,SAAS,SAAS,OAAO,QAAQ;AACvC,MAAI,CAAC,sBAAsB,WAAW,MAAM,KAAK,UAAU,QAAQ,GAAG;AACpE,WAAO,OAAO,UAAU,QAAQ;AAAA,EAClC;AAEA,QAAM,OAAO,GAAG,OAAO,SAAS,SAAS,WAAW,CAAC,GAAG,QAAQ,GAAG,SAAS,MAAM;AAClF,SAAO,GAAG,OAAO,SAAS,MAAM,CAAC,GAAG,MAAM;AAAA,EAAK,IAAI;AACrD;AAaA,SAAS,oBAAoB,OAAyB;AACpD,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,WAAW;AAClD,SAAO,cAAc,KAAK,KAAK,OAAO,KAAK,KAAK,EAAE,WAAW;AAC/D;AAEA,SAAS,OAAO,UAAkB,UAAgC;AAChE,SAAO,GAAG,OAAO,SAAS,MAAM,CAAC,GAAG,SAAS,MAAM,GAAG,QAAQ,GAAG,SAAS,MAAM;AAClF;AAGA,SAAS,YAAY,OAAgB,UAAgC;AACnE,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,YAAY,aAAa,KAAK,GAAG,QAAQ;AAC1E,MAAI,cAAc,KAAK,EAAG,QAAO,aAAa,OAAO,QAAQ;AAC7D,SAAO,aAAa,KAAK;AAC3B;AAEA,SAAS,YACP,SACA,UACQ;AACR,QAAM,OAAO,UAAU,OAAO;AAC9B,MAAI,SAAS,UAAa,KAAK,MAAM,QAAQ,EAAG,QAAO;AAEvD,QAAM,QAAQ,SAAS,SAAS;AAChC,QAAM,QAAQ,QAAQ,IAAI,CAAC,UAAU,gBAAgB,OAAO,KAAK,CAAC;AAClE,SAAO,CAAC,KAAK,GAAG,OAAO,GAAG,OAAO,SAAS,MAAM,CAAC,GAAG,EAAE,KAAK,IAAI;AACjE;AAEA,SAAS,gBAAgB,OAAmB,QAAwB;AAClE,MAAI,MAAM,SAAS,UAAW,QAAO,GAAG,OAAO,MAAM,CAAC,MAAM,MAAM,IAAI;AACtE,MAAI,MAAM,SAAS,SAAU,QAAO,GAAG,OAAO,MAAM,CAAC,GAAG,MAAM,MAAM;AACpE,SAAO,gBAAgB,MAAM,OAAO,EAAE,QAAQ,QAAQ,IAAI,QAAQ,IAAI,CAAC;AACzE;AAEA,SAAS,aACP,QACA,UACQ;AACR,QAAM,aAAa,OAAO,QAAQ,MAAM;AAGxC,MAAI,WAAW,WAAW,EAAG,QAAO;AAEpC,QAAM,OAAO,WAAW,MAAM;AAC9B,MAAI,KAAK,MAAM,QAAQ,EAAG,QAAO;AAEjC,QAAM,QAAQ,SAAS,SAAS;AAChC,QAAM,QAAQ,WAAW;AAAA,IAAI,CAAC,CAAC,KAAK,KAAK,MACvC,gBAAgB,OAAO;AAAA,MACrB,QAAQ;AAAA,MACR,QAAQ,GAAG,UAAU,GAAG,CAAC;AAAA,MACzB,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AACA,SAAO,CAAC,KAAK,GAAG,OAAO,GAAG,OAAO,SAAS,MAAM,CAAC,GAAG,EAAE,KAAK,IAAI;AACjE;AAGA,SAAS,UAAU,SAAoD;AACrE,QAAM,QAAkB,CAAC;AAEzB,aAAW,SAAS,SAAS;AAG3B,QAAI,MAAM,SAAS,UAAW,QAAO;AACrC,UAAM,KAAK,MAAM,SAAS,WAAW,MAAM,SAAS,UAAU,MAAM,KAAK,CAAC;AAAA,EAC5E;AAEA,SAAO,SAAS,KAAK;AACvB;AAEA,SAAS,UAAU,OAAwB;AACzC,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,SAAS,MAAM,IAAI,SAAS,CAAC;AAC9D,MAAI,cAAc,KAAK,EAAG,QAAO,WAAW,KAAK;AACjD,SAAO,aAAa,KAAK;AAC3B;AAEA,SAAS,SAAS,OAAkC;AAClD,SAAO,MAAM,WAAW,IAAI,cAAc,IAAI,MAAM,KAAK,IAAI,CAAC;AAChE;AAEA,SAAS,WAAW,QAAyC;AAC3D,QAAM,aAAa,OAAO,QAAQ,MAAM,EAAE;AAAA,IACxC,CAAC,CAAC,KAAK,KAAK,MAAM,GAAG,UAAU,GAAG,CAAC,KAAK,UAAU,KAAK,CAAC;AAAA,EAC1D;AACA,SAAO,WAAW,WAAW,IAAI,eAAe,KAAK,WAAW,KAAK,IAAI,CAAC;AAC5E;AAEA,SAAS,aAAa,OAAwB;AAC5C,SAAO,OAAO,UAAU,WAAW,UAAU,KAAK,IAAI,OAAO,KAAK;AACpE;AAEA,SAAS,KAAK,MAAc,UAAiC;AAC3D,QAAM,QACJ,SAAS,SACT,SAAS,OAAO,SAChB,KAAK,SACL,SAAS,OAAO;AAElB,SAAO,SAAS;AAClB;AAEA,SAAS,YAAY,OAAe,WAA2B;AAC7D,SAAO,MAAM,MAAM,SAAS,EAAE,SAAS;AACzC;AAMA,SAAS,WAAW,OAAe,OAAuB;AACxD,QAAM,WAAW,KAAK,UAAU,KAAK,EAAE,MAAM,GAAG,EAAE;AAClD,MAAI,UAAU,eAAgB,QAAO;AAErC,SAAO,SAAS,WAAW,OAAO,GAAG,EAAE,WAAW,KAAK,KAAK;AAC9D;AAGO,SAAS,OAAO,OAAuB;AAC5C,SAAO,IAAI,OAAO,KAAK;AACzB;;;ADrRO,IAAM,sBAAsB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGA,IAAM,mBAAmB,oBAAI,IAAI;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AASD,IAAM,wBAAwB;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAgBA,IAAM,8BAA8B;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,8BAA8B;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,6BAA6B;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAOA,SAAS,sBACP,QACA,aACyB;AACzB,QAAM,QAAQ,IAAI,IAAY,WAAW;AACzC,QAAM,gBAAgB,YACnB,OAAO,CAAC,QAAQ,OAAO,MAAM,EAC7B,IAAI,CAAC,QAA2B,CAAC,KAAK,OAAO,GAAG,CAAC,CAAC;AACrD,QAAM,cAAc,OAAO,QAAQ,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC;AAE5E,SAAO,OAAO,YAAY,CAAC,GAAG,eAAe,GAAG,WAAW,CAAC;AAC9D;AAGA,SAAS,uBACP,SACyB;AACzB,SAAO,sBAAsB,SAAS,qBAAqB;AAC7D;AASA,SAAS,yBACP,SACyB;AACzB,QAAM,YAAY,EAAE,GAAG,QAAQ;AAC/B,MAAI,MAAM,QAAQ,UAAU,MAAM,GAAG;AACnC,cAAU,SAAS;AAAA,MACjB,UAAU;AAAA,MACV;AAAA,IACF;AAAA,EACF;AACA,MAAI,MAAM,QAAQ,UAAU,MAAM,GAAG;AACnC,cAAU,SAAS;AAAA,MACjB,UAAU;AAAA,MACV;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAQA,SAAS,qBACP,SACA,aACW;AACX,SAAO,QAAQ;AAAA,IAAI,CAAC,UAClB,cAAc,KAAK,IAAI,sBAAsB,OAAO,WAAW,IAAI;AAAA,EACrE;AACF;AAGA,SAAS,kBACP,QACA,aACmB;AACnB,SAAO,OAAO;AAAA,IACZ,OAAO,QAAQ,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC;AAAA,EAC7D;AACF;AASA,SAAS,4BAA4B,GAAW,GAAmB;AACjE,MAAI,MAAM,EAAG,QAAO;AACpB,SAAO,IAAI,IAAI,KAAK;AACtB;AAeA,SAAS,uBACP,OACA,SACyC;AACzC,QAAM,gBAAgB,2BAA2B,OAAO;AACxD,QAAM,wBAAwB,OAAO,QAAQ,KAAK,EAAE;AAAA,IAClD,CAAC,CAAC,OAAO,UAAU,MACjB,CAAC,OAAO,kBAAkB,YAAY,aAAa,CAAC;AAAA,EACxD;AAEA,SAAO;AAAA,IACL,OAAO,YAAY,qBAAqB;AAAA,IACxC;AAAA,EACF;AACF;AAGA,IAAM,yBAAyB;AAG/B,IAAM,aAAa;AAGnB,SAAS,oBAAoB,MAAc,MAA4B;AACrE,SAAO,EAAE,QAAQ,GAAG,QAAQ,SAAS,IAAI,KAAK,IAAI,OAAO,QAAQ,GAAG;AACtE;AAOA,SAAS,YAAY,MAAc,MAAc,OAA0B;AACzE,SAAO,CAAC,IAAI,gBAAgB,OAAO,oBAAoB,MAAM,IAAI,CAAC,CAAC;AACrE;AAGA,SAAS,iBACP,MACA,MACA,SACU;AACV,SAAO,CAAC,IAAI,gBAAgB,SAAS,oBAAoB,MAAM,IAAI,CAAC,CAAC;AACvE;AAGA,SAAS,oBAAoB,KAA2B;AACtD,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,QAAQ,GAAG,UAAU,GAAG,CAAC;AAAA,IACzB,QAAQ;AAAA,EACV;AACF;AAGA,SAAS,kBAAkB,KAAa,OAAwB;AAC9D,SAAO,gBAAgB,OAAO,oBAAoB,GAAG,CAAC;AACxD;AAUA,SAAS,oBAAoB,SAAgD;AAK3E,SAAO;AAAA,IACL,QAAS,QAAQ,UAAU,CAAC;AAAA,IAC5B,QAAS,QAAQ,UAAU,CAAC;AAAA,IAC5B,OAAO,QAAQ;AAAA,IACf,iBAAkB,QAAQ,mBAAmB,CAAC;AAAA,EAChD;AACF;AAYA,SAAS,iBACP,QACA,SACA,SACyB;AAGzB,QAAM,UAAU,KAAK,MAAM,KAAK,UAAU,MAAM,CAAC;AACjD,MAAI,QAAQ,cAAc;AACxB,WAAO,QAAQ;AAAA,EACjB;AACA,MAAI,QAAQ,OAAO;AAGjB,UAAM,YAAY;AAAA,MAChB,QAAQ;AAAA,MACR;AAAA,IACF;AACA,YAAQ,QAAQ,uBAAuB,WAAW,OAAO;AAAA,EAC3D;AACA,SAAO,uBAAuB,yBAAyB,OAAO,CAAC;AACjE;AAaO,SAAS,qBACd,QACA,SACA,SACQ;AACR,MAAI,SAAS,iBAAiB;AAC5B,WAAO,sBAAsB,QAAQ,SAAS,OAAO;AAAA,EACvD;AAEA,SAAO;AAAA,IACL,iBAAiB,QAAQ,SAAS,EAAE,cAAc,MAAM,CAAC;AAAA,EAC3D;AACF;AAcA,SAAS,sBACP,QACA,SACA,SACQ;AACR,QAAM,UAAU,iBAAiB,QAAQ,SAAS,EAAE,cAAc,KAAK,CAAC;AAExE,MAAI,QAAQ,cAAc;AACxB,WAAO;AAAA,MACL;AAAA,MACA,iBAAiB,QAAQ,cAAc,SAAS,EAAE,cAAc,KAAK,CAAC;AAAA,IACxE;AAAA,EACF;AACA,MAAI,QAAQ,qBAAqB,QAAW;AAC1C,WAAO;AAAA,MACL;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,QAAM,IAAI;AAAA,IACR;AAAA,EAIF;AACF;AAQA,SAAS,sCACP,SACA,kBACQ;AACR,QAAM,aAAa,GAAG,gBAAgB;AAEtC,QAAM,EAAE,QAAQ,QAAQ,OAAO,gBAAgB,IAC7C,oBAAoB,OAAO;AAE7B,QAAM,oBAAoB,gBAAgB,SAAS;AACnD,QAAM,WAAW,SAAS,QAAQ,OAAO,KAAK,KAAK,EAAE,SAAS;AAE9D,QAAM,cAAc,iBAAiB;AAAA;AAAA,IAEnC,WAAW;AAAA,IACX,WAAW;AAAA,IACX;AAAA,IACA,oBAAoB;AAAA,EACtB,CAAC;AAED,QAAM,QAAkB;AAAA,IACtB,4BAA4B,UAAU,UAAU,CAAC;AAAA,IACjD,qBAAqB,aAAa,sBAAsB;AAAA,EAC1D;AAEA,QAAM;AAAA,IACJ,GAAG,iBAAiB,UAAU,iBAAiB;AAAA,MAC7C,YAAY,wBAAwB;AAAA,MACpC,GAAG,aAAa,MAAM;AAAA,IACxB,CAAC;AAAA,EACH;AACA,QAAM;AAAA,IACJ,GAAG,iBAAiB,UAAU,sBAAsB;AAAA,MAClD,YAAY,wBAAwB;AAAA,MACpC,GAAG,aAAa,MAAM;AAAA,IACxB,CAAC;AAAA,EACH;AAEA,MAAI,UAAU;AACZ,UAAM,KAAK,GAAG,YAAY,SAAS,YAAY,KAAK,CAAC;AAAA,EACvD;AAEA,MAAI,mBAAmB;AACrB,UAAM;AAAA,MACJ,GAAG,iBAAiB,mBAAmB,YAAY;AAAA,QACjD,YAAY,yCAAyC;AAAA,QACrD,GAAG,aAAa,eAAe;AAAA,MACjC,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,eAAe,OAAO,QAAQ,OAAO,EACxC,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,iBAAiB,IAAI,GAAG,KAAK,QAAQ,MAAM,EAC9D,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,kBAAkB,KAAK,KAAK,CAAC;AAEtD,QAAM,eAAyB;AAAA,IAC7B;AAAA,IACA,kBAAkB,QAAQ,mBAAmB,OAAO,CAAC;AAAA,IACrD;AAAA,IACA;AAAA,IACA,GAAI,WAAW,CAAC,UAAU,IAAI,CAAC;AAAA,IAC/B,GAAI,oBAAoB,CAAC,oBAAoB,IAAI,CAAC;AAAA,IAClD,GAAG;AAAA,EACL;AAEA,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,kBAAkB;AAC7B,QAAM,KAAK,GAAG,YAAY;AAC1B,QAAM,KAAK,2BAA2B;AAEtC,QAAM,KAAK,EAAE;AACb,SAAO,MAAM,KAAK,IAAI;AACxB;AAMA,SAAS,yBAAyB,SAA0C;AAC1E,QAAM,EAAE,QAAQ,QAAQ,OAAO,gBAAgB,IAC7C,oBAAoB,OAAO;AAE7B,QAAM,YAAY,OAAO,SAAS;AAClC,QAAM,YAAY,OAAO,SAAS;AAClC,QAAM,WAAW,SAAS,QAAQ,OAAO,KAAK,KAAK,EAAE,SAAS;AAC9D,QAAM,qBAAqB,gBAAgB,SAAS;AAEpD,QAAM,cAAc,iBAAiB;AAAA,IACnC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,QAAkB;AAAA,IACtB,qBAAqB,aAAa,sBAAsB;AAAA,EAC1D;AAEA,MAAI,WAAW;AACb,UAAM,KAAK,GAAG,YAAY,UAAU,iBAAiB,MAAM,CAAC;AAAA,EAC9D;AAEA,MAAI,WAAW;AACb,UAAM,KAAK,GAAG,YAAY,UAAU,sBAAsB,MAAM,CAAC;AAAA,EACnE;AAEA,MAAI,UAAU;AACZ,UAAM,KAAK,GAAG,YAAY,SAAS,YAAY,KAAK,CAAC;AAAA,EACvD;AAEA,MAAI,oBAAoB;AACtB,UAAM,KAAK,GAAG,YAAY,mBAAmB,YAAY,eAAe,CAAC;AAAA,EAC3E;AAIA,QAAM,oBAAoB,CAAC,KAAa,UAA6B;AACnE,QAAI,CAAC,iBAAiB,IAAI,GAAG,EAAG,QAAO,CAAC,kBAAkB,KAAK,KAAK,CAAC;AACrE,QAAI,QAAQ,SAAU,QAAO,CAAC,WAAW,YAAY,KAAK,MAAM,GAAG;AACnE,QAAI,QAAQ,SAAU,QAAO,CAAC,WAAW,YAAY,KAAK,MAAM,GAAG;AACnE,QAAI,QAAQ,QAAS,QAAO,WAAW,CAAC,UAAU,IAAI,CAAC;AACvD,WAAO,CAAC,oBAAoB,qBAAqB,KAAK,MAAM,GAAG;AAAA,EACjE;AACA,QAAM,eAAe,OAAO,QAAQ,OAAO,EAAE;AAAA,IAAQ,CAAC,CAAC,KAAK,KAAK,MAC/D,kBAAkB,KAAK,KAAK;AAAA,EAC9B;AAEA,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,kBAAkB;AAC7B,QAAM,KAAK,GAAG,YAAY;AAC1B,QAAM,KAAK,2BAA2B;AAEtC,QAAM,KAAK,EAAE;AACb,SAAO,MAAM,KAAK,IAAI;AACxB;AAMA,SAAS,iBAAiB,OAKb;AACX,SAAO;AAAA,IACL,MAAM,sBAAsB;AAAA,IAC5B;AAAA,IACA,MAAM,YAAY;AAAA,IAClB,MAAM,aAAa;AAAA,IACnB,MAAM,aAAa;AAAA,IACnB,MAAM,YAAY;AAAA,EACpB,EAAE,OAAO,CAAC,MAAmB,QAAQ,CAAC,CAAC;AACzC;AAGA,SAAS,mBAAmB,SAA2C;AACrE,SAAO,QAAQ,QAAQ,QAAQ,SAAS,qBACpC,QAAQ,OACR;AACN;AA0BA,SAAS,8BACP,SACA,eACwB;AACxB,QAAM,UAAU,oBAAoB,OAAO;AAC3C,QAAM,SAAS,oBAAoB,aAAa;AAEhD,QAAM,aAAa,CAAC,UACjB,MAAiC,aAAa;AACjD,QAAM,OAAO,CAAC,UAA4B,MAAyB;AACnE,QAAM,SAAS,CAAC,UAA4B,MAA2B;AAEvE,QAAM,uBAAuB,QAAQ,OAAO,OAAO,UAAU;AAC7D,QAAM,uBAAuB,QAAQ,OAAO,OAAO,UAAU;AAC7D,QAAM,gBAAgB,QAAQ,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;AACjE,QAAM,gBAAgB,QAAQ,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;AAEjE,QAAM,mBAAmB,IAAI,IAAI,qBAAqB,IAAI,IAAI,CAAC;AAC/D,QAAM,qBAAqB,IAAI,IAAI,qBAAqB,IAAI,MAAM,CAAC;AACnE,QAAM,eAAe;AAAA,IACnB,GAAG,OAAO,OAAO,OAAO,CAAC,MAAM,CAAC,iBAAiB,IAAI,KAAK,CAAC,CAAC,CAAC;AAAA,IAC7D,GAAG;AAAA,EACL;AACA,QAAM,eAAe;AAAA,IACnB,GAAG,OAAO,OAAO,OAAO,CAAC,MAAM,CAAC,mBAAmB,IAAI,OAAO,CAAC,CAAC,CAAC;AAAA,IACjE,GAAG;AAAA,EACL;AAEA,QAAM,oBAAoB,IAAI,IAAI,cAAc,IAAI,MAAM,CAAC;AAC3D,QAAM,gBAAqD,QAAQ,QAC/D,OAAO;AAAA,IACL,OAAO,QAAQ,QAAQ,KAAK,EAAE;AAAA,MAAO,CAAC,CAAC,KAAK,MAC1C,kBAAkB,IAAI,KAAK;AAAA,IAC7B;AAAA,EACF,IACA;AAEJ,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,iBAAiB;AAAA,MACf,GAAG,oBAAI,IAAI,CAAC,GAAG,OAAO,iBAAiB,GAAG,QAAQ,eAAe,CAAC;AAAA,IACpE;AAAA,EACF;AACF;AAaA,SAAS,yBACP,SACA,eACqB;AACrB,SAAO,OAAO;AAAA,IACZ,uBAAuB;AAAA,MACrB,GAAG,KAAK,eAAe,mBAAmB;AAAA,MAC1C,GAAG;AAAA,IACL,CAAC;AAAA,EACH,EAAE,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,iBAAiB,IAAI,GAAG,KAAK,QAAQ,MAAM;AAClE;AAQA,SAAS,uCACP,SACA,eACQ;AACR,QAAMC,aAAY,8BAA8B,SAAS,aAAa;AACtE,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAIA;AAEJ,QAAM,kBAAkB,aAAa,SAAS;AAC9C,QAAM,mBAAmB,cAAc,SAAS;AAChD,QAAM,YAAY,mBAAmB;AAErC,QAAM,kBAAkB,aAAa,SAAS;AAC9C,QAAM,mBAAmB,cAAc,SAAS;AAChD,QAAM,YAAY,mBAAmB;AAErC,QAAM,WACJ,iBAAiB,QAAQ,OAAO,KAAK,aAAa,EAAE,SAAS;AAC/D,QAAM,qBAAqBA,WAAU,gBAAgB,SAAS;AAE9D,QAAM,cAAc,iBAAiB;AAAA,IACnC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,QAAkB;AAAA,IACtB,qBAAqB,aAAa,sBAAsB;AAAA,EAC1D;AAEA,MAAI,WAAW;AACb,UAAM;AAAA,MACJ,GAAG;AAAA,QACD;AAAA,QACA;AAAA,QACA,oBAAoB,cAAc,aAAa;AAAA,MACjD;AAAA,IACF;AAAA,EACF;AAEA,MAAI,WAAW;AACb,UAAM;AAAA,MACJ,GAAG;AAAA,QACD;AAAA,QACA;AAAA,QACA,oBAAoB,cAAc,aAAa;AAAA,MACjD;AAAA,IACF;AAAA,EACF;AAEA,MAAI,UAAU;AACZ,UAAM,KAAK,GAAG,YAAY,SAAS,YAAY,aAAa,CAAC;AAAA,EAC/D;AAEA,MAAI,oBAAoB;AACtB,UAAM;AAAA,MACJ,GAAG,YAAY,mBAAmB,YAAYA,WAAU,eAAe;AAAA,IACzE;AAAA,EACF;AAEA,QAAM,eAAe,yBAAyB,SAAS,aAAa;AAEpE,QAAM,eAAyB;AAAA,IAC7B,kBAAkB,QAAQ,mBAAmB,OAAO,CAAC;AAAA,IACrD,GAAG,aAAa,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,kBAAkB,KAAK,KAAK,CAAC;AAAA,IACnE,YAAY,cAAc;AAAA,IAC1B,YAAY,cAAc;AAAA,IAC1B,GAAI,WAAW,CAAC,UAAU,IAAI,CAAC;AAAA,IAC/B,GAAI,qBAAqB,CAAC,oBAAoB,IAAI,CAAC;AAAA,EACrD;AAEA,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,kBAAkB;AAC7B,QAAM,KAAK,GAAG,YAAY;AAC1B,QAAM,KAAK,2BAA2B;AAEtC,QAAM,KAAK,EAAE;AACb,SAAO,MAAM,KAAK,IAAI;AACxB;AAWA,SAAS,oBACP,QACA,SACc;AACd,SAAO;AAAA,IACL,GAAI,OAAO,SAAS,IAChB,CAAC,aAAa,QAAQ,GAAG,GAAG,aAAa,MAAM,CAAC,IAChD,CAAC;AAAA,IACL,GAAI,QAAQ,SAAS,IACjB,CAAC,aAAa,SAAS,GAAG,GAAG,aAAa,OAAO,CAAC,IAClD,CAAC;AAAA,EACP;AACF;AAGA,SAAS,aAAa,YAAsC;AAC1D,SAAO,QAAQ,WAAW,aAAa,WAAW,SAAS,WAAW,IAAI;AAC5E;AAOA,SAASC,mBAAkB,OAA0C;AACnE,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AAExD,SAAO,OAAQ,MAA2B,OAAO;AACnD;AAaA,SAAS,kBAAkB,YAA8B;AACvD,MAAI,CAACA,mBAAkB,UAAU,EAAG,QAAO;AAC3C,MAAI,CAAC,aAAa,UAAU,EAAG,QAAO,WAAW;AACjD,SAAO,sBAAsB,YAAY,0BAA0B;AACrE;AAaA,SAAS,2BACP,UACA,aACA,SACS;AACT,QAAM,YAAY,YAAY,IAAI,iBAAiB;AACnD,MAAI,CAAC,oBAAoB,SAAS,QAAQ,EAAG,QAAO;AAEpD,MAAI,UAAU,SAAS,GAAG;AACxB,UAAM,IAAI;AAAA,MACR,aAAa,QAAQ,4BAA4B,UAAU,MAAM,YAAY,KAAK,UAAU,SAAS,CAAC;AAAA,IACxG;AAAA,EACF;AACA,SAAO,UAAU,CAAC;AACpB;AASO,SAAS,sBACd,OACA,SACM;AACN,aAAW,cAAc,OAAO,OAAO,SAAS,CAAC,CAAC,GAAG;AACnD,sBAAkB,YAAY,OAAO;AAAA,EACvC;AACF;AAEA,SAAS,kBACP,YACA,SACyB;AACzB,SAAO,OAAO;AAAA,IACZ,OAAO,QAAQ,UAAU,EACtB;AAAA,MACC,CAAC,CAAC,EAAE,WAAW,MACb,MAAM,QAAQ,WAAW,KAAK,YAAY,SAAS;AAAA,IACvD,EACC,IAAI,CAAC,CAAC,UAAU,WAAW,MAAM;AAAA,MAChC;AAAA,MACA,2BAA2B,UAAU,aAAa,OAAO;AAAA,IAC3D,CAAC;AAAA,EACL;AACF;AAEA,SAAS,wBACP,OACA,SACyC;AACzC,SAAO,OAAO;AAAA,IACZ,OAAO,QAAQ,KAAK,EACjB;AAAA,MACC,CAAC,CAAC,OAAO,UAAU,MACjB,CAAC,OAAO,kBAAkB,YAAY,OAAO,CAAC;AAAA,IAClD,EACC,OAAO,CAAC,CAAC,EAAE,UAAU,MAAM,OAAO,KAAK,UAAU,EAAE,SAAS,CAAC;AAAA,EAClE;AACF;AAKO,SAAS,kCAA0C;AACxD,SAAO,sCAAsC,UAAU,sBAAsB,CAAC;AAAA;AAAA;AAAA,UAGtE,UAAU,kBAAkB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAKvC;;;AE36BO,SAASC,cACd,KACU;AACV,SAAO,OAAO,QAAQ,GAAG;AAC3B;AAGO,SAASC,WACd,KACK;AACL,SAAO,OAAO,KAAK,GAAG;AACxB;AAGO,SAASC,kBACd,SACuB;AACvB,SAAO,OAAO,YAAY,OAAO;AACnC;;;AHgDA,IAAM,qBAAqB;AAE3B,SAAS,wBACP,cACsB;AACtB,MAAI,iBAAiB,sBAAuB,QAAO;AAEnD,SAAO;AACT;AAmCO,SAAS,oBACd,OACA,SACQ;AACR,SAAO,GAAG,KAAK,IAAI,OAAO;AAC5B;AAGA,SAASC,aAAY,OAAmC;AACtD,SAAQ,YAAkC,SAAS,KAAK;AAC1D;AAGA,SAASC,WAAU,OAAiC;AAClD,SAAQ,UAAgC,SAAS,KAAK;AACxD;AAQA,SAAS,eACP,eACA,OACA,UACA,SACuB;AACvB,QAAM,QAAQ,cAAc,KAAK,IAAI,QAAQ,GAAG,KAAK,CAAC,MAAM,EAAE,OAAO,OAAO;AAC5E,MAAI,UAAU,OAAW,QAAO;AAEhC,SAAO,MAAM,cAAc,OAAO,cAAc;AAClD;AAaA,SAAS,gBAAgB,SAAkB,OAA6B;AACtE,MAAI,CAACA,WAAU,OAAO,KAAK,CAACD,aAAY,KAAK,EAAG,QAAO;AAEvD,SAAO,iBAAiB,EAAE,SAAS,SAAS,MAAM,CAAC;AACrD;AAaA,SAAS,eACP,SACA,SACA,UACyB;AAGzB,QAAM,WAAW,eAAe,SAAS,QAAQ;AACjD,MAAI,aAAa,OAAW,QAAO;AAEnC,SAAO,EAAE,IAAI,SAAS,UAAU,YAAY,SAAS;AACvD;AAOA,SAAS,eACP,SACA,SACA,UACA,OACS;AACT,SAAO,kBAAkB,eAAe,SAAS,SAAS,QAAQ,CAAC,EAAE;AAAA,IACnE,CAAC,WAAW,OAAO,YAAY;AAAA,EACjC;AACF;AAQA,SAAS,sBACP,OACA,UACA,SACA,QACS;AACT,QAAM,gBACJ,eAAe,OAAO,eAAe,OAAO,UAAU,OAAO,MAAM;AACrE,SACE,iBAAiB,eAAe,OAAO,SAAS,SAAS,UAAU,KAAK;AAE5E;AAEA,SAAS,gBACP,KACA,KACA,MACY;AACZ,QAAM,QAAQ,IAAI,IAAI,GAAG;AACzB,MAAI,UAAU,QAAW;AACvB,UAAM,IAAI;AAAA,MACR,oCAAoC,IAAI,KAAK,OAAO,GAAG,CAAC,kBACnD,SAAS,UAAU,iBAAiB,cAAc,wBAC/B,SAAS,UAAU,gBAAgB,kBAAkB,uBACrD,IAAI;AAAA,IAC9B;AAAA,EACF;AACA,SAAO;AACT;AAUO,SAAS,sBACd,YACA,YACS;AACT,SAAO,wBAAwB,YAAY,UAAU;AACvD;AAEA,SAAS,kBACP,SACA,OACA,YACA,YACS;AACT,QAAM,SAAS,gBAAgB,YAAY,SAAS,OAAO;AAC3D,QAAM,SAAS,gBAAgB,YAAY,OAAO,OAAO;AACzD,SAAO,sBAAsB,QAAQ,MAAM;AAC7C;AAwBA,SAAS,oBACP,OACA,UACA,SACA,QACS;AAET,MAAI,OAAO,uBAAuB,OAAW,QAAO;AAEpD,QAAM,qBAAqB,OAAO,cAAc,KAAK;AACrD,MAAI,uBAAuB,QAAW;AAEpC,WAAO;AAAA,EACT;AAEA,QAAM,gBAAgB,mBAAmB,QAAQ;AACjD,MAAI,iBAAiB,cAAc,KAAK,CAAC,MAAM,EAAE,OAAO,OAAO,EAAG,QAAO;AAEzE,MAAI,OAAO,mBAAmB,IAAI,OAAO,EAAG,QAAO;AACnD,QAAM,mBAAmB,OAAO;AAChC,MACE,oBACA,iBAAiB,IAAI,oBAAoB,OAAO,OAAO,CAAC,GACxD;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAGA,SAAS,kBACP,IACA,OACA,UACA,QACiB;AACjB,QAAM,QAAQ,eAAe,OAAO,eAAe,OAAO,UAAU,EAAE;AACtE,QAAM,OAAO,SAAS,gBAAgB,IAAI,KAAK;AAE/C,SAAO,SAAS,cAAc,EAAE,IAAI,WAAW,KAAK,IAAI,EAAE,GAAG;AAC/D;AASA,SAAS,yBACP,wBACA,SACyB;AACzB,QAAM,gBAAgB,2BAA2B,OAAO;AACxD,SAAO,CAAC,GAAG,sBAAsB,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC;AAC3E;AAEA,SAAS,gBACP,OACA,QAC8B;AAC9B,QAAM,aAA+B,CAAC;AACtC,aAAW,CAAC,UAAU,QAAQ,KAAK;AAAA,IACjC,OAAO;AAAA,IACP,OAAO;AAAA,EACT,GAAG;AACD,UAAM,cAAc,SACjB;AAAA,MAAO,CAAC,OACP,kBAAkB,IAAI,OAAO,OAAO,YAAY,OAAO,UAAU;AAAA,IACnE,EACC,OAAO,CAAC,OAAO,oBAAoB,OAAO,UAAU,IAAI,MAAM,CAAC,EAC/D,OAAO,CAAC,OAAO,sBAAsB,OAAO,UAAU,IAAI,MAAM,CAAC,EACjE,IAAI,CAAC,OAAO,kBAAkB,IAAI,OAAO,UAAU,MAAM,CAAC;AAC7D,QAAI,YAAY,SAAS,GAAG;AAC1B,iBAAW,QAAQ,IAAI;AAAA,IACzB;AAAA,EACF;AACA,SAAOE,WAAoB,UAAU,EAAE,SAAS,IAAI,aAAa;AACnE;AAEA,SAAS,uBACP,QAC0D;AAG1D,MAAI,OAAO,UAAU,WAAW,GAAG;AACjC,gBAAY,EAAE;AAAA,MACZ;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAOA,QAAM,SAAuD,CAAC;AAC9D,aAAW,SAAS,OAAO,WAAW;AACpC,UAAM,QAAQ,gBAAgB,OAAO,MAAM;AAC3C,QAAI,MAAO,QAAO,KAAK,IAAI;AAAA,EAC7B;AACA,SAAO;AACT;AAUA,SAAS,mBACP,kBACA,cACA,SAKA;AACA,QAAM,SAAS,iBAAiB,IAAI,CAAC,aAAa;AAAA,IAChD;AAAA,IACA,OAAO,QAAQ,OAAO,OAAO;AAAA,EAC/B,EAAE;AACF,QAAM,QAAQ,OAAO;AAAA,IACnB,CACE,UAEA,MAAM,SAAS;AAAA,EACnB;AACA,QAAM,iBAAiB,OACpB,OAAO,CAAC,UAAU,MAAM,SAAS,IAAI,EACrC,IAAI,CAAC,UAAU,MAAM,OAAO;AAE/B,qBAAmB,gBAAgB,OAAO;AAE1C,QAAM,mBAAmB,4BAA4B,YAAY;AAEjE,QAAM,cAAc,MACjB,IAAI,CAAC,EAAE,SAAS,MAAM,OAAO;AAAA,IAC5B;AAAA;AAAA,IAEA,UAAU,wBAAwB,MAAM,QAAwB;AAAA,EAClE,EAAE,EACD;AAAA,IACC,CAAC,UACC,MAAM,YAAY;AAAA,EACtB,EACC,OAAO,CAAC,UAAU,CAAC,iBAAiB,IAAI,MAAM,OAAO,CAAC;AAEzD,SAAO;AAAA,IACL;AAAA,IACA,YAAY,MAAM;AAAA,IAClB,cAAc,eAAe;AAAA,EAC/B;AACF;AAUA,SAAS,mBACP,gBACA,SACM;AACN,MAAI,eAAe,WAAW,EAAG;AAEjC,aAAW,WAAW,gBAAgB;AACpC,gBAAY,EAAE,KAAK,mBAAmB,OAAO,CAAC;AAAA,EAChD;AAEA,QAAM,eAAeA,WAAmB,QAAQ,MAAM,EACnD,MAAM,GAAG,kBAAkB,EAC3B,KAAK,IAAI;AACZ,cAAY,EAAE;AAAA,IACZ,GAAG,eAAe,MAAM,wDAAwD,YAAY;AAAA,EAC9F;AACF;AAUA,SAAS,mBAAmB,SAA0B;AACpD,SACE,UAAU,OAAO,wGACc,kBAAkB,2DAC9B,kBAAkB;AAEzC;AAOA,SAAS,mBACP,cAC0B;AAC1B,QAAM,CAAC,iBAAiB,aAAa,IAAIC;AAAA,IAAU;AAAA,IAAc,CAAC,MAChE,QAAQ,EAAE,QAAQ;AAAA,EACpB;AACA,SAAO,IAAI;AAAA,IACT,CAAC,GAAG,iBAAiB,GAAG,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC;AAAA,EACnE;AACF;AAOA,SAAS,0BACP,WACA,iBACoB;AACpB,QAAM,iBAAiB,kBACnB;AAAA,IACE,gBAAgB,OAAO,CAAC,MAAM,CAAC,EAAE,QAAQ;AAAA,IACzC,CAAC,MAAM,EAAE;AAAA,EACX,IACA,CAAC;AACL,SAAO,UAAU,IAAI,CAAC,cAAc;AAClC,QAAI,iBAAiB;AACnB,YAAM,WAAW,eAAe,SAAS;AACzC,UAAI,CAAC,UAAU;AACb,cAAM,IAAI;AAAA,UACR,oDAAoD,SAAS;AAAA,QAE/D;AAAA,MACF;AACA,aAAO;AAAA,IACT;AACA,WAAO,EAAE,MAAM,WAAW,OAAO,UAAmB;AAAA,EACtD,CAAC;AACH;AAwBO,SAAS,gCACd,MACA,kBACA,SAsBe;AACf,QAAM,UAAU,cAAc;AAC9B,QAAM,YAAY,SAAS,iBACvB,CAAC,GAAG,QAAQ,cAAc,EAAE,KAAK,IACjC,CAAC;AAKL,MAAI,UAAU,SAAS,GAAG;AACxB,QAAI,CAAC,SAAS,cAAc;AAC1B,YAAM,IAAI;AAAA,QACR;AAAA,MAEF;AAAA,IACF;AACA,QAAI,CAAC,QAAQ,cAAc;AACzB,YAAM,IAAI;AAAA,QACR;AAAA,MAEF;AAAA,IACF;AAAA,EACF;AAIA,QAAM,eAAe,SAAS,gBAAgB,CAAC;AAC/C,QAAM,eAAe,SAAS,gBAAgB,CAAC;AAE/C,cAAY,EAAE;AAAA,IACZ,oCAAoC,iBAAiB,MAAM,uBAC3CD,WAAmB,QAAQ,MAAM,EAAE,MAAM,qBAC5C,UAAU,KAAK,IAAI,CAAC;AAAA,EACnC;AAEA,QAAM,EAAE,aAAa,YAAY,aAAa,IAAI;AAAA,IAChD;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,cAAY,EAAE;AAAA,IACZ,oCAAoC,UAAU,WAAW,YAAY,eAChE,UAAU,MAAM;AAAA,EACvB;AAEA,QAAM,yBAAyB,IAAI;AAAA,IACjCE,cAAa,QAAQ,aAAa,CAAC,UAAU,MAAM,QAAQ,CAAC,EAAE;AAAA,MAC5D,CAAC,CAAC,UAAU,OAAO,MAAM,CAAC,UAAU,QAAQ,IAAI,CAAC,UAAU,MAAM,OAAO,CAAC;AAAA,IAC3E;AAAA,EACF;AAEA,QAAM,aAAa,mBAAmB,YAAY;AAClD,QAAM,aAAa,oBAAoB,YAAY;AAGnD,QAAM,wBACJ,SAAS,uBAAuB,SAC5B,SACA,IAAI,IAAI,QAAQ,kBAAkB;AAExC,QAAM,gBAAgB,uBAAuB;AAAA,IAC3C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,eAAe,SAAS,iBAAiB,CAAC;AAAA,IAC1C,GAAI,0BAA0B,UAAa;AAAA,MACzC,oBAAoB;AAAA,IACtB;AAAA,IACA,GAAI,SAAS,2BAA2B,UAAa;AAAA,MACnD,wBAAwB,QAAQ;AAAA,IAClC;AAAA,EACF,CAAC;AAED,QAAM,SACJ,SAAS,gBACT,iBAAiB,IAAI,CAAC,QAAQ;AAAA,IAC5B;AAAA,IACA,OAAO;AAAA,IACP,QAAQ;AAAA,EACV,EAAE;AAEJ,QAAM,qBAAqB;AAAA,IACzB;AAAA,IACA,SAAS;AAAA,EACX;AAEA,QAAM,uBAAuB,aAAa,OAAO,CAAC,OAAO,GAAG,QAAQ;AACpE,QAAM,oBAAwC;AAAA,IAC5C,GAAG;AAAA,IACH,GAAG;AAAA,EACL;AAEA,SAAO;AAAA,IACL;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA,GAAI,iBAAiB,EAAE,OAAO,cAAc;AAAA,IAC5C,GAAI,SAAS,eAAe,EAAE,aAAa,QAAQ,YAAY;AAAA,IAC/D,GAAI,SAAS,UAAU,EAAE,QAAQ,QAAQ,OAAO;AAAA,EAClD;AACF;AAUA,SAAS,0BACP,YACA,OACiB;AACjB,MAAI,WAAW,cAAc,OAAW,QAAO;AAC/C,MAAI,gBAAgB,WAAW,IAAI,KAAK,MAAM,OAAQ,QAAO;AAE7D,SAAO,EAAE,GAAG,YAAY,WAAW,KAAK;AAC1C;AASO,SAAS,mBACd,OAC8C;AAC9C,SAAOC;AAAA,IACLD,cAA0C,MAAM,MAAM,EACnD;AAAA,MACC,CAAC,CAAC,EAAE,WAAW;AAAA;AAAA,QAEb,eAAeF,WAAoB,WAAW,EAAE,SAAS;AAAA;AAAA,IAC7D,EACC,IAAI,CAAC,CAAC,SAAS,WAAW,MAAM;AAC/B,YAAM,mBAAqCG;AAAA,QACzCD,cAA0C,WAAW,EAElD,OAAO,CAAC,CAAC,EAAE,WAAW,MAAM,eAAe,YAAY,SAAS,CAAC,EACjE,IAAI,CAAC,CAAC,UAAU,WAAW,MAAM;AAAA,UAChC;AAAA,UACA,YAAY;AAAA,YAAI,CAAC,eACf,0BAA0B,YAAY,OAAO;AAAA,UAC/C;AAAA,QACF,CAAC;AAAA,MACL;AACA,aAAO,CAAC,SAAS,gBAAgB;AAAA,IACnC,CAAC,EACA,OAAO,CAAC,CAAC,EAAE,QAAQ,MAAMF,WAAoB,QAAQ,EAAE,SAAS,CAAC;AAAA,EACtE;AACF;AAGA,SAAS,gBACP,YACA,gBACyD;AACzD,QAAM,cAAcE,cAA0C,UAAU,EAErE,OAAO,CAAC,CAAC,EAAE,WAAW,MAAM,gBAAgB,MAAS,EACrD,IAAI,CAAC,CAAC,UAAU,WAAW,MAAM;AAChC,UAAM,CAAC,YAAY,WAAW,IAAID;AAAA,MAAU;AAAA,MAAa,CAAC,MACxD,eAAe,IAAI,EAAE,EAAE;AAAA,IACzB;AACA,WAAO,EAAE,UAAU,YAAY,YAAY;AAAA,EAC7C,CAAC;AACH,SAAO;AAAA,IACL,QAAQ,OAAO;AAAA,MACb,YACG,OAAO,CAAC,MAAM,EAAE,WAAW,SAAS,CAAC,EACrC,IAAI,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC;AAAA,IAC1C;AAAA,IACA,SAAS,OAAO;AAAA,MACd,YACG,OAAO,CAAC,MAAM,EAAE,YAAY,SAAS,CAAC,EACtC,IAAI,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,WAAW,CAAC;AAAA,IAC3C;AAAA,EACF;AACF;AASO,SAAS,mBAAmB,QAA0C;AAG3E,QAAM,CAAC,cAAc,aAAa,IAAIA;AAAA,IAAU,OAAO;AAAA,IAAQ,CAAC,MAC9D,WAAW,GAAG,QAAQ;AAAA,EACxB;AACA,QAAM,CAAC,cAAc,aAAa,IAAIA;AAAA,IAAU,OAAO;AAAA,IAAQ,CAAC,MAC9D,WAAW,GAAG,QAAQ;AAAA,EACxB;AAIA,QAAM,iBAAiB,IAAI,IAAI,aAAa,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;AAC5D,QAAM,cAAmD,CAAC;AAC1D,QAAM,eAAoD,CAAC;AAE3D,MAAI,OAAO,OAAO;AAChB,eAAW,SAAS,cAAc;AAChC,YAAM,aAAa,OAAO,MAAM,MAAM,IAAI;AAC1C,UAAI,CAAC,WAAY;AACjB,YAAM,QAAQ,gBAAgB,YAAY,cAAc;AACxD,UAAID,WAAoB,MAAM,MAAM,EAAE,SAAS,GAAG;AAChD,oBAAY,MAAM,IAAI,IAAI,MAAM;AAAA,MAClC;AACA,UAAIA,WAAoB,MAAM,OAAO,EAAE,SAAS,GAAG;AACjD,qBAAa,MAAM,IAAI,IAAI,MAAM;AAAA,MACnC;AAAA,IACF;AACA,eAAW,SAAS,eAAe;AACjC,YAAM,aAAa,OAAO,MAAM,MAAM,IAAI;AAC1C,UAAI,YAAY;AACd,qBAAa,MAAM,IAAI,IAAI;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AAeA,QAAM,eAA8B;AAAA,IAClC,GAAGI,MAAK,QAAQ,mBAAmB;AAAA,IACnC,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,OAAO;AAAA,EACT;AAEA,QAAM,gBAA+B;AAAA,IACnC,GAAG;AAAA,IACH,MAAM,OAAO;AAAA,IACb,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,OAAO;AAAA,EACT;AAEA,SAAO,EAAE,QAAQ,cAAc,SAAS,cAAc;AACxD;AAsDA,IAAM,eAAe,IAAI,IAAY,WAAW;AAGhD,SAAS,eAAe,OAA6B;AACnD,SACE,MAAM,kBAAkB,KAAK,CAAC,MAAM,EAAE,OAAO,GAAG,QAChD;AAEJ;AAEA,SAAS,sBACP,YACA,QACA,UACA,SACM;AACN,QAAM,qBAAsB,WAAW,MAAM,MAAM,CAAC;AACpD,QAAM,YAAa,mBAAmB,QAAQ,MAAM,CAAC;AACrD,MAAI,CAAC,UAAU,SAAS,OAAO,EAAG,WAAU,KAAK,OAAO;AAC1D;AAOA,SAAS,gBACP,OACA,OACA,UACA,YACM;AACN,QAAM,aAAc,MAAM,KAAK,MAAM,CAAC;AACtC,QAAM,cAAe,WAAW,QAAQ,MAAM,CAAC;AAC/C,cAAY,KAAK,UAAU;AAC7B;AAGA,SAAS,kBACP,SACA,MACiB;AACjB,SAAO,EAAE,IAAI,SAAS,WAAW,SAAS,YAAY;AACxD;AAYA,SAAS,aAAa,QAA6C;AACjE,QAAM,QAAQ,oBAAI,IAA0B;AAC5C,QAAM,cAAc,oBAAI,IAAY;AACpC,QAAM,UAAoB,CAAC;AAE3B,aAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AAClD,QAAI,CAACN,aAAY,IAAI,EAAG,SAAQ,KAAK,IAAI;AAAA,aAChC,MAAM,OAAO,MAAO,aAAY,IAAI,IAAI;AAAA,QAC5C,OAAM,IAAI,MAAM,KAAK;AAAA,EAC5B;AAEA,SAAO,EAAE,OAAO,aAAa,QAAQ;AACvC;AAMA,SAAS,iBACP,MACA,OACkB;AAClB,SAAO;AAAA,IACL;AAAA,IACA,OAAO,eAAe,KAAK;AAAA,IAC3B,GAAI,OAAO,UAAU,UAAa,EAAE,OAAO,MAAM,MAAM;AAAA,IACvD,GAAI,OAAO,WAAW,UAAa,EAAE,QAAQ,MAAM,OAAO;AAAA,EAC5D;AACF;AAWA,SAAS,2BACP,aACQ;AACR,SAAO;AAAA,IACL;AAAA,IAEA,GAAG,YAAY,IAAI,CAAC,EAAE,SAAS,MAAM,MAAM,KAAK,OAAO,OAAO,KAAK,EAAE;AAAA,IACrE;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AA6BO,SAAS,mBACd,SACA,SACa;AACb,QAAM,mBAAqC,CAAC;AAC5C,QAAM,gBAA8D,CAAC;AACrE,QAAM,SAAwB,CAAC;AAC/B,QAAM,kBAA4B,CAAC;AACnC,QAAM,aAAqC,CAAC;AAC5C,QAAM,aAAa,oBAAI,IAAe;AACtC,QAAM,WAAW,aAAa,QAAQ,MAAM;AAC5C,QAAM,oBAAoB,IAAI,IAAY,SAAS,OAAO;AAE1D,aAAW,CAAC,SAAS,KAAK,KAAK,OAAO,QAAQ,QAAQ,MAAM,GAAG;AAC7D,UAAM,QAAQ,QAAQ,OAAO,OAAO;AACpC,UAAM,SAAS,OAAO,WAClB,eAAe,SAAS,MAAM,QAAQ,IACtC;AAEJ,QAAI,CAAC,OAAO,YAAY,WAAW,QAAW;AAC5C,sBAAgB,KAAK,OAAO;AAC5B;AAAA,IACF;AAKA,UAAM,KAAK;AACX,UAAM,WAAW,MAAM;AAEvB,0BAAsB,kBAAkB,QAAkB,UAAU,EAAE;AAEtE,WAAO,KAAK;AAAA,MACV;AAAA,MACA,OAAO,MAAM;AAAA;AAAA,MAEb,QAAQ,MAAM,YAAY,UAAU,eAAe,eAAe,KAAK;AAAA,IACzE,CAAC;AAID,eAAW,CAAC,WAAW,IAAI,KAAK,OAAO,QAAQ,MAAM,WAAW,GAAG;AACjE,UAAI,SAAS,YAAY,IAAI,SAAS,EAAG;AACzC,UAAI,CAAC,aAAa,IAAI,SAAS,GAAG;AAChC,0BAAkB,IAAI,SAAS;AAC/B;AAAA,MACF;AAGA,YAAM,QAAQ;AAGd,UACE,CAAC;AAAA,QACC,MAAM;AAAA,QACN,eAAe,SAAS,MAAM,IAAI,KAAK,CAAC;AAAA,MAC1C,GACA;AACA,mBAAW,KAAK,EAAE,SAAS,IAAI,MAAM,CAAC;AACtC;AAAA,MACF;AAEA,iBAAW,IAAI,KAAK;AAGpB;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA,kBAAkB,IAAI,IAAI;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AAEA,MAAI,WAAW,SAAS;AACtB,UAAM,IAAI,MAAM,2BAA2B,UAAU,CAAC;AAGxD,aAAW,CAAC,MAAM,KAAK,KAAK,SAAS,OAAO;AAC1C,QAAI,MAAM,OAAO,KAAM,YAAW,IAAI,IAAI;AAAA,EAC5C;AAEA,QAAM,iBAAiB,CAAC,GAAG,UAAU;AAErC,SAAO;AAAA,IACL,QAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA,cAAc,eAAe;AAAA,QAAI,CAAC,SAChC,iBAAiB,MAAM,SAAS,MAAM,IAAI,IAAI,CAAC;AAAA,MACjD;AAAA,MACA;AAAA,MACA,iBAAiB,QAAQ;AAAA;AAAA;AAAA;AAAA,MAIzB,GAAI,QAAQ,gBAAgB,UAAa;AAAA,QACvC,aAAa,QAAQ;AAAA,MACvB;AAAA,MACA;AAAA,MACA,iBAAiB,aAAaE,WAAkB,gBAAgB,CAAC;AAAA;AAAA;AAAA,MAGjE,sBAAsB,CAAC;AAAA,MACvB,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA,MAKX,YAAY;AAAA,QACV,OAAO,IAAI,CAAC,UAAU,MAAM,EAAE;AAAA,QAC9B;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,IACA,mBAAmB,CAAC,GAAG,iBAAiB;AAAA,EAC1C;AACF;;;AItnCA,SAAS,WAAAK,UAAS,QAAAC,OAAM,MAAM,YAAAC,iBAAgB;;;ACA9C,OAAOC,SAAQ;AACf,OAAOC,WAAU;;;ACDjB,OAAOC,WAAU;AACjB,SAAS,SAAS,WAAAC,UAAS,WAAW,aAAAC,YAAW,MAAM,UAAAC,SAAQ,gBAAgB;AAqB/E,IAAM,cAAc,oBAAI,IAAqB;AAUtC,SAAS,qBAAqB,aAAwD;AAG3F,SAAO,UAAU,aAAa,CAAC,UAAU;AACvC,UAAM,QAAQ,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AACnD,WAAO,MAAM,IAAI,CAAC,SAA0B;AAC1C,UAAI,OAAO,SAAS,SAAU,QAAO,EAAE,IAAI,MAAiB,WAAW,MAAM;AAC7E,UAAI,kBAAkB,IAAI,EAAG,QAAO;AACpC,WAAK,6CAA6C,KAAK,UAAU,IAAI,CAAC,EAAE;AACxE,aAAO;AAAA,IACT,CAAC;AAAA,EACH,CAAC;AACH;AAQA,SAAS,eAAe,SAAwC;AAC9D,QAAM,WAAW,OAAO,OAAO,OAAO,GAAG;AACzC,MAAI,aAAa,UAAa,aAAa,sBAAuB,QAAO;AAEzE,SAAO;AACT;AAQA,SAAS,iBAAiB,aAAmD;AAC3E,SAAO,aAA0C,WAAW,EAAE;AAAA,IAC5D,CAAC,CAAC,gBAAgB,WAAW;AAAA;AAAA,OAE1B,eAAe,CAAC,GAAG,IAAI,CAAC,gBAAgB;AAAA,QACvC;AAAA,QACA,cAAc,eAAe,WAAW,EAAE,KAAK;AAAA,QAC/C;AAAA,MACF,EAAE;AAAA;AAAA,EACN;AACF;AAkBA,SAAS,sBAAsB,aAAiD;AAC9E,QAAM,CAAC,SAAS,KAAK,IAAIC;AAAA,IACvB,iBAAiB,WAAW;AAAA,IAC5B,CAAC,WAAW,OAAO,iBAAiB,OAAO;AAAA,EAC7C;AAEA,MAAI,MAAM,SAAS,GAAG;AACpB;AAAA,MACE,oDACE,MACG,IAAI,CAAC,MAAM,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,cAAc,OAAO,EAAE,YAAY,GAAG,EAC1E,KAAK,IAAI;AAAA,IAChB;AAAA,EACF;AAEA,SAAO;AAAA,IACLC,SAAQ,CAAC,GAAG,SAAS,GAAG,KAAK,GAAG,CAAC,WAAW,OAAO,YAAY;AAAA,IAC/D,CAAC,WACC;AAAA,MACE,OAAO,IAAI,CAAC,MAAM,EAAE,UAAU;AAAA,MAC9B,CAAC,eAAe,WAAW;AAAA,IAC7B;AAAA,EACJ;AACF;AAaO,SAAS,qBACd,UACkC;AAClC,SAAO;AAAA,IAAU;AAAA,IAAU,CAAC,gBAC1B,sBAAsB,qBAAqB,WAAW,CAAC;AAAA,EACzD;AACF;AAEA,eAAsB,WAAW,WAAmB,YAAuC;AACzF,QAAM,qBAAqB,cAAc;AACzC,QAAM,WAAW,GAAG,SAAS,IAAI,kBAAkB;AACnD,QAAM,SAAS,YAAY,IAAI,QAAQ;AACvC,MAAI,OAAQ,QAAO;AAEnB,QAAM,aAAaC,MAAK,KAAK,WAAW,kBAAkB;AAE1D,MAAI;AACF,UAAM,MAAM,MAAM,WAAW,YAAY,kBAAkB;AAE3D,QAAI,OAAO,MAAM;AACf,cAAQ,2BAA2B,UAAU,EAAE;AAC/C,aAAO,CAAC;AAAA,IACV;AAKA,UAAM,SAAkB,IAAI,OAAO,IAAI,CAAC,WAAW;AAAA,MACjD,GAAG;AAAA,MACH,QAAQ;AAAA,QACN,MAAM;AAAA,QACN,CAAC,gBAAgB,qBAAqB,WAAW;AAAA,MACnD;AAAA,IACF,EAAE;AAEF,gBAAY,IAAI,UAAU,MAAM;AAChC,YAAQ,UAAU,OAAO,MAAM,gBAAgB,UAAU,EAAE;AAE3D,WAAO;AAAA,EACT,SAAS,OAAO;AACd,UAAM,eAAe,gBAAgB,KAAK;AAC1C,UAAM,IAAI,MAAM,+BAA+B,UAAU,MAAM,YAAY,IAAI;AAAA,MAC7E,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACF;AAiBA,eAAsB,cACpB,SACA,WACA,QACuB;AACvB,QAAM,SAAS,MAAM,WAAW,SAAS;AACzC,QAAM,QAAQ,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,OAAO;AAEjD,MAAI,OAAO;AACT,YAAQ,gBAAgB,MAAM,IAAI,KAAK,OAAO,GAAG;AACjD,WAAO;AAAA,EACT;AAEA,MAAI,CAAE,MAAM,oBAAoB,WAAW,MAAM,GAAI;AACnD;AAAA,MACE,gBAAgB,MAAM,0BAA0B,OAAO;AAAA,IACzD;AACA,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,cAAc,KAAK,CAAC,MAAM,EAAE,OAAO,OAAO,KAAK;AACpE,MAAI,cAAc;AAChB,YAAQ,wBAAwB,aAAa,IAAI,KAAK,OAAO,GAAG;AAAA,EAClE,OAAO;AACL,YAAQ,UAAU,OAAO,yDAAyD;AAAA,EACpF;AACA,SAAO;AACT;AAUO,SAAS,uBAAuB,SAAiB,QAAwB;AAC9E,SACE,UAAU,OAAO,gCAAgC,MAAM;AAI3D;AAgBO,SAAS,qBAAqB,UAA0B;AAC7D,SAAO,yBAAyB,QAAQ;AAC1C;AAgBA,SAAS,eAAe,SAAkB,UAA4B;AACpE,QAAM,SAAS,OAAO,OAAO,OAAO,GAAG;AACvC,SAAO,WAAW,UAAa,OAAO,KAAK,MAAM,KAAK,SAAS,qBAAqB,QAAQ;AAC9F;AAIO,SAAS,2BAA2B,aAAiD;AAC1F,SAAO,aAA0C,WAAW,EAAE;AAAA,IAAQ,CAAC,CAAC,UAAU,WAAW;AAAA;AAAA,OAE1F,eAAe,CAAC,GAAG,IAAI,CAAC,gBAAgC;AAAA,QACvD,IAAI,WAAW;AAAA,QACf,OAAO,eAAe,WAAW,IAAI,QAAQ;AAAA,QAC7C,WAAW,WAAW,aAAa;AAAA,MACrC,EAAE;AAAA;AAAA,EACJ;AACF;AAGO,SAAS,iBAAiB,OAAoD;AACnF,SAAO;AAAA,IACL,OAAO,OAAO,KAAK;AAAA,IACnB,QAAQ,0BAA0B;AAAA,IAClC,CAAC,SAAS,KAAK,IAAI,CAAC,MAAM,EAAE,EAAE;AAAA,IAC9BC,QAAO;AAAA,EACT;AACF;;;AD1PO,IAAM,kBAAN,cAA8B,MAAM;AAAA,EAGzC,YACW,YACA,QAEA,WACT;AACA,UAAM,cAAc,UAAU,0BAA0B,MAAM,EAAE;AALvD;AACA;AAEA;AAGT,SAAK,OAAO;AACZ,SAAK,QAAQ,gBAAgB,SAAS,IAAI,WAAW;AAAA,EACvD;AAAA,EARW;AAAA,EACA;AAAA,EAEA;AAAA,EANF;AAYX;AAaA,eAAsB,yBACpB,YACA,UACqC;AACrC,SAAO,oBAAoB,qBAAqB,YAAY,QAAQ,GAAG,YAAY,QAAQ;AAC7F;AAQA,eAAsB,oBACpB,YACA,YACA,UACqC;AACrC,QAAM,QAAQ,gBAAgB,UAAU,IAAI,WAAW;AACvD,QAAMC,cAAa,UAAU,YAAY,YAAY;AAErD,MAAI,CAAE,MAAM,WAAW,UAAU,GAAI;AACnC,YAAQ,GAAGA,WAAU,wBAAwB,UAAU,EAAE;AACzD,WAAO;AAAA,EACT;AAKA,MAAI;AACJ,MAAI;AAEF,UAAM,MAAM,WAA0B,UAAU;AAAA,EAClD,SAAS,OAAO;AACd,UAAM,IAAI,gBAAgB,YAAY,gBAAgB,KAAK,GAAG,UAAU;AAAA,EAC1E;AAEA,MAAI,CAAC,OAAO,OAAO,QAAQ,UAAU;AACnC,UAAM,IAAI,gBAAgB,YAAY,yBAAyB,UAAU;AAAA,EAC3E;AAEA,QAAM,SAAS,0BAA0B,UAAU,GAAG;AACtD,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,IAAI,gBAAgB,YAAY,gBAAgB,OAAO,KAAK,EAAE,KAAK,IAAI,GAAG,UAAU;AAAA,EAC5F;AAIA,QAAM,SAAS,OAAO;AACtB,QAAM,kBAAkB,OAAO,QAAQ,qBAAqB,OAAO,KAAK,IAAI;AAC5E,MAAI,OAAO,SAAS,QAAW;AAC7B;AAAA,MACE,sBAAsB,UAAU;AAAA,IAClC;AAAA,EACF;AACA,MAAI,OAAO,WAAW,QAAW;AAC/B,SAAK,sBAAsB,UAAU,wDAAmD;AAAA,EAC1F;AAYA,QAAM,SAAS;AAAA,IACb,GAAG;AAAA,IACH,MAAM,OAAO,QAAQC,MAAK,SAAS,UAAU;AAAA,IAC7C,QAAQ,OAAO,UAAU,CAAC;AAAA,IAC1B,QAAQ,OAAO,UAAU,CAAC;AAAA,IAC1B,GAAI,mBAAmB,EAAE,OAAO,gBAAgB;AAAA,EAClD;AAEA,UAAQ,UAAU,KAAK,gBAAgB,UAAU,EAAE;AACnD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AASA,eAAsB,oBAAoB,KAAkD;AAC1F,SAAO,yBAAyB,KAAK,cAAc,GAAG,CAAC;AACzD;AAMO,SAAS,iBAAiB,YAA8B;AAC7D,SAAO,gBAAgB,UAAU,IAAI,CAAC,UAAU,IAAI,CAAC,YAAYC,IAAG,QAAQ,CAAC;AAC/E;AAYA,eAAsB,uBAAuB,YAAgD;AAC3F,QAAM,WAAW,MAAM,QAAQ,IAAI,iBAAiB,UAAU,EAAE,IAAI,iBAAiB,CAAC;AACtF,SAAO,SAAS,OAAO,CAAC,YAAwC,YAAY,MAAS;AACvF;AAEA,eAAe,kBAAkB,KAAmD;AAClF,MAAI;AACF,UAAM,oBAAoB,GAAG;AAC7B,WAAO;AAAA,EACT,SAAS,OAAO;AACd,QAAI,iBAAiB,gBAAiB,QAAO;AAC7C,UAAM;AAAA,EACR;AACF;AAiBA,eAAsB,kBAAkB,YAAyD;AAC/F,QAAM,WAAW,cAAc,UAAU;AACzC,QAAM,gBAAgB,MAAM,yBAAyB,YAAY,QAAQ;AACzE,MAAI,cAAe,QAAO;AAG1B,QAAM,UAAUA,IAAG,QAAQ;AAC3B,MAAI,CAAC,gBAAgB,UAAU,GAAG;AAChC,WAAO,yBAAyB,SAAS,QAAQ;AAAA,EACnD;AAEA,SAAO;AACT;AAQO,SAAS,sBAAsB,QAAmC;AACvE,QAAM,SAAS,0BAA0B,UAAU,MAAM;AACzD,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,EAAE,OAAO,OAAO,QAAQ,gBAAgB,OAAO,KAAK,GAAG,UAAU,CAAC,EAAE;AAAA,EAC7E;AAEA,QAAM,SAAS;AAAA,IACb,GAAI,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,uCAAuC;AAAA,IACpE,GAAI,OAAO,KAAK,SAAS,CAAC,IAAI,CAAC,yCAAyC;AAAA,EAC1E;AACA,SAAO,EAAE,OAAO,OAAO,WAAW,GAAG,QAAQ,UAAU,CAAC,EAAE;AAC5D;;;AD/MA,IAAM,WAAW,CAAC,MAChB,GAAG,EAAE,IAAI,IAAI,EAAE,KAAK,GAAG,EAAE,WAAW,cAAc,EAAE;AAOtD,IAAM,WAAW,CAAC,MAA2B,GAAG,EAAE,EAAE,IAAI,EAAE,KAAK,GAAG,EAAE,WAAW,cAAc,EAAE;AAQ/F,IAAM,iBAAmD;AAAA,EACvD,OAAO;AAAA,EACP,YAAY,CAAC,UAAU,MAAM;AAC/B;AAEA,IAAM,iBAA8C;AAAA,EAClD,OAAO;AAAA,EACP,YAAY,CAAC,UAAU,MAAM;AAC/B;AAUA,SAAS,yBAAyB,OAAoB,OAAoC;AACxF,MAAI,UAAU,MAAO,QAAO;AAC5B,SAAO,eAAe,KAAK;AAC7B;AAUA,SAAS,YACP,UACA,UACA,UACA,oBACS;AACT,QAAM,gBAAgBC,SAAQ,UAAU,SAAS,KAAK;AACtD,QAAM,qBAAqB,IAAI,IAAI,SAAS,IAAI,SAAS,UAAU,CAAC;AACpE,QAAM,eAAe,IAAI,IAAI,SAAS,IAAI,SAAS,KAAK,CAAC;AAMzD,QAAM,sBAAsB,IAAI,IAAI,SAAS,OAAO,iBAAiB,EAAE,IAAI,SAAS,UAAU,CAAC;AAE/F,QAAM,kBAAkB,SAAS,QAAQ,CAAC,UAAU;AAClD,UAAM,WAAW,cAAc,SAAS,MAAM,KAAK,CAAC;AACpD,QAAI,aAAa,OAAW,QAAO,CAAC,QAAQ;AAI5C,QAAI,mBAAmB,IAAI,SAAS,WAAW,KAAK,CAAC,EAAG,QAAO,CAAC;AAChE,QAAI,oBAAoB,IAAI,SAAS,WAAW,KAAK,CAAC,EAAG,QAAO,CAAC;AAGjE,QAAI,sBAAsB,yBAAyB,OAAO,kBAAkB,EAAG,QAAO,CAAC;AACvF,WAAO,CAAC,KAAK;AAAA,EACf,CAAC;AACD,QAAM,QAAQ,SAAS,OAAO,CAAC,UAAU,CAAC,aAAa,IAAI,SAAS,MAAM,KAAK,CAAC,CAAC;AACjF,SAAOC,UAAS,CAAC,GAAG,iBAAiB,GAAG,KAAK,GAAG,SAAS,KAAK;AAChE;AA4CO,SAAS,aACd,WACA,gBACA,SACe;AACf,QAAM,SAAS,EAAE,GAAG,UAAU;AAE9B,MAAI,eAAe,MAAM;AACvB,WAAO,OAAO,eAAe;AAAA,EAC/B;AAEA,MAAI,eAAe,aAAa;AAC9B,WAAO,cAAc,eAAe;AAAA,EACtC;AAEA,MAAI,eAAe,eAAe,CAAC,UAAU,aAAa;AACxD,WAAO,cAAc,eAAe;AAAA,EACtC;AAEA,SAAO,SAAS;AAAA,IACd,OAAO;AAAA,IACP,eAAe;AAAA,IACf;AAAA,IACA,SAAS;AAAA,EACX;AACA,SAAO,SAAS;AAAA,IACd,OAAO;AAAA,IACP,eAAe;AAAA,IACf;AAAA,IACA,SAAS;AAAA,EACX;AAKA,MAAI,UAAU,UAAU,UAAa,eAAe,OAAO;AACzD,WAAO,QAAQ,eAAe;AAAA,EAChC;AAEA,MAAI,eAAe,QAAQ;AACzB,WAAO,SAAS,eAAe;AAAA,EACjC;AAEA,MAAI,eAAe,cAAc;AAC/B,WAAO,eAAe,eAAe;AAAA,EACvC;AAIA,MAAI,eAAe,mBAAmB,OAAO,gBAAgB,eAAe,aAAa;AACvF,WAAO,kBAAkB,eAAe;AAAA,EAC1C;AAIA,SAAO,OAAO,QAAQ,KAAK,gBAAgB,mBAAmB,CAAC;AAK/D,MAAI,eAAe,YAAY,CAAC,UAAU,UAAU;AAClD,WAAO,WAAW,eAAe;AAAA,EACnC;AAEA,SAAO;AACT;AAmBA,SAAS,uBACP,QACA,YACA,SACe;AAGf,QAAM,oBAAoB,OAAO,eAAe,qBAAqB,YAAY,OAAO,QAAQ;AAChG,MAAI,kBAAmB,QAAO,OAAO;AAErC,SAAO,EAAE,GAAGC,MAAK,OAAO,QAAQ,mBAAmB,GAAG,MAAM,QAAQ;AACtE;AAEA,eAAsB,wBACpB,WACA,SACsB;AACtB,QAAM,qBAAqB,MAAM,kBAAkB,QAAQ,UAAU;AACrE,MAAI,oBAAoB;AAKtB,UAAM,iBAAiB;AAAA,MACrB;AAAA,MACA,QAAQ;AAAA,MACR,UAAU;AAAA,IACZ;AACA,UAAM,SAAS,aAAa,WAAW,gBAAgB;AAAA,MACrD,GAAI,QAAQ,uBAAuB,UAAa;AAAA,QAC9C,oBAAoB,QAAQ;AAAA,MAC9B;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL;AAAA,MACA,QAAQ;AAAA,MACR,oBAAoB,mBAAmB;AAAA,IACzC;AAAA,EACF;AAMA,QAAM,cAAc,EAAE,GAAG,UAAU;AACnC,QAAM,wBAAwB,MAAM,wBAAwB,QAAQ,UAAU;AAC9E,MAAI,uBAAuB,QAAQ;AACjC,gBAAY,SAAS,sBAAsB;AAAA,EAC7C;AACA,MAAI,uBAAuB,cAAc;AACvC,gBAAY,eAAe,sBAAsB;AAAA,EACnD;AAEA,SAAO,EAAE,QAAQ,aAAa,QAAQ,MAAM;AAC9C;;;AG1SA,SAAS,WAAAC,UAAS,UAAAC,eAAc;AA4ChC,IAAM,mBAAmB;AAyBzB,SAAS,mBAAmB,SAAoC;AAC9D,SAAO,UAAU,QAAQ,IAAI,SAAS,CAAC;AACzC;AAMO,IAAM,8BAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAY/B,mBAAmB,WAAW,CAAC;AAAA,aAC9B,mBAAmB,YAAY,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAUtC,IAAM,iCAAiC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2DvC,IAAM,gCACX;AAeK,SAAS,0BAA0B,OAS/B;AACT,QAAM,gBAAgB,MAAM,cAAc,GAAG,MAAM,WAAW;AAAA;AAAA,IAAS;AACvE,SAAO;AAAA;AAAA,EAEP,aAAa,GAAG,YAAY,WAAW,MAAM,OAAO,CAAC;AAAA;AAAA,EAErD,YAAY,aAAa,MAAM,SAAS,CAAC;AAAA;AAAA,EAEzC,YAAY,qBAAqB,MAAM,iBAAiB,CAAC;AAAA;AAAA,EAEzD,YAAY,oBAAoB,MAAM,gBAAgB,CAAC;AAAA;AAAA,EAEvD,YAAY,UAAU,MAAM,MAAM,CAAC;AAAA;AAAA,EAEnC,YAAY,YAAY,MAAM,QAAQ,CAAC;AAAA;AAAA,EAEvC,2BAA2B;AAAA,EAC3B,MAAM,gBAAgB;AAAA;AAAA,EAEtB,8BAA8B;AAChC;AAmBA,SAAS,aAAa,SAAsC;AAC1D,SAAO,QAAQ,WAAW,IACtB,cAAc,gBAAgB,IAC9B,EAAE,MAAM,SAAS,SAAS,QAAQ,IAAI,SAAS,EAAE;AACvD;AAGA,SAAS,cAAc,MAAwB;AAC7C,SAAO,EAAE,MAAM,SAAS,SAAS,CAAC,IAAI,EAAE;AAC1C;AAGA,SAAS,YAAY,MAAc,KAAuB;AACxD,QAAM,OAAO,eAAe,IAAI;AAChC,MAAI,IAAI,SAAS,aAAa;AAC5B,WAAO,GAAG,IAAI;AAAA,EAAK,qBAAqB,IAAI,QAAQ,IAAI,WAAW,CAAC;AAAA,EACtE;AAEA,QAAM,SAAS,YAAY,IAAI,SAAS;AAAA,IACtC,WAAW,KAAK,SAAS,IAAI;AAAA,IAC7B,WAAW;AAAA,IACX,YAAY;AAAA,EACd,CAAC;AAED,SAAO,WAAW,WACd,GAAG,IAAI,IAAI,UAAU,IAAI,OAAO,CAAC,KACjC,GAAG,IAAI;AAAA,EAAK,gBAAgB,IAAI,SAAS,QAAQ,WAAW,CAAC;AACnE;AAYA,SAAS,qBACP,QACA,aACQ;AACR,MAAI,YAAY,SAAS,GAAG;AAC1B,WAAO;AAAA,MACL,eAAe,QAAQ;AAAA,MACvB,gBAAgB,QAAQ,WAAW,WAAW;AAAA,MAC9C,eAAe,aAAa;AAAA,MAC5B,gBAAgB,aAAa,WAAW,WAAW;AAAA,IACrD,EAAE,KAAK,IAAI;AAAA,EACb;AAEA,SAAO;AAAA,IACL,eAAe,QAAQ;AAAA,IACvB;AAAA,MACE;AAAA,MACA,kBAAkB,QAAQ,WAAW;AAAA,MACrC;AAAA,IACF;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAGA,SAAS,eAAe,MAAsB;AAC5C,SAAO,GAAG,OAAO,WAAW,CAAC,MAAM,IAAI;AACzC;AAWA,SAAS,yBACP,kBACA,SACQ;AACR,MAAI,iBAAiB,SAAS,GAAG;AAC/B,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,CAAC,GAAG,iBAAiB,QAAQ,CAAC,EAG9C,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC,EACjC,IAAI,CAAC,CAAC,UAAU,MAAM,MAAM,oBAAoB,UAAU,QAAQ,OAAO,CAAC;AAE7E,SAAO,CAAC,oCAAoC,GAAG,YAAY,GAAG,EAAE,KAAK,IAAI;AAC3E;AAWA,SAAS,oBACP,UACA,QACA,SACQ;AACR,QAAM,UAAU,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE,IAAI,SAAS;AAChD,QAAM,OAAO,IAAI,oBAAoB,SAAS,QAAQ,IAAI,KAAK,IAAI;AACnE,QAAM,OAAO,GAAG,OAAO,WAAW,CAAC,GAAG,UAAU,QAAQ,CAAC;AACzD,QAAM,aAAa,cAAc;AAEjC,QAAM,SAAS,YAAY,SAAS;AAAA,IAClC,WAAW,KAAK;AAAA,IAChB,WAAW,KAAK;AAAA,IAChB;AAAA,EACF,CAAC;AACD,MAAI,WAAW,SAAU,QAAO,GAAG,IAAI,GAAG,UAAU,OAAO,CAAC,GAAG,IAAI;AAEnE,SAAO;AAAA,IACL;AAAA,IACA,gBAAgB,SAAS,QAAQ,UAAU;AAAA,IAC3C,GAAG,OAAO,WAAW,CAAC,GAAG,IAAI;AAAA,EAC/B,EAAE,KAAK,IAAI;AACb;AAMA,SAAS,sBACP,UACA,YACA,SAC0B;AAC1B,QAAM,cAAc,IAAI,IAAI,UAAU;AACtC,QAAM,WAAW,CAAC,GAAG,IAAI,IAAI,QAAQ,CAAC,EACnC,IAAI,CAAC,QAAQ,EAAE,IAAI,UAAU,QAAQ,OAAO,EAAE,GAAG,SAAS,EAAE,EAC5D;AAAA,IACC,CAAC,UACC,MAAM,aAAa,UACnB,MAAM,aAAa;AAAA;AAAA;AAAA,IAInB,YAAY,IAAI,MAAM,QAAoB;AAAA,EAC9C;AAEF,SAAO,IAAI;AAAA,IACTC,cAAaC,SAAQ,UAAU,CAAC,UAAU,MAAM,QAAQ,CAAC,EAAE;AAAA,MACzD,CAAC,CAAC,UAAU,OAAO,MAAM,CAAC,UAAU,QAAQ,IAAI,CAAC,UAAU,MAAM,EAAE,CAAC;AAAA,IACtE;AAAA,EACF;AACF;AAWA,SAAS,qBACP,UACA,SACS;AACT,SAAO,QAAQ,WAAW,QAAQ,MAAM;AAC1C;AAcA,SAAS,cAAc,SAAkB,SAAkC;AACzE,QAAM,WAAW,QAAQ,OAAO,OAAO;AACvC,SAAO,aAAa,UAAa,SAAS,WAAW;AACvD;AASA,SAAS,cACP,WACA,UACA,eACS;AACT,SAAO,CAAC,SAAS,IAAI,SAAS,KAAK,cAAc,IAAI,SAAS;AAChE;AAKA,SAAS,eACP,QACA,UACS;AACT,SAAO,CAAC,SAAS,IAAI,MAAM;AAC7B;AAYO,SAAS,0BACd,SACA,YACA,mBAAgC,CAAC,GACjC,QACA,QACQ;AAER,QAAM,gBAAiB,QAAQ,iBAAiB,CAAC;AACjD,QAAM,qBAAsB,QAAQ,mBAAmB,CAAC;AACxD,QAAM,kBAAkB,QAAQ,gBAAgB,CAAC;AACjD,QAAM,qBAAsB,QAAQ,mBAAmB,CAAC;AAExD,MAAI;AACJ,MAAI;AACJ,MAAI;AACJ,MAAI;AAEJ,MAAI,QAAQ;AAEV,UAAM,iBAAiB,OAAO,OAAO,IAAI,CAAC,MAAM,EAAE,EAAE;AACpD,eAAWC,QAAO,CAAC,GAAG,gBAAgB,GAAG,aAAa,CAAC,EAAE,KAAK;AAE9D,UAAM,mBAAmB,OAAO,OAAO,IAAI,CAAC,MAAM,EAAE,IAAI;AACxD,mBAAeA,QAAO,CAAC,GAAG,kBAAkB,GAAG,kBAAkB,CAAC,EAAE,KAAK;AAEzE,UAAM,mBAAmB,iBAAiB,gBAAgB,OAAO;AACjE,iBAAaA,QAAO,CAAC,GAAG,kBAAkB,GAAG,kBAAkB,CAAC,EAAE,KAAK;AAGvE,UAAM,gBAAgB,cAAc,YAAY,OAAO;AACvD,cAAUA,QAAO;AAAA,MACf,GAAG;AAAA,MACH,GAAI,OAAO,mBAAmB,CAAC;AAAA,MAC/B,GAAG;AAAA,IACL,CAAC,EAAE,KAAK;AAAA,EACV,OAAO;AAEL,eAAWA,QAAO;AAAA,MAChB,GAAGC,WAAmB,QAAQ,MAAM;AAAA,MACpC,GAAG;AAAA,IACL,CAAC,EAAE,KAAK;AACR,mBAAeD,QAAO,CAAC,GAAG,YAAY,GAAG,kBAAkB,CAAC,EAAE,KAAK;AACnE,cAAUA,QAAO,CAAC,GAAG,eAAe,OAAO,GAAG,GAAG,eAAe,CAAC,EAAE,KAAK;AACxE,iBAAaA,QAAO;AAAA,MAClB,GAAGC,WAAoB,QAAQ,UAAU;AAAA,MACzC,GAAG;AAAA,IACL,CAAC,EAAE,KAAK;AAAA,EACV;AAEA,QAAM,iBAAiB,IAAI,IAAe,UAAU;AACpD,QAAM,sBAAsB,IAAI,IAAe,gBAAgB;AAC/D,QAAM,kBAAkB,IAAI,IAAY,eAAe,OAAO,CAAC;AAE/D,QAAM,cAAc;AAAA,IAA0B;AAAA,IAAU,CAAC,OACvD,cAAc,IAAI,OAAO;AAAA,EAC3B;AACA,QAAM,gBAAgB;AAAA,IAA0B;AAAA,IAAc,CAAC,SAC7D,cAAc,MAAM,gBAAgB,mBAAmB;AAAA,EACzD;AACA,QAAM,aAAa;AAAA,IAA0B;AAAA,IAAS,CAAC,WACrD,eAAe,QAAQ,eAAe;AAAA,EACxC;AACA,QAAM,eAAe;AAAA,IAA0B;AAAA,IAAY,CAAC,aAC1D,qBAAqB,UAAU,OAAO;AAAA,EACxC;AAEA,QAAM,iBAAiB,QAAQ,SAAS,iBAAiB,OAAO,MAAM,IAAI,CAAC;AAC3E,QAAM,wBACJ,eAAe,SAAS,IACpB,aAAa,cAAc,IAC3B,cAAc,WAAW;AAE/B,QAAM,sBAAsB,QAAQ,SAChC,wBAAwB,OAAO,MAAM,IACrC,CAAC;AACL,QAAM,uBACJ,oBAAoB,SAAS,IACzB,aAAa,mBAAmB,IAChC,cAAc,mBAAmB;AAEvC,QAAM,mBAAmB,sBAAsB,UAAU,YAAY,OAAO;AAC5E,QAAM,uBAAuB;AAAA,IAC3B;AAAA,IACA;AAAA,EACF;AAEA,SAAO,0BAA0B;AAAA,IAC/B,SAAS;AAAA,IACT,WAAW;AAAA,IACX,mBAAmB;AAAA,IACnB,kBAAkB;AAAA,IAClB,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,kBAAkB;AAAA,EACpB,CAAC;AACH;AAIA,SAAS,eAAe,SAAmC;AACzD,SAAO,cAAcA,WAAoB,QAAQ,UAAU,GAAG,OAAO,EAAE,KAAK;AAC9E;AAGA,IAAM,qBAAqB,CACzB,aAEA,QAAQ,QAAQ,KAAK,aAAa;AAM7B,SAAS,iBACd,UACA,SACY;AACZ,SAAOD;AAAA,IACL,SAEG,IAAI,CAAC,OAAO,QAAQ,OAAO,EAAE,GAAG,QAAoC,EACpE,OAAO,kBAAkB;AAAA,EAC9B;AACF;AAMO,SAAS,cACd,YACA,SACU;AACV,SAAOA;AAAA,IACL,WACG,IAAI,CAAC,QAAQ,QAAQ,WAAW,GAAG,GAAG,MAAM,EAC5C,OAAO,CAAC,WAA6B,WAAW,MAAS;AAAA,EAC9D;AACF;AAMA,SAAS,0BACP,SACA,UACU;AACV,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO,cAAc,gBAAgB;AAAA,EACvC;AAEA,QAAM,SAAS,QAAQ,OAAO,QAAQ;AACtC,QAAM,cAAc,QAAQ,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;AAGtD,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO,aAAa,OAAO;AAAA,EAC7B;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,QAAQ,OAAO,IAAI,SAAS;AAAA,IAC5B,aAAa,YAAY,IAAI,SAAS;AAAA,EACxC;AACF;AA2BO,SAAS,iCACd,SACQ;AACR,QAAM,aAAa,GAAG,QAAQ,qBAAqB;AAEnD,QAAM,eAAe;AAAA,IACnB;AAAA,IACA,QAAQ;AAAA,EACV;AACA,QAAM,iBAAiB;AAAA,IACrB;AAAA,IACA,QAAQ;AAAA,EACV;AACA,QAAM,cAAc;AAAA,IAClB;AAAA,IACA,QAAQ;AAAA,EACV;AAEA,QAAM,oBAAoB,QAAQ,qBAAqB,CAAC;AACxD,QAAM,gBAAgB,oBAAoB,kBAAkB,iBAAiB;AAE7E,QAAM,yBAAyB,QAAQ,oBAAoB,SACvD,aAAa,QAAQ,kBAAkB,IACvC,cAAc,WAAW;AAE7B,QAAM,wBAAwB,QAAQ,yBAAyB,SAC3D,aAAa,QAAQ,uBAAuB,IAC5C,cAAc,mBAAmB;AAIrC,QAAM,cAAc;AAAA,IAClB;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,EACF;AAEA,SAAO,0BAA0B;AAAA,IAC/B;AAAA,IACA,SAAS;AAAA,IACT,WAAW;AAAA,IACX,mBAAmB;AAAA,IACnB,kBAAkB;AAAA,IAClB,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,kBAAkB;AAAA,EACpB,CAAC;AACH;AAKO,SAAS,uCAA+C;AAC7D,SAAO,0BAA0B;AAAA,IAC/B,SAAS,cAAc,gBAAgB;AAAA,IACvC,WAAW,cAAc,gBAAgB;AAAA,IACzC,mBAAmB,cAAc,gBAAgB;AAAA,IACjD,kBAAkB,cAAc,mBAAmB;AAAA,IACnD,QAAQ,cAAc,gBAAgB;AAAA,IACtC,UAAU,cAAc,gBAAgB;AAAA,IACxC,kBAAkB;AAAA,EACpB,CAAC;AACH;AAMA,SAAS,oBACP,gBACA,gBACU;AACV,MAAI,eAAe,WAAW,GAAG;AAC/B,WAAO,cAAc,cAAc;AAAA,EACrC;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS,CAAC,gBAAgB,GAAG,CAAC,GAAG,cAAc,EAAE,KAAK,EAAE,IAAI,SAAS,CAAC;AAAA,EACxE;AACF;;;ACptBA,OAAOE,WAAU;AAyCjB,eAAsB,yBAAyB,UAA4C;AACzF,QAAM,wBAAwBC,MAAK;AAAA,IACjC,kBAAkB,kBAAkB,GAAG,QAAQ,EAAE;AAAA,IACjD,eAAe;AAAA,EACjB;AACA,MAAI,MAAM,WAAW,qBAAqB,GAAG;AAC3C,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAgBA,SAAS,6BAA6B,YAAoB,UAA4B;AACpF,QAAM,mBAAmB,kBAAkB,YAAY,QAAQ,EAAE;AACjE,QAAM,kBAAkB,kBAAkB,kBAAkB,GAAG,QAAQ,EAAE;AACzE,QAAM,eAAeA,MAAK,SAAS,kBAAkB,eAAe;AAEpE,SAAO,aAAa,MAAMA,MAAK,GAAG,EAAE,KAAK,GAAG;AAC9C;AAkBO,SAAS,+BACdC,SACA,QAC2B;AAC3B,QAAM,aAAa,UAAqB,MAAM;AAC9C,SAAO;AAAA,IACL,QAAAA;AAAA,IACA;AAAA,IACA,kBAAkB,WAAW,OAAO,CAAC,SAAS,OAAO,IAAI,GAAG,WAAW,IAAI;AAAA,EAC7E;AACF;AAUA,eAAsB,sBACpB,YACA,gBACA,QACe;AAGf,QAAM,WAAW,cAAc,UAAU;AAMzC,MAAI,gBAAgB,UAAU,GAAG;AAC/B,UAAM,IAAI;AAAA,MACRD,MAAK,KAAK,kBAAkB,YAAY,QAAQ,EAAE,KAAK,eAAe,eAAe;AAAA,IACvF;AAAA,EACF;AAEA,QAAM,OAAO,MAAM;AAEnB,QAAM,kBAAkB,kBAAkB,YAAY,QAAQ,EAAE;AAIhE,QAAM,oBAAoB,MAAM,yBAAyB,QAAQ;AACjE,QAAM,eAAe,MAAM,yBAAyB,YAAY,QAAQ;AAOxE,QAAM,SAAS,oBACX,2BAA2B,YAAY,UAAU,cAAc,OAAO,QAAQ,MAAM,IACpF;AAAA,IACE,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL;AAAA,IACA,cAAc;AAAA,EAChB;AAEJ,QAAM,kBAAkBA,MAAK,KAAK,iBAAiB,eAAe,eAAe;AACjF,QAAM,UAAU,iBAAiB,MAAM;AACvC,UAAQ,eAAe,eAAe,eAAe,EAAE;AACzD;AAMA,SAAS,2BACP,YACA,UACA,QACA,QACQ;AACR,QAAM,qBAAqB,SAAS,iBAAiB,MAAM,IAAI;AAC/D,QAAM,0BAA0B,SAAS,wBAAwB,MAAM,IAAI;AAC3E,QAAM,SAAS,iCAAiC;AAAA,IAC9C,uBAAuB,6BAA6B,YAAY,QAAQ;AAAA,IACxE,iBAAiB,QAAQ,iBAAiB,CAAC;AAAA,IAC3C,mBAAmB,QAAQ,mBAAmB,CAAC;AAAA,IAC/C,gBAAgB,QAAQ,gBAAgB,CAAC;AAAA,IACzC,mBAAmB,QAAQ,mBAAmB,CAAC;AAAA,IAC/C,GAAI,oBAAoB,SAAS,EAAE,mBAAmB,IAAI,CAAC;AAAA,IAC3D,GAAI,yBAAyB,SAAS,EAAE,wBAAwB,IAAI,CAAC;AAAA,EACvE,CAAC;AACD,UAAQ,wDAAwD;AAChE,SAAO;AACT;;;ACrLA,OAAOE,YAAU;AACjB,SAAS,SAAS,WAAW,aAAa,qBAAqB;;;ACD/D,SAAS,kBAAkB;AAC3B,OAAOC,WAAU;AAajB,IAAM,kBAAkB;AAEjB,SAAS,iBAAyB;AACvC,UAAO,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,eAAe;AAC1D;AAEO,SAAS,kBAAkB,SAAyB;AACzD,QAAM,OAAO,WAAW,QAAQ;AAChC,OAAK,OAAO,OAAO;AACnB,SAAO,KAAK,OAAO,KAAK,EAAE,MAAM,GAAG,kBAAkB;AACvD;AAEA,eAAsB,gBAAgB,UAAmC;AACvE,QAAM,UAAU,MAAM,SAAS,QAAQ;AACvC,SAAO,kBAAkB,OAAO;AAClC;AAEA,eAAsB,uBAAuB,WAAoC;AAC/E,QAAM,WAAqB,CAAC;AAE5B,aAAW,YAAY,qBAAqB;AAC1C,UAAM,WAAWC,MAAK,KAAK,WAAW,QAAQ;AAC9C,QAAI,MAAM,WAAW,QAAQ,GAAG;AAC9B,YAAM,UAAU,MAAM,SAAS,QAAQ;AACvC,eAAS,KAAK,GAAG,QAAQ,IAAI,OAAO,EAAE;AAAA,IACxC;AAAA,EACF;AAEA,aAAW,WAAW,oBAAoB;AACxC,UAAM,UAAUA,MAAK,KAAK,WAAW,OAAO;AAC5C,QAAI,MAAM,WAAW,OAAO,GAAG;AAC7B,YAAM,QAAQ,MAAM,KAAK,QAAQ,OAAO;AACxC,iBAAW,QAAQ,MAAM,KAAK,GAAG;AAC/B,cAAM,WAAWA,MAAK,KAAK,SAAS,IAAI;AACxC,cAAM,UAAU,MAAM,SAAS,QAAQ;AACvC,iBAAS,KAAK,GAAG,OAAO,IAAI,IAAI,IAAI,OAAO,EAAE;AAAA,MAC/C;AAAA,IACF;AAAA,EACF;AAEA,QAAM,WAAW,SAAS,KAAK,SAAS;AACxC,SAAO,kBAAkB,QAAQ;AACnC;AAOA,IAAM,oBAAoB;AAEnB,SAAS,kBAAkB,SAAyB;AACzD,QAAM,CAAC,EAAE,KAAK,IAAI,QAAQ,MAAM,UAAU,KAAK,CAAC;AAChD,SAAO,UAAU,SAAY,IAAI,SAAS,OAAO,EAAE;AACrD;AAEO,SAAS,iBAAiB,SAAyB;AACxD,QAAM,QAAQ,kBAAkB,OAAO;AACvC,SAAO,GAAG,QAAQ,CAAC;AACrB;AAEA,eAAe,2BACb,WACA,iBACsE;AACtE,QAAM,eAAe,gBAAgB,SAAS;AAE9C,MAAI,CAAE,MAAM,WAAW,YAAY,GAAI;AACrC,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,UAAU,MAAM,aAAa,cAAc,oBAAoB;AACrE,UAAM,WAAW,qBAAqB,MAAM,KAAK,MAAM,OAAO,CAAC;AAE/D,UAAM,eAAe,aAAa,QAAQ,eAAe,aAAa,iBAAiB;AACvF,UAAM,cAAe,MAAM,WAAW,YAAY,KAC7C,MAAM,SAAS,YAAY,GAAG,KAAK,IACpC;AAEJ,WAAO;AAAA,MACL,SAAS,SAAS,WAAW;AAAA,MAC7B;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,SAAK,sCAAsC,YAAY,MAAM,gBAAgB,KAAK,CAAC,EAAE;AACrF,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,uBACpB,SACA,WACA,iBACmD;AACnD,QAAM,WAAW,MAAM,2BAA2B,WAAW,eAAe;AAE5E,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,MACL,SAAS;AAAA,MACT,aAAa;AAAA,IACf;AAAA,EACF;AAEA,MAAI,SAAS,gBAAgB,SAAS;AACpC,WAAO;AAAA,MACL,SAAS,iBAAiB,SAAS,OAAO;AAAA,MAC1C,aAAa;AAAA,IACf;AAAA,EACF;AAEA,SAAO;AAAA,IACL,SAAS,SAAS;AAAA,IAClB,aAAa;AAAA,EACf;AACF;AAEA,eAAsB,iBACpB,WACA,aACA,iBACe;AACf,QAAM,eAAe,gBAAgB,SAAS,EAAE;AAAA,IAC9C,eAAe;AAAA,IACf;AAAA,EACF;AACA,QAAM,UAAU,cAAc,WAAW;AAC3C;;;AC5IO,SAAS,kBAAkB,YAA4B;AAC5D,SAAO,mCAAmC,UAAU;AACtD;AAOO,SAAS,uBAAuB,SAGrC;AACA,QAAM,QAAQ,QAAQ,MAAM,IAAI;AAChC,MAAI,MAAM,CAAC,GAAG,WAAW,yBAAyB,GAAG;AACnD,WAAO,EAAE,eAAe,GAAG,MAAM,CAAC,CAAC;AAAA,GAAM,aAAa,MAAM,MAAM,CAAC,EAAE,KAAK,IAAI,EAAE;AAAA,EAClF;AACA,SAAO,EAAE,eAAe,IAAI,aAAa,QAAQ;AACnD;;;AFoDA,eAAsB,uBAAuB,UAAsD;AACjG,QAAM,WAAW,MAAM,uBAAuB,QAAQ;AACtD,SAAO,UAAU,cAAc;AACjC;AAWA,eAAsB,uBAAuB,UAAsD;AACjG,QAAM,eAAeC,OAAK,KAAK,UAAU,eAAe,aAAa;AAErE,MAAI,CAAE,MAAM,WAAW,YAAY,GAAI;AACrC,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,MAAM,SAAS,YAAY;AAC3C,QAAM,OAAO,SAAS,OAAO;AAE7B,MAAI,CAAC,KAAK,QAAQ;AAChB,SAAK,4BAA4B,YAAY,KAAK,KAAK,MAAM,EAAE;AAC/D,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,yBAAyB,UAAU,KAAK,KAAK;AAE5D,MAAI,CAAC,OAAO,SAAS;AACnB,SAAK,4BAA4B,YAAY,KAAK,gBAAgB,OAAO,MAAM,MAAM,CAAC,EAAE;AACxF,WAAO;AAAA,EACT;AAEA,SAAO,OAAO;AAChB;AA0BA,eAAsB,yBACpB,UACA,SACA,aACA,SAAsD,CAAC,GACxC;AACf,QAAM,eAAeA,OAAK,KAAK,UAAU,eAAe,aAAa;AACrE,QAAM,aAAa,MAAM,SAAS,YAAY;AAC9C,QAAM,EAAE,YAAY,IAAI,uBAAuB,UAAU;AAEzD,QAAM,WAA+B;AAAA,IACnC,GAAG,uBAAuB,aAAa,YAAY;AAAA,IACnD,YAAY;AAAA,MACV;AAAA,MACA;AAAA,MACA,MAAM,eAAe;AAAA,MACrB,GAAI,OAAO,WAAW,UAAa,EAAE,QAAQ,OAAO,OAAO;AAAA,MAC3D,GAAI,OAAO,SAAS,UAAa,EAAE,MAAM,OAAO,KAAK;AAAA,IACvD;AAAA,EACF;AAEA,QAAM,kBAAkB,cAAc,UAAU,GAAG,kBAAkB,aAAa,QAAQ,CAAC;AAAA,CAAI;AACjG;AAMA,eAAsB,kBACpB,UACA,UACA,gBAAgB,IACD;AACf,QAAM,cAAc,cAAc,UAAU,EAAE,WAAW,gBAAgB,gBAAgB,CAAC;AAC1F,QAAM,UAAU,UAAU,gBAAgB,WAAW;AACvD;AAkBA,SAAS,SAAS,SAA2B;AAC3C,MAAI;AACF,WAAO,EAAE,QAAQ,MAAM,OAAO,UAAU,OAAO,EAAE;AAAA,EACnD,SAAS,OAAO;AACd,WAAO,EAAE,QAAQ,OAAO,QAAQ,gBAAgB,KAAK,EAAE;AAAA,EACzD;AACF;AAUA,SAAS,uBACP,aACA,cAC6B;AAC7B,QAAM,OAAO,SAAS,WAAW;AAEjC,MAAI,KAAK,QAAQ;AACf,UAAM,SAAS,yBAAyB,UAAU,KAAK,KAAK;AAC5D,QAAI,OAAO,QAAS,QAAO,OAAO;AAAA,EACpC;AAEA,OAAK,+BAA+B,YAAY,sCAAiC;AACjF,SAAO,CAAC;AACV;;;AGxNA,OAAOC,YAAU;AAoBjB,IAAMC,qBAAoB;AAMnB,SAAS,kBACd,cACA,gBACA,WACM;AACN,MAAIA,mBAAkB,KAAK,SAAS,GAAG;AACrC,UAAM,IAAI,MAAM,wBAAwB,SAAS,uBAAuB;AAAA,EAC1E;AAEA,MAAI,CAAC,aAAa,cAAc,cAAc,GAAG;AAC/C,UAAM,IAAI;AAAA,MACR,wBAAwB,SAAS,iCAAiCC,OAAK,QAAQ,cAAc,CAAC;AAAA,IAChG;AAAA,EACF;AACF;AAOA,SAAS,iBAAiB,UAAkB,WAA2B;AACrE,QAAM,WAAWA,OAAK,KAAK,UAAU,SAAS;AAC9C,oBAAkB,UAAU,UAAU,SAAS;AAC/C,SAAO;AACT;AAEA,SAAS,mBAAmB,OAAsB,SAAyB;AACzE,QAAM,SAASA,OAAK,KAAK,SAAS,cAAc;AAChD,SAAO,iBAAiB,QAAQ,MAAM,IAAI;AAC5C;AAQA,eAAe,kBAAkB,iBAA0C;AACzE,QAAM,cAAcC,OAAK,KAAK,iBAAiB,eAAe,QAAQ;AACtE,SAAO,gBAAgB,WAAW;AACpC;AAGA,eAAe,YACb,OACA,YACA,UACA,QACsB;AACtB,QAAM,cAAc,MAAM,kBAAkB,UAAU;AAEtD,QAAM,UAAUA,OAAK,QAAQ,QAAQ,CAAC;AACtC,QAAM,KAAK,YAAY,QAAQ;AAK/B,QAAM,yBAAyB,UAAU,MAAM,IAAI,aAAa;AAAA,IAC9D,GAAI,WAAW,UAAa,EAAE,OAAO;AAAA,EACvC,CAAC;AAED,SAAO,EAAE,SAAS,MAAM,IAAI,aAAa,YAAY,SAAS;AAChE;AAiCA,eAAe,wBACb,OACA,WACsB;AACtB,QAAM,cAAc,MAAM,kBAAkB,SAAS;AACrD,SAAO;AAAA,IACL,SAAS,MAAM;AAAA,IACf,YAAY;AAAA,IACZ,UAAU;AAAA,IACV;AAAA,IACA,OAAO;AAAA,EACT;AACF;AAkBA,eAAe,cACb,kBACA,SACwB;AACxB,QAAM,WAAW,MAAM,QAAQ;AAAA,IAC7B,iBAAiB,IAAI,OAAO,YAAY,YAAY,SAAS,OAAO,CAAC;AAAA,EACvE;AACA,QAAM,WAAW,SAAS,OAAO,aAAa;AAE9C,MAAI,SAAS,SAAS,EAAG,OAAM,IAAI,MAAM,mBAAmB,UAAU,iBAAiB,MAAM,CAAC;AAE9F,SAAO,SAAS,OAAO,aAAa,EAAE,IAAI,CAAC,YAAY,QAAQ,MAAM;AACvE;AAMA,eAAe,YACb,SACA,SACsB;AACtB,MAAI;AACF,WAAO,EAAE,SAAS,QAAQ,MAAM,QAAQ,OAAO,EAAE;AAAA,EACnD,SAAS,OAAO;AACd,WAAO,EAAE,SAAS,SAAS,gBAAgB,KAAK,EAAE;AAAA,EACpD;AACF;AAEA,SAAS,cAAc,SAA8C;AACnE,SAAO,aAAa;AACtB;AAEA,SAAS,cAAc,SAA8C;AACnE,SAAO,YAAY;AACrB;AAGA,SAAS,mBAAmB,UAAyB,WAA2B;AAC9E,QAAM,QAAQ,SAAS,IAAI,CAAC,YAAY,KAAK,QAAQ,OAAO,KAAK,QAAQ,OAAO,EAAE;AAElF,SAAO,kBAAkB,SAAS,MAAM,OAAO,OAAO,WAAW,OAAO,CAAC;AAAA,EAAM,MAAM,KAAK,IAAI,CAAC;AACjG;AAEA,SAAS,0BAA0B,OAAsB,gBAAgC;AACvF,SAAO,iBAAiB,gBAAgB,MAAM,EAAE;AAClD;AAEA,eAAe,0BACb,OACA,gBACA,cACsB;AACtB,SAAO;AAAA,IACL;AAAA,IACA,mBAAmB,OAAO,aAAa,UAAU;AAAA,IACjD,0BAA0B,OAAO,cAAc;AAAA,IAC/C,aAAa,aAAa;AAAA,EAC5B;AACF;AAEA,eAAsB,2BACpB,kBACA,gBACA,cACA,kBACwB;AACxB,SAAO,cAAc,kBAAkB,OAAO,YAAY;AACxD,UAAM,QAAQ,aAAa,OAAO;AAElC,UAAM,iBAAiB,mBAAmB,OAAO;AACjD,UAAM,qBAAqB,kBAAkB,mBAAmB;AAChE,QAAI,CAAC,MAAM,SAAS,CAAC,MAAM,aAAa,oBAAoB;AAC1D,aAAO,0BAA0B,OAAO,gBAAgB,YAAY;AAAA,IACtE;AAEA,UAAM,WAAW,0BAA0B,OAAO,cAAc;AAChE,QAAIC,OAAK,QAAQ,MAAM,SAAS,MAAMA,OAAK,QAAQ,QAAQ,GAAG;AAC5D,aAAO,wBAAwB,OAAO,MAAM,SAAS;AAAA,IACvD;AAEA,UAAM,cAAc,MAAM,kBAAkB,MAAM,SAAS;AAC3D,UAAM,UAAUA,OAAK,QAAQ,QAAQ,CAAC;AACtC,UAAM,KAAK,MAAM,WAAW,QAAQ;AAEpC,WAAO,EAAE,SAAS,MAAM,IAAI,YAAY,MAAM,WAAW,UAAU,YAAY;AAAA,EACjF,CAAC;AACH;;;AC/OA,OAAOC,YAAU;AACjB,SAAS,SAASC,kBAAiB;;;ACDnC,OAAOC,YAAU;AAMjB,IAAM,kBAAkB;AACxB,IAAMC,wBAAuB,eAAe;AAC5C,IAAM,sBAAsB;AAkB5B,SAAS,YAAY,MAAe,OAA0C;AAC5E,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AACA,SAAO,EAAE,MAAM,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC,EAAG;AAC7C;AAEO,SAAS,4BAA4B,SAA+C;AACzF,QAAM,SAAS,YAAY,QAAQ,QAAQ,QAAQ,WAAW;AAC9D,SAAO;AAAA,IACL,MAAM,QAAQ;AAAA,IACd,SAAS,QAAQ,WAAW;AAAA,IAC5B,QAAQ;AAAA,IACR,GAAI,QAAQ,cAAc,EAAE,aAAa,QAAQ,YAAY,IAAI,CAAC;AAAA,IAClE,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,QAAQ,WAAW,EAAE,UAAU,QAAQ,SAAS,IAAI,CAAC;AAAA,IACzD,GAAI,QAAQ,UAAU,SAAS,EAAE,UAAU,QAAQ,SAAS,IAAI,CAAC;AAAA,EACnE;AACF;AAEO,SAAS,4BAA4B,SAA+C;AACzF,SAAO;AAAA,IACL,MAAM,GAAG,mBAAmB,GAAG,QAAQ,SAAS;AAAA,IAChD,SAAS,QAAQ,WAAW;AAAA,IAC5B,QAAQ;AAAA,IACR,GAAI,QAAQ,cAAc,EAAE,aAAa,QAAQ,YAAY,IAAI,CAAC;AAAA,EACpE;AACF;AAEA,eAAsB,oBACpB,WACA,UACiB;AACjB,QAAM,YAAYC,OAAK,KAAK,WAAW,eAAe;AACtD,QAAM,eAAeA,OAAK,KAAK,WAAWD,qBAAoB;AAE9D,QAAM,UAAU,SAAS;AAEzB,QAAM,UAAU,KAAK,UAAU,UAAU,MAAM,CAAC;AAChD,QAAM,UAAU,cAAc,OAAO;AAErC,SAAO;AACT;;;AChEO,SAAS,0BAA0B,IAAY,aAA6B;AACjF,SAAO,GAAG,EAAE,IAAI,WAAW;AAC7B;AAMO,SAAS,0BAA0B,KAAqB;AAC7D,QAAM,YAAY,IAAI,QAAQ,GAAG;AACjC,SAAO,cAAc,KAAK,MAAM,IAAI,MAAM,GAAG,SAAS;AACxD;;;ACfA,OAAOE,SAAQ;AACf,OAAOC,YAAU;AAeV,SAAS,oBAA4B;AAC1C,SAAOC,OAAK,KAAKC,IAAG,QAAQ,GAAG,YAAY,cAAc;AAC3D;AAEO,SAAS,qBAAqB,YAA6B;AAChE,QAAM,MAAM,cAAc,QAAQ,IAAI;AACtC,SAAOD,OAAK,KAAK,KAAK,YAAY,cAAc;AAClD;AAEO,SAAS,mBAAmB,WAA2B;AAC5D,SAAOA,OAAK,KAAK,WAAW,QAAQ;AACtC;AAEO,SAAS,sBAAsB,WAA2B;AAC/D,SAAOA,OAAK,KAAK,WAAW,qBAAqB,oBAAoB;AACvE;AAEA,eAAsB,mBAAmB,WAAmD;AAC1F,QAAM,eAAe,sBAAsB,SAAS;AAEpD,MAAI,CAAE,MAAM,WAAW,YAAY,GAAI;AACrC,YAAQ,oBAAoB,YAAY,EAAE;AAC1C,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,UAAU,MAAM,aAAa,cAAc,oBAAoB;AACrE,UAAM,WAAW,qBAAqB,MAAM,KAAK,MAAM,OAAO,CAAC;AAE/D,QAAI,CAAC,SAAS,QAAQ,OAAO,SAAS,SAAS,UAAU;AACvD,cAAQ,yBAAyB,YAAY,gBAAgB;AAC7D,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,YAAQ,iCAAiC,YAAY,KAAK,gBAAgB,KAAK,CAAC,EAAE;AAClF,WAAO;AAAA,EACT;AACF;;;ACvDA,SAAS,eAAe;;;ACAxB,OAAOE,SAAQ;AACf,OAAOC,YAAU;AAYV,IAAM,sBAAsB;AAAA,EACjC,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,OAAO;AACT;AAsBO,IAAM,4BAA4B;AAAA,EACvC,QAAQ,GAAG,oBAAoB,MAAM;AAAA,EACrC,OAAO,GAAG,oBAAoB,KAAK;AACrC;AAmBO,SAAS,kBAAkB,QAAgC;AAChE,SAAO,OAAO,OAAO,WAAW,KAAK,OAAO,OAAO,WAAW;AAChE;AAGO,SAAS,kBAAkB,QAAoC;AACpE,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,QAAM,WAAW,OAAO,KAAK,CAAC,MAAM,EAAE,WAAW,YAAY;AAC7D,QAAM,YAAY,OAAO,KAAK,CAAC,MAAM,EAAE,WAAW,YAAY;AAC9D,MAAI,YAAY,UAAW,QAAO;AAClC,SAAO,WAAW,UAAU;AAC9B;AAIA,eAAe,wBACb,KACA,OAC8B;AAI9B,QAAM,WAAW,cAAc,GAAG;AAClC,QAAM,aAAa,qBAAqB,KAAK,QAAQ;AAErD,MAAI,CAAE,MAAM,WAAW,UAAU,GAAI;AACnC,WAAO;AAAA,EACT;AAMA,QAAM,SAAS,MAAM,yBAAyB,KAAK,QAAQ;AAC3D,MAAI,CAAC,QAAQ;AAEX,WAAO;AAAA,EACT;AAQA,MAAI,kBAAkB,OAAO,MAAM,GAAG;AACpC,WAAO;AAAA,EACT;AAEA,QAAM,OAAoB,kBAAkB,OAAO,OAAO,MAAM;AAEhE,SAAO;AAAA,IACL;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA,WAAW,UAAU,UAAU,OAAO,GAAG;AAAA;AAAA;AAAA,IAGzC,WAAWC,OAAK,KAAK,KAAK,YAAY,SAAS,WAAW,iBAAiB,QAAQ;AAAA,IACnF,YAAY;AAAA,EACd;AACF;AAGA,eAAsB,0BAA0B,YAAkD;AAChG,SAAO,wBAAwB,YAAY,SAAS;AACtD;AAOA,eAAsB,wBAAwB,KAA+B;AAC3E,MAAI;AACF,WAAQ,MAAM,0BAA0B,GAAG,MAAO;AAAA,EACpD,SAAS,OAAO;AACd,QAAI,iBAAiB,gBAAiB,QAAO;AAC7C,UAAM;AAAA,EACR;AACF;AAGA,eAAsB,2BAAyD;AAC7E,SAAO,wBAAwBC,IAAG,QAAQ,GAAG,QAAQ;AACvD;AAMA,eAAsB,mBACpB,aAAqB,QAAQ,IAAI,GACH;AAE9B,QAAM,sBAAsB,MAAM,0BAA0B,UAAU;AACtE,MAAI,oBAAqB,QAAO;AAGhC,SAAO,yBAAyB;AAClC;;;ACrKA,OAAOC,UAAQ;AACf,OAAOC,YAAU;AACjB,SAAS,UAAAC,eAAc;;;ACFvB,SAAS,SAASC,kBAAiB;AACnC,OAAOC,YAAU;;;ACDjB,SAAS,SAASC,kBAAiB;AAInC,IAAM,sBAAsB;AAK5B,SAAS,gBAAgB,SAAkC;AACzD,QAAM,QAAQ,QAAQ,MAAM,mBAAmB,IAAI,CAAC;AACpD,MAAI,CAAC,MAAO,QAAO,EAAE,YAAY,wDAAwD;AAEzF,MAAI;AACF,WAAO,EAAE,QAAQC,WAAU,KAAK,EAAE;AAAA,EACpC,SAAS,OAAO;AACd,WAAO,EAAE,YAAY,gBAAgB,KAAK,EAAE;AAAA,EAC9C;AACF;AAEO,SAAS,mBAAmB,SAA0B;AAC3D,QAAM,OAAO,gBAAgB,OAAO;AACpC,SAAO,YAAY,OAAO,KAAK,SAAS;AAC1C;AASO,SAAS,sBAAsB,SAAqC;AACzE,QAAM,OAAO,gBAAgB,OAAO;AACpC,MAAI,gBAAgB,KAAM,QAAO,KAAK;AACtC,SAAO,KAAK,WAAW,OAAO,6BAA6B;AAC7D;;;ADkBA,eAAsB,kBAAkB,cAAkD;AACxF,MAAI;AACJ,MAAI;AACF,aAASC,WAAU,MAAM,SAAS,YAAY,CAAC;AAAA,EACjD,SAAS,OAAO;AACd,WAAO,EAAE,QAAQ,OAAO,QAAQ,gBAAgB,KAAK,EAAE;AAAA,EACzD;AAEA,MAAI,CAAC,eAAe,MAAM,GAAG;AAC3B,WAAO,EAAE,QAAQ,OAAO,QAAQ,mCAAmC,cAAc,MAAM,CAAC,GAAG;AAAA,EAC7F;AAEA,QAAM,YAAY,uBAAuB,UAAU,MAAM;AACzD,MAAI,CAAC,UAAU,SAAS;AACtB,WAAO,EAAE,QAAQ,OAAO,QAAQ,8BAA8B,UAAU,MAAM,QAAQ,MAAM,EAAE;AAAA,EAChG;AAEA,SAAO,EAAE,QAAQ,MAAM,UAAU,UAAU,KAAK;AAClD;AAiBO,SAAS,yBAAyB,UAAqC;AAC5E,SAAO,SAAS,aAAa;AAC/B;AAEA,SAAS,eAAe,OAAkD;AACxE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAGA,SAAS,cAAc,OAAwB;AAC7C,MAAI,UAAU,QAAQ,UAAU,OAAW,QAAO;AAClD,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO;AACjC,SAAO,KAAK,OAAO,KAAK;AAC1B;AAEO,SAAS,iBAAiB,SAAiB,UAA4C;AAC5F,QAAM,iBAAiB,mBAAmB,OAAO;AACjD,MAAI,mBAAmB,KAAM,QAAO;AAEpC,QAAM,SAAS,6BAA6B,UAAU,cAAc;AAEpE,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,WAAW,YAAY;AAC7B,SAAK,oCAAoC,QAAQ,MAAM,gBAAgB,OAAO,MAAM,MAAM,CAAC,EAAE;AAC7F,WAAO;AAAA,EACT;AACA,SAAO,OAAO;AAChB;AAiBA,SAAS,uBAAuB,cAAsB,QAAwB;AAC5E,SAAO,oBAAoB,eAAe,mBAAmB,QAAQ,YAAY,MAAM,MAAM;AAC/F;AAIA,eAAe,kBACbC,YACA,YACA,SACsD;AACtD,QAAM,SAA0C,CAAC;AACjD,QAAM,QAAQ,MAAM,KAAK,MAAM,eAAe,mBAAmB,IAAIA,UAAS;AAE9E,aAAW,QAAQ,OAAO;AACxB,UAAM,WAAWC,OAAK,KAAKD,YAAW,IAAI;AAC1C,QAAI;AACF,YAAM,UAAU,MAAM,SAAS,QAAQ;AAGvC,YAAM,SAAS,sBAAsB,UAAUD,WAAU,OAAO,CAAC;AACjE,UAAI,CAAC,OAAO,SAAS;AACnB,aAAK,uBAAuB,UAAU,gBAAgB,OAAO,MAAM,MAAM,CAAC,CAAC;AAC3E;AAAA,MACF;AACA,YAAM,SAAS,OAAO;AAEtB,aAAO,OAAO,EAAE,IAAI,kBAAkB,QAAQ,MAAM,YAAY,OAAO;AACvE,cAAQ,UAAU,QAAQ,YAAY,KAAK,OAAO,EAAE,SAAS,IAAI,EAAE;AAAA,IACrE,SAAS,OAAO;AACd,WAAK,uBAAuB,UAAU,gBAAgB,KAAK,CAAC,CAAC;AAAA,IAC/D;AAAA,EACF;AAEA,SAAO;AACT;AAMA,SAAS,kBACP,QACA,MACA,YACA,SACiB;AACjB,SAAO;AAAA,IACL,OAAO,OAAO;AAAA,IACd,aAAa,OAAO;AAAA,IACpB,GAAI,OAAO,UAAU,UAAa,EAAE,OAAO,OAAO,MAAM;AAAA,IACxD,GAAI,OAAO,WAAW,UAAa,EAAE,QAAQ,OAAO,OAAO;AAAA,IAC3D,OAAO,OAAO;AAAA;AAAA;AAAA,IAGd,GAAI,OAAO,oBAAoB,UAAa;AAAA,MAC1C,iBAAiB,OAAO;AAAA,IAC1B;AAAA,IACA,GAAI,OAAO,mBAAmB,UAAa,EAAE,gBAAgB,OAAO,eAAe;AAAA,IACnF,GAAI,OAAO,cAAc,UAAa,EAAE,WAAW,OAAO,UAAU;AAAA,IACpE,GAAI,OAAO,UAAU,UAAa,EAAE,OAAO,OAAO,MAAM;AAAA,IACxD,GAAI,OAAO,iBAAiB,UAAa,EAAE,cAAc,OAAO,aAAa;AAAA,IAC7E,GAAI,OAAO,iBAAiB,UAAa,EAAE,cAAc,OAAO,aAAa;AAAA,IAC7E,MAAME,OAAK,QAAQ,IAAI;AAAA,IACvB;AAAA,IACA,GAAI,QAAQ,eAAe,EAAE,cAAc,QAAQ,aAAa,IAAI,CAAC;AAAA,IACrE,GAAI,OAAO,SAAS,EAAE,QAAQ,OAAO,OAAO,IAAI,CAAC;AAAA,IACjD,GAAI,QAAQ,qBAAqB,OAAO,WAAW,OAAO,EAAE,QAAQ,KAAK,IAAI,CAAC;AAAA,EAChF;AACF;AAEA,eAAsB,cACpB,aACsD;AACtD,SAAO,kBAAkBA,OAAK,KAAK,aAAa,KAAK,MAAM,GAAG,aAAa;AAAA,IACzE,mBAAmB;AAAA,IACnB,cAAc;AAAA,EAChB,CAAC;AACH;AAMA,eAAsB,iBACpB,YACsD;AACtD,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,QAAQ,IAAI;AAAA,IAClD,cAAc,YAAY;AAAA,IAC1B,cAAc,UAAU;AAAA,EAC1B,CAAC;AACD,SAAO,EAAE,GAAG,WAAW,GAAG,aAAa;AACzC;AAEA,eAAsB,kBACpB,aACsD;AACtD,QAAM,eAAe,kBAAkB,aAAa,cAAc,WAAW,CAAC;AAC9E,QAAM,mBAAmBA,OAAK,KAAK,aAAa,KAAK,cAAc,MAAM;AAEzE,MAAI,CAAE,MAAMC,iBAAgB,gBAAgB,GAAI;AAC9C,YAAQ,kCAAkC,gBAAgB,EAAE;AAC5D,UAAM,WAA4C,CAAC;AACnD,WAAO;AAAA,EACT;AAEA,SAAO,kBAAkB,kBAAkB,aAAa;AAAA;AAAA;AAAA,IAGtD,cAAc,GAAG,aAAa,OAAO,IAAI,cAAc,MAAM;AAAA,IAC7D,cAAc;AAAA,EAChB,CAAC;AACH;AAsCA,eAAsB,kBACpBC,YACA,UAAoC,CAAC,GACd;AACvB,QAAM,EAAE,aAAa,IAAI,kBAAkB,MAAM,IAAI;AACrD,QAAM,SAA6B,CAAC;AACpC,QAAM,mBAA4C,CAAC;AAEnD,MAAI,CAAE,MAAMD,iBAAgBC,UAAS,GAAI;AACvC,WAAO,EAAE,QAAQ,iBAAiB;AAAA,EACpC;AAEA,QAAM,aAAa,MAAM,KAAK,MAAM,eAAe,QAAQ,IAAIA,UAAS;AAExE,aAAW,aAAa,YAAY;AAClC,UAAM,QAAQ,YAAYA,YAAW,WAAW,UAAU;AAE1D,QAAI,iBAAiB;AACnB,YAAM,UAAU,MAAM,mBAAmB,KAAK;AAC9C,UAAI,QAAQ,SAAS,WAAY,kBAAiB,KAAK,QAAQ,OAAO;AACtE,UAAI,QAAQ,SAAS,WAAY;AAAA,IACnC;AAEA,UAAM,aAAa,MAAM,oBAAoB,KAAK;AAClD,QAAI,WAAY,QAAO,WAAW,EAAE,IAAI;AAAA,EAC1C;AAEA,SAAO,EAAE,QAAQ,iBAAiB;AACpC;AAgBA,SAAS,YAAYA,YAAmB,WAAmB,YAAmC;AAC5F,QAAM,cAAcF,OAAK,KAAKE,YAAW,SAAS;AAClD,QAAM,WAAWF,OAAK,QAAQ,WAAW;AACzC,QAAM,eAAeA,OAAK,SAASE,YAAW,QAAQ;AAEtD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAcF,OAAK,SAAS,QAAQ;AAAA,IACpC,aAAa,aAAa,GAAG,UAAU,IAAI,YAAY,MAAM,GAAG,YAAY;AAAA,EAC9E;AACF;AASA,eAAe,mBAAmB,OAAqD;AACrF,QAAM,eAAeA,OAAK,KAAK,MAAM,UAAU,eAAe,aAAa;AAC3E,MAAI,CAAE,MAAM,WAAW,YAAY,GAAI;AACrC;AAAA,MACE,UAAU,MAAM,YAAY,SAAS,MAAM,WAAW,gBAAgB,eAAe,aAAa,wBAAmB,eAAe,aAAa;AAAA,IACnJ;AACA,WAAO,EAAE,MAAM,UAAU;AAAA,EAC3B;AAKA,QAAM,OAAO,MAAM,kBAAkB,YAAY;AACjD,MAAI,CAAC,KAAK,QAAQ;AAChB,YAAQ,cAAc,eAAe,aAAa,QAAQ,MAAM,YAAY,GAAG;AAC/E,WAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS,EAAE,cAAc,MAAM,cAAc,cAAc,QAAQ,KAAK,OAAO;AAAA,IACjF;AAAA,EACF;AAKA,MAAI,yBAAyB,KAAK,QAAQ,GAAG;AAC3C,YAAQ,iBAAiB,cAAc,QAAQ,QAAQ,MAAM,YAAY,GAAG;AAC5E,WAAO,EAAE,MAAM,UAAU;AAAA,EAC3B;AAEA,SAAO,EAAE,MAAM,WAAW;AAC5B;AAMA,eAAe,oBAAoB,OAA4D;AAC7F,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,MAAM,WAAW;AAChD,UAAM,cAAc,iBAAiB,SAAS,MAAM,WAAW;AAE/D,QAAI,CAAC,aAAa,MAAM;AACtB,WAAK,sBAAsB,MAAM,YAAY,wCAAwC;AACrF,aAAO;AAAA,IACT;AAEA,UAAM,cAAc,YAAY;AAChC,YAAQ,mBAAmB,WAAW,EAAE;AACxC,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,MAAM,MAAM;AAAA,MACZ,aAAa,YAAY,eAAe;AAAA,IAC1C;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,2BAA2B,MAAM,SAAS,MAAM,gBAAgB,KAAK,CAAC,EAAE;AAChF,WAAO;AAAA,EACT;AACF;AAOA,eAAsB,iBAAiB,WAAgD;AACrF,QAAM,EAAE,OAAO,IAAI,MAAM,kBAAkBA,OAAK,KAAK,WAAW,QAAQ,GAAG;AAAA,IACzE,YAAY;AAAA,IACZ,iBAAiB;AAAA,EACnB,CAAC;AACD,SAAO;AACT;;;AElaA,SAAS,cAAAG,mBAAkB;AAE3B,SAAS,wBAAqD;AAC9D,OAAOC,SAAQ;AACf,OAAOC,YAAU;;;ACJjB,OAAOC,YAAU;AACjB,SAAS,SAAS,cAAc;AAiBhC,IAAM,uBAAuB,GAAG,mBAAmB,IAAI,oBAAoB;AAC3E,IAAM,yBAAyB;AAG/B,IAAM,2BAA2B;AAGjC,IAAM,wBAAwB;AAY9B,IAAM,6BAAgD;AAAA,EACpD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGA,IAAM,oCAAoC;AAW1C,SAAS,mCACP,UACA,YACA,eACmB;AACnB,SAAO;AAAA,IACL,MAAM,SAAS;AAAA,IACf,QAAQ,KAAK,UAAU,IAAI,aAAa;AAAA,IACxC,GAAI,SAAS,gBAAgB,UAAa,EAAE,aAAa,SAAS,YAAY;AAAA,IAC9E,GAAI,SAAS,YAAY,UAAa,EAAE,SAAS,SAAS,QAAQ;AAAA,IAClE,GAAI,SAAS,WAAW,UAAa,EAAE,QAAQ,SAAS,OAAO;AAAA,IAC/D,GAAI,SAAS,aAAa,UAAa,EAAE,UAAU,SAAS,SAAS;AAAA,IACrE,GAAI,SAAS,aAAa,UAAa,EAAE,UAAU,SAAS,SAAS;AAAA,EACvE;AACF;AAEA,eAAsB,oBACpBC,aACA,SACsB;AACtB,UAAQ,+BAA+BA,WAAU,EAAE;AAEnD,QAAM,gBAAgB,MAAM,KAAK,MAAM,oBAAoB,IAAIA,WAAU;AACzE,UAAQ,SAAS,cAAc,MAAM,mBAAmB;AAExD,QAAM,UAA+B,CAAC;AAEtC,aAAW,gBAAgB,eAAe;AACxC,UAAM,gBAAgB,gBAAgB,YAAY;AAClD,UAAM,YAAYC,OAAK,KAAKD,aAAY,aAAa;AAErD,UAAM,WAAW,MAAM,mBAAmB,SAAS;AACnD,QAAI,CAAC,UAAU;AACb,WAAK,oCAAoC,YAAY,GAAG;AACxD;AAAA,IACF;AAEA,UAAM,SAAS;AAAA,MACb;AAAA,MACA,QAAQ,WAAW,QAAQ,SAAS,EAAE;AAAA,MACtC;AAAA,IACF;AACA,YAAQ,KAAK,MAAM;AACnB,YAAQ,UAAU,OAAO,IAAI,EAAE;AAAA,EACjC;AAEA,QAAM,gBAAgB,OAAO,SAAS,CAAC,MAAM,EAAE,IAAI;AAInD,SAAO;AAAA,IACL,SAAS;AAAA,IACT,MAAM,QAAQ;AAAA,IACd,SAAS,QAAQ,WAAW;AAAA,IAC5B,OAAO;AAAA,MACL,MAAM,QAAQ;AAAA,MACd,GAAI,QAAQ,aAAa,EAAE,OAAO,QAAQ,WAAW,IAAI,CAAC;AAAA,IAC5D;AAAA,IACA,UAAU;AAAA,MACR,YAAY,QAAQ;AAAA,IACtB;AAAA,IACA,SAAS;AAAA,IACT,GAAI,QAAQ,cAAc,EAAE,aAAa,QAAQ,YAAY,IAAI,CAAC;AAAA,EACpE;AACF;AAMA,SAAS,gBAAgB,cAA8B;AACrD,QAAM,YAAY,aAAa,QAAQ,GAAG;AAC1C,SAAO,cAAc,KAAK,eAAe,aAAa,MAAM,GAAG,SAAS;AAC1E;AAcO,SAAS,wBACd,iBACA,aACA,QACe;AACf,MAAI,CAAC,2BAA2B,SAAS,eAAe,EAAG,QAAO;AAClE,MAAI,2BAA2B,iBAAiB,WAAW,EAAG,QAAO;AAErE,SAAO,kBAAkB,iBAAiB,MAAM;AAClD;AAUO,SAAS,8BACd,iBACA,QACe;AACf,MAAI,oBAAoB,2BAA4B,QAAO;AAC3D,SAAO,2BAA2B,SAAS,eAAe,IACtD,kBAAkB,iBAAiB,MAAM,IACzC;AACN;AAWO,SAAS,yBAAyB,aAAyC;AAChF,MAAI,YAAY,SAAS,2BAA4B,QAAO;AAE5D,QAAM,aAAa,YAAY,QAC5B,OAAO,CAAC,WAAW,CAAC,iBAAiB,OAAO,MAAM,YAAY,IAAI,CAAC,EACnE,IAAI,CAAC,WAAW,OAAO,IAAI;AAE9B,MAAI,WAAW,WAAW,EAAG,QAAO;AAEpC,SAAO,wBAAwB,YAAY,YAAY,IAAI;AAC7D;AAWA,SAAS,2BAA2B,iBAAyB,aAA8B;AACzF,SAAO,oBAAoB,8BAA8B,gBAAgB;AAC3E;AAEA,SAAS,iBAAiB,SAAiB,iBAAkC;AAC3E,SAAO,QAAQ,WAAW,GAAG,eAAe,GAAG;AACjD;AAEA,SAAS,kBAAkB,iBAAyB,QAAwB;AAC1E,SACE,qBAAqB,eAAe,mBAChC,0BAA0B,+CAC1B,wBAAwB,UAAU,qBAAqB,yDACnC,YAAY,yMAEkB,MAAM;AAEhE;AAEA,SAAS,wBAAwB,YAAsB,iBAAiC;AACtF,QAAM,SAAS,WACZ,MAAM,GAAG,iCAAiC,EAC1C,IAAI,CAAC,OAAO,KAAK,EAAE,OAAO,eAAe,IAAI,EAAE,EAAE;AACpD,QAAM,WAAW,WAAW,SAAS,OAAO;AAE5C,SAAO;AAAA,IACL,gBAAgB,eAAe,WAAW,WAAW,MAAM;AAAA,IAE3D,GAAG;AAAA,IACH,GAAI,WAAW,IAAI,CAAC,aAAa,QAAQ,OAAO,IAAI,CAAC;AAAA,IACrD;AAAA,EAEF,EAAE,KAAK,IAAI;AACb;AAEA,eAAsB,iBACpB,YACA,aACe;AACf,QAAM,UAAUC,OAAK,QAAQ,UAAU,CAAC;AACxC,QAAM,UAAU,GAAG,KAAK,UAAU,aAAa,MAAM,CAAC,CAAC;AAAA;AACvD,QAAM,UAAU,YAAY,OAAO;AACrC;AAEO,SAAS,oBAAoB,aAGlC;AACA,SAAO;AAAA,IACL,OAAO,YAAY,QAAQ;AAAA,IAC3B,YAAY,QAAQ,YAAY,SAAS,CAAC,MAAM,EAAE,YAAY,eAAe;AAAA,EAC/E;AACF;;;ADrNA,IAAM,oBAAoB;AAC1B,IAAM,kBAAkB;AAGxB,IAAM,kBAAkB;AAMxB,IAAM,aAAa;AAYZ,SAAS,uBAAuB,QAAwB;AAC7D,QAAM,OAAOC,YAAW,QAAQ,EAAE,OAAO,MAAM,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,iBAAiB;AAEzF,QAAM,WAAW,OACd,QAAQ,iBAAiB,GAAG,EAC5B,QAAQ,QAAQ,GAAG,EACnB,QAAQ,UAAU,EAAE,EACpB,MAAM,GAAG,4BAA4B;AAExC,SAAO,WAAW,GAAG,QAAQ,IAAI,IAAI,KAAK;AAC5C;AAEA,SAAS,YAAY,QAAwB;AAC3C,QAAM,YAAY,uBAAuB,MAAM,KAAK;AACpD,SAAOC,OAAK,KAAK,UAAU,GAAG,WAAW,SAAS;AACpD;AAEA,eAAsB,gBACpB,QACA,UAAwB,CAAC,GACH;AACtB,QAAM,EAAE,OAAO,IAAI;AAEnB,MAAI,cAAc,MAAM,GAAG;AACzB,WAAO,qBAAqB,QAAQ,MAAM;AAAA,EAC5C;AAEA,SAAO,sBAAsB,QAAQ,MAAM;AAC7C;AAEA,eAAe,qBAAqB,QAAgB,QAAuC;AACzF,QAAM,WAAW,SAASA,OAAK,KAAK,QAAQ,MAAM,IAAI;AACtD,QAAM,eAAeA,OAAK,WAAW,QAAQ,IAAI,WAAWA,OAAK,QAAQ,QAAQ,IAAI,GAAG,QAAQ;AAEhG,MAAI,CAAE,MAAMC,iBAAgB,YAAY,GAAI;AAC1C,UAAM,IAAI;AAAA,MACR,iCAAiC,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA,kBAGxB,cAAc;AAAA,IACrC;AAAA,EACF;AAEA,UAAQ,4BAA4B,YAAY,EAAE;AAElD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,WAAW;AAAA,IACX;AAAA,EACF;AACF;AAWO,SAAS,iBAAiB,QAAoC;AACnE,QAAM,aAAa,OAAO,MAAM,eAAe;AAG/C,MAAI,eAAe,WAAW,CAAC,MAAM,UAAU,WAAW,CAAC,MAAM,UAAU;AACzE,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,aAAa,CAAC,KAAK;AACxC,QAAM,YAAY,aAAa,OAAO,MAAM,WAAW,CAAC,EAAE,MAAM,IAAI;AAEpE,QAAM,WAAW,UAAU,MAAM,UAAU;AAC3C,MAAI,CAAC,UAAU,QAAQ,MAAM;AAC3B,WAAO;AAAA,EACT;AAGA,QAAM,eAAe,SAAS,OAAO,KAAK,QAAQ,KAAK,GAAG,EAAE,QAAQ,eAAe,GAAG;AAEtF,QAAM,iBAAiB,QAAQ,IAAI,iBAC/BD,OAAK,QAAQ,QAAQ,IAAI,gBAAgB,OAAO,IAChDA,OAAK,QAAQE,IAAG,QAAQ,GAAG,UAAU,OAAO;AAEhD,SAAOF,OAAK,KAAK,gBAAgB,cAAc,YAAY;AAC7D;AAMA,eAAe,gBAAgB,QAA+B;AAC5D,QAAM,WAAW,iBAAiB,MAAM;AACxC,MAAI,CAAC,SAAU;AAEf,MAAI,MAAMC,iBAAgB,QAAQ,GAAG;AACnC,YAAQ,yBAAyB,QAAQ,EAAE;AAC3C,UAAM,OAAO,QAAQ;AAAA,EACvB;AACF;AAEA,eAAe,sBAAsB,QAAgB,QAAuC;AAC1F,QAAM,WAAW,YAAY,MAAM;AACnC,QAAM,aAAa,SAAS,GAAG,MAAM,IAAI,MAAM,KAAK;AAEpD,UAAQ,yBAAyB,UAAU,EAAE;AAC7C,UAAQ,oBAAoB,QAAQ,EAAE;AAEtC,MAAI,MAAMA,iBAAgB,QAAQ,GAAG;AACnC,UAAM,UAAU,MAAM,qBAAqB,UAAU,MAAM;AAC3D,UAAM,SAAsB,EAAE,MAAM,UAAU,WAAW,MAAM,QAAQ,WAAW;AAElF,QAAI,YAAY,aAAa,YAAY,eAAe;AACtD,cAAQ,6BAA6B,QAAQ,EAAE;AAC/C,aAAO;AAAA,IACT;AAEA,oBAAgB,OAAO;AACvB,UAAM,gBAAgB,MAAM;AAC5B,UAAM,OAAO,QAAQ;AAAA,EACvB;AAEA,QAAM,UAAUD,OAAK,QAAQ,QAAQ,CAAC;AAEtC,MAAI;AACF,UAAM,SAAS,MAAM,iBAAiB,YAAY;AAAA,MAChD,KAAK;AAAA,MACL,OAAO;AAAA;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAED,YAAQ,kBAAkB,OAAO,GAAG,EAAE;AACtC,UAAM,kBAAkB,UAAU,MAAM;AACxC,8BAA0B,QAAQ;AAElC,WAAO;AAAA,MACL,MAAM,OAAO;AAAA,MACb,WAAW;AAAA,MACX,QAAQ;AAAA,IACV;AAAA,EACF,SAAS,OAAO;AACd,UAAM,yBAAyB,OAAO,MAAM;AAAA,EAC9C;AACF;AAwBA,IAAM,0BAA0B;AAGhC,IAAM,sBAAsB;AAO5B,IAAM,eAAe,oBAAI,IAAmC;AAU5D,SAAS,gBAAgB,SAAmE;AAC1F,MAAI,YAAY,cAAc;AAC5B,QAAI,gBAAgB,6BAA6B;AAAA,EACnD;AACF;AAEA,SAAS,qBAAqB,UAAkB,QAAuC;AACrF,QAAM,QAAQ,aAAa,IAAI,QAAQ;AACvC,MAAI,MAAO,QAAO;AAElB,QAAM,UAAU,mBAAmB,UAAU,MAAM;AACnD,eAAa,IAAI,UAAU,OAAO;AAClC,SAAO;AACT;AASA,SAAS,0BAA0B,UAAwB;AACzD,eAAa,IAAI,UAAU,QAAQ,QAAQ,SAAS,CAAC;AACvD;AAWA,eAAe,mBAAmB,UAAkB,QAAuC;AACzF,QAAM,SAAS,MAAM,gBAAgB,QAAQ;AAC7C,MAAI,CAAC,OAAQ,QAAO;AAEpB,MAAI,OAAO,SAAS,QAAW;AAC7B,YAAQ,4BAA4B,OAAO,GAAG,iCAA4B;AAC1E,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,OAAO,MAAM,UAAU,OAAO,GAAG;AACvC,QAAI,SAAS,QAAW;AACtB,cAAQ,GAAG,OAAO,GAAG,0DAAqD;AAC1E,aAAO;AAAA,IACT;AACA,WAAO,SAAS,OAAO,OAAO,YAAY;AAAA,EAC5C,SAAS,OAAO;AACd,YAAQ,wBAAwB,OAAO,GAAG,KAAK,gBAAgB,KAAK,CAAC,EAAE;AACvE,SAAK,4BAA4B,MAAM,CAAC;AACxC,WAAO;AAAA,EACT;AACF;AAQA,eAAe,UAAU,KAA0C;AACjE,QAAM,OAAO,QAAQ,IAAI;AACzB,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,QAAQ;AAAA,IACR,GAAI,QAAQ,EAAE,SAAS,EAAE,eAAe,UAAU,IAAI,GAAG,EAAE;AAAA,IAC3D,QAAQ,YAAY,QAAQ,uBAAuB;AAAA,EACrD,CAAC;AACD,SAAO,SAAS,QAAQ,IAAI,MAAM,KAAK;AACzC;AAQO,SAAS,gBAAgB,UAA0B;AACxD,SAAO,GAAG,QAAQ,GAAG,mBAAmB;AAC1C;AAEA,eAAe,gBAAgB,UAA2D;AACxF,QAAM,MAAM,MAAM,iBAAiB,gBAAgB,QAAQ,CAAC;AAC5D,MAAI,CAAC,IAAK,QAAO;AAEjB,QAAM,SAAS,yBAAyB,UAAU,qBAAqB,GAAG,CAAC;AAC3E,MAAI,CAAC,OAAO,SAAS;AACnB,YAAQ,4BAA4B,gBAAgB,QAAQ,CAAC,qCAAgC;AAC7F,WAAO;AAAA,EACT;AAEA,SAAO,OAAO;AAChB;AAYA,eAAe,kBAAkB,UAAkB,QAA+C;AAChG,QAAM,MAAe,OAAO;AAC5B,MAAI,OAAO,QAAQ,UAAU;AAC3B,YAAQ,kFAA6E;AACrF;AAAA,EACF;AAEA,QAAM,OAAO,MAAM,UAAU,GAAG,EAAE,MAAM,MAAM,MAAS;AACvD,QAAM,SAA6B,EAAE,KAAK,GAAI,SAAS,UAAa,EAAE,KAAK,EAAG;AAC9E,QAAM,UAAU,gBAAgB,QAAQ,GAAG,KAAK,UAAU,MAAM,CAAC;AACnE;AAEA,SAAS,qBAAqB,KAAsB;AAClD,MAAI;AACF,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,yBAAyB,OAAgB,QAAuB;AACvE,QAAM,UAAU,gBAAgB,KAAK;AAErC,MAAI,QAAQ,SAAS,KAAK,KAAK,QAAQ,SAAS,WAAW,GAAG;AAC5D,WAAO,IAAI;AAAA,MACT,yBAAyB,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOjC;AAAA,EACF;AAEA,MAAI,QAAQ,SAAS,KAAK,KAAK,QAAQ,SAAS,cAAc,GAAG;AAC/D,WAAO,IAAI;AAAA,MACT,gCAAgC,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAKxC;AAAA,EACF;AAEA,MAAI,QAAQ,SAAS,KAAK,KAAK,QAAQ,SAAS,WAAW,GAAG;AAC5D,WAAO,IAAI;AAAA,MACT,qBAAqB,MAAM;AAAA;AAAA;AAAA;AAAA,IAG7B;AAAA,EACF;AAEA,MACE,QAAQ,SAAS,WAAW,KAC5B,QAAQ,SAAS,WAAW,KAC5B,QAAQ,SAAS,SAAS,GAC1B;AACA,WAAO,IAAI;AAAA,MACT,2BAA2B,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAKnC;AAAA,EACF;AAEA,SAAO,IAAI,MAAM,mBAAmB,MAAM,KAAK,OAAO,EAAE;AAC1D;AAWO,IAAM,iCAAN,cAA6C,MAAM;AAAC;AAepD,IAAM,8BAAN,cAA0C,MAAM;AAAC;AAMxD,IAAM,sBAAyC;AAO/C,IAAM,sBAAsB;AAS5B,SAAS,eAAe,QAAwC;AAC9D,SAAO,OAAO,KAAK,CAAC,UAAU,MAAM,KAAK,WAAW,KAAK,MAAM,KAAK,CAAC,MAAM,mBAAmB;AAChG;AAOA,SAAS,gBAAgB,iBAAyB,QAAsC;AACtF,QAAM,UACJ,WAAW,gBAAgB,QAAQ,eAAe;AAAA;AAAA,qBAC5B,gBAAgB,CAAC,GAAG,MAAM,CAAC,CAAC;AAEpD,SAAO,eAAe,MAAM,IAAI,IAAI,4BAA4B,OAAO,IAAI,IAAI,MAAM,OAAO;AAC9F;AAEA,eAAsB,iBAAiB,QAAiD;AACtF,QAAM,SAAS,MAAM,gBAAgB,QAAQ;AAAA,IAC3C,QAAQ;AAAA;AAAA,EACV,CAAC;AAED,QAAM,kBAAkB,wBAAwB,OAAO,IAAI;AAK3D,MAAI,CAAE,MAAM,WAAW,eAAe,GAAI;AACxC,UAAM,IAAI;AAAA,MACR,6BAA6B,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMrC;AAAA,EACF;AAEA,QAAM,UAAU,MAAM,aAAa,iBAAiB,yBAAyB;AAC7E,QAAM,SAAkB,KAAK,MAAM,OAAO;AAE1C,MAAI,CAAC,qBAAqB,QAAQ,sBAAsB,GAAG;AACzD,UAAM,IAAI;AAAA,MACR,gCAAgC,eAAe;AAAA;AAAA,kDACM,sBAAsB;AAAA,IAC7E;AAAA,EACF;AAEA,QAAM,aAAa,kBAAkB,UAAU,MAAM;AAErD,MAAI,CAAC,WAAW,SAAS;AACvB,UAAM,gBAAgB,iBAAiB,WAAW,MAAM,MAAM;AAAA,EAChE;AAEA,QAAM,cAAc,WAAW;AAE/B,QAAM,eAAe,8BAA8B,YAAY,MAAM,mBAAmB;AACxF,MAAI,cAAc;AAChB,UAAM,IAAI;AAAA,MACR,WAAW,gBAAgB,QAAQ,eAAe;AAAA;AAAA,EAAO,YAAY;AAAA,IACvE;AAAA,EACF;AAEA,QAAM,4BAA4B;AAAA,IAChC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,MAAI,SAAS,MAAM,GAAG;AACpB,sBAAkB,QAAQ,2BAA2B,gBAAgB;AAAA,EACvE;AAEA,MAAI,YAAY,QAAQ,SAAS,yBAAyB;AACxD,UAAM,IAAI;AAAA,MACR,gCAAgC,eAAe;AAAA;AAAA,oBACxB,YAAY,QAAQ,MAAM,YAAY,uBAAuB;AAAA,IACtF;AAAA,EACF;AAEA,aAAW,UAAU,YAAY,SAAS;AACxC,QAAI,OAAO,KAAK,SAAS,iBAAiB;AACxC;AAAA,QACE,qCAAqC,OAAO,KAAK,MAAM,aAAa,OAAO,KAAK,MAAM,GAAG,EAAE,CAAC;AAAA,MAC9F;AAAA,IACF;AACA,QAAI,CAAC,kBAAkB,KAAK,OAAO,IAAI,GAAG;AACxC,WAAK,wDAAwD,OAAO,KAAK,MAAM,GAAG,EAAE,CAAC,GAAG;AAAA,IAC1F;AAAA,EACF;AAEA,UAAQ,uBAAuB,YAAY,IAAI,KAAK,YAAY,OAAO,EAAE;AAEzE,SAAO;AAAA,IACL;AAAA,IACA,YAAY,OAAO;AAAA,IACnB,WAAW,OAAO;AAAA,EACpB;AACF;;;AE9jBA,OAAOG,SAAQ;AA0BR,SAAS,iBAAiB,OAA2C;AAC1E,SACE,OAAO,qBAAqB,UAC5B,CAAC,MAAM,iBAAiB,KAAK,CAAC,WAAW,OAAO,SAAS,OAAO;AAEpE;AAMA,SAAS,mBACP,OACA,QACM;AACN,QAAM,mBAAmB,MAAM,oBAAoB,CAAC;AACpD,QAAM,iBAAiB,KAAK,MAAM;AACpC;AAgCA,eAAsB,yBACpB,eACA,cACA,YACA,aACA,mBAAyC,oBAAI,IAAI,GAClC;AACf,QAAM,EAAE,MAAM,mBAAmB,MAAM,kBAAkB,IAAI;AAAA,IAC3D;AAAA,IACA;AAAA,EACF;AAEA,yBAAuB,eAAe,cAAc,aAAa,gBAAgB;AACjF,iBAAe,aAAa;AAC5B,QAAM,gBAAgB,eAAe,YAAY,mBAAmB,iBAAiB;AACrF,mBAAiB,aAAa;AAChC;AAWO,SAAS,kBAAkB,cAA8B,aAAmC;AACjG,SAAO;AAAA,IACL,MAAM,eAAe,aAAa,eAAe;AAAA,IACjD,MAAM,gBAAgB,aAAa,MAAM,IAAI,WAAW;AAAA,IACxD,WAAW;AAAA,IACX,SAAS;AAAA,EACX;AACF;AAEA,SAAS,uBACPC,SACA,cACA,aACA,kBACM;AACN,aAAW,CAAC,IAAI,KAAK,KAAK,aAAaA,QAAO,MAAM,GAAG;AAErD,QAAI,CAAC,MAAO;AACZ,QAAI,iBAAiB,IAAI,EAAE,EAAG;AAE9B,uBAAmB,OAAO,kBAAkB,cAAc,WAAW,CAAC;AAAA,EACxE;AACF;AAEA,SAAS,eAAeA,SAAkC;AACxD,MAAI,QAAQ;AACZ,aAAW,CAAC,EAAE,KAAK,KAAK,aAAaA,QAAO,MAAM,GAAG;AAEnD,QAAI,CAAC,MAAO;AACZ,QAAI,CAAC,MAAM,MAAO;AAElB,UAAM,SAAsB;AAAA,MAC1B,MAAM;AAAA,MACN,MAAM;AAAA,MACN,WAAW;AAAA,MACX,aAAa;AAAA,IACf;AAEA,uBAAmB,OAAO,MAAM;AAChC;AAAA,EACF;AAEA,UAAQ,UAAU,KAAK,iCAAiC;AAC1D;AAEA,eAAe,gBACbA,SACA,YACA,mBACA,mBACe;AACf,QAAM,oBAAoB,MAAM,sBAAsB,UAAU;AAEhE,MAAI,kBAAkB,WAAW,GAAG;AAClC;AAAA,EACF;AAEA,aAAW,WAAW,mBAAmB;AACvC,UAAM,QAAQA,QAAO,OAAO,OAAO;AACnC,QAAI,CAAC,MAAO;AAEZ,0BAAsB,OAAO,mBAAmB,iBAAiB;AAAA,EACnE;AAEA,UAAQ,UAAU,kBAAkB,MAAM,0BAA0B;AACtE;AAWA,SAAS,sBACP,OACA,mBACA,mBACM;AACN,QAAM,mBAAmB,MAAM,oBAAoB,CAAC;AAEpD,QAAM,iBAAiB,MAAM,iBAAiB,KAAK,CAAC,MAAM,EAAE,YAAY,IAAI;AAC5E,MAAI,kBAAkB,CAAC,eAAe,aAAa;AACjD,mBAAe,YAAY;AAC3B,mBAAe,cAAc;AAC7B;AAAA,EACF;AACA,MAAI,MAAM,iBAAiB,KAAK,CAAC,MAAM,EAAE,gBAAgB,QAAQ,EAAG;AAEpE,qBAAmB,OAAO;AAAA,IACxB,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,aAAa;AAAA,IACb,SAAS;AAAA,EACX,CAAC;AACH;AAOA,eAAe,sBAAsB,YAAwC;AAC3E,QAAM,eAAe,MAAM,wBAAwB,UAAU;AAC7D,QAAM,WAAW,UAAmB,YAAY;AAIhD,QAAM,UAAUC,IAAG,QAAQ;AAC3B,MAAI,CAAC,gBAAgB,UAAU,GAAG;AAChC,UAAM,qBAAqB,MAAM,wBAAwB,OAAO;AAChE,UAAM,iBAAiB,UAAmB,kBAAkB;AAC5D,QAAI,eAAe,SAAS,GAAG;AAC7B,cAAQ,SAAS,eAAe,MAAM,yBAAyB;AAC/D,YAAM,SAAS,oBAAI,IAAI,CAAC,GAAG,UAAU,GAAG,cAAc,CAAC;AACvD,aAAO,CAAC,GAAG,MAAM;AAAA,IACnB;AAAA,EACF;AAEA,MAAI,SAAS,WAAW,GAAG;AACzB,YAAQ,gDAAgD;AAAA,EAC1D;AAEA,SAAO;AACT;AAGA,SAAS,iBAAiBD,SAAkC;AAC1D,aAAW,CAAC,EAAE,KAAK,KAAK,aAAaA,QAAO,MAAM,GAAG;AAEnD,QAAI,CAAC,MAAO;AACZ,QAAI,CAAC,MAAM,oBAAoB,MAAM,iBAAiB,WAAW,EAAG;AAGpE,UAAM,CAAC,WAAW,IAAI,MAAM;AAC5B,QAAI,CAAC,YAAa;AAClB,UAAM,eAAe,MAAM,iBAAiB,KAAK,CAAC,MAAM,EAAE,SAAS,KAAK;AAAA,EAC1E;AACF;;;ACpOO,SAAS,sBACd,KACA,QACc;AACd,QAAM,aAAa,OAAO,IAAI,EAAE;AAChC,MAAI,CAAC,YAAY;AACf,YAAQ,UAAU,IAAI,EAAE,2CAA2C;AACnE,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,OAAO,IAAI;AAAA,IACX,WAAW,IAAI,aAAa;AAAA,IAC5B,GAAI,IAAI,WAAW,UAAa,EAAE,QAAQ,IAAI,OAAO;AAAA,EACvD;AACF;AAEO,SAAS,uBACd,WACA,QACS;AACT,SAAO,UACJ,IAAI,CAAC,QAAQ,sBAAsB,KAAK,MAAM,CAAC,EAC/C,OAAO,CAAC,UAA0B,UAAU,IAAI;AACrD;AAWO,SAAS,yBAAyB,YAAgD;AACvF,SAAO,2BAA2B,UAAU;AAC9C;AAWO,SAAS,sBAAsB,aAAmD;AACvF,SAAO,YAAY,UAAU,CAAC;AAChC;AAyBA,eAAsB,cACpB,QACA,QACA,eACA,cACkD;AAClD,QAAM,UAAU,aAA4C,cAAc,MAAM,EAAE;AAAA,IAChF,CAAC,CAAC,WAAW,WAAW,MAAM;AAC5B,YAAM,aAAa,OAAO,SAAS;AACnC,UAAI,CAAC,WAAY,OAAM,IAAI,MAAM,mBAAmB,WAAW,MAAM,CAAC;AAEtE,YAAM,YAAY,sBAAsB,WAAW;AACnD,YAAM,iBAAiB,uBAAuB,WAAW,MAAM;AAE/D,aAAO;AAAA,QACL;AAAA,QACA,oBAAoB,WAAW,YAAY,aAAa,cAAc;AAAA,MACxE;AAAA,IACF;AAAA,EACF;AAEA,SAAO,iBAAiB,OAAO;AACjC;AAGA,IAAM,8BAA8B;AAGpC,SAAS,mBACP,WACA,QACQ;AACR,QAAM,kBAAkB,wBAAwB,UAAqB,MAAM,CAAC;AAC5E,SAAO,UAAU,SAAS,mEAAmE,eAAe,2BAA2B,SAAS;AAClJ;AAGA,SAAS,wBAAwB,iBAAsC;AACrE,MAAI,gBAAgB,WAAW,EAAG,QAAO;AAEzC,QAAM,SAAS,gBAAgB,MAAM,GAAG,2BAA2B,EAAE,KAAK,IAAI;AAC9E,QAAM,WAAW,gBAAgB,SAAS;AAC1C,SAAO,WAAW,IACd,qBAAqB,MAAM,SAAS,QAAQ,WAC5C,qBAAqB,MAAM;AACjC;AAMA,SAAS,oBACP,WACA,YACA,aACA,gBACa;AAIb,QAAM,QAAQ,YAAY,SAAS,WAAW;AAC9C,QAAM,SAAS,YAAY,UAAU,WAAW;AAEhD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO,WAAW;AAAA,IAClB,aAAa,WAAW;AAAA,IACxB,GAAI,UAAU,UAAa,EAAE,MAAM;AAAA,IACnC,GAAI,WAAW,UAAa,EAAE,OAAO;AAAA,IACrC,OAAO,WAAW;AAAA;AAAA;AAAA;AAAA,IAIlB,GAAI,WAAW,oBAAoB,UAAa;AAAA,MAC9C,iBAAiB,WAAW;AAAA,IAC9B;AAAA,IACA,GAAI,WAAW,mBAAmB,UAAa;AAAA,MAC7C,gBAAgB,WAAW;AAAA,IAC7B;AAAA,IACA,GAAI,WAAW,cAAc,UAAa,EAAE,WAAW,WAAW,UAAU;AAAA,IAC5E,GAAI,WAAW,UAAU,UAAa,EAAE,OAAO,WAAW,MAAM;AAAA,IAChE,GAAI,WAAW,iBAAiB,UAAa;AAAA,MAC3C,cAAc,WAAW;AAAA,IAC3B;AAAA,IACA,QAAQ;AAAA,IACR,GAAI,WAAW,SAAS,UAAa,EAAE,MAAM,WAAW,KAAK;AAAA,IAC7D,GAAI,WAAW,eAAe,UAAa,EAAE,YAAY,WAAW,WAAW;AAAA,IAC/E,GAAI,WAAW,iBAAiB,UAAa,EAAE,cAAc,WAAW,aAAa;AAAA,EACvF;AACF;;;ANlIA,SAAS,0BACP,eACA,aACoB;AACpB,QAAM,iBAAiB,IAAI,KAAK,eAAe,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;AAC9F,QAAM,mBAAmB,cAAc,OAAO,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE;AACjF,SAAOE,QAAO,iBAAiB,OAAO,CAAC,OAAO,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC;AACxE;AAcA,SAAS,8BACP,eACA,eACA,aACA,aACqB;AACrB,QAAM,kBAAkB,oBAAoB,WAAW;AACvD,QAAM,kBAAkB,oBAAoB,WAAW;AACvD,QAAM,sBAAsB,CAAC,OAAoB,UAC/C,sBAAsB,MAAM,OAAO,MAAM,KAAK,KAC9C,CAAC,oBAAoB,gBAAgB,IAAI,MAAM,EAAE,GAAG,gBAAgB,IAAI,MAAM,IAAI,CAAC;AAErF,QAAM,sBAAsB,cAAc,OAAO,CAAC,MAAM,CAAC,EAAE,QAAQ;AACnE,QAAM,sBAAsB,cAAc,OAAO,CAAC,MAAM,CAAC,EAAE,QAAQ;AAEnE,QAAM,aAAa,oBAAoB;AAAA,IAAQ,CAAC,UAC9C,oBACG,OAAO,CAAC,UAAU,oBAAoB,OAAO,KAAK,CAAC,EACnD,IAAI,CAAC,UAAU,oBAAoB,MAAM,MAAM,MAAM,EAAE,CAAC;AAAA,EAC7D;AACA,SAAO,IAAI,IAAI,UAAU;AAC3B;AAMA,SAAS,oBACP,iBACA,iBACS;AACT,SACE,oBAAoB,UACpB,oBAAoB,UACpB,sBAAsB,iBAAiB,eAAe;AAE1D;AAgBA,SAAS,qBACP,WACA,UACwB;AACxB,SAAO,aAAa,WAAW,WAAW;AAC5C;AAcA,SAAS,mBACP,aACA,QACoB;AACpB,SAAO,gBAAgB,OAAO,SAAS,YAAY;AACrD;AAgBA,SAAS,cAAc,YAA4B;AACjD,SAAO,gBAAgB,UAAU,IAAI,sBAAsBC,OAAK,SAAS,UAAU;AACrF;AAkBA,eAAe,iBACb,YACA,cACuD;AAGvD,QAAM,cAAc,gBAAgB,UAAU,IAAI,SAAY,MAAM,gBAAgB;AAKpF,SAAO,EAAE,GAAG,aAAa,GAAG,aAAa;AAC3C;AAGA,eAAe,kBAAmD;AAChE,UAAQ,MAAM,oBAAoBC,KAAG,QAAQ,CAAC,IAAI,OAAO;AAC3D;AAEA,eAAe,mBACb,cACA,cACA,YAC+D;AAC/D,QAAM,WAAWF,QAAO,aAAa,OAAO,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;AAC5D;AAAA,IACE,wCAAwC,aAAa,eAAe,cACvD,SAAS,KAAK,IAAI,CAAC,sBACX,aAAa,eAAe,KAAK,IAAI,CAAC;AAAA,EAC7D;AAEA,QAAM,cAAc,MAAM,kBAAkB,aAAa,iBAAiB,YAAY;AACtF,QAAM,WAAW,MAAM,kBAAkB,UAAU;AACnD,QAAM,gBAAgB,MAAM,iBAAiB,YAAY,UAAU,OAAO,KAAK;AAE/E,QAAM,UAAU;AAAA,IACd;AAAA,IACA,UAAU;AAAA,IACV,gBAAgB,aAAa,aAAa;AAAA,EAC5C;AACA,QAAM,YAAY,gCAAgC,cAAc,UAAU,GAAG,UAAU,OAAO;AAC9F,QAAM,QAAQ,qBAAqB,UAAU,OAAO,aAAa,aAAa;AAC9E,QAAM,cAAc,mBAAmB,aAAa,aAAa,WAAW;AAC5E,QAAM,cAA6B;AAAA,IACjC,GAAG;AAAA,IACH,GAAI,SAAS,EAAE,MAAM;AAAA,IACrB,GAAI,gBAAgB,UAAa,EAAE,YAAY;AAAA,EACjD;AAEA;AAAA,IACE,oCAAoC,gBAAgB,YAAY,KAAK,CAAC,aACzD,YAAY,OAAO,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC,aAAa,YAAY,OAAO,MAAM;AAAA,EACrG;AAEA,SAAO,EAAE,QAAQ,aAAa,YAAY;AAC5C;AASA,eAAsB,qBACpB,SACA,cACe;AACf,QAAM,kBAAkB,SAAS,YAAY;AAC/C;AAMA,eAAe,kBACb,SACA,cACuB;AACvB,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,EAAE,OAAO,IAAI,aAAa;AAChC,QAAM,cAAc,MAAM,cAAc,SAAS,aAAa,YAAY,MAAM;AAChF;AAAA,IACE,mCAAmC,cAAc,cAAc,YAAY,EAAE,OAAO,WAAW;AAAA,EACjG;AACA,MAAI,CAAC,YAAa,OAAM,IAAI,MAAM,uBAAuB,SAAS,MAAM,CAAC;AAEzE,SAAO;AACT;AAiBA,SAAS,gBACP,aACA,cAC8C;AAC9C,MAAI,gBAAgB,KAAM,QAAO;AACjC,SAAO,EAAE,GAAG,mBAAmB,WAAW,GAAG,GAAG,aAAa;AAC/D;AAgBA,SAAS,oBACP,cACA,WACA,eAQA;AACA,SAAO;AAAA,IACL,cAAc,aAAa;AAAA,IAC3B,cAAc,aAAa;AAAA,IAC3B;AAAA,IACA,oBAAoB,0BAA0B,aAAa,QAAQ,WAAW,MAAM;AAAA,IACpF,wBAAwB;AAAA,MACtB,aAAa;AAAA,MACb,aAAa;AAAA,MACb,WAAW;AAAA,MACX,WAAW;AAAA,IACb;AAAA,IACA,GAAI,aAAa,eAAe,SAAS,KAAK;AAAA,MAC5C,gBAAgB,aAAa;AAAA,IAC/B;AAAA,EACF;AACF;AAGA,SAAS,gBAAgB,OAAuC;AAC9D,SAAO,QAAQ,GAAG,OAAO,KAAK,KAAK,EAAE,MAAM,YAAY;AACzD;AAEO,SAAS,kBACd,QACA,cACA,cACA,YACe;AACf,QAAM,SAAS,EAAE,GAAG,OAAO;AAG3B,MAAI,aAAa,gBAAgB,SAAS,GAAG;AAC3C,WAAO,kBAAkB,aAAa;AAAA,EACxC;AAEA,MAAI,YAAY;AACd,WAAO,cAAc;AAAA,EACvB,WAAW,aAAa,aAAa,QAAQ;AAC3C,WAAO,cAAc,aAAa,aAAa;AAAA,EACjD;AAEA,MAAI,aAAa,aAAa;AAC5B,WAAO,kBAAkB,aAAa;AAAA,EACxC;AAEA,SAAO;AACT;AAEA,eAAsB,oBACpB,cACA,cACA,YACA,YACA,oBACsB;AACtB,QAAM,EAAE,OAAO,IAAI,MAAM,mBAAmB,cAAc,cAAc,UAAU;AAClF,UAAQ,kDAA6C,gBAAgB,OAAO,KAAK,CAAC,EAAE;AACpF,QAAM,qBAAqB,kBAAkB,QAAQ,cAAc,cAAc,UAAU;AAC3F,QAAM,SAAS,MAAM,wBAAwB,oBAAoB;AAAA,IAC/D;AAAA,IACA,GAAI,uBAAuB,UAAa,EAAE,mBAAmB;AAAA,EAC/D,CAAC;AACD;AAAA,IACE,iDAA4C,gBAAgB,OAAO,OAAO,KAAK,CAAC,YAAY,OAAO,MAAM;AAAA,EAC3G;AACA,SAAO;AACT;AAEO,SAAS,mBACd,QACA,QACgD;AAChD,QAAM,eAAe,OAAO,OAAO,OAAO,CAAC,MAAM,CAAC,EAAE,QAAQ;AAC5D,QAAM,mBAAmB,4BAA4B,OAAO,MAAM;AAClE,QAAM,iBAAiB,IAAI;AAAA,IACzB,OAAO,OAAO,OAAO,CAAC,MAAM,WAAW,GAAG,QAAQ,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE;AAAA,EACtE;AACA,QAAM,aAAa,IAAI,IAAqB,OAAO,OAAO,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AAItF,QAAM,eAAe,CAAC,KAAqB,gBAA2C;AACpF,QAAI,iBAAiB,IAAI,IAAI,EAAE,EAAG,QAAO;AACzC,QAAI,YAAY,UAAU,SAAU,QAAO,eAAe,IAAI,IAAI,EAAE;AACpE,WAAO;AAAA,EACT;AAKA,QAAM,gBAAgB,CAAC,QAAwC;AAC7D,UAAM,SAAS,WAAW,IAAI,IAAI,EAAE;AACpC,WAAO,EAAE,GAAG,KAAK,GAAI,WAAW,UAAa,EAAE,OAAO,EAAG;AAAA,EAC3D;AAEA,QAAM,yBAAyB,CAAC,gBAAsD;AAGpF,UAAM,SAA6B;AAAA,MACjC,GAAI,YAAY,UAAU,UAAa,EAAE,OAAO,YAAY,MAAM;AAAA,MAClE,GAAI,YAAY,WAAW,UAAa,EAAE,QAAQ,YAAY,OAAO;AAAA,IACvE;AAEA,UAAM,aAAa,OAAO,QAAQ,YAAY,IAAI;AAClD,QAAI,CAAC,WAAY,QAAO;AAExB,UAAM,eAAe,yBAAyB,UAAU,EACrD,OAAO,CAAC,QAAQ,aAAa,KAAK,WAAW,CAAC,EAC9C,IAAI,aAAa;AACpB,WAAO,EAAE,GAAG,QAAQ,QAAQ,aAAa;AAAA,EAC3C;AAEA,SAAO;AAAA,IACL,aACG,OAAO,CAAC,gBAAgB,OAAO,YAAY,IAAI,CAAC,EAChD,IAAI,CAAC,gBAAgB,CAAC,YAAY,MAAM,uBAAuB,WAAW,CAAC,CAAC;AAAA,EACjF;AACF;AAEO,SAAS,mBAAmB,QAAmD;AACpF,SAAO,oBAAoB,OAAO,MAAM;AAC1C;;;AO3bA,OAAOG,UAAQ;AAwER,SAAS,gBAAgB,OAAoB,MAAgC;AAClF,SAAO,MAAM,SAAS,KAAK,KAAK,UAAU,KAAK,GAAG;AACpD;AAYA,eAAsB,mBAAmB,KAAqC;AAC5E,QAAM,SAAS,MAAM,QAAQ;AAAA,IAC3B,iBAAiB,GAAG,EAAE;AAAA,MAAI,OAAO,EAAE,MAAM,KAAK,MAC5C,cAAc,MAAM,MAAM,cAAc,IAAI,CAAC;AAAA,IAC/C;AAAA,EACF;AACA,SAAO,OAAO,OAAO,CAAC,UAAgC,UAAU,IAAI;AACtE;AAUO,SAAS,iBAAiB,KAA0B;AACzD,QAAM,SAAoB,EAAE,MAAM,UAAU,MAAMC,KAAG,QAAQ,EAAE;AAC/D,MAAI,gBAAgB,GAAG,EAAG,QAAO,CAAC,MAAM;AACxC,SAAO,CAAC,QAAQ,EAAE,MAAM,WAAW,MAAM,IAAI,CAAC;AAChD;AAGA,eAAsB,cACpB,MACA,MACA,UAC6B;AAC7B,QAAM,WAAW,iBAAiB,MAAM,QAAQ;AAChD,QAAM,UAAU,SAAS,UAAW,MAAMC,iBAAgB,SAAS,GAAG;AACtE,MAAI,CAAC,QAAS,QAAO;AAErB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ,SAAS;AAAA,IACjB,MAAM,SAAS;AAAA,IACf,SAAS,SAAS;AAAA,IAClB,MAAM,wBAAwB,MAAM,QAAQ;AAAA,EAC9C;AACF;;;ACpFA,eAAsB,oBAAoB,KAA8C;AACtF,QAAM,uBAAuB,iBAAiB,GAAG,EAAE,QAAQ,kBAAkB;AAC7E,QAAM,QAAQ,MAAM,QAAQ,IAAI,qBAAqB,IAAI,qBAAqB,CAAC;AAE/E,SAAO,MAAM;AAAA,IACX,CAAC,iBAAuD,iBAAiB;AAAA,EAC3E;AACF;AAGA,SAAS,mBAAmB,EAAE,MAAM,KAAK,GAAsC;AAC7E,SAAO,UAAU,IAAI,CAAC,cAAc;AAAA,IAClC;AAAA,IACA,OAAO;AAAA,IACP,YAAY,qBAAqB,MAAM,QAAQ;AAAA,EACjD,EAAE;AACJ;AAGA,eAAe,sBACb,WACsC;AACtC,SAAQ,MAAM,WAAW,UAAU,UAAU,IAAK,YAAY;AAChE;;;AC/CA,OAAOC,UAAQ;AACf,OAAOC,YAAU;AACjB,SAAS,KAAAC,UAAS;;;ACZlB,SAAS,aAAa;AACtB,OAAOC,YAAU;AAGjB,IAAM,yBAAyB;AAC/B,IAAM,yBAAyB;AAC/B,IAAM,gCAAgC;AAGtC,IAAMC,qBAAoB;AAG1B,IAAM,2BAA2B;AAGjC,IAAM,wBAAwB;AAU9B,SAAS,6BAA6B,QAAyB;AAC7D,SAAOD,OAAK,WAAW,MAAM,KAAK,sBAAsB,KAAK,MAAM;AACrE;AAGA,IAAM,uBAAuB;AAEtB,SAAS,mBAAmB,YAA0B;AAC3D,MAAI,CAAC,cAAc,WAAW,KAAK,EAAE,WAAW,GAAG;AACjD,UAAM,IAAI,MAAM,gCAAgC;AAAA,EAClD;AAEA,MAAI,WAAW,SAAS,wBAAwB;AAC9C,UAAM,IAAI;AAAA,MACR,4BAA4B,WAAW,MAAM,oBAAoB,sBAAsB;AAAA,IACzF;AAAA,EACF;AAEA,MAAI,qBAAqB,KAAK,UAAU,GAAG;AACzC,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACpE;AAEA,MAAI,CAAC,yBAAyB,KAAK,UAAU,GAAG;AAC9C,UAAM,IAAI;AAAA,MACR,6CAA6C,UAAU;AAAA;AAAA,IAEzD;AAAA,EACF;AACF;AAyBO,SAAS,0BAA0B,QAAsB;AAC9D,MAAI,CAAC,UAAU,OAAO,KAAK,EAAE,WAAW,GAAG;AACzC,UAAM,IAAI,MAAM,gCAAgC;AAAA,EAClD;AAEA,MAAI,OAAO,SAAS,+BAA+B;AACjD,UAAM,IAAI;AAAA,MACR,4BAA4B,OAAO,MAAM,oBAAoB,6BAA6B;AAAA,IAC5F;AAAA,EACF;AAEA,MAAI,qBAAqB,KAAK,MAAM,GAAG;AACrC,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACpE;AAEA,MAAI,6BAA6B,MAAM,EAAG;AAE1C,MAAI,CAAC,yBAAyB,KAAK,MAAM,GAAG;AAC1C,UAAM,IAAI;AAAA,MACR,6CAA6C,MAAM;AAAA;AAAA,IAErD;AAAA,EACF;AACF;AAEO,SAAS,mBAAmB,YAA0B;AAC3D,MAAI,CAAC,cAAc,WAAW,KAAK,EAAE,WAAW,GAAG;AACjD,UAAM,IAAI,MAAM,gCAAgC;AAAA,EAClD;AAEA,MAAI,WAAW,SAAS,wBAAwB;AAC9C,UAAM,IAAI;AAAA,MACR,4BAA4B,WAAW,MAAM,oBAAoB,sBAAsB;AAAA,IACzF;AAAA,EACF;AAEA,MAAI,qBAAqB,KAAK,UAAU,GAAG;AACzC,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACpE;AAEA,MAAI,CAACC,mBAAkB,KAAK,UAAU,GAAG;AACvC,UAAM,IAAI;AAAA,MACR,6CAA6C,UAAU;AAAA;AAAA,IAEzD;AAAA,EACF;AACF;AAeA,eAAsB,YACpB,SACA,MACA,SACqB;AACrB,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,OAAO,MAAM,SAAS,MAAM;AAAA,MAChC,KAAK,SAAS;AAAA,MACd,KAAK,EAAE,GAAG,QAAQ,KAAK,GAAG,SAAS,IAAI;AAAA,MACvC,OAAO,CAAC,UAAU,QAAQ,MAAM;AAAA,IAClC,CAAC;AAED,QAAI,SAAS;AACb,QAAI,SAAS;AAEb,SAAK,OAAO,GAAG,QAAQ,CAAC,SAAiB;AACvC,gBAAU,KAAK,SAAS;AAAA,IAC1B,CAAC;AAED,SAAK,OAAO,GAAG,QAAQ,CAAC,SAAiB;AACvC,gBAAU,KAAK,SAAS;AAAA,IAC1B,CAAC;AAED,SAAK,GAAG,SAAS,CAAC,SAAS;AACzB,cAAQ;AAAA,QACN;AAAA,QACA;AAAA,QACA,UAAU,QAAQ;AAAA,MACpB,CAAC;AAAA,IACH,CAAC;AAED,SAAK,GAAG,SAAS,CAAC,QAAQ;AACxB,aAAO,GAAG;AAAA,IACZ,CAAC;AAAA,EACH,CAAC;AACH;;;ACxLA,OAAOC,YAAU;AACjB,SAAS,KAAAC,UAAS;AA2BlB,IAAM,uBAAuBC,GAC1B,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMN,gBAAgBA,GAAE,OAAOA,GAAE,OAAO,GAAGA,GAAE,QAAQ,CAAC,EAAE,cAAc;AAClE,CAAC,EACA,YAAY;AAGf,IAAM,qBAAqB;AAAA,EACzB,aAAaA,GAAE,OAAO;AAAA,EACtB,SAASA,GAAE,OAAO;AAAA,EAClB,aAAaA,GAAE,OAAO;AACxB;AAQA,IAAM,2BAA2BA,GAAE,mBAAmB,SAAS;AAAA,EAC7DA,GAAE,OAAO,EAAE,OAAOA,GAAE,QAAQ,SAAS,GAAG,aAAaA,GAAE,OAAO,GAAG,GAAG,mBAAmB,CAAC;AAAA,EACxFA,GAAE,OAAO,EAAE,OAAOA,GAAE,QAAQ,MAAM,GAAG,GAAG,mBAAmB,CAAC;AAAA,EAC5DA,GAAE,OAAO,EAAE,OAAOA,GAAE,QAAQ,OAAO,GAAG,GAAG,mBAAmB,CAAC;AAC/D,CAAC;AAED,IAAM,yBAAyBA,GAC5B,OAAO;AAAA,EACN,SAASA,GAAE,OAAO;AAAA,EAClB,SAASA,GAAE,OAAOA,GAAE,OAAO,GAAGA,GAAE,MAAM,wBAAwB,CAAC;AACjE,CAAC,EACA,YAAY;AAEf,IAAM,gBAAgB,eAAe;AAG9B,SAAS,gCAAgCC,aAA4B;AAC1E,SAAOC,OAAK,KAAKD,aAAY,sBAAsB;AACrD;AASA,eAAe,4BACbA,aACsD;AACtD,QAAM,eAAe,gCAAgCA,WAAU;AAC/D,QAAM,UAAU,MAAM,aAAa,cAAc,oBAAoB;AACrE,QAAM,MAAe,KAAK,MAAM,OAAO;AACvC,QAAM,SAAS,uBAAuB,UAAU,GAAG;AAEnD,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,IAAI;AAAA,MACR,WAAW,sBAAsB,KAAK,gBAAgB,OAAO,KAAK,EAAE,KAAK,IAAI,CAAC;AAAA,IAChF;AAAA,EACF;AAEA,SAAO,OAAO,KAAK;AACrB;AAWA,eAAsB,6BAA6BA,aAA+C;AAChG,QAAM,gBAAgB,MAAM,4BAA4BA,WAAU;AAElE,SAAO,aAAa,aAAa,EAAE,QAAQ,CAAC,CAAC,WAAW,MAAM,MAAM;AAClE,UAAM,cAAc,CAAC,GAAG,IAAI,IAAI,OAAO,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AACjE,WAAO,YAAY,IAAI,CAAC,iBAAiB,EAAE,WAAW,YAAY,EAAE;AAAA,EACtE,CAAC;AACH;AAcA,eAAsB,6BACpBA,aACA,YAC2B;AAC3B,QAAM,gBAAgB,MAAM,4BAA4BA,WAAU;AAElE,SAAO,aAAa,aAAa,EAAE,QAAQ,CAAC,CAAC,WAAW,MAAM,MAAM;AAClE,UAAM,SAAS,iBAAiB,QAAQ,UAAU;AAClD,QAAI,CAAC,QAAQ;AACX,cAAQ,uBAAuB,SAAS,iBAAiB,UAAU,GAAG;AACtE,aAAO,CAAC;AAAA,IACV;AACA,WAAO,CAAC,EAAE,WAAW,aAAa,OAAO,YAAY,CAAC;AAAA,EACxD,CAAC;AACH;AAKA,eAAsB,qBAAqB,YAA0C;AACnF,QAAM,eAAeC,OAAK,KAAK,YAAY,YAAY,aAAa;AAEpE,MAAI,CAAE,MAAM,WAAW,YAAY,GAAI;AACrC,YAAQ,8BAA8B,YAAY,GAAG;AACrD,WAAO,CAAC;AAAA,EACV;AAEA,MAAI;AACF,UAAM,UAAU,MAAM,aAAa,cAAc,oBAAoB;AACrE,UAAM,MAAe,KAAK,MAAM,OAAO;AACvC,UAAM,SAAS,qBAAqB,UAAU,GAAG;AAEjD,QAAI,CAAC,OAAO,SAAS;AACnB,cAAQ,oCAAoC,gBAAgB,OAAO,KAAK,CAAC,EAAE;AAC3E,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,WAAW,OAAO;AAExB,QAAI,CAAC,SAAS,gBAAgB;AAC5B,cAAQ,+BAA+B,YAAY,GAAG;AACtD,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,cAAc,aAAa,SAAS,cAAc,EACrD,OAAO,CAAC,CAAC,EAAE,OAAO,MAAM,YAAY,IAAI,EACxC,IAAI,CAAC,CAAC,GAAG,MAAM,GAAG;AAErB,YAAQ,SAAS,YAAY,MAAM,mCAAmC;AACtE,WAAO;AAAA,EACT,SAAS,OAAO;AACd,YAAQ,iCAAiC,gBAAgB,KAAK,CAAC,EAAE;AACjE,WAAO,CAAC;AAAA,EACV;AACF;AAKA,SAAS,iBACP,eACA,YACoC;AACpC,SACE,cAAc,KAAK,CAAC,MAAM,EAAE,UAAU,aAAa,EAAE,gBAAgB,UAAU,KAC/E,cAAc,KAAK,CAAC,MAAM,EAAE,UAAU,MAAM;AAEhD;;;AF9IA,IAAM,SAAiC;AAUvC,IAAM,yBAAyB,CAAC,iBAAiB,WAAW;AAS5D,SAAS,0BAA8C;AACrD,SAAO;AAAA,IACL,EAAE,MAAM,UAAU,OAAO,SAAS;AAAA,IAClC,EAAE,MAAM,UAAU,OAAO,UAAU;AAAA,IACnC,EAAE,MAAM,SAAS,OAAO,SAAS;AAAA,IACjC,EAAE,MAAM,SAAS,OAAO,UAAU;AAAA,EACpC;AACF;AAOO,SAAS,oBAAoB,OAAkD;AACpF,SAAO,UAAU,WAAW,SAAS;AACvC;AAGA,SAAS,iBAAiB,OAA0B,YAA4B;AAC9E,SAAO,UAAU,SAASC,KAAG,QAAQ,IAAI;AAC3C;AAiBA,SAAS,aAAa,SAAuE;AAC3F,MAAI,SAAS,cAAc,OAAW,QAAO,CAAC;AAC9C,SAAO,EAAE,KAAK,EAAE,mBAAmB,QAAQ,UAAU,EAAE;AACzD;AAEA,eAAsB,oBACpB,YACA,OACA,YACA,SACe;AACf,qBAAmB,UAAU;AAE7B,QAAM,MAAM,iBAAiB,OAAO,UAAU;AAC9C,QAAM,OAAO,CAAC,UAAU,WAAW,YAAY,WAAW,KAAK;AAC/D,QAAM,SAAS,MAAM,YAAY,UAAU,MAAM,EAAE,KAAK,GAAG,aAAa,OAAO,EAAE,CAAC;AAElF,MAAI,OAAO,aAAa,GAAG;AACzB,UAAM,IAAI,MAAM,+BAA+B,gBAAgB,MAAM,CAAC,EAAE;AAAA,EAC1E;AACF;AAaA,eAAsB,qBAAqB,SAAiD;AAC1F,MAAI;AACF,UAAM,SAAS,MAAM,YAAY,UAAU,CAAC,WAAW,GAAG,aAAa,OAAO,CAAC;AAC/E,WAAO,OAAO,aAAa;AAAA,EAC7B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AASA,IAAM,4BAA0DC,GAAE;AAAA,EAChEA,GAAE,OAAO;AAAA,IACP,MAAMA,GAAE,OAAO;AAAA,IACf,QAAQA,GAAE,OAAO;AAAA,IACjB,MAAMA,GAAE,OAAO,EAAE,cAAc;AAAA,IAC/B,MAAMA,GAAE,OAAO,EAAE,cAAc;AAAA,EACjC,CAAC;AACH;AAEA,eAAsB,4BACpB,SAC4B;AAC5B,MAAI;AACF,UAAM,SAAS,MAAM;AAAA,MACnB;AAAA,MACA,CAAC,UAAU,eAAe,QAAQ,QAAQ;AAAA,MAC1C,aAAa,OAAO;AAAA,IACtB;AAEA,QAAI,OAAO,aAAa,EAAG,QAAO,CAAC;AACnC,WAAO,qBAAqB,OAAO,MAAM;AAAA,EAC3C,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAGA,SAAS,qBAAqB,QAAmC;AAC/D,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,MAAM;AAAA,EAC5B,QAAQ;AACN,SAAK,iDAAiD;AACtD,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,aAAa,0BAA0B,UAAU,MAAM;AAC7D,MAAI,CAAC,WAAW,SAAS;AACvB,SAAK,oFAA+E;AACpF,WAAO,CAAC;AAAA,EACV;AAEA,SAAO,WAAW;AACpB;AAEA,eAAsB,8BACpB,MACA,SACkB;AAClB,QAAM,eAAe,MAAM,4BAA4B,OAAO;AAC9D,SAAO,aAAa,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AACjD;AAEA,eAAsB,2BACpB,QACA,SACe;AACf,4BAA0B,MAAM;AAEhC,QAAM,OAAO,CAAC,UAAU,eAAe,OAAO,MAAM;AACpD,QAAM,SAAS,MAAM,UAAU,MAAM,SAAS,iBAAiB;AAC/D,MAAI,OAAO,aAAa,EAAG;AAE3B,QAAM,OAAO,gBAAgB,MAAM;AACnC,MAAI,KAAK,SAAS,mBAAmB,EAAG;AACxC,QAAM,IAAI,MAAM,8BAA8B,IAAI,EAAE;AACtD;AAiBA,eAAsB,8BACpB,MACA,SACe;AACf,qBAAmB,IAAI;AAEvB,QAAM,OAAO,CAAC,UAAU,eAAe,UAAU,IAAI;AACrD,QAAM,SAAS,MAAM,UAAU,MAAM,SAAS,oBAAoB;AAClE,MAAI,OAAO,aAAa,EAAG;AAE3B,QAAM,IAAI,MAAM,iCAAiC,gBAAgB,MAAM,CAAC,EAAE;AAC5E;AAQA,eAAe,UACb,MACA,SACA,SACqB;AACrB,MAAI;AACF,WAAO,MAAM,YAAY,UAAU,MAAM,aAAa,OAAO,CAAC;AAAA,EAChE,SAAS,KAAK;AACZ,UAAM,IAAI,MAAM,aAAa,OAAO,KAAK,gBAAgB,GAAG,CAAC,IAAI,EAAE,OAAO,IAAI,CAAC;AAAA,EACjF;AACF;AAGA,SAAS,gBAAgB,QAA4B;AACnD,UAAQ,OAAO,UAAU,OAAO,UAAU,iBAAiB,KAAK;AAClE;AAUA,eAAsB,sBACpB,YACA,OACA,YACA,SAC+B;AAC/B,qBAAmB,UAAU;AAE7B,QAAM,MAAM,iBAAiB,OAAO,UAAU;AAC9C,QAAM,OAAO,CAAC,UAAU,aAAa,YAAY,WAAW,KAAK;AACjE,QAAM,SAAS,MAAM,YAAY,UAAU,MAAM,EAAE,KAAK,GAAG,aAAa,OAAO,EAAE,CAAC;AAElF,MAAI,OAAO,aAAa,EAAG,QAAO;AAElC,QAAM,OAAO,gBAAgB,MAAM;AACnC,MAAI,oBAAoB,IAAI,EAAG,QAAO;AACtC,QAAM,IAAI,MAAM,4BAA4B,IAAI,EAAE;AACpD;AAGA,SAAS,oBAAoB,SAA0B;AACrD,SAAO,uBAAuB,KAAK,CAAC,WAAW,QAAQ,SAAS,MAAM,CAAC;AACzE;AAYA,SAAS,kBACP,YACA,SACe;AACf,MAAI,SAAS,cAAc,OAAW,QAAOC,OAAK,KAAK,QAAQ,WAAW,cAAc;AACxF,SAAO,WAAW,QAAQ,UAAU,UAAU;AAChD;AAkBA,eAAe,kBACb,YACA,SACuB;AACvB,QAAM,cAAc,kBAAkB,YAAY,OAAO;AACzD,MAAI,gBAAgB,KAAM,QAAO,CAAC;AAClC,MAAI,CAAE,MAAM,WAAW,gCAAgC,WAAW,CAAC,EAAI,QAAO,CAAC;AAE/E,QAAM,CAAC,UAAU,OAAO,IAAI,MAAM,QAAQ,IAAI;AAAA,IAC5C,6BAA6B,aAAa,UAAU;AAAA,IACpD,qBAAqB,UAAU;AAAA,EACjC,CAAC;AACD,QAAM,cAAc,IAAI,IAAI,OAAO;AAEnC,SAAO,SAAS,IAAI,CAAC,EAAE,WAAW,YAAY,OAAO;AAAA,IACnD;AAAA,IACA;AAAA,IACA,SAAS,YAAY,IAAI,SAAS;AAAA,EACpC,EAAE;AACJ;AASO,SAAS,aAAyB;AACvC,SAAO;AAAA,IACL,UAAU;AAAA,IACV,mBAAmB,wBAAwB;AAAA,IAC3C,8BAA8B;AAAA,IAC9B,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,gBAAgB;AAAA,IAChB,oBAAoB;AAAA,IACpB,eAAe,CAAC,WAAW,OAAO,YAAY,YAC5C,oBAAoB,WAAW,oBAAoB,KAAK,GAAG,YAAY,OAAO;AAAA,IAChF,iBAAiB,CAAC,WAAW,OAAO,YAAY,YAC9C,sBAAsB,WAAW,oBAAoB,KAAK,GAAG,YAAY,OAAO;AAAA,IAClF,aAAa;AAAA,EACf;AACF;;;AGjWA,OAAOC,UAAQ;AACf,OAAOC,YAAU;AACjB,SAAS,KAAAC,UAAS;AAwBlB,IAAM,QAAgC;AAUtC,IAAM,sBAAsB;AAU5B,IAAM,mBAAmB;AAkBzB,SAAS,iBAAyB;AAChC,SAAOC,KAAG,QAAQ;AACpB;AAQA,SAAS,yBAA6C;AACpD,SAAO;AAAA,IACL,EAAE,MAAM,UAAU,OAAO,SAAS;AAAA,IAClC,EAAE,MAAM,SAAS,OAAO,SAAS;AAAA,IACjC,EAAE,MAAM,SAAS,OAAO,UAAU;AAAA,EACpC;AACF;AAeA,SAAS,aAAa,SAAsE;AAC1F,MAAI,SAAS,cAAc,OAAW,QAAO,CAAC;AAC9C,SAAO,EAAE,KAAK,EAAE,YAAY,QAAQ,UAAU,EAAE;AAClD;AASA,SAAS,eAAe,SAAyC,WAA2B;AAC1F,SAAO,SAAS,aAAa,eAAe,OAAO,UAAU,SAAS;AACxE;AA0BA,eAAe,SACb,MACA,SACA,WACqB;AACrB,QAAM,iBAAiB,eAAe,SAAS,SAAS,CAAC;AACzD,SAAO,YAAY,SAAS,MAAM,EAAE,KAAK,WAAW,GAAG,aAAa,OAAO,EAAE,CAAC;AAChF;AAYA,eAAe,iBAAiB,MAA6B;AAC3D,MAAI;AACF,UAAM,UAAU,IAAI;AAAA,EACtB,SAAS,OAAO;AACd,YAAQ,iDAAiD,IAAI,KAAK,gBAAgB,KAAK,CAAC,EAAE;AAAA,EAC5F;AACF;AAWA,eAAe,gBACb,MACA,SACA,SACA,WACqB;AACrB,MAAI;AACJ,MAAI;AACF,aAAS,MAAM,SAAS,MAAM,SAAS,SAAS;AAAA,EAClD,SAAS,OAAO;AACd,UAAM,IAAI,MAAM,aAAa,OAAO,KAAK,gBAAgB,KAAK,CAAC,IAAI,EAAE,OAAO,MAAM,CAAC;AAAA,EACrF;AAEA,MAAI,OAAO,aAAa,EAAG,OAAM,IAAI,MAAM,aAAa,OAAO,KAAK,YAAY,MAAM,CAAC,EAAE;AACzF,SAAO;AACT;AASA,SAAS,0BAA0B,QAAwB;AACzD,SAAO,OACJ,MAAM,IAAI,EACV,OAAO,CAACC,UAAS,CAAC,iBAAiB,KAAKA,KAAI,CAAC,EAC7C,KAAK,IAAI,EACT,KAAK;AACV;AAGA,SAAS,YAAY,QAA4B;AAC/C,QAAM,OAAO,0BAA0B,OAAO,MAAM,KAAK,0BAA0B,OAAO,MAAM;AAChG,SAAO,QAAQ;AACjB;AAWA,eAAe,kBACb,QACA,MACA,SACA,SACA,WACY;AACZ,QAAM,SAAS,MAAM,gBAAgB,MAAM,SAAS,SAAS,SAAS;AAEtE,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,OAAO,MAAM;AAAA,EACnC,SAAS,OAAO;AACd,UAAM,IAAI,MAAM,aAAa,OAAO,mCAAmC,EAAE,OAAO,MAAM,CAAC;AAAA,EACzF;AAEA,QAAM,YAAY,OAAO,UAAU,MAAM;AACzC,MAAI,CAAC,UAAU,SAAS;AACtB,UAAM,IAAI,MAAM,aAAa,OAAO,sDAAsD;AAAA,EAC5F;AACA,SAAO,UAAU;AACnB;AASA,IAAM,4BAA4BC,GAAE,OAAO;AAAA,EACzC,cAAcA,GAAE;AAAA,IACdA,GAAE,OAAO;AAAA,MACP,MAAMA,GAAE,OAAO;AAAA,MACf,mBAAmBA,GAAE,OAAO,EAAE,YAAYA,GAAE,OAAO,GAAG,QAAQA,GAAE,OAAO,EAAE,CAAC;AAAA,IAC5E,CAAC;AAAA,EACH;AACF,CAAC;AAYD,IAAM,sBAAsBA,GAAE,OAAO;AAAA,EACnC,WAAWA,GAAE;AAAA,IACXA,GAAE,OAAO;AAAA,MACP,UAAUA,GAAE,OAAO;AAAA,MACnB,MAAMA,GAAE,OAAO;AAAA,MACf,iBAAiBA,GAAE,OAAO;AAAA,MAC1B,SAASA,GAAE,OAAO;AAAA,MAClB,SAASA,GAAE,QAAQ;AAAA,IACrB,CAAC;AAAA,EACH;AACF,CAAC;AAeD,SAAS,iBACP,YACA,SACe;AACf,MAAI,SAAS,cAAc,OAAW,QAAOC,OAAK,KAAK,QAAQ,WAAW,cAAc;AACxF,SAAO,WAAW,OAAO,UAAU,UAAU;AAC/C;AAUA,eAAsB,oBAAoB,SAAgD;AACxF,MAAI;AACF,UAAM,SAAS,MAAM,SAAS,CAAC,WAAW,GAAG,SAAS,eAAe,CAAC;AACtE,WAAO,OAAO,aAAa;AAAA,EAC7B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAyBA,IAAM,yBAAyB;AAG/B,SAAS,6BAA6B,OAAyB;AAC7D,SAAO,uBAAuB,KAAK,gBAAgB,KAAK,CAAC;AAC3D;AAGA,eAAe,kBACb,SAC6B;AAC7B,QAAM,WAAW,MAAM;AAAA,IACrB;AAAA,IACA,CAAC,UAAU,eAAe,QAAQ,QAAQ;AAAA,IAC1C;AAAA,IACA;AAAA,IACA,eAAe;AAAA,EACjB;AACA,SAAO,SAAS;AAClB;AAwBA,eAAe,uBACb,MACA,SACkB;AAClB,SAAQ,MAAM,2BAA2B,MAAM,OAAO,MAAO;AAC/D;AAaA,eAAe,2BACb,MACA,SACkC;AAClC,MAAI;AACJ,MAAI;AACF,iBAAa,MAAM,kBAAkB,OAAO;AAAA,EAC9C,SAAS,OAAO;AACd,QAAI,CAAC,6BAA6B,KAAK,EAAG,OAAM;AAChD,aAAS,oBAAoB,kCAAkC,gBAAgB,KAAK,CAAC,CAAC;AACtF,WAAO;AAAA,EACT;AAEA,SAAO,WAAW,KAAK,CAAC,gBAAgB,YAAY,SAAS,IAAI,KAAK;AACxE;AAUA,SAAS,oBAAoB,SAAiB,MAAsB;AAClE,SAAO,mBAAmB,OAAO,yDAAyD,IAAI;AAChG;AAGA,eAAsB,oBACpB,QACA,SACe;AACf,4BAA0B,MAAM;AAChC,QAAM;AAAA,IACJ,CAAC,UAAU,eAAe,OAAO,QAAQ,QAAQ;AAAA,IACjD;AAAA,IACA;AAAA,IACA,eAAe;AAAA,EACjB;AACF;AAqBA,eAAe,wBAAwB,MAAc,SAA6C;AAChG,qBAAmB,IAAI;AAEvB,QAAM,cAAc,MAAM,kBAAkB,OAAO,GAAG;AAAA,IACpD,CAAC,gBAAgB,YAAY,SAAS;AAAA,EACxC;AACA,MAAI,eAAe,QAAW;AAC5B,UAAM,IAAI,MAAM,kEAAkE,IAAI,GAAG;AAAA,EAC3F;AAEA,MAAI,aAAa,UAAU,EAAG,QAAO,sBAAsB,MAAM,OAAO;AACxE,SAAO,sBAAsB,MAAM,OAAO;AAC5C;AAGA,SAAS,aAAa,aAAwC;AAC5D,SAAO,YAAY,kBAAkB,eAAe;AACtD;AAGA,eAAe,sBACb,MACA,SACe;AACf,QAAM;AAAA,IACJ,CAAC,UAAU,eAAe,WAAW,MAAM,QAAQ;AAAA,IACnD;AAAA,IACA;AAAA,IACA,eAAe;AAAA,EACjB;AACF;AAGA,eAAe,sBACb,MACA,SACe;AAGf,QAAM,YAAY,MAAM,mBAAmB,SAAS,eAAe,CAAC;AAKpE,aAAW,UAAU,UAAU,OAAO,CAAC,UAAU,MAAM,oBAAoB,IAAI,GAAG;AAChF,UAAM,mBAAmB,OAAO,UAAU,OAAO;AAAA,EACnD;AACF;AAUA,eAAe,mBACb,WACA,QACA,aACA,SACe;AACf,QAAM,mBAAmB,WAAW,OAAO;AAC7C;AAGA,eAAe,mBACb,WACA,SACe;AACf,qBAAmB,SAAS;AAC5B,QAAM;AAAA,IACJ,CAAC,UAAU,OAAO,WAAW,QAAQ;AAAA,IACrC;AAAA,IACA,WAAW,SAAS;AAAA,IACpB,eAAe;AAAA,EACjB;AACF;AAmBA,eAAe,qBACb,WACA,QACA,aACA,SAC+B;AAC/B,qBAAmB,SAAS;AAE5B,QAAM,eAAe,MAAM,SAAS,WAAW,OAAO;AACtD,QAAM;AAAA,IACJ,CAAC,UAAU,UAAU,WAAW,QAAQ;AAAA,IACxC;AAAA,IACA,UAAU,SAAS;AAAA,IACnB,eAAe;AAAA,EACjB;AAEA,MAAI,MAAM,SAAS,WAAW,OAAO,GAAG;AACtC,UAAM,IAAI;AAAA,MACR,oBAAoB,SAAS;AAAA,IAE/B;AAAA,EACF;AAEA,SAAO,eAAe,YAAY;AACpC;AASA,eAAe,SACb,WACA,SACkB;AAClB,QAAM,YAAY,MAAM,mBAAmB,SAAS,eAAe,CAAC;AACpE,SAAO,UAAU,KAAK,CAAC,WAAW,OAAO,aAAa,SAAS;AACjE;AAGA,eAAe,mBACb,SACA,WACiC;AACjC,QAAM,UAAU,MAAM;AAAA,IACpB;AAAA,IACA,CAAC,UAAU,QAAQ,QAAQ;AAAA,IAC3B;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,SAAO,QAAQ;AACjB;AA+CA,eAAe,iBACb,YACA,SACuB;AACvB,QAAM,UAAU,MAAM,yBAAyB,YAAY,OAAO;AAClE,MAAI,QAAQ,SAAS,SAAU,QAAO,CAAC,GAAG,QAAQ,OAAO;AAEzD,WAAS,oBAAoB,qCAAqC,QAAQ,MAAM,CAAC;AACjF,SAAO,CAAC;AACV;AAcA,eAAe,yBACb,YACA,SAC6B;AAC7B,QAAM,cAAc,iBAAiB,YAAY,OAAO;AACxD,MAAI,gBAAgB,KAAM,QAAO,EAAE,MAAM,UAAU,SAAS,CAAC,EAAE;AAC/D,QAAMC,aAAYD,OAAK,KAAK,aAAa,mBAAmB;AAE5D,MAAI;AACJ,MAAI;AACF,gBAAY,MAAM,mBAAmB,SAAS,UAAU;AAAA,EAC1D,SAAS,OAAO;AACd,QAAI,CAAC,6BAA6B,KAAK,EAAG,OAAM;AAChD,WAAO,EAAE,MAAM,cAAc,QAAQ,gBAAgB,KAAK,EAAE;AAAA,EAC9D;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS,UAAU,IAAI,CAAC,YAAY;AAAA,MAClC,WAAW,OAAO;AAAA,MAClB,aAAaA,OAAK,KAAKC,YAAW,OAAO,iBAAiB,OAAO,MAAM,OAAO,OAAO;AAAA,MACrF,SAAS,OAAO;AAAA,IAClB,EAAE;AAAA,EACJ;AACF;AASO,SAAS,YAAwB;AACtC,SAAO;AAAA,IACL,UAAU;AAAA,IACV,mBAAmB,uBAAuB;AAAA,IAC1C,8BAA8B;AAAA,IAC9B,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,gBAAgB;AAAA,IAChB,oBAAoB;AAAA,IACpB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,aAAa;AAAA,EACf;AACF;;;AChuBA,SAAS,cAAc,WAAqC;AAC1D,SAAO,GAAG,UAAU,IAAI,IAAI,UAAU,KAAK;AAC7C;AAEA,SAAS,gBAAgB,MAAkB,WAAsC;AAC/E,SAAO,KAAK,kBAAkB;AAAA,IAC5B,CAAC,YAAY,QAAQ,SAAS,UAAU,QAAQ,QAAQ,UAAU,UAAU;AAAA,EAC9E;AACF;AASO,SAAS,yBACd,MACA,WACA,SACM;AACN,MAAI,gBAAgB,MAAM,SAAS,EAAG;AAEtC,QAAM,IAAI;AAAA,IACR,uBAAuB,OAAO,OAAO,cAAc,SAAS,CAAC,SAAS,KAAK,QAAQ,gBACvE,KAAK,kBAAkB,IAAI,aAAa,EAAE,KAAK,IAAI,CAAC;AAAA,EAClE;AACF;AASA,SAAS,kBAAkB,OAAsC;AAC/D,SAAO,EAAE,MAAM,MAAM,WAAW,eAAe,UAAU,UAAU,OAAO,MAAM,MAAM;AACxF;AAwBO,SAAS,0BAA0B,QAAgC,MAAwB;AAChG,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,aAAa,KAAM;AAC7B,6BAAyB,MAAM,kBAAkB,KAAK,GAAG,MAAM,EAAE;AAAA,EACnE;AACF;AASO,SAAS,0BAA0B,MAA8B;AACtE,SAAO;AAAA,IACL,GAAG;AAAA;AAAA;AAAA;AAAA,IAIH,eAAe,OAAO,WAAW,OAAO,YAAY,YAAY;AAC9D,+BAAyB,MAAM,EAAE,MAAM,UAAU,MAAM,GAAG,SAAS;AACnE,aAAO,KAAK,cAAc,WAAW,OAAO,YAAY,OAAO;AAAA,IACjE;AAAA,EACF;AACF;;;AC/EO,SAAS,QAAQ,UAAgC;AACtD,UAAQ,UAAU;AAAA,IAChB,KAAK;AACH,aAAO,0BAA0B,WAAW,CAAC;AAAA,IAC/C,KAAK;AACH,aAAO,0BAA0B,UAAU,CAAC;AAAA,IAC9C,SAAS;AACP,YAAM,cAAqB;AAC3B,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAQO,SAAS,OAAO,MAA0B;AAC/C,SAAO,QAAQ,cAAc,IAAI,CAAC;AACpC;;;ACWO,SAAS,sBAAsB,aAA6B;AACjE,SAAO,kBAAkB,WAAW,8HAA8H,kBAAkB;AACtL;AAMO,SAAS,iBACd,WACA,WACe;AACf,QAAM,UAAU,IAAI,IAAI,UAAU,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AACvD,QAAM,aAAa,UAAU,QAAQ,CAAC,aAAa;AACjD,UAAM,WAAW,QAAQ,IAAI,SAAS,EAAE;AACxC,WAAO,WAAW,CAAC,iBAAiB,UAAU,QAAQ,CAAC,IAAI,CAAC;AAAA,EAC9D,CAAC;AAED,SAAO;AAAA,IACL,SAAS,WAAW,OAAO,eAAe;AAAA,IAC1C,UAAU,WAAW,OAAO,gBAAgB;AAAA,IAC5C,cAAc,WAAW,OAAO,8BAA8B;AAAA,EAChE;AACF;AAGA,SAAS,iBAAiB,UAAuB,UAAuC;AACtF,SAAO;AAAA,IACL,IAAI,SAAS;AAAA,IACb,WAAW,SAAS;AAAA,IACpB,WAAW,SAAS;AAAA,IACpB,UAAU,SAAS;AAAA,IACnB,UAAU,SAAS;AAAA,EACrB;AACF;AAEA,SAAS,WAAW,WAAoC;AACtD,SAAO,UAAU,cAAc;AACjC;AAEA,SAAS,UAAU,WAAoC;AACrD,SAAO,UAAU,cAAc;AACjC;AAEA,SAAS,gBAAgB,WAAoC;AAC3D,SAAO,CAAC,WAAW,SAAS,KAAK,UAAU,SAAS;AACtD;AAEA,SAAS,iBAAiB,WAAoC;AAC5D,SAAO,WAAW,SAAS,KAAK,CAAC,UAAU,SAAS;AACtD;AAMA,SAAS,+BAA+B,WAAoC;AAC1E,SACE,UAAU,aAAa,UAAU,YAAY,WAAW,SAAS,MAAM,UAAU,SAAS;AAE9F;AAOA,eAAsB,iBACpB,MACA,YACA,cAC0B;AAC1B,QAAM,OAAO,OAAO,UAAU;AAE9B,QAAM,cAAc,MAAM,0BAA0B,KAAK,SAAS,YAAY,YAAY;AAK1F,QAAM,WAAW,MAAM;AAAA,IACrB,0BAA0B,KAAK,SAAS,WAAW;AAAA,IACnD;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,iBAAiB,MAAM;AAAA,IAC3B,KAAK;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,SAAO,EAAE,aAAa,gBAAgB,SAAS;AACjD;AAgBA,eAAe,uBACb,YACA,YACA,cACA,MAC8B;AAC9B,QAAM,WAAgC,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,EAAE;AAClE,MAAI,WAAW,WAAW,EAAG,QAAO;AAEpC,MAAI,CAAC,aAAa,aAAa;AAC7B,UAAM,IAAI;AAAA,MACR,6EACM,aAAa,aAAa,MAAM;AAAA,IAExC;AAAA,EACF;AAEA,aAAW,aAAa,YAAY;AAClC,UAAM,YAAY,0BAA0B,UAAU,IAAI,aAAa,WAAW;AAClF,QAAI;AACF,YAAM,KAAK,cAAc,WAAW,UAAU,UAAU,UAAU;AAAA,IACpE,SAAS,OAAO;AACd,eAAS,OAAO,KAAK,EAAE,IAAI,UAAU,IAAI,OAAO,gBAAgB,KAAK,EAAE,CAAC;AACxE;AAAA,IACF;AACA,aAAS,UAAU,KAAK,EAAE,IAAI,UAAU,IAAI,KAAK,UAAU,CAAC;AAC5D,YAAQ,wBAAwB,UAAU,EAAE,EAAE;AAC9C,UAAM,yBAAyB,WAAW,UAAU;AAAA,EACtD;AAEA,SAAO;AACT;AAkBA,eAAe,0BACb,YACA,YACA,cAC0B;AAC1B,QAAM,SAA0B,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE;AAEzD,aAAW,aAAa,YAAY;AAClC,UAAM,EAAE,WAAAC,WAAU,IAAI,oBAAoB,YAAY,UAAU,QAAQ;AACxE,QAAI;AACF,YAAM,SAAS,MAAM,2BAA2B,CAAC,UAAU,EAAE,GAAGA,YAAW,YAAY;AACvF,aAAO,OAAO,KAAK,GAAG,OAAO,IAAI,CAAC,UAAU,MAAM,OAAO,CAAC;AAAA,IAC5D,SAAS,OAAO;AACd,aAAO,OAAO,KAAK,EAAE,IAAI,UAAU,IAAI,OAAO,gBAAgB,KAAK,EAAE,CAAC;AAAA,IACxE;AAAA,EACF;AAEA,SAAO;AACT;AAGA,SAAS,0BACP,YACA,QACkB;AAClB,QAAM,SAAS,IAAI,IAAI,OAAO,MAAM;AACpC,SAAO,WAAW,OAAO,CAAC,cAAc,OAAO,IAAI,UAAU,EAAE,CAAC;AAClE;AAOA,SAAS,8BAA8B,WAAoC;AACzE,SAAO,UAAU,aAAa,YAAY,UAAU,aAAa;AACnE;AAYA,eAAe,yBACb,YACA,YACA,cACA,MACmB;AACnB,QAAM,WAAqB,CAAC;AAE5B,aAAW,aAAa,YAAY;AAClC,QAAI,8BAA8B,SAAS,GAAG;AAC5C,cAAQ,6BAA6B,UAAU,EAAE,8BAA8B;AAC/E;AAAA,IACF;AACA,QAAI,CAAC,aAAa,aAAa;AAC7B,eAAS,KAAK,kCAAkC,UAAU,EAAE,6BAA6B;AACzF;AAAA,IACF;AAQA,UAAM,YAAY,0BAA0B,UAAU,IAAI,aAAa,WAAW;AAClF,QAAI;AACF,YAAM,KAAK,gBAAgB,WAAW,UAAU,UAAU,UAAU;AAAA,IACtE,SAAS,OAAO;AACd,eAAS,KAAK,kCAAkC,UAAU,EAAE,KAAK,gBAAgB,KAAK,CAAC,EAAE;AACzF;AAAA,IACF;AACA,YAAQ,0BAA0B,UAAU,EAAE,EAAE;AAAA,EAClD;AAEA,SAAO;AACT;AAOA,eAAe,yBACb,WACA,YACe;AACf,MAAI,UAAU,aAAa,YAAY,UAAU,aAAa,WAAW;AACvE,YAAQ,kCAAkC,UAAU,EAAE,+BAA+B;AACrF;AAAA,EACF;AACA,QAAM,iBAAiB,YAAY,UAAU,IAAI,UAAU,QAAQ;AACrE;;;AjBpTA,IAAM,uBAAuB;AAY7B,eAAsB,sBAAwD;AAC5E,QAAM,eAAe,MAAM,mBAAmB;AAC9C,MAAI,CAAC,aAAc,QAAO;AAE1B,QAAM,SAAS,MAAM,kBAAkB,aAAa,UAAU;AAC9D,QAAM,iBAAiB,MAAM;AAAA,IAC3B;AAAA,IACA,gBAAgB,YAAY;AAAA,EAC9B;AAEA,SAAO;AAAA,IACL,MAAM,aAAa;AAAA,IACnB,MAAM,QAAQ,OAAO,QAAQ;AAAA,IAC7B,YAAY,mBAAmB,MAAM;AAAA,IACrC,YAAY,UAAU,cAAc;AAAA,IACpC,YAAY,aAAa;AAAA,IACzB,WAAW,eAAe,OAAO,UAAU,EAAE,IAAI,CAAC,eAAe,WAAW,GAAG;AAAA,EACjF;AACF;AAaA,SAAS,mBAAmB,QAA4C;AACtE,MAAI,CAAC,OAAQ,QAAO;AAEpB,QAAM,UAAU,OAAO,OAAO,OAAO,OAAO,CAAC,UAAU,CAAC,MAAM,QAAQ;AACtE,SAAO,IAAI,IAAI,QAAQ,IAAI,CAAC,UAAU,MAAM,EAAE,CAAC,EAAE;AACnD;AASA,SAAS,gBAAgB,cAA0C;AACjE,SAAO,gBAAgB,aAAa,UAAU,IAAI,CAAC,SAAS,IAAI,CAAC,UAAU,SAAS;AACtF;AAOA,SAAS,WAAW,YAAiC;AACnD,SAAO,WAAW,QAAQ;AAC5B;AAEA,SAAS,UAAU,aAAmC;AACpD,SAAO,YAAY,OAAO,CAAC,OAAO,eAAe,QAAQ,WAAW,OAAO,CAAC;AAC9E;AASA,eAAe,4BACb,cACA,QACuB;AACvB,SAAO,QAAQ;AAAA,IACb,OAAO,IAAI,OAAO,UAAU;AAC1B,YAAM,MAAM,oBAAoB,aAAa,YAAY,KAAK,EAAE;AAChE,aAAO,EAAE,KAAK,OAAO,MAAM,gBAAgB,KAAK,mBAAmB,EAAE;AAAA,IACvE,CAAC;AAAA,EACH;AACF;AAEA,SAAS,oBAAoB,OAAwB;AACnD,SAAO,MAAM,OAAO,KAAK,MAAM,KAAK,SAAS,oBAAoB;AACnE;AAGA,eAAe,gBAAgB,KAAa,MAAmD;AAC7F,MAAI;AACF,UAAM,UAAU,MAAM,QAAQ,KAAK,EAAE,eAAe,KAAK,CAAC;AAC1D,WAAO,QAAQ,OAAO,IAAI,EAAE;AAAA,EAC9B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,0BAA0B,MAAgC;AACxE,QAAM,gBAAgB,KAAK,UAAU,IAAI,CAAC,QAAQ;AAAA,aAAgB,GAAG,EAAE,EAAE,KAAK,EAAE;AAEhF,SAAO,iBAAiB,KAAK,IAAI;AAAA,aACtB,oBAAoB,KAAK,IAAI,CAAC;AAAA,aAC9B,KAAK,UAAU;AAAA,aACf,KAAK,UAAU;AAAA,aACf,KAAK,UAAU,GAAG,aAAa;AAC5C;;;AkBjIA,OAAOC,YAAU;AACjB,OAAOC,SAAQ;;;ACKR,SAAS,cAAgC;AAC9C,SAAO,EAAE,OAAO,MAAM,QAAQ,CAAC,GAAG,UAAU,CAAC,EAAE;AACjD;AAGO,SAAS,cAAc,SAAmC;AAC/D,SAAO,EAAE,OAAO,OAAO,QAAQ,CAAC,OAAO,GAAG,UAAU,CAAC,EAAE;AACzD;AAQO,SAAS,uBACd,SACgD;AAChD,QAAM,SAAS,QAAQ,QAAQ,CAAC,MAAM,EAAE,MAAM;AAC9C,QAAM,WAAW,QAAQ,QAAQ,CAAC,MAAM,EAAE,QAAQ;AAClD,SAAO,EAAE,OAAO,OAAO,WAAW,GAAG,QAAQ,SAAS;AACxD;;;ADCA,IAAM,aAAa;AACnB,IAAM,kBAAkB,eAAe;AACvC,IAAM,eACJ;AAEF,SAAS,YAAY,KAAsB;AACzC,SAAO,mBAAmB,KAAK,GAAG;AACpC;AAEA,SAAS,cAAc,KAAsB;AAC3C,SAAO,aAAa,KAAK,GAAG;AAC9B;AAWA,eAAsB,wBAAwB,YAA+C;AAC3F,QAAM,SAAmB,CAAC;AAC1B,QAAM,WAAqB,CAAC;AAE5B,MAAI,CAAE,MAAMC,iBAAgB,UAAU,GAAI;AACxC,WAAO,cAAc,oCAAoC,UAAU,EAAE;AAAA,EACvE;AAEA,QAAM,YAAYC,OAAK,KAAK,YAAY,UAAU;AAClD,MAAI,CAAE,MAAMD,iBAAgB,SAAS,GAAI;AACvC,WAAO,KAAK,WAAW,UAAU,aAAa;AAAA,EAChD;AAEA,QAAM,eAAeC,OAAK,KAAK,WAAW,eAAe;AACzD,MAAI,CAAE,MAAM,WAAW,YAAY,GAAI;AACrC,WAAO,KAAK,WAAW,UAAU,IAAI,eAAe,EAAE;AAAA,EACxD;AAEA,QAAM,aAAaA,OAAK,KAAK,YAAY,eAAe,SAAS;AACjE,MAAI,CAAE,MAAM,WAAW,UAAU,GAAI;AACnC,aAAS,KAAK,mDAAmD;AAAA,EACnE;AAEA,SAAO;AAAA,IACL,OAAO,OAAO,WAAW;AAAA,IACzB;AAAA,IACA;AAAA,EACF;AACF;AAkBA,eAAsB,uBAAuB,cAAiD;AAC5F,QAAM,SAAmB,CAAC;AAC1B,QAAM,WAAqB,CAAC;AAE5B,MAAI,CAAE,MAAM,WAAW,YAAY,GAAI;AACrC,WAAO,cAAc,4BAA4B,YAAY,EAAE;AAAA,EACjE;AAOA,MAAI;AACJ,MAAI;AACF,UAAM,UAAU,MAAM,aAAa,cAAc,oBAAoB;AACrE,UAAM,SAAkB,KAAK,MAAM,OAAO;AAC1C,QAAI,CAAC,SAAS,MAAM,EAAG,QAAO,cAAc,GAAG,eAAe,6BAA6B;AAC3F,eAAW;AAAA,EACb,SAAS,KAAK;AACZ,WAAO,cAAc,mBAAmB,eAAe,KAAK,gBAAgB,GAAG,CAAC,EAAE;AAAA,EACpF;AAEA,QAAM,SAAS,+BAA+B,UAAU,QAAQ;AAEhE,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,KAAK,GAAG,gBAAgB,OAAO,KAAK,CAAC;AAAA,EAC9C;AAEA,MAAI,SAAS,QAAQ,OAAO,SAAS,SAAS,UAAU;AACtD,QAAI,CAAC,YAAY,SAAS,IAAI,GAAG;AAC/B,aAAO,KAAK,6BAA6B,SAAS,IAAI,GAAG;AAAA,IAC3D;AAAA,EACF;AAEA,MAAI,SAAS,WAAW,OAAO,SAAS,YAAY,UAAU;AAC5D,QAAI,CAAC,cAAc,SAAS,OAAO,GAAG;AACpC,aAAO;AAAA,QACL,YAAY,SAAS,OAAO;AAAA,MAC9B;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,SAAS,aAAa;AACzB,aAAS,KAAK,6DAA6D;AAAA,EAC7E;AAEA,QAAM,YAAYA,OAAK,QAAQA,OAAK,QAAQ,YAAY,CAAC;AAEzD,MAAI,SAAS,UAAU,OAAO,SAAS,WAAW,UAAU;AAC1D,UAAM,aAAaA,OAAK,KAAK,WAAW,SAAS,MAAM;AACvD,QAAI,CAAE,MAAMD,iBAAgB,UAAU,GAAI;AACxC,aAAO,KAAK,+BAA+B,SAAS,MAAM,EAAE;AAAA,IAC9D;AAAA,EACF;AAEA,MAAI,SAAS,UAAU,OAAO,SAAS,WAAW,UAAU;AAC1D,UAAM,aAAaC,OAAK,KAAK,WAAW,SAAS,MAAM;AACvD,QAAI,CAAE,MAAMD,iBAAgB,UAAU,GAAI;AACxC,aAAO,KAAK,+BAA+B,SAAS,MAAM,EAAE;AAAA,IAC9D;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO,OAAO,WAAW;AAAA,IACzB;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAsB,yBAAyB,WAA8C;AAC3F,QAAM,SAAmB,CAAC;AAC1B,QAAM,WAAqB,CAAC;AAE5B,MAAI,CAAE,MAAM,WAAW,SAAS,GAAI;AAClC,WAAO,cAAc,yBAAyB,SAAS,EAAE;AAAA,EAC3D;AAEA,QAAM,UAAU,MAAM,SAAS,SAAS;AACxC,QAAM,cAAc,mBAAmB,OAAO;AAE9C,MAAI,gBAAgB,MAAM;AACxB,WAAO,cAAc,qCAAqC;AAAA,EAC5D;AAEA,QAAM,SAAS,iCAAiC,UAAU,WAAW;AAErE,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,KAAK,GAAG,gBAAgB,OAAO,KAAK,CAAC;AAAA,EAC9C;AAEA,SAAO;AAAA,IACL,OAAO,OAAO,WAAW;AAAA,IACzB;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAsB,yBAAyB,WAA8C;AAC3F,QAAM,SAAmB,CAAC;AAC1B,QAAM,WAAqB,CAAC;AAE5B,MAAI,CAAE,MAAM,WAAW,SAAS,GAAI;AAClC,WAAO,cAAc,yBAAyB,SAAS,EAAE;AAAA,EAC3D;AAEA,QAAM,UAAU,MAAM,SAAS,SAAS;AACxC,QAAM,cAAc,mBAAmB,OAAO;AAE9C,MAAI,gBAAgB,MAAM;AACxB,WAAO,cAAc,qCAAqC;AAAA,EAC5D;AAEA,QAAM,SAAS,iCAAiC,UAAU,WAAW;AAErE,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,KAAK,GAAG,gBAAgB,OAAO,KAAK,CAAC;AAAA,EAC9C;AAGA,QAAM,KAAK;AAEX,MAAI,GAAG,QAAQ,OAAO,GAAG,SAAS,UAAU;AAC1C,QAAI,CAAC,YAAY,GAAG,IAAI,GAAG;AACzB,aAAO,KAAK,6BAA6B,GAAG,IAAI,GAAG;AAAA,IACrD;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO,OAAO,WAAW;AAAA,IACzB;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,aAAa,QAA0B,QAAkC;AAChF,SAAO;AAAA,IACL,OAAO,OAAO;AAAA,IACd,QAAQ,OAAO,QAAQ,CAAC,IAAI,OAAO,OAAO,IAAI,CAAC,MAAM,GAAG,MAAM,KAAK,CAAC,EAAE;AAAA,IACtE,UAAU,OAAO,SAAS,IAAI,CAAC,MAAM,GAAG,MAAM,KAAK,CAAC,EAAE;AAAA,EACxD;AACF;AAEA,eAAe,yBACb,YACA,eAC2B;AAC3B,QAAME,aAAYD,OAAK,KAAK,YAAY,aAAa;AACrD,MAAI,CAAE,MAAMD,iBAAgBE,UAAS,EAAI,QAAO,YAAY;AAE5D,QAAM,QAAQ,MAAMC,IAAG,MAAM,eAAe,QAAQ,IAAI,EAAE,KAAKD,YAAW,UAAU,KAAK,CAAC;AAC1F,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,CAAC;AAAA,MACT,UAAU,CAAC,2DAA2D,aAAa,EAAE;AAAA,IACvF;AAAA,EACF;AAEA,QAAM,UAAU,MAAM,QAAQ;AAAA,IAC5B,MAAM;AAAA,MAAI,OAAO,MACf,aAAa,MAAM,yBAAyB,CAAC,GAAGD,OAAK,SAAS,YAAY,CAAC,CAAC;AAAA,IAC9E;AAAA,EACF;AACA,SAAO,uBAAuB,OAAO;AACvC;AAEA,eAAe,yBACb,YACA,eAC2B;AAC3B,QAAMG,aAAYH,OAAK,KAAK,YAAY,aAAa;AACrD,MAAI,CAAE,MAAMD,iBAAgBI,UAAS,EAAI,QAAO,YAAY;AAE5D,QAAM,QAAQ,MAAMD,IAAG,QAAQ,EAAE,KAAKC,YAAW,UAAU,KAAK,CAAC;AACjE,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,CAAC;AAAA,MACT,UAAU,CAAC,sDAAsD,aAAa,EAAE;AAAA,IAClF;AAAA,EACF;AAEA,QAAM,UAAU,MAAM,QAAQ;AAAA,IAC5B,MAAM;AAAA,MAAI,OAAO,MACf,aAAa,MAAM,yBAAyB,CAAC,GAAGH,OAAK,SAAS,YAAY,CAAC,CAAC;AAAA,IAC9E;AAAA,EACF;AACA,SAAO,uBAAuB,OAAO;AACvC;AAEA,eAAe,0BACb,cACyC;AACzC,MAAI;AACF,UAAM,UAAU,MAAM,aAAa,cAAc,oBAAoB;AACrE,UAAM,SAAkB,KAAK,MAAM,OAAO;AAC1C,WAAO,SAAS,MAAM,IAAI,SAAS;AAAA,EACrC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAYA,eAAsB,eAAe,YAA+C;AAClF,QAAM,kBAAkB,MAAM,wBAAwB,UAAU;AAChE,MAAI,CAAC,gBAAgB,MAAO,QAAO;AAEnC,QAAM,eAAe,sBAAsB,UAAU;AACrD,QAAM,iBAAiB,MAAM,uBAAuB,YAAY;AAChE,QAAM,WAAW,MAAM,0BAA0B,YAAY;AAE7D,QAAM,eACJ,UAAU,UAAU,OAAO,SAAS,WAAW,WAC3C,MAAM,yBAAyB,YAAY,SAAS,MAAM,IAC1D,YAAY;AAElB,QAAM,eACJ,UAAU,UAAU,OAAO,SAAS,WAAW,WAC3C,MAAM,yBAAyB,YAAY,SAAS,MAAM,IAC1D,YAAY;AAElB,SAAO,uBAAuB,CAAC,iBAAiB,gBAAgB,cAAc,YAAY,CAAC;AAC7F;AAWA,eAAsB,mBAAmBI,aAStC;AACD,QAAM,UAA6D,CAAC;AAEpE,MAAI,CAAE,MAAML,iBAAgBK,WAAU,GAAI;AACxC,WAAO;AAAA,MACL,OAAO;AAAA,MACP,SAAS;AAAA,QACP;AAAA,UACE,MAAMA;AAAA,UACN,QAAQ,cAAc,6BAA6BA,WAAU,EAAE;AAAA,QACjE;AAAA,MACF;AAAA,MACA,SAAS,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,cAAc,EAAE;AAAA,IAC7D;AAAA,EACF;AAEA,QAAM,UAAU,MAAM,gBAAgBA,WAAU;AAChD,QAAM,YAAY,MAAM,QAAQ;AAAA,IAC9B,QAAQ,IAAI,OAAO,aAAa;AAAA,MAC9B;AAAA,MACA,UAAU,MAAML,iBAAgBC,OAAK,KAAKI,aAAY,SAAS,UAAU,CAAC;AAAA,IAC5E,EAAE;AAAA,EACJ;AACA,QAAM,aAAa,UAAU,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO;AAE3E,MAAI,WAAW,WAAW,GAAG;AAC3B,WAAO;AAAA,MACL,OAAO;AAAA,MACP,SAAS;AAAA,QACP;AAAA,UACE,MAAMA;AAAA,UACN,QAAQ;AAAA,YACN,kCAAkCA,WAAU,4BAA4B,UAAU;AAAA,UACpF;AAAA,QACF;AAAA,MACF;AAAA,MACA,SAAS,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,cAAc,EAAE;AAAA,IAC7D;AAAA,EACF;AAEA,aAAW,cAAc,YAAY;AACnC,UAAM,aAAaJ,OAAK,KAAKI,aAAY,UAAU;AACnD,UAAM,SAAS,MAAM,eAAe,UAAU;AAC9C,YAAQ,KAAK,EAAE,MAAM,YAAY,OAAO,CAAC;AAAA,EAC3C;AAEA,QAAM,aAAa,QAAQ,OAAO,CAAC,MAAM,EAAE,OAAO,KAAK,EAAE;AACzD,QAAM,UAAU;AAAA,IACd,OAAO,QAAQ;AAAA,IACf,OAAO;AAAA,IACP,SAAS,QAAQ,SAAS;AAAA,IAC1B,cAAc,QAAQ,OAAO,CAAC,MAAM,EAAE,OAAO,SAAS,SAAS,CAAC,EAAE;AAAA,EACpE;AAEA,SAAO;AAAA,IACL,OAAO,QAAQ,YAAY;AAAA,IAC3B;AAAA,IACA;AAAA,EACF;AACF;;;AElXA,eAAsB,8BAA8B,YAA+C;AACjG,MAAI;AACJ,MAAI;AACF,UAAM,YAAY,MAAM,OAAO,UAAU,EAAE,YAAY,UAAU;AACjE,cAAU,UACP,OAAO,CAAC,WAAW,OAAO,OAAO,EACjC,IAAI,CAAC,EAAE,WAAW,YAAY,OAAO,EAAE,WAAW,YAAY,EAAE;AAAA,EACrE,SAAS,OAAO;AACd,YAAQ,qCAAqC,gBAAgB,KAAK,CAAC,EAAE;AACrE,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,SAAS,MAAM,QAAQ,IAAI,QAAQ,IAAI,iBAAiB,CAAC;AAC/D,QAAM,WAAW,QAAQ,OAAO,CAAC,GAAG,UAAU,OAAO,KAAK,MAAM,IAAI;AAEpE,UAAQ,YAAY,SAAS,MAAM,uBAAuB;AAC1D,SAAO;AACT;AAGA,eAAe,kBAAkB,EAAE,WAAW,YAAY,GAAqC;AAC7F,QAAM,iBAAiB,sBAAsB,WAAW;AACxD,QAAM,iBAAiB,MAAM,WAAW,cAAc;AACtD,MAAI,CAAC,gBAAgB;AACnB,YAAQ,WAAW,SAAS,kCAAkC,cAAc,GAAG;AAAA,EACjF;AACA,SAAO;AACT;AAWA,eAAsB,wBAAwB,YAAiD;AAC7F,MAAI;AACF,UAAM,cAAc,MAAM,8BAA8B,UAAU;AAElE,QAAI,YAAY,WAAW,GAAG;AAC5B,cAAQ,iCAAiC,UAAU,GAAG;AACtD,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,kBAAkB,MAAM,QAAQ,IAAI,YAAY,IAAI,kBAAkB,CAAC;AAC7E,WAAO,mBAAmB,eAAe;AAAA,EAC3C,SAAS,OAAO;AACd,YAAQ,4BAA4B,gBAAgB,KAAK,CAAC,EAAE;AAC5D,WAAO,CAAC;AAAA,EACV;AACF;AAGA,eAAe,mBAAmB;AAAA,EAChC;AAAA,EACA;AACF,GAAgD;AAC9C,UAAQ,oCAAoC,SAAS,GAAG;AACxD,MAAI;AACF,WAAO,MAAM,iBAAiB,WAAW;AAAA,EAC3C,SAAS,OAAO;AACd,YAAQ,+BAA+B,SAAS,MAAM,gBAAgB,KAAK,CAAC,EAAE;AAC9E,WAAO,CAAC;AAAA,EACV;AACF;AAMA,SAAS,mBAAmB,iBAAoE;AAC9F,QAAMC,aAAgC,CAAC;AACvC,aAAW,gBAAgB,iBAAiB;AAC1C,eAAW,CAAC,IAAI,KAAK,KAAK,aAAa,YAAY,GAAG;AAEpD,UAAI,MAAO,CAAAA,WAAU,EAAE,IAAI;AAAA,IAC7B;AAAA,EACF;AACA,SAAOA;AACT;AAQA,eAAsB,gBAAgB,YAAuC;AAC3E,MAAI;AACF,UAAM,cAAc,MAAM,8BAA8B,UAAU;AAClE,WAAO,YAAY,IAAI,CAAC,EAAE,UAAU,MAAM,SAAS;AAAA,EACrD,SAAS,OAAO;AACd,YAAQ,gCAAgC,gBAAgB,KAAK,CAAC,EAAE;AAChE,WAAO,CAAC;AAAA,EACV;AACF;;;AxBhGA,SAAS,kBAAkB,MAAsB;AAC/C,SAAO,KAAK,QAAQ,OAAO,GAAG;AAChC;AAaA,eAAe,wBAAwB,WAAkD;AACvF,QAAM,eAAeC,OAAK,KAAK,WAAW,eAAe,aAAa;AAEtE,MAAI,CAAE,MAAM,WAAW,YAAY,GAAI;AACrC,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,YAAY;AAC3C,UAAM,EAAE,YAAY,IAAI,uBAAuB,OAAO;AAEtD,UAAM,SAAS,0BAA0B,UAAUC,WAAU,WAAW,CAAC;AACzE,QAAI,CAAC,OAAO,SAAS;AACnB,WAAK,6BAA6B,SAAS,MAAM,gBAAgB,OAAO,MAAM,MAAM,CAAC,EAAE;AACvF,aAAO;AAAA,IACT;AACA,WAAO,OAAO;AAAA,EAChB,SAAS,OAAO;AACd,SAAK,oCAAoC,SAAS,MAAM,gBAAgB,KAAK,CAAC,EAAE;AAChF,WAAO;AAAA,EACT;AACF;AAEA,SAAS,eAAe,WAAmB,aAAuC;AAChF,SAAO,KAAK,SAAS;AAAA;AAAA,EAErB,YAAY,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAQR,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAUV,iBAAiB,IAAI;AAAA;AAErC;AAEA,eAAsB,mBACpB,SAC8B;AAC9B,QAAM,EAAE,WAAW,WAAW,WAAW,aAAa,IAAI;AAE1D,QAAM,cAAcD,OAAK,SAAS,SAAS;AAE3C,QAAM,cAAcA,OAAK,KAAK,WAAW,eAAe,QAAQ;AAChE,MAAI,CAAE,MAAM,WAAW,WAAW,GAAI;AACpC,UAAM,IAAI;AAAA,MACR,UAAU,WAAW,yBAAyB,eAAe,QAAQ,uBAAuB,WAAW;AAAA,IACzG;AAAA,EACF;AAEA,QAAM,iBAAiB,MAAM,SAAS,WAAW;AACjD,QAAM,cAAc,iBAAiB,gBAAgB,WAAW;AAQhE,MAAI,CAAC,aAAa;AAChB,UAAM,IAAI;AAAA,MACR,UAAU,WAAW,gDAAgD,eAAe,QAAQ,WACjF,WAAW;AAAA,IACxB;AAAA,EACF;AAEA,QAAM,YAAY,gBAAgB,kBAAkB,YAAY,IAAI;AAEpE,UAAQ,2BAA2B,SAAS,SAAS,SAAS,EAAE;AAEhE,QAAM,WAAW,MAAM,wBAAwB,SAAS;AAExD,QAAM,YAAYA,OAAK,KAAK,WAAW,SAAS;AAChD,QAAME,aAAYF,OAAK,KAAK,WAAW,UAAU,SAAS;AAE1D,QAAM,UAAU,SAAS;AACzB,QAAM,UAAUE,UAAS;AAEzB,QAAM,UAAU,MAAM,uBAAuB,SAAS;AAEtD,QAAM,EAAE,SAAS,YAAY,IAAI,MAAM;AAAA,IACrC;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,QAAM,WAAW,4BAA4B;AAAA,IAC3C;AAAA,IACA,aAAa,YAAY;AAAA,IACzB,GAAI,UAAU,WAAW,UAAa,EAAE,QAAQ,SAAS,OAAO;AAAA,IAChE,GAAI,UAAU,aAAa,UAAa,EAAE,UAAU,SAAS,SAAS;AAAA,IACtE;AAAA,EACF,CAAC;AAED,QAAM,oBAAoB,WAAW,QAAQ;AAE7C,QAAM,iBAAiB,WAAW,aAAa,qBAAqB;AAEpE,UAAQ,2BAA2B,SAAS,MAAM,OAAO,GAAG;AAE5D,QAAM,UAAUF,OAAK,KAAKE,YAAW,eAAe,QAAQ,GAAG,cAAc;AAC7E,UAAQ,YAAY,eAAe,QAAQ,EAAE;AAE7C,aAAW,YAAY,qBAAqB;AAC1C,QAAI,aAAa,eAAe,SAAU;AAE1C,UAAM,aAAaF,OAAK,KAAK,WAAW,QAAQ;AAChD,QAAI,MAAM,WAAW,UAAU,GAAG;AAChC,YAAM,UAAU,MAAM,SAAS,UAAU;AACzC,YAAM,UAAUA,OAAK,KAAKE,YAAW,QAAQ,GAAG,OAAO;AACvD,cAAQ,YAAY,QAAQ,EAAE;AAAA,IAChC;AAAA,EACF;AAEA,aAAW,WAAW,oBAAoB;AACxC,UAAMC,aAAYH,OAAK,KAAK,WAAW,OAAO;AAC9C,QAAI,MAAM,WAAWG,UAAS,GAAG;AAC/B,YAAM,KAAKA,YAAWH,OAAK,KAAKE,YAAW,OAAO,CAAC;AACnD,cAAQ,YAAY,OAAO,GAAG;AAAA,IAChC;AAAA,EACF;AAEA,QAAM,SAAS,eAAe,WAAW,WAAW;AACpD,QAAM,UAAUF,OAAK,KAAK,WAAW,eAAe,SAAS,GAAG,MAAM;AACtE,UAAQ,uBAAuB;AAE/B,SAAO;AAAA,IACL,YAAY;AAAA,IACZ;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAsB,uBACpBE,YACA,WAC8B;AAC9B,QAAM,WAAkC,CAAC;AACzC,QAAM,SAAmB,CAAC;AAE1B,QAAM,eAAe,MAAM,KAAK,MAAM,eAAe,QAAQ,IAAIA,UAAS;AAE1E,aAAW,eAAe,cAAc;AACtC,UAAM,YAAYF,OAAK,KAAKE,YAAWF,OAAK,QAAQ,WAAW,CAAC;AAEhE,QAAI;AACF,YAAM,SAAS,MAAM,mBAAmB;AAAA,QACtC;AAAA,QACA;AAAA,MACF,CAAC;AACD,eAAS,KAAK,MAAM;AACpB,UAAI,UAAU,OAAO,SAAS,EAAE;AAAA,IAClC,SAAS,OAAO;AACd,YAAM,eAAe,gBAAgB,KAAK;AAC1C,YAAM,cAAcA,OAAK,SAAS,SAAS;AAC3C,aAAO,KAAK,WAAW;AACvB,WAAK,iCAAiC,WAAW,MAAM,YAAY,EAAE;AAAA,IACvE;AAAA,EACF;AAEA,SAAO,EAAE,UAAU,OAAO;AAC5B;AAEO,SAAS,wBAAwB,SAAsC;AAC5E,MAAI;AAAA,WAAc,OAAO,QAAQ,QAAQ,cAAc,CAAC,GAAG;AAC3D,aAAW,UAAU,SAAS;AAC5B,QAAI,OAAO,OAAO,SAAS,MAAM,OAAO,SAAS,OAAO,GAAG;AAAA,EAC7D;AACF;;;AyB3OA,OAAOI,YAAU;AA6BjB,eAAsB,oBACpB,YAC2C;AAC3C,QAAM,kBAAkBC,OAAK,KAAK,YAAY,iBAAiB;AAE/D,MAAI,CAAE,MAAMC,iBAAgB,eAAe,GAAI;AAC7C,YAAQ,qCAAqC,eAAe,EAAE;AAC9D,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,MAAM,gBAAgB,eAAe;AACvD,QAAM,YAAY,MAAM,QAAQ;AAAA,IAC9B,UAAU,IAAI,CAAC,iBAAiB,kBAAkB,iBAAiB,YAAY,CAAC;AAAA,EAClF;AACA,QAAM,SAAS,UAAU,OAAO,CAAC,UAAU,UAAU,IAAI;AAEzD,UAAQ,cAAc,OAAO,OAAO,QAAQ,aAAa,CAAC,SAAS,eAAe,EAAE;AAEpF,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAe,kBACb,iBACA,cACwC;AACxC,QAAM,WAAWD,OAAK,KAAK,iBAAiB,YAAY;AACxD,QAAM,eAAeA,OAAK,KAAK,UAAU,eAAe,aAAa;AACrE,QAAM,cAAcA,OAAK,KAAK,UAAU,eAAe,QAAQ;AAE/D,MAAI,CAAE,MAAM,WAAW,YAAY,GAAI;AACrC,YAAQ,yBAAyB,YAAY,2BAA2B;AACxE,WAAO;AAAA,EACT;AAEA,MAAI,CAAE,MAAM,WAAW,WAAW,GAAI;AACpC,YAAQ,yBAAyB,YAAY,sBAAsB;AACnE,WAAO;AAAA,EACT;AAKA,QAAM,OAAO,MAAM,kBAAkB,YAAY;AACjD,MAAI,CAAC,KAAK,QAAQ;AAChB;AAAA,MACE,yBAAyB,YAAY,MAAM,eAAe,aAAa,OAAO,YAAY,gCAA2B,KAAK,MAAM;AAAA,IAClI;AACA,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,KAAK;AAMtB,MAAI,yBAAyB,QAAQ,GAAG;AACtC;AAAA,MACE,yBAAyB,YAAY,MAAM,cAAc,QAAQ,KAAK,qBAAqB,yFAAyF,cAAc,QAAQ,OAAO,YAAY;AAAA,IAC/N;AACA,WAAO;AAAA,EACT;AAEA,QAAM,iBAAiB,MAAM,SAAS,WAAW;AACjD,QAAM,cAAc,iBAAiB,gBAAgB,WAAW;AAEhE,MAAI,CAAC,aAAa;AAChB,YAAQ,yBAAyB,YAAY,iCAAiC;AAC9E,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,GAAG,iBAAiB,IAAI,YAAY;AACzD,QAAM,eAAeA,OAAK,KAAK,iBAAiB,YAAY,IAAIA,OAAK;AACrE,QAAM,UAAU,YAAY;AAE5B,QAAM,YAAoC;AAAA,IACxC,IAAI;AAAA,IACJ,eAAe;AAAA,IACf,aAAa,SAAS,kBAAkB,YAAY;AAAA,IACpD,GAAI,YAAY,eAAe,EAAE,uBAAuB,YAAY,YAAY;AAAA,IAChF,GAAI,SAAS,kBAAkB,UAAa,EAAE,eAAe,SAAS,cAAc;AAAA,IACpF,UAAU,SAAS;AAAA,IACnB,QAAQ,eAAe;AAAA,IACvB,MAAM;AAAA,IACN,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ,SAAS;AAAA,IACjB,GAAI,SAAS,WAAW,UAAa,EAAE,QAAQ,SAAS,OAAO;AAAA,IAC/D,MAAM,SAAS;AAAA,IACf,aAAa,SAAS;AAAA,EACxB;AAEA,UAAQ,0BAA0B,OAAO,EAAE;AAC3C,SAAO;AACT;;;AC9HA,OAAOE,YAAU;AA+CjB,eAAsB,+BACpB,eACA,aACA,YACkC;AAClC,QAAM,aAAa,MAAM,yBAAyB,eAAe,aAAa,UAAU;AACxF,SAAO,WAAW,QAAQ,CAAC,EAAE,KAAK,MAAO,KAAK,SAAS,sBAAsB,CAAC,KAAK,MAAM,IAAI,CAAC,CAAE;AAClG;AAeA,eAAsB,8BACpB,eACA,aACA,YACA,aACuC;AACvC,QAAM,aAAa,MAAM,yBAAyB,eAAe,aAAa,UAAU;AACxF,SAAO,IAAI;AAAA,IACT,WAAW,QAAQ,CAAC,EAAE,IAAI,KAAK,MAAM;AACnC,YAAM,SAAS,cAAc,IAAI,MAAM,WAAW;AAClD,aAAO,WAAW,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,MAAM,CAAU;AAAA,IACtD,CAAC;AAAA,EACH;AACF;AAEA,eAAe,yBACb,eACA,aACA,YAC4B;AAC5B,SAAO,QAAQ;AAAA,IACb,cAAc,IAAI,OAAO,OAAO;AAC9B,YAAM,QAAQ,YAAY,KAAK,CAAC,UAAU,MAAM,OAAO,EAAE;AACzD,aAAO,EAAE,IAAI,MAAM,MAAM,mBAAmB,IAAI,OAAO,UAAU,EAAE;AAAA,IACrE,CAAC;AAAA,EACH;AACF;AAMA,eAAe,mBACb,IACA,OACA,YACyB;AACzB,MAAI,OAAO,WAAW,aAAc,QAAO,EAAE,MAAM,oBAAoB;AAEvE,QAAM,WAAWC,OAAK,KAAK,oBAAoB,YAAY,MAAM,KAAK,EAAE,WAAW,EAAE;AACrF,MAAI,CAAE,MAAMC,iBAAgB,QAAQ,EAAI,QAAO,EAAE,MAAM,cAAc,SAAS;AAE9E,QAAM,eAAeD,OAAK,KAAK,UAAU,eAAe,aAAa;AAGrE,MAAI,CAAE,MAAM,WAAW,YAAY,EAAI,QAAO,EAAE,MAAM,uBAAuB,SAAS;AAEtF,QAAM,OAAO,MAAM,kBAAkB,YAAY;AACjD,MAAI,CAAC,KAAK,QAAQ;AAChB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,QAAQ,EAAE,cAAc,IAAI,cAAc,QAAQ,KAAK,OAAO;AAAA,IAChE;AAAA,EACF;AAKA,MAAI,CAAE,MAAM,aAAa,UAAU,EAAE,EAAI,QAAO,EAAE,MAAM,uBAAuB,SAAS;AAOxF,SAAO,EAAE,MAAM,wBAAwB,UAAU,UAAU,KAAK,SAAS,SAAS;AACpF;AAGA,eAAe,aAAa,UAAkB,IAA+B;AAC3E,QAAM,cAAcA,OAAK,KAAK,UAAU,eAAe,QAAQ;AAC/D,MAAI,CAAE,MAAM,WAAW,WAAW,EAAI,QAAO;AAE7C,QAAM,cAAc,iBAAiB,MAAM,SAAS,WAAW,GAAG,WAAW;AAC7E,SAAO,aAAa,SAAS;AAC/B;AAGA,SAAS,cAAc,IAAa,MAAsB,aAAoC;AAC5F,UAAQ,KAAK,MAAM;AAAA,IACjB,KAAK;AACH,aAAO,kBAAkB,WAAW;AAAA,IACtC,KAAK;AACH,aAAO,kCAAkC,KAAK,QAAQ;AAAA,IACxD,KAAK;AACH,aAAO,mBAAmB,EAAE,qBAAqB,KAAK,QAAQ;AAAA,IAChE,KAAK;AACH,aAAO,gBAAgB,KAAK,QAAQ,uBAAuB,KAAK,QAAQ;AAAA,IAC1E,KAAK;AACH,aAAO;AAAA,IACT,SAAS;AACP,YAAM,aAAoB;AAC1B,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;ACpKA,OAAOE,YAAU;AAmBjB,SAAS,gBAAgB,SAA2B;AAClD,SAAO,EACL,QAAQ,WAAW,KACnB,QAAQ,SAAS,IAAI,KACrB,QAAQ,SAAS,IAAI,KACrB,QAAQ,SAAS,GAAG,KACpB,QAAQ,SAAS,IAAI;AAEzB;AAYA,eAAsB,iBACpB,YACA,SACA,QAAoB,WACL;AACf,MAAI,CAAC,gBAAgB,OAAO,GAAG;AAC7B,SAAK,mCAAmC,OAAO,GAAG;AAClD;AAAA,EACF;AAEA,QAAMC,aAAYC,OAAK,QAAQ,oBAAoB,YAAY,KAAK,EAAE,SAAS;AAC/E,QAAM,YAAYA,OAAK,QAAQD,YAAW,OAAO;AAEjD,MAAI,CAAC,aAAa,WAAWA,UAAS,GAAG;AACvC,SAAK,aAAa,OAAO,0CAA0C;AACnE;AAAA,EACF;AAEA,MAAI;AACF,UAAM,OAAO,SAAS;AAAA,EACxB,QAAQ;AAAA,EAER;AAIA,QAAM,iBAAiBA,UAAS;AAEhC,UAAQ,wBAAwB,OAAO,GAAG;AAC5C;AAUA,eAAsB,uBACpB,SACA,WACA,YACe;AACf,MAAI,CAAC,gBAAgB,OAAO,GAAG;AAC7B,SAAK,0CAA0C,OAAO,GAAG;AACzD;AAAA,EACF;AAEA,QAAM,UAAsB,cAAc,WAAW,YAAY;AAGjE,QAAM,gBAAgBC,OAAK,QAAQ,oBAAoB,YAAY,SAAS,EAAE,SAAS;AACvF,QAAM,cAAcA,OAAK,QAAQ,oBAAoB,YAAY,OAAO,EAAE,SAAS;AAEnF,QAAM,WAAWA,OAAK,QAAQ,eAAe,OAAO;AACpD,QAAM,SAASA,OAAK,QAAQ,aAAa,OAAO;AAEhD,MAAI,CAAC,aAAa,UAAU,aAAa,GAAG;AAC1C,SAAK,aAAa,OAAO,iDAAiD;AAC1E;AAAA,EACF;AACA,MAAI,CAAC,aAAa,QAAQ,WAAW,GAAG;AACtC,SAAK,aAAa,OAAO,sDAAsD;AAC/E;AAAA,EACF;AAEA,MAAI,CAAE,MAAMC,iBAAgB,QAAQ,GAAI;AACtC,QAAI,MAAMA,iBAAgB,MAAM,GAAG;AACjC,cAAQ,UAAU,OAAO,gBAAgB,OAAO,mCAA8B;AAC9E;AAAA,IACF;AACA,SAAK,4BAA4B,OAAO,oCAA+B;AACvE;AAAA,EACF;AAEA,QAAM,UAAU,WAAW;AAC3B,QAAM,KAAK,UAAU,MAAM;AAI3B,MAAI,cAAc,WAAW;AAC3B,UAAM,OAAO,QAAQ;AAAA,EACvB;AAEA,UAAQ,mBAAmB,OAAO,UAAU,SAAS,OAAO,OAAO,EAAE;AACvE;AAUA,eAAsB,yBACpB,YACA,SACe;AACf,QAAM,iBAAiB,YAAY,SAAS,QAAQ;AACpD,QAAM,uBAAuB,SAAS,WAAW,UAAU;AAC7D;;;AC7IA,SAAS,SAASC,kBAAiB;AACnC,OAAOC,YAAU;AAwBjB,eAAsB,oBAAoB,YAA0C;AAClF,QAAM,OAAO,MAAM,WAAW,YAAY,yBAAyB;AAEnE,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,MAAM,gCAAgC,UAAU,+BAA+B;AAAA,EAC3F;AAEA,UAAQ,4BAA4B,UAAU,EAAE;AAChD,SAAO,KAAK;AACd;AASA,eAAsB,eAAe,YAA+C;AAClF,QAAM,OAAO,MAAM,WAAW,YAAY,oBAAoB;AAE9D,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,MAAM,2BAA2B,UAAU,+BAA+B;AAAA,EACtF;AAEA,QAAM,SAA2B;AAAA,IAC/B,SAAS,KAAK;AAAA,IACd,eAAe,KAAK,iBAAiB;AAAA,MACnC,WAAW,CAAC;AAAA,MACZ,aAAa,CAAC;AAAA,MACd,UAAU,CAAC;AAAA,MACX,cAAc,CAAC;AAAA,IACjB;AAAA,EACF;AAEA,UAAQ,uBAAuB,UAAU,EAAE;AAC3C,SAAO;AACT;AAqBA,eAAsB,iBAAiBC,YAAsD;AAC3F,QAAM,SAAmC,CAAC;AAC1C,QAAM,gBAAgB,MAAM,KAAK,MAAM,eAAe,aAAa,IAAIA,UAAS;AAEhF,aAAW,gBAAgB,eAAe;AACxC,UAAM,WAAWC,OAAK,QAAQ,YAAY;AAC1C,UAAM,cAAcA,OAAK,KAAKD,YAAW,UAAU,eAAe,QAAQ;AAC1E,UAAM,eAAeC,OAAK,KAAKD,YAAW,YAAY;AAEtD,QAAI,CAAE,MAAM,WAAW,WAAW,GAAI;AACpC,cAAQ,YAAY,YAAY,QAAQ,eAAe,QAAQ,QAAQ;AACvE;AAAA,IACF;AAEA,UAAM,kBAAkB,MAAM,SAAS,YAAY;AAKnD,QAAI;AACJ,QAAI;AACF,oBAAcE,WAAU,eAAe;AAAA,IACzC,SAAS,OAAO;AACd;AAAA,QACE,aAAa,YAAY,kBAAkB,eAAe,aAAa,OAAO,YAAY,WAAM,gBAAgB,KAAK,CAAC;AAAA,MACxH;AACA;AAAA,IACF;AAEA,UAAM,iBAAiB,wBAAwB,UAAU,WAAW;AAEpE,QAAI,CAAC,eAAe,SAAS;AAC3B;AAAA,QACE,aAAa,YAAY,mCAA8B,gBAAgB,eAAe,MAAM,MAAM,CAAC;AAAA,MACrG;AACA;AAAA,IACF;AAEA,UAAM,WAAW,eAAe;AAChC,UAAM,iBAAiB,MAAM,SAAS,WAAW;AACjD,UAAM,cAAc,iBAAiB,gBAAgB,WAAW;AAIhE,QAAI,CAAC,aAAa;AAChB,YAAM,aAAa,sBAAsB,cAAc;AACvD,UAAI,eAAe,QAAW;AAC5B;AAAA,UACE,aAAaD,OAAK,KAAK,UAAU,eAAe,QAAQ,CAAC,kBAAkB,eAAe,QAAQ,mBAAmB,WAAW,WAAM,UAAU;AAAA,QAClJ;AAAA,MACF;AACA;AAAA,IACF;AAEA,QAAI,CAAC,SAAS,aAAa;AACzB,YAAM,IAAI;AAAA,QACR,YAAY,YAAY,yBAAyB,cAAc,YAAY;AAAA,MAC7E;AAAA,IACF;AAEA,UAAM,UAAU,YAAY;AAE5B,UAAM,YAAoC;AAAA,MACxC,IAAI;AAAA,MACJ,eAAe;AAAA,MACf,aAAa,SAAS,kBAAkB,YAAY;AAAA,MACpD,GAAI,YAAY,eAAe,EAAE,uBAAuB,YAAY,YAAY;AAAA,MAChF,GAAI,SAAS,kBAAkB,UAAa,EAAE,eAAe,SAAS,cAAc;AAAA,MACpF,UAAU,SAAS;AAAA,MACnB,QAAQ,SAAS;AAAA,MACjB,MAAM,UAAU,QAAQ;AAAA,MACxB,QAAQ,SAAS;AAAA,MACjB,aAAa,SAAS;AAAA,MACtB,MAAM,SAAS;AAAA,MACf,GAAI,SAAS,WAAW,OAAO,EAAE,QAAQ,KAAK,IAAI,CAAC;AAAA,IACrD;AAEA,WAAO,KAAK,SAAS;AACrB,YAAQ,oBAAoB,OAAO,EAAE;AAAA,EACvC;AAEA,SAAO;AACT;;;ACpKA,SAAS,UAAAE,SAAQ,YAAAC,iBAAgB;AA0BjC,IAAM,mBAAmB;AAqBzB,SAAS,yBACP,OACA,WACM;AACN,MAAI,MAAM,WAAW,UAAU,OAAQ;AAEvC;AAAA,IACE,aAAa,MAAM,QAAQ,uFACT,UAAU,EAAE,MAAM,UAAU,MAAM,OAAO,MAAM,EAAE,eAC7D,MAAM,MAAM,8BAA8B,UAAU,MAAM;AAAA,EAElE;AACF;AAEO,SAAS,mBAAmB,UAAoB,QAAoC;AACzF;AAAA,IACE,aAAa,QAAQ;AAAA,EACvB;AACA,QAAM,cAAc,YAAY,QAAQ;AAExC,SAAO;AAAA,IACL,IAAI;AAAA,IACJ;AAAA,IACA,aAAa,+BAA+B,QAAQ;AAAA,IACpD;AAAA,IACA,WAAW;AAAA,IACX,OAAO;AAAA,EACT;AACF;AAcO,SAAS,UAAU,SAAuB,MAAiB,IAAmB;AACnF,UAAQ,SAAS,IAAI,MAAM;AAC7B;AAQA,SAAS,aAAa,QAAgD;AACpE,QAAM,UAAwB,EAAE,UAAU,CAAC,EAAE;AAE7C,aAAW,EAAE,MAAM,GAAG,KAAK,QAAQ;AACjC,UAAM,YAAY,QAAQ,SAAS,IAAI;AACvC,QAAI,cAAc,UAAa,cAAc,IAAI;AAC/C,WAAK,mBAAmB,IAAI,yBAAyB,SAAS,gBAAgB,EAAE,GAAG;AAAA,IACrF;AACA,cAAU,SAAS,MAAM,EAAE;AAAA,EAC7B;AAEA,SAAO;AACT;AAQA,SAAS,sBACP,QACA,YACA,eACA,SACyC;AACzC,QAAM,iBAA0D,CAAC;AAEjE,aAAW,SAAS,QAAQ;AAC1B,UAAM,WAAW,eAAe,MAAM,EAAE;AACxC,QAAI,UAAU;AACZ;AAAA,QACE,uBAAuB,MAAM,EAAE,6BAA6B,SAAS,IAAI,gBAAgB,MAAM,IAAI;AAAA,MACrG;AACA;AAAA,IACF;AAEA,mBAAe,MAAM,EAAE,IAAI,mBAAmB,OAAO,YAAY,eAAe,OAAO;AAAA,EACzF;AAEA,SAAO;AACT;AAEA,SAAS,qBACP,MACA,UACA,SACgB;AAChB,QAAM,aAAa,SAAS,IAAI;AAChC,MAAI,YAAY;AACd,WAAO;AAAA,EACT;AACA,QAAM,WAAW,UAAU,OAAO,OAAO,KAAK;AAC9C,OAAK,oBAAoB,IAAI,IAAI,QAAQ,kBAAa;AACtD,SAAO;AACT;AAGA,SAAS,kBAAkB,eAAqD;AAC9E,SAAO;AAAA,IACL,GAAG,cAAc,UAAU,QAAQ,CAAC,SAAS,KAAK,MAAM;AAAA,IACxD,GAAG,cAAc,YAAY,QAAQ,CAAC,SAAS,KAAK,MAAM;AAAA,IAC1D,GAAG,cAAc,SAAS,QAAQ,CAAC,SAAS,CAAC,KAAK,OAAO,GAAG,KAAK,KAAK,CAAC;AAAA,IACvE,GAAG,cAAc,aAAa,QAAQ,CAAC,SAAS,KAAK,MAAM;AAAA,EAC7D;AACF;AASA,SAAS,uBACP,eACA,UACa;AACb,SAAOC,QAAO,kBAAkB,aAAa,EAAE,OAAO,CAAC,SAAS,SAAS,IAAI,MAAM,MAAS,CAAC;AAC/F;AAGA,SAAS,mBACP,QACA,UACyB;AACzB,SAAO;AAAA,IACL,WAAW,CAAC,GAAG,OAAO,WAAW,GAAG,SAAS,SAAS;AAAA,IACtD,aAAa,CAAC,GAAG,OAAO,aAAa,GAAG,SAAS,WAAW;AAAA,IAC5D,UAAU,CAAC,GAAG,OAAO,UAAU,GAAG,SAAS,QAAQ;AAAA,IACnD,cAAc,CAAC,GAAG,OAAO,cAAc,GAAG,SAAS,YAAY;AAAA,EACjE;AACF;AAGA,IAAM,8BAA8B;AAGpC,SAAS,oBACP,OACA,SACQ;AACR,SAAO,MACJ,IAAI,CAAC,UAAU,EAAE,GAAG,MAAM,QAAQ,KAAK,OAAO,OAAO,CAAC,SAAS,QAAQ,IAAI,IAAI,CAAC,EAAE,EAAE,EACpF,OAAO,CAAC,SAAS,KAAK,OAAO,UAAU,2BAA2B;AACvE;AAOA,SAAS,0BACP,OACA,SACe;AACf,SAAO,MACJ,OAAO,CAAC,SAAS,QAAQ,IAAI,KAAK,KAAK,CAAC,EACxC,IAAI,CAAC,UAAU,EAAE,GAAG,MAAM,OAAO,KAAK,MAAM,OAAO,CAAC,SAAS,QAAQ,IAAI,IAAI,CAAC,EAAE,EAAE,EAClF,OAAO,CAAC,SAAS,KAAK,MAAM,SAAS,CAAC;AAC3C;AAEA,SAAS,qBACP,OACA,SACyB;AACzB,SAAO;AAAA,IACL,WAAW,oBAAoB,MAAM,WAAW,OAAO;AAAA,IACvD,aAAa,oBAAoB,MAAM,aAAa,OAAO;AAAA,IAC3D,UAAU,0BAA0B,MAAM,UAAU,OAAO;AAAA,IAC3D,cAAc,oBAAoB,MAAM,cAAc,OAAO;AAAA,EAC/D;AACF;AAgBO,SAAS,uBACd,QACA,aACyB;AACzB,QAAM,UAAU,IAAI,IAAI,OAAO,IAAI,CAAC,UAAU,MAAM,IAAI,CAAC;AACzD,QAAM,UAAU,qBAAqB,aAAa,eAAe,OAAO;AACxE,SAAO,cAAc,mBAAmB,YAAY,eAAe,OAAO,IAAI;AAChF;AAeO,SAAS,sBACd,YACA,eACA,QACoB;AACpB,QAAM,UAAU,aAAa,MAAM;AACnC,QAAM,iBAAiB,sBAAsB,QAAQ,YAAY,eAAe,OAAO;AAGvF,QAAM,wBAAwB,EAAE,GAAG,WAAW;AAC9C,QAAM,kBAAkB,oBAAI,IAAoC;AAChE,aAAW,SAAS,QAAQ;AAE1B,QAAI,MAAM,aAAa,sBAAuB;AAM9C,QAAI,WAAW,MAAM,QAAQ,EAAG;AAEhC,UAAM,UAAU,gBAAgB,IAAI,MAAM,QAAQ;AAClD,QAAI,YAAY,QAAW;AACzB,4BAAsB,MAAM,QAAQ,IAAI,mBAAmB,MAAM,UAAU,MAAM,MAAM;AACvF,sBAAgB,IAAI,MAAM,UAAU,KAAK;AACzC,cAAQ,8BAA8B,MAAM,QAAQ,gBAAgB,MAAM,EAAE,GAAG;AAC/E;AAAA,IACF;AAEA,6BAAyB,OAAO,OAAO;AAAA,EACzC;AAEA,QAAM,kBAAkB,uBAAuB,eAAe,QAAQ,QAAQ;AAE9E,QAAM,SAA6B;AAAA,IACjC,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,iBAAiB,CAAC;AAAA,IAClB;AAAA,IACA,GAAI,gBAAgB,SAAS,KAAK,EAAE,gBAAgB;AAAA,IACpD,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,EACtC;AAEA,SAAO;AACT;AAWA,SAAS,mBAAmB,OAAoB,SAAoB,SAA4B;AAC9F,SAAO,MAAM,IAAI,CAAC,SAAS,QAAQ,MAAM,OAAO,CAAC,EAAE,OAAO,CAAC,OAAsB,OAAO,IAAI;AAC9F;AAaA,SAAS,iBAAiB,OAAoB,SAAsC;AAGlF,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,QAAM,WAAW,mBAAmB,OAAO,SAAS,gBAAgB;AACpE,SAAO,SAAS,WAAW,MAAM,SAAS,WAAW;AACvD;AAOA,SAAS,6BACP,OACA,SACA,SACA,SAC0C;AAC1C,QAAM,UAAU,MAAM,QAAQ,CAAC,SAAS;AACtC,UAAM,WAAW,mBAAmB,KAAK,QAAQ,SAAS,OAAO;AACjE,QAAI,CAAC,SAAS,SAAS,OAAO,EAAG,QAAO,CAAC;AACzC,WAAO,SAAS,OAAO,CAAC,OAAO,OAAO,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,UAAU,KAAK,EAAE;AAAA,EACvF,CAAC;AACD,SAAOC,UAAS,SAAS,CAAC,MAAM,EAAE,QAAQ;AAC5C;AAMA,SAAS,qBACP,SACA,eACA,SACuB;AAEvB,QAAM,gBAAiC;AAAA,IACrC,cAAc;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,IAAI,CAAC,EAAE,UAAU,KAAK,OAAO,EAAE,SAAS,UAAU,QAAQ,KAAK,OAAO,EAAE;AAE1E,QAAM,cAA+B;AAAA,IACnC,cAAc;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,IAAI,CAAC,EAAE,UAAU,KAAK,OAAO,EAAE,SAAS,UAAU,QAAQ,KAAK,OAAO,EAAE;AAE1E,QAAM,eAAmC;AAAA,IACvC,cAAc;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,IAAI,CAAC,EAAE,UAAU,KAAK,OAAO,EAAE,SAAS,UAAU,SAAS,KAAK,QAAQ,EAAE;AAG5E,QAAM,WAA+B,CAAC;AACtC,aAAW,QAAQ,cAAc,UAAU;AACzC,UAAM,cAAc,QAAQ,KAAK,OAAO,gBAAgB;AACxD,QAAI,gBAAgB,QAAS;AAC7B,UAAM,gBAAgB,iBAAiB,KAAK,OAAO,OAAO;AAC1D,QAAI,CAAC,cAAe;AACpB,aAAS,KAAK;AAAA,MACZ,UAAU;AAAA,MACV,UAAU,KAAK,YAAY;AAAA,MAC3B,QAAQ,KAAK;AAAA,IACf,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,mBACP,OACA,aACA,eACA,SACe;AACf,QAAM,UAAqB,CAACC,OAAM,YAChC,qBAAqBA,OAAM,QAAQ,UAAU,UAAU,GAAG,MAAM,EAAE,IAAI,OAAO,KAAK,MAAS;AAE7F,QAAM,OAAO,MAAM;AAEnB,QAAM,WAAW,qBAAqB,MAAM,IAAI,eAAe,OAAO;AAEtE,SAAO;AAAA,IACL,IAAI,MAAM;AAAA,IACV;AAAA,IACA,aAAa,MAAM;AAAA,IACnB,aAAa,MAAM;AAAA,IACnB,GAAI,MAAM,0BAA0B,UAAa;AAAA,MAC/C,uBAAuB,MAAM;AAAA,IAC/B;AAAA,IACA,GAAI,MAAM,kBAAkB,UAAa,EAAE,eAAe,MAAM,cAAc;AAAA,IAC9E,UAAU,MAAM;AAAA,IAChB,QAAQ,MAAM;AAAA,IACd,GAAG;AAAA,IACH,MAAM,MAAM;AAAA,IACZ,GAAI,MAAM,WAAW,OAAO,EAAE,QAAQ,KAAK,IAAI,CAAC;AAAA,EAClD;AACF;;;AC1bA,SAAS,WAAAC,gBAAe;AAyBxB,SAAS,SAAS,OAAmD;AACnE,SAAO,sBAAsB,MAAM,WAAW;AAChD;AAEA,SAAS,oBAAoB,OAAiB,aAAmC;AAC/E,MAAI,MAAM,UAAU,EAAG,QAAO,MAAM,CAAC,KAAK;AAC1C,MAAI,MAAM,WAAW,EAAG,QAAO,GAAG,MAAM,CAAC,CAAC,IAAI,WAAW,IAAI,MAAM,CAAC,CAAC;AACrE,SAAO,GAAG,MAAM,MAAM,GAAG,EAAE,EAAE,KAAK,IAAI,CAAC,IAAI,WAAW,IAAI,MAAM,MAAM,SAAS,CAAC,CAAC;AACnF;AAOA,SAAS,2BAA2B,mBAAgD;AAClF,QAAM,qBAAqB,kBAAkB,IAAI,CAAC,MAAM,aAAa,CAAC,EAAE,EAAE;AAC1E,QAAM,cAAc,IAAI,IAAa,kBAAkB;AACvD,SAAO,EAAE,oBAAoB,YAAY;AAC3C;AASA,SAAS,iBAAiB,QAAmD;AAC3E,SAAO;AAAA,IACL,QAAQ,YAAY,OAAO,MAAM,EAAE,IAAI,CAAC,WAAW;AAAA,MACjD,IAAI,MAAM;AAAA,MACV,YAAY,MAAM;AAAA,MAClB,eAAe,MAAM,cAAc,IAAI,CAAC,aAAa,SAAS,OAAO;AAAA,MACrE,aAAa,MAAM,YAAY,IAAI,CAAC,cAAc;AAAA,QAChD,SAAS,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,QAKlB,QAAQ,sBAAsB,SAAS,MAAM;AAAA,MAC/C,EAAE;AAAA,MACF,UAAU,MAAM,SAAS,IAAI,CAAC,iBAAiB;AAAA,QAC7C,UAAU,YAAY;AAAA,QACtB,UAAU,YAAY;AAAA,MACxB,EAAE;AAAA,IACJ,EAAE;AAAA,IACF,sBAAsB,IAAI;AAAA,MACxB,YAAY,OAAO,UAAU,EAC1B,OAAO,CAAC,aAAa,SAAS,cAAc,KAAK,EACjD,IAAI,CAAC,aAAa,SAAS,EAAE;AAAA,IAClC;AAAA,EACF;AACF;AAIA,IAAI;AACJ,IAAI;AAEJ,SAAS,gBAAgB,oBAAmD;AAC1E,MAAI,CAAC,kBAAkB,YAAY,QAAQ;AACzC,qBAAiB,yBAAyB,iBAAiB,MAAM,CAAC;AAClE,cAAU;AAAA,EACZ;AACA,SAAO,eAAe,kBAAkB;AAC1C;AAGA,SAAS,sBAAsB,OAAqC;AAClE,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,aAAO,kBAAkB,QAAQ,MAAM,OAAO,CAAC;AAAA,IACjD,KAAK,0BAA0B;AAC7B,UAAI,MAAM,YAAY,UAAU;AAC9B,cAAM,SAAS,MAAM,YAAY,SAAS,IAAI,OAAO;AACrD,eAAO,YAAY,oBAAoB,QAAQ,IAAI,CAAC;AAAA,MACtD;AACA,YAAM,aAAa,MAAM,QAAQ,IAAI,OAAO;AAC5C,aAAO,YAAY,oBAAoB,YAAY,KAAK,CAAC;AAAA,IAC3D;AAAA,EACF;AACF;AAEA,SAAS,QAAQ,SAAyB;AAGxC,SAAO,SAAS,aAAa,OAAkB,CAAC;AAClD;AAKA,SAAS,iBAAiB,KAAuB,aAA4C;AAC3F,SAAO,IAAI,WACP,IAAI,SAAS,KAAK,CAAC,OAAO,YAAY,IAAI,EAAE,CAAC,IAC7C,IAAI,SAAS,MAAM,CAAC,OAAO,YAAY,IAAI,EAAE,CAAC;AACpD;AAGA,SAAS,sBACP,KACA,aACW;AACX,MAAI,iBAAiB,KAAK,WAAW,EAAG,QAAO,CAAC;AAChD,SAAO,IAAI,WAAW,CAAC,GAAG,IAAI,QAAQ,IAAI,IAAI,SAAS,OAAO,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC;AAC5F;AAOO,SAAS,mBACd,SACA,mBACoB;AACpB,eAAa,OAAO;AACpB,QAAM,EAAE,oBAAoB,YAAY,IAAI,2BAA2B,iBAAiB;AAExF,MAAI,YAAY,IAAI,OAAO,EAAG,QAAO;AAErC,aAAW,cAAc,oBAAoB;AAC3C,UAAM,gBAAgB,OAAO,OAAO,UAAU;AAC9C,QAAI,CAAC,cAAe;AAEpB,eAAW,OAAO,cAAc,UAAU;AACxC,UAAI,CAAC,IAAI,SAAS,SAAS,OAAO,EAAG;AAErC,UAAI,IAAI,UAAU;AAEhB,YAAI,CAAC,IAAI,SAAS,KAAK,CAAC,OAAO,YAAY,IAAI,EAAE,CAAC,GAAG;AACnD,iBAAO,SAAS,aAAa;AAAA,QAC/B;AAAA,MACF,OAAO;AAEL,eAAO,SAAS,aAAa;AAAA,MAC/B;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAMO,SAAS,qBAAqB,SAAkB,mBAAuC;AAC5F,SAAO,2BAA2B,SAAS,iBAAiB,MAAM;AACpE;AAUO,SAAS,aAAa,SAAkB,mBAA2C;AACxF,QAAM,QAAQ,aAAa,OAAO;AAClC,QAAM,EAAE,mBAAmB,IAAI,2BAA2B,iBAAiB;AAE3E,QAAM,UAAU,gBAAgB,kBAAkB,EAAE,UAAU,MAAM,EAAE;AACtE,SAAO,QAAQ,WAAW,iBACtB,EAAE,QAAQ,gBAAgB,QAAQ,sBAAsB,QAAQ,KAAK,EAAE,IACvE;AACN;AAKO,SAAS,2BACd,SACA,mBACoB;AACpB,QAAM,QAAQ,aAAa,OAAO;AAElC,QAAM,EAAE,YAAY,IAAI,2BAA2B,iBAAiB;AAEpE,aAAW,eAAe,MAAM,UAAU;AACxC,UAAM,UAAU,sBAAsB,aAAa,WAAW;AAC9D,QAAI,QAAQ,WAAW,EAAG;AAC1B,UAAM,QAAQ,QAAQ,IAAI,CAAC,OAAO;AAChC,YAAM,IAAI,OAAO,OAAO,EAAE;AAC1B,aAAO,IAAI,SAAS,CAAC,IAAI,sBAAsB,EAAE;AAAA,IACnD,CAAC;AACD,WAAO,kBAAkB,gBAAgB,OAAO,YAAY,QAAQ,GAAG,YAAY,MAAM;AAAA,EAC3F;AAEA,SAAO;AACT;AAGA,SAAS,gBAAgB,OAAiB,UAAuC;AAC/E,SAAO,YAAY,oBAAoB,OAAO,WAAW,OAAO,KAAK,CAAC;AACxE;AAcA,IAAM,gBAAgB;AAetB,SAAS,kBAAkB,aAAqB,QAAwB;AACtE,QAAM,SAAS,OAAO,KAAK;AAC3B,MAAI,WAAW,GAAI,QAAO;AAE1B,SAAO,GAAG,WAAW,WAAM,aAAa,QAAQ,aAAa,CAAC;AAChE;AAMA,SAAS,2BACP,YACA,SACA,mBACsC;AACtC,MAAI,CAAC,WAAY,QAAO,CAAC;AACzB,QAAM,SAAS,2BAA2B,SAAS,iBAAiB;AACpE,SAAO,WAAW,SAAY,CAAC,IAAI,EAAE,yBAAyB,OAAO;AACvE;AAEO,SAAS,kBAAkB,oBAAkD;AAClF,QAAM,SAA4B,CAAC;AAEnC,aAAW,CAAC,OAAO,QAAQ,KAAK,mBAAmB,QAAQ,GAAG;AAC5D,UAAM,SAAS,OAAO,OAAO,QAAQ;AACrC,QAAI,CAAC,OAAQ;AAEb,eAAW,YAAY,mBAAmB,MAAM,QAAQ,CAAC,GAAG;AAC1D,YAAM,WAAW,OAAO,cAAc,KAAK,CAAC,MAAM,EAAE,YAAY,QAAQ;AACxE,UAAI,UAAU;AACZ,eAAO,KAAK;AAAA,UACV,MAAM;AAAA;AAAA;AAAA;AAAA,UAIN,SAAS,GAAG,SAAS,MAAM,CAAC,mBAAmB,SAAS,aAAa,QAAQ,CAAC,CAAC,KAAK,sBAAsB,SAAS,MAAM,CAAC;AAAA,UAC1H,QAAQ,CAAC,OAAO,IAAI,QAAQ;AAAA,QAC9B,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,qBACd,oBACA,aACmB;AACnB,QAAM,SAA4B,CAAC;AAEnC,aAAW,WAAW,oBAAoB;AACxC,UAAM,QAAQ,OAAO,OAAO,OAAO;AACnC,QAAI,CAAC,MAAO;AAEZ,eAAW,eAAe,MAAM,UAAU;AACxC,UAAI,YAAY,UAAU;AACxB,cAAM,SAAS,YAAY,SAAS,KAAK,CAAC,UAAU,YAAY,IAAI,KAAK,CAAC;AAC1E,YAAI,CAAC,QAAQ;AACX,iBAAO,KAAK;AAAA,YACV,MAAM;AAAA,YACN,SAAS,GAAG,SAAS,KAAK,CAAC,qBAAqB,YAAY,SAAS,IAAI,CAAC,OAAO,SAAS,aAAa,EAAE,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,YACvH,QAAQ,CAAC,SAAS,GAAG,YAAY,QAAQ;AAAA,UAC3C,CAAC;AAAA,QACH;AAAA,MACF,OAAO;AACL,cAAM,aAAa,YAAY,SAAS,OAAO,CAAC,UAAU,CAAC,YAAY,IAAI,KAAK,CAAC;AACjF,YAAI,WAAW,SAAS,GAAG;AACzB,iBAAO,KAAK;AAAA,YACV,MAAM;AAAA,YACN,SAAS,GAAG,SAAS,KAAK,CAAC,cAAc,WAAW,IAAI,CAAC,OAAO,SAAS,aAAa,EAAE,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,YACtG,QAAQ,CAAC,SAAS,GAAG,UAAU;AAAA,UACjC,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,oBAAoB,oBAAkD;AACpF,QAAM,SAA4B,CAAC;AAEnC,QAAM,cAAc,mBACjB,IAAI,CAAC,aAAa,EAAE,SAAS,OAAO,OAAO,OAAO,OAAO,EAAE,EAAE,EAC7D,OAAO,CAAC,UAA+D,MAAM,SAAS,IAAI;AAC7F,QAAM,qBAAqBC,SAAQ,aAAa,CAAC,UAAU,MAAM,MAAM,QAAQ;AAE/E,aAAW,CAAC,YAAY,OAAO,KAAK,aAAa,kBAAkB,GAAG;AACpE,QAAI,QAAQ,SAAS,GAAG;AACtB,YAAM,WAAW,QAAQ,IAAI,CAAC,MAAM,EAAE,OAAO;AAE7C,UAAI,eAAe,sBAAuB;AAC1C,YAAM,WAAW,OAAO,WAAW,UAAU;AAC7C,UAAI,UAAU,WAAW;AACvB,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,SAAS,aAAa,sBAAsB,SAAS,WAAW,CAAC,uDAAuD,SAAS,IAAI,CAAC,OAAO,SAAS,aAAa,EAAE,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,UACnL,QAAQ;AAAA,QACV,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAiBO,SAASC,mBAAkB,YAA4C;AAC5E,QAAM,EAAE,oBAAoB,YAAY,IAAI,2BAA2B,UAAU;AAEjF,QAAM,SAAS;AAAA,IACb,GAAG,kBAAkB,kBAAkB;AAAA,IACvC,GAAG,qBAAqB,oBAAoB,WAAW;AAAA,IACvD,GAAG,oBAAoB,kBAAkB;AAAA,EAC3C;AAEA,SAAO;AAAA,IACL,OAAO,OAAO,WAAW;AAAA,IACzB;AAAA,EACF;AACF;AAkBO,SAAS,mBACd,YACA,mBACe;AACf,QAAM,EAAE,YAAY,IAAI,2BAA2B,iBAAiB;AAEpE,SAAO,oBAAoB,UAAU,EAAE,IAAI,CAAC,UAAU;AACpD,UAAM,aAAa,YAAY,IAAI,MAAM,EAAE;AAC3C,WAAO;AAAA,MACL,IAAI,MAAM;AAAA,MACV,UAAU;AAAA,MACV,sBAAsB,cAAc,qBAAqB,MAAM,IAAI,iBAAiB;AAAA,MACpF,GAAG,2BAA2B,YAAY,MAAM,IAAI,iBAAiB;AAAA,IACvE;AAAA,EACF,CAAC;AACH;AAGO,SAAS,oBAAoB,YAA2C;AAC7E,SAAO,UAAU,EAAE,OAAO,CAAC,UAAU,MAAM,aAAa,UAAU;AACpE;;;AC1XO,IAAM,aAA+C;AAAA;AAAA,EAE1D,uBAAuB;AAAA,IACrB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,qCAAqC;AAAA,IACnC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,oCAAoC;AAAA,IAClC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,yBAAyB;AAAA,IACvB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,wBAAwB;AAAA,IACtB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,6BAA6B;AAAA,IAC3B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,4BAA4B;AAAA,IAC1B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,2BAA2B;AAAA,IACzB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,gCAAgC;AAAA,IAC9B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,4BAA4B;AAAA,IAC1B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,2BAA2B;AAAA,IACzB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,iCAAiC;AAAA,IAC/B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,IAC7C,SAAS,CAAC,uBAAuB;AAAA,EACnC;AAAA,EACA,gCAAgC;AAAA,IAC9B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,IAC7C,SAAS,CAAC,qCAAqC,uBAAuB;AAAA,EACxE;AAAA,EACA,4BAA4B;AAAA,IAC1B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,IACpD,SAAS,CAAC,yBAAyB;AAAA,EACrC;AAAA,EACA,+BAA+B;AAAA,IAC7B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,IACpD,gBACE;AAAA,EACJ;AAAA,EACA,gCAAgC;AAAA,IAC9B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,IACpD,gBACE;AAAA,EACJ;AAAA,EACA,yBAAyB;AAAA,IACvB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,0BAA0B;AAAA,IACxB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,oCAAoC;AAAA,IAClC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,kCAAkC;AAAA,IAChC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB;AAAA,MACd,OAAO;AAAA,MACP,YAAY,CAAC,SAAS,uBAAuB,WAAW,QAAQ;AAAA,IAClE;AAAA,EACF;AAAA;AAAA,EAGA,mBAAmB;AAAA,IACjB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,IACpD,gBACE;AAAA,EACJ;AAAA,EACA,kBAAkB;AAAA,IAChB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,2BAA2B;AAAA,IACzB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,qBAAqB;AAAA,IACnB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,mBAAmB;AAAA,IACjB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,qBAAqB,EAAE;AAAA,EACpE;AAAA,EACA,8BAA8B;AAAA,IAC5B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,oBAAoB,EAAE;AAAA,EACnE;AAAA,EACA,6BAA6B;AAAA,IAC3B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,2BAA2B;AAAA,IACzB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB;AAAA,MACd,OAAO;AAAA,MACP,YAAY,CAAC,SAAS,uBAAuB,sBAAsB,SAAS;AAAA,IAC9E;AAAA,IACA,gBACE;AAAA,EACJ;AAAA,EACA,0BAA0B;AAAA,IACxB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,qBAAqB,EAAE;AAAA,EACpE;AAAA,EACA,4BAA4B;AAAA,IAC1B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,IAC7C,SAAS,CAAC,iBAAiB;AAAA,EAC7B;AAAA,EACA,uCAAuC;AAAA,IACrC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,mCAAmC;AAAA,IACjC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,sBAAsB;AAAA,IACpB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,QAAQ,EAAE;AAAA,EACvD;AAAA,EACA,uBAAuB;AAAA,IACrB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,qBAAqB;AAAA,IACnB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,qBAAqB,EAAE;AAAA,EACpE;AAAA,EACA,sBAAsB;AAAA,IACpB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,0BAA0B;AAAA,IACxB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,wBAAwB;AAAA,IACtB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,qBAAqB,EAAE;AAAA,EACpE;AAAA,EACA,2BAA2B;AAAA,IACzB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA;AAAA,EAGA,oBAAoB;AAAA,IAClB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,cAAc;AAAA,IACZ,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,SAAS,QAAQ,EAAE;AAAA,EAChE;AAAA,EACA,oBAAoB;AAAA,IAClB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,kBAAkB;AAAA,IAChB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,qBAAqB;AAAA,IACnB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,SAAS,QAAQ,EAAE;AAAA,EAChE;AAAA,EACA,kBAAkB;AAAA,IAChB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,qBAAqB,EAAE;AAAA,EACpE;AAAA,EACA,mBAAmB;AAAA,IACjB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,sBAAsB;AAAA,IACpB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,kBAAkB;AAAA,IAChB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,IACpD,SAAS,CAAC,qBAAqB;AAAA,EACjC;AAAA,EACA,yBAAyB;AAAA,IACvB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,wBAAwB;AAAA,IACtB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,4BAA4B;AAAA,IAC1B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,IAC7C,gBACE;AAAA,EACJ;AAAA,EACA,mBAAmB;AAAA,IACjB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,uBAAuB;AAAA,IACrB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,6BAA6B;AAAA,IAC3B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,+BAA+B;AAAA,IAC7B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,gCAAgC;AAAA,IAC9B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,kCAAkC;AAAA,IAChC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,sBAAsB;AAAA,IACpB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,IACpD,SAAS,CAAC,qBAAqB;AAAA,EACjC;AAAA,EACA,qBAAqB;AAAA,IACnB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,SAAS,qBAAqB,EAAE;AAAA,EAC7E;AAAA,EACA,4BAA4B;AAAA,IAC1B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,IACpD,SAAS,CAAC,0BAA0B;AAAA,EACtC;AAAA,EACA,mBAAmB;AAAA,IACjB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,IACpD,SAAS;AAAA,MACP;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,8BAA8B;AAAA,IAC5B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,2BAA2B;AAAA,IACzB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,IAC7C,gBACE;AAAA,EACJ;AAAA,EACA,qCAAqC;AAAA,IACnC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,8BAA8B;AAAA,IAC5B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,qBAAqB,EAAE;AAAA,EACpE;AAAA,EACA,sBAAsB;AAAA,IACpB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,iCAAiC;AAAA,IAC/B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,IAC7C,gBACE;AAAA,EACJ;AAAA,EACA,yBAAyB;AAAA,IACvB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB;AAAA,MACd,OAAO;AAAA,MACP,YAAY;AAAA,QACV;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,IACA,SAAS,CAAC,gEAAgE;AAAA,IAC1E,gBACE;AAAA,EACJ;AAAA,EACA,oBAAoB;AAAA,IAClB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,IAC7C,gBACE;AAAA,EACJ;AAAA,EACA,iCAAiC;AAAA,IAC/B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,IACpD,SAAS;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAAA,EACA,2BAA2B;AAAA,IACzB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,0BAA0B;AAAA,IACxB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,IACpD,gBACE;AAAA,EACJ;AAAA,EACA,oBAAoB;AAAA,IAClB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,2BAA2B;AAAA,IACzB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,yBAAyB;AAAA,IACvB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,kBAAkB;AAAA,IAChB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,wBAAwB;AAAA,IACtB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,IACpD,SAAS,CAAC,sBAAsB;AAAA,EAClC;AAAA,EACA,oBAAoB;AAAA,IAClB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,mBAAmB;AAAA,IACjB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,IAC7C,gBACE;AAAA,EACJ;AAAA,EACA,iBAAiB;AAAA,IACf,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,kCAAkC;AAAA,IAChC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,4BAA4B;AAAA,IAC1B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,mCAAmC;AAAA,IACjC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,uCAAuC;AAAA,IACrC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA;AAAA,EAGA,sBAAsB;AAAA,IACpB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,yBAAyB;AAAA,IACvB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,yBAAyB;AAAA,IACvB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,wBAAwB;AAAA,IACtB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,wBAAwB;AAAA,IACtB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,6BAA6B;AAAA,IAC3B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,WAAW,SAAS,EAAE;AAAA,EACnE;AAAA,EACA,oBAAoB;AAAA,IAClB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,yBAAyB;AAAA,IACvB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,SAAS,EAAE;AAAA,IACtD,SAAS;AAAA,MACP;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EACA,qCAAqC;AAAA,IACnC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,MAAM,EAAE;AAAA,IACnD,SAAS;AAAA,MACP;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EACA,qBAAqB;AAAA,IACnB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,QAAQ,EAAE;AAAA,IACrD,SAAS,CAAC,oBAAoB;AAAA,EAChC;AAAA,EACA,kBAAkB;AAAA,IAChB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,QAAQ,EAAE;AAAA,EACvD;AAAA,EACA,qBAAqB;AAAA,IACnB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,0BAA0B;AAAA,IACxB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,0BAA0B;AAAA,IACxB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,oBAAoB;AAAA,IAClB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,IAC7C,SAAS;AAAA,MACP;AAAA,MACA;AAAA,IACF;AAAA,IACA,gBACE;AAAA,EACJ;AAAA,EACA,mCAAmC;AAAA,IACjC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,uBAAuB;AAAA,IACrB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA;AAAA,EAGA,2BAA2B;AAAA,IACzB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,sBAAsB;AAAA,IACpB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,4BAA4B;AAAA,IAC1B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,wBAAwB;AAAA,IACtB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,uBAAuB;AAAA,IACrB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,IAC7C,gBACE;AAAA,EACJ;AAAA,EACA,0BAA0B;AAAA,IACxB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,wBAAwB;AAAA,IACtB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,qBAAqB;AAAA,IACnB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,wBAAwB;AAAA,IACtB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,yBAAyB;AAAA,IACvB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,uBAAuB;AAAA,IACrB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,0BAA0B;AAAA,IACxB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,sBAAsB;AAAA,IACpB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,wBAAwB;AAAA,IACtB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,0BAA0B;AAAA,IACxB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,IAC7C,gBACE;AAAA,EACJ;AAAA,EACA,gCAAgC;AAAA,IAC9B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,IAC7C,gBACE;AAAA,EACJ;AAAA,EACA,qBAAqB;AAAA,IACnB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,qBAAqB;AAAA,IACnB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,qBAAqB;AAAA,IACnB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,iBAAiB;AAAA,IACf,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,wBAAwB;AAAA,IACtB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,kBAAkB;AAAA,IAChB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,IAC7C,gBACE;AAAA,EACJ;AAAA;AAAA,EAGA,0BAA0B;AAAA,IACxB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,wBAAwB;AAAA,IACtB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,wBAAwB;AAAA,IACtB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,IAC7C,gBACE;AAAA,EACJ;AAAA,EACA,0BAA0B;AAAA,IACxB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,4BAA4B;AAAA,IAC1B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,IAC7C,gBACE;AAAA,EACJ;AAAA,EACA,0BAA0B;AAAA,IACxB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA;AAAA;AAAA,EAGA,oBAAoB;AAAA,IAClB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,mBAAmB;AAAA,IACjB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,QAAQ,EAAE;AAAA,IACrD,gBACE;AAAA,EACJ;AAAA,EACA,kBAAkB;AAAA,IAChB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,kBAAkB;AAAA,IAChB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,+BAA+B;AAAA,IAC7B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,2BAA2B;AAAA,IACzB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,mCAAmC;AAAA,IACjC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,6CAA6C;AAAA,IAC3C,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,QAAQ,EAAE;AAAA,IACrD,SAAS;AAAA,MACP;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EACA,uCAAuC;AAAA,IACrC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,0BAA0B;AAAA,IACxB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,IACpD,SAAS,CAAC,0BAA0B;AAAA,EACtC;AAAA,EACA,gCAAgC;AAAA,IAC9B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,IACpD,gBACE;AAAA,EACJ;AAAA;AAAA,EAGA,6BAA6B;AAAA,IAC3B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,0BAA0B;AAAA,IACxB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,iCAAiC;AAAA,IAC/B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,2BAA2B;AAAA,IACzB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,0BAA0B;AAAA,IACxB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,0BAA0B;AAAA,IACxB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,6BAA6B;AAAA,IAC3B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,8BAA8B;AAAA,IAC5B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,2CAA2C;AAAA,IACzC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,iCAAiC;AAAA,IAC/B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,6BAA6B;AAAA,IAC3B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,IAC7C,gBACE;AAAA,EACJ;AAAA,EACA,+BAA+B;AAAA,IAC7B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,2BAA2B;AAAA,IACzB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,4BAA4B;AAAA,IAC1B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,8BAA8B;AAAA,IAC5B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,+BAA+B;AAAA,IAC7B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,kCAAkC;AAAA,IAChC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,EACtD;AAAA,EACA,6BAA6B;AAAA,IAC3B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,8BAA8B;AAAA,IAC5B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,iCAAiC;AAAA,IAC/B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA;AAAA,EAGA,iCAAiC;AAAA,IAC/B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,yBAAyB;AAAA,IACvB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,sCAAsC;AAAA,IACpC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,cAAc,EAAE;AAAA,IAC3D,SAAS,CAAC,6BAA6B;AAAA,EACzC;AAAA,EACA,iCAAiC;AAAA,IAC/B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,MAAM,EAAE;AAAA,IACnD,SAAS,CAAC,4CAA4C;AAAA,EACxD;AAAA,EACA,6BAA6B;AAAA,IAC3B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,cAAc,EAAE;AAAA,IAC3D,SAAS,CAAC,4BAA4B;AAAA,EACxC;AAAA,EACA,4BAA4B;AAAA,IAC1B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,cAAc,EAAE;AAAA,IAC3D,SAAS,CAAC,wBAAwB;AAAA,EACpC;AAAA,EACA,wBAAwB;AAAA,IACtB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,cAAc,EAAE;AAAA,IAC3D,SAAS,CAAC,8BAA8B;AAAA,EAC1C;AAAA,EACA,0BAA0B;AAAA,IACxB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,IAC7C,SAAS,CAAC,yDAAyD;AAAA,IACnE,gBACE;AAAA,EACJ;AAAA,EACA,gCAAgC;AAAA,IAC9B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,gBAAgB,OAAO,EAAE;AAAA,IACpE,SAAS,CAAC,+CAA+C,oCAAoC;AAAA,IAC7F,gBACE;AAAA,EACJ;AAAA,EACA,2CAA2C;AAAA,IACzC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,cAAc,EAAE;AAAA,IAC3D,SAAS,CAAC,iDAAiD;AAAA,EAC7D;AAAA,EACA,+BAA+B;AAAA,IAC7B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,cAAc,EAAE;AAAA,IAC3D,SAAS,CAAC,qDAAqD;AAAA,EACjE;AAAA,EACA,oCAAoC;AAAA,IAClC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,cAAc,EAAE;AAAA,IAC3D,SAAS,CAAC,0DAA0D;AAAA,EACtE;AAAA,EACA,yBAAyB;AAAA,IACvB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,cAAc,EAAE;AAAA,IAC3D,SAAS,CAAC,8CAA8C;AAAA,EAC1D;AAAA,EACA,uBAAuB;AAAA,IACrB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,cAAc,EAAE;AAAA,IAC3D,SAAS,CAAC,+CAA+C;AAAA,EAC3D;AAAA,EACA,mCAAmC;AAAA,IACjC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,cAAc,EAAE;AAAA,IAC3D,SAAS,CAAC,0DAA0D;AAAA,EACtE;AAAA,EACA,+BAA+B;AAAA,IAC7B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,cAAc,EAAE;AAAA,IAC3D,SAAS,CAAC,+DAA+D;AAAA,IACzE,gBACE;AAAA,EACJ;AAAA,EACA,yBAAyB;AAAA,IACvB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,MAAM,EAAE;AAAA,IACnD,SAAS,CAAC,2CAA2C;AAAA,EACvD;AAAA,EACA,+BAA+B;AAAA,IAC7B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,cAAc,EAAE;AAAA,IAC3D,SAAS,CAAC,wCAAwC;AAAA,EACpD;AAAA,EACA,2BAA2B;AAAA,IACzB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,cAAc,EAAE;AAAA,IAC3D,SAAS;AAAA,MACP;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EACA,6BAA6B;AAAA,IAC3B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,cAAc,EAAE;AAAA,IAC3D,SAAS;AAAA,MACP;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EACA,2BAA2B;AAAA,IACzB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,cAAc,EAAE;AAAA,IAC3D,SAAS;AAAA,MACP;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EACA,iCAAiC;AAAA,IAC/B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,cAAc,EAAE;AAAA,IAC3D,SAAS;AAAA,MACP;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EACA,mCAAmC;AAAA,IACjC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,cAAc,EAAE;AAAA,IAC3D,SAAS,CAAC,0CAA0C;AAAA,EACtD;AAAA,EACA,gCAAgC;AAAA,IAC9B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,cAAc,EAAE;AAAA,IAC3D,SAAS;AAAA,MACP;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,8BAA8B;AAAA,IAC5B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,2BAA2B;AAAA,IACzB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,wBAAwB;AAAA,IACtB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,UAAU,EAAE;AAAA,IACvD,SAAS,CAAC,qDAAqD;AAAA,EACjE;AAAA,EACA,4BAA4B;AAAA,IAC1B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,UAAU,EAAE;AAAA,IACvD,SAAS;AAAA,MACP;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EACA,uBAAuB;AAAA,IACrB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,UAAU,EAAE;AAAA,IACvD,SAAS,CAAC,iDAAiD;AAAA,EAC7D;AAAA,EACA,4BAA4B;AAAA,IAC1B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,UAAU,EAAE;AAAA,IACvD,SAAS,CAAC,gDAAgD;AAAA,EAC5D;AAAA,EACA,oCAAoC;AAAA,IAClC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,UAAU,EAAE;AAAA,IACvD,SAAS;AAAA,MACP;AAAA,MACA;AAAA,IACF;AAAA,IACA,gBACE;AAAA,EACJ;AAAA,EACA,gCAAgC;AAAA,IAC9B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,UAAU,EAAE;AAAA,IACvD,SAAS,CAAC,wDAAwD;AAAA,EACpE;AAAA,EACA,6BAA6B;AAAA,IAC3B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,UAAU,EAAE;AAAA,IACvD,SAAS,CAAC,uDAAuD;AAAA,EACnE;AAAA,EACA,oCAAoC;AAAA,IAClC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,UAAU,EAAE;AAAA,IACvD,SAAS,CAAC,8BAA8B;AAAA,EAC1C;AAAA,EACA,yBAAyB;AAAA,IACvB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,IACpD,SAAS,CAAC,4CAA4C;AAAA,EACxD;AAAA,EACA,2BAA2B;AAAA,IACzB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,IACpD,SAAS,CAAC,kCAAkC;AAAA,EAC9C;AAAA,EACA,yBAAyB;AAAA,IACvB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,IACpD,SAAS,CAAC,8BAA8B;AAAA,EAC1C;AAAA,EACA,6BAA6B;AAAA,IAC3B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,IACpD,SAAS,CAAC,gDAAgD;AAAA,EAC5D;AAAA,EACA,0BAA0B;AAAA,IACxB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,IACpD,SAAS,CAAC,6CAA6C;AAAA,EACzD;AAAA,EACA,wBAAwB;AAAA,IACtB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,IACpD,SAAS;AAAA,MACP;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,8BAA8B;AAAA,IAC5B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,sBAAsB;AAAA,IACpB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,4BAA4B;AAAA,IAC1B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,WAAW,EAAE;AAAA,IACxD,SAAS,CAAC,4BAA4B;AAAA,EACxC;AAAA,EACA,0BAA0B;AAAA,IACxB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,UAAU,MAAM,EAAE;AAAA,EAC/D;AAAA,EACA,+BAA+B;AAAA,IAC7B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,uBAAuB;AAAA,IACrB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,IAC7C,gBACE;AAAA,EACJ;AAAA,EACA,oBAAoB;AAAA,IAClB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,iBAAiB;AAAA,IACf,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,IAC7C,gBACE;AAAA,EACJ;AAAA,EACA,yBAAyB;AAAA,IACvB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,IAC7C,gBACE;AAAA,EACJ;AAAA,EACA,0BAA0B;AAAA,IACxB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,IAC7C,gBACE;AAAA,EACJ;AAAA,EACA,qCAAqC;AAAA,IACnC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,0BAA0B;AAAA,IACxB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,+BAA+B;AAAA,IAC7B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,2BAA2B;AAAA,IACzB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,qBAAqB;AAAA,IACnB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA;AAAA,EAGA,6BAA6B;AAAA,IAC3B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,sBAAsB;AAAA,IACpB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,mCAAmC;AAAA,IACjC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,wBAAwB;AAAA,IACtB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,IAC7C,gBACE;AAAA,EACJ;AAAA,EACA,kCAAkC;AAAA,IAChC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,oCAAoC;AAAA,IAClC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,4BAA4B;AAAA,IAC1B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,6BAA6B;AAAA,IAC3B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,4BAA4B;AAAA,IAC1B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,iCAAiC;AAAA,IAC/B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,qCAAqC;AAAA,IACnC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,qCAAqC;AAAA,IACnC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,IACpD,SAAS;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAAA,EACA,yCAAyC;AAAA,IACvC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,8BAA8B;AAAA,IAC5B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,8BAA8B;AAAA,IAC5B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,8BAA8B;AAAA,IAC5B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,6BAA6B;AAAA,IAC3B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,4BAA4B;AAAA,IAC1B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,gCAAgC;AAAA,IAC9B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,OAAO,EAAE;AAAA,IACpD,SAAS;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAAA,EACA,gCAAgC;AAAA,IAC9B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,gCAAgC;AAAA,IAC9B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,+BAA+B;AAAA,IAC7B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AAAA,EACA,kCAAkC;AAAA,IAChC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,gBAAgB,EAAE,OAAO,KAAK,YAAY,CAAC,EAAE;AAAA,EAC/C;AACF;AAaO,IAAM,4BAA8D,CAAC;;;AC3mDrE,SAAS,kBAAkBC,SAAiD;AACjF,QAAM,SAAS;AAAA,IACb,GAAG,qBAAqBA,OAAM;AAAA,IAC9B,GAAG,qBAAqBA,OAAM;AAAA,IAC9B,GAAG,uBAAuBA,OAAM;AAAA,IAChC,GAAG,yBAAyBA,OAAM;AAAA,IAClC,GAAG,gCAAgCA,OAAM;AAAA,IACzC,GAAG,qBAAqBA,OAAM;AAAA,EAChC;AAEA,aAAW,SAAS,QAAQ;AAC1B,SAAK,YAAY,MAAM,OAAO,EAAE;AAAA,EAClC;AAEA,SAAO;AACT;AAGA,SAAS,qBAAqBA,SAAiD;AAC7E,SACE,aAA2CA,QAAO,UAAU,EAEzD,OAAO,CAAC,CAAC,EAAE,GAAG,MAAM,QAAQ,UAAa,CAAC,IAAI,MAAM,EACpD,IAAI,CAAC,CAAC,KAAK,OAAO;AAAA,IACjB,UAAU;AAAA,IACV,SAAS;AAAA,IACT,SAAS,aAAa,KAAK;AAAA,EAC7B,EAAE;AAER;AAEA,SAAS,qBAAqBA,SAAiD;AAC7E,SAAO,aAAqCA,QAAO,MAAM,EACtD;AAAA,IACC,CAAC,CAAC,EAAE,KAAK;AAAA;AAAA,MAEP,UAAU;AAAA,MAEV,MAAM,aAAa,yBACnB,CAACA,QAAO,WAAW,MAAM,QAAQ;AAAA;AAAA,EACrC,EACC,IAAI,CAAC,CAAC,SAAS,KAAK,OAAO;AAAA,IAC1B,UAAU;AAAA,IACV,SAAS;AAAA,IACT,SAAS,UAAU,OAAO,0BAA0B,MAAM,QAAQ;AAAA,EACpE,EAAE;AACN;AAGA,SAAS,aAAa,OAA8D;AAClF,SAAO;AAAA,IACL,GAAG,MAAM,cAAc,IAAI,CAAC,cAAc,EAAE,OAAO,iBAAiB,KAAK,SAAS,QAAQ,EAAE;AAAA,IAC5F,GAAG,MAAM,SAAS;AAAA,MAAQ,CAAC,gBACzB,YAAY,SAAS,IAAI,CAAC,SAAS,EAAE,OAAO,YAAY,IAAI,EAAE;AAAA,IAChE;AAAA,EACF;AACF;AAEA,SAAS,uBAAuBA,SAAiD;AAC/E,SAAO,aAAqCA,QAAO,MAAM,EAAE;AAAA,IAAQ,CAAC,CAAC,SAAS,KAAK;AAAA;AAAA,MAEjF,UAAU,SACN,CAAC,IACD,aAAa,KAAK,EACf,OAAO,CAAC,EAAE,IAAI,MAAM,CAACA,QAAO,OAAO,GAAG,CAAC,EACvC,IAAI,CAAC,EAAE,OAAO,IAAI,OAAO;AAAA,QACxB,UAAU;AAAA,QACV,SAAS;AAAA,QACT,SAAS,UAAU,OAAO,+BAA+B,GAAG,SAAS,KAAK;AAAA,MAC5E,EAAE;AAAA;AAAA,EACV;AACF;AAcA,SAAS,yBAAyBA,SAAiD;AACjF,UAAQA,QAAO,mBAAmB,CAAC,GAAG,IAAI,CAAC,UAAU;AAAA,IACnD,UAAU;AAAA,IACV,SAAS;AAAA,IACT,SAAS,oBAAoB,IAAI;AAAA,EACnC,EAAE;AACJ;AAEA,SAASC,qBAAoBD,SAA4B,UAAiC;AAExF,MAAI,aAAa,sBAAuB,QAAO;AAE/C,QAAM,aAAaA,QAAO,WAAW,QAAQ;AAC7C,SAAO,eAAe,UAAa,WAAW;AAChD;AAOO,SAAS,iBAAiBA,SAA4B,SAA2B;AACtF,QAAM,QAAQA,QAAO,OAAO,OAAO;AACnC,MAAI,UAAU,OAAW,QAAO;AAEhC,SAAO,MAAM,SAAS,SAAS,KAAKC,qBAAoBD,SAAQ,MAAM,QAAQ;AAChF;AAGA,SAAS,cAAc,SAA+C;AACpE,SAAO,OAAO,OAAO,YAAY,OAAO,IAAI,WAAW,OAAO,IAAI;AACpE;AAEA,SAAS,iBAAiBA,SAA4B,OAA8B;AAClF,MAAI,MAAM,SAAS,SAAS,EAAG,QAAO;AACtC,SAAO,iBAAiB,MAAM,QAAQ;AACxC;AAQA,SAAS,gCAAgCA,SAAiD;AACxF,SAAO,aAAqCA,QAAO,MAAM,EACtD,OAAO,CAAC,CAAC,SAAS,KAAK,MAAM;AAE5B,QAAI,UAAU,UAAa,0BAA0B,OAAO,EAAG,QAAO;AACtE,UAAM,QAAQ,cAAc,OAAO;AAEnC,WAAO,OAAO,YAAY,eAAe,iBAAiBA,SAAQ,OAAO;AAAA,EAC3E,CAAC,EACA,IAAI,CAAC,CAAC,SAAS,KAAK,OAAO;AAAA,IAC1B,UAAU;AAAA,IACV,SAAS;AAAA,IACT,SAAS,UAAU,OAAO,gCAAgC,iBAAiBA,SAAQ,KAAK,CAAC;AAAA,EAC3F,EAAE;AACN;AAcA,SAAS,qBAAqBA,SAAiD;AAC7E,SAAO,aAAqCA,QAAO,MAAM,EACtD;AAAA,IACC,CAAC,CAAC,SAAS,KAAK;AAAA;AAAA,MAEd,UAAU,UACV,CAAC,MAAM,SACP,UAAU,OAAO,KACjB,cAAc,OAAO,MAAM;AAAA;AAAA,EAC/B,EACC,IAAI,CAAC,CAAC,OAAO,OAAO;AAAA,IACnB,UAAU;AAAA,IACV,SAAS;AAAA,IACT,SAAS,UAAU,OAAO;AAAA,EAC5B,EAAE;AACN;;;AnE7EA,eAAsB,2BACpB,UAA6B,CAAC,GACH;AAC3B,QAAM;AAAA,IACJ,UAAU;AAAA,IACV,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV,aAAa;AAAA,EACf,IAAI;AAKJ,QAAM,eAAe,MAAM,cAAc,EAAE,QAAQ,MAAM,YAAY,WAAW,CAAC;AACjF,QAAM,EAAE,OAAO,IAAI;AAEnB,UAAQ,+BAA+B,MAAM,EAAE;AAE/C,QAAM,YAAY,MAAM,kBAAkB,cAAc,EAAE,SAAS,SAAS,WAAW,CAAC;AAExF,QAAM,qBAAqB,cAAc,QAAQ,IAAI;AAKrD,QAAM,SAA2B;AAAA,IAC/B,GAAG;AAAA,IACH,qBAAqB,IAAI,IAAI,UAAmB,UAAU,OAAO,MAAM,CAAC;AAAA,EAC1E;AAGA,QAAM,UAAUE,KAAG,QAAQ;AAC3B,MAAI,CAAC,gBAAgB,kBAAkB,GAAG;AACxC,WAAO,SAAS,MAAM,2BAA2B,OAAO,QAAQ,SAAS,QAAQ;AAAA,EACnF;AACA,SAAO,SAAS,MAAM,2BAA2B,OAAO,QAAQ,oBAAoB,SAAS;AAC7F,QAAM,6BAA6B,OAAO,QAAQ,QAAQ,OAAO;AAEjE,MAAI,CAAC,QAAQ,kBAAkB;AAC7B,UAAM;AAAA,MACJ,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA,OAAO;AAAA,MACP,sBAAsB,OAAO,QAAQ,OAAO,mBAAmB;AAAA,IACjE;AAAA,EACF;AAEA,oBAAkB,OAAO,MAAM;AAC/B,mBAAiB,OAAO,MAAM;AAE9B,SAAO;AACT;AAoBA,eAAe,6BACbC,SACA,cACA,SACe;AACf,QAAM,YAAY,MAAM,4BAA4BA,OAAM;AAC1D,MAAI,UAAU,WAAW,EAAG;AAE5B,QAAM,kBAAkB,MAAM,gCAAgC,cAAc,OAAO;AACnF,MAAI,oBAAoB,KAAM;AAE9B,aAAW,MAAM,UAAW,mBAAkBA,SAAQ,iBAAiB,EAAE;AAC3E;AASA,eAAe,4BAA4BA,SAAgD;AACzF,MAAI;AACF,UAAM,eAAe,MAAM,uBAAuB;AAClD,YAAQ,cAAc,UAAU,CAAC,GAC9B,OAAO,cAAc,EACrB,OAAO,CAAC,UAAUA,QAAO,OAAO,MAAM,EAAE,MAAM,MAAS,EACvD,IAAI,CAAC,UAAU,MAAM,EAAE;AAAA,EAC5B,SAAS,OAAO;AACd,YAAQ,kDAA6C,gBAAgB,KAAK,CAAC,EAAE;AAC7E,WAAO,CAAC;AAAA,EACV;AACF;AAGA,SAAS,eAAe,OAA6B;AACnD,SAAO,CAAC,MAAM,YAAY,MAAM,WAAW;AAC7C;AAQA,eAAe,gCACb,cACA,SAC+B;AAC/B,MAAI;AACF,UAAM,qBAAqB,MAAM,cAAc,EAAE,QAAQ,UAAU,YAAYD,KAAG,QAAQ,EAAE,CAAC;AAC7F,QAAI,mBAAmB,WAAW,aAAc,QAAO;AACvD,WAAO,MAAM,kBAAkB,oBAAoB;AAAA,MACjD;AAAA,MACA,SAAS;AAAA,MACT,YAAY;AAAA,IACd,CAAC;AAAA,EACH,SAAS,OAAO;AACd,YAAQ,uDAAkD,gBAAgB,KAAK,CAAC,EAAE;AAClF,WAAO;AAAA,EACT;AACF;AAGA,SAAS,kBACPC,SACA,WACA,IACM;AACN,QAAM,QAAQ,UAAU,OAAO,OAAO,EAAE;AAExC,MAAI,CAAC,MAAO;AAEZ,EAAAA,QAAO,OAAO,EAAE,IAAI,oBAAoB,OAAO,SAAS;AACxD,YAAUA,QAAO,SAAS,MAAM,MAAM,EAAE;AACxC,gBAAcA,SAAQ,UAAU,QAAQ,MAAM,QAAQ;AACxD;AAGA,SAAS,oBAAoB,OAAsB,WAAyC;AAC1F,SAAO;AAAA,IACL,GAAG;AAAA,IACH,eAAe,CAAC;AAAA,IAChB,UAAU,CAAC;AAAA,IACX,cAAc,CAAC;AAAA,IACf,aAAa,CAAC;AAAA,IACd,kBAAkB,CAAC,kBAAkB,UAAU,cAAc,UAAU,WAAW,CAAC;AAAA,EACrF;AACF;AAMA,SAAS,cACPA,SACA,MACA,YACM;AACN,MAAI,eAAe,yBAAyBA,QAAO,WAAW,UAAU,EAAG;AAC3E,QAAM,WAAW,KAAK,WAAW,UAAU;AAC3C,MAAI,SAAU,CAAAA,QAAO,WAAW,UAAU,IAAI;AAChD;AAQA,SAAS,sBACPA,SACA,qBACsB;AACtB,SAAO,IAAI,IAAI,UAAmBA,QAAO,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,oBAAoB,IAAI,EAAE,CAAC,CAAC;AAC/F;AAQA,SAAS,sBAA0C;AACjD,SAAO;AAAA,IACL,GAAG;AAAA,IACH,QAAQ,EAAE,GAAG,gBAAgB,OAAO;AAAA,IACpC,YAAY,EAAE,GAAG,gBAAgB,WAAW;AAAA,IAC5C,iBAAiB,CAAC,GAAG,gBAAgB,eAAe;AAAA,IACpD,SAAS;AAAA,MACP,UAAU,EAAE,GAAG,gBAAgB,QAAQ,SAAS;AAAA,IAClD;AAAA,EACF;AACF;AASA,eAAe,kBACb,cACA,EAAE,SAAS,SAAS,WAAW,GACP;AACxB,6BAA2B,YAAY;AACvC,QAAM,EAAE,OAAO,IAAI;AACnB,MAAI,gBAAgB,MAAM,KAAK,CAAC,SAAS;AAMvC,UAAM,aAAa,aAAa,MAAM,MAAM,gBAAgB,MAAM,GAAG;AACrE,WAAO;AAAA,MACL,QAAQ,oBAAoB;AAAA,MAC5B;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT,GAAI,aAAa,gBAAgB,UAAa,EAAE,aAAa,aAAa,YAAY;AAAA,IACxF;AAAA,EACF;AAEA,QAAM,UAAU,cAAc,MAAM,KAAK;AACzC,SAAO,UACH,cAAc,QAAQ,cAAc,OAAO,IAC3C,eAAe,QAAQ,cAAc,OAAO;AAClD;AAMA,SAAS,mBAAmB,YAA4B;AACtD,SAAO,kFAAkF,UAAU;AACrG;AAQA,SAAS,2BAA2B,EAAE,aAAa,sBAAsB,GAAyB;AAChG,MAAI,gBAAgB,OAAW;AAC/B,QAAM,eAAe;AAAA,IACnB;AAAA,IACA,mBAAmB,qBAAqB;AAAA,EAC1C;AACA,MAAI,aAAc,OAAM,IAAI,4BAA4B,YAAY;AACtE;AA4BA,eAAe,kBAAkB,QAAwC;AACvE,MAAI;AACF,UAAM,EAAE,YAAY,IAAI,MAAM,iBAAiB,MAAM;AACrD,WAAO,EAAE,MAAM,SAAS,MAAM,YAAY,KAAK;AAAA,EACjD,SAAS,OAAO;AACd,QAAI,iBAAiB,+BAAgC,QAAO,EAAE,MAAM,SAAS;AAC7E,QAAI,iBAAiB,6BAA6B;AAChD,aAAO,EAAE,MAAM,WAAW,QAAQ,gBAAgB,KAAK,EAAE;AAAA,IAC3D;AACA,WAAO,EAAE,MAAM,cAAc,QAAQ,gBAAgB,KAAK,EAAE;AAAA,EAC9D;AACF;AAaO,IAAM,mCAAN,cAA+C,MAAM;AAAC;AAgB7D,eAAe,yBACb,cACA,cACA,SAC4B;AAC5B,QAAM,QAAQ,MAAM,kBAAkB,YAAY;AAElD,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK,SAAS;AACZ,YAAM,cAAc,aAAa,eAAe,MAAM;AACtD,cAAQ,+BAA+B,gBAAgB,KAAK,WAAW,EAAE;AACzE,aAAO,EAAE,YAAY;AAAA,IACvB;AAAA,IACA,KAAK;AACH,YAAM,IAAI,4BAA4B,MAAM,MAAM;AAAA,IACpD,KAAK;AAAA,IACL,KAAK;AACH,aAAO,qBAAqB,OAAO,cAAc,OAAO;AAAA,IAC1D,SAAS;AACP,YAAM,aAAoB;AAC1B,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAMA,SAAS,qBACP,OACA,cACA,SACmB;AACnB,QAAM,EAAE,OAAO,IAAI;AACnB,MAAI,sBAAsB,QAAQ,OAAO,GAAG;AAC1C,YAAQ,IAAI,MAAM,mBAAmB,gBAAgB,yCAAyC;AAC9F,WAAO,gBAAgB,YAAY;AAAA,EACrC;AAEA,QAAM,IAAI;AAAA,IACR,MAAM,SAAS,WACX,2BAA2B,MAAM,IACjC,8BAA8B,QAAQ,MAAM,MAAM;AAAA,EACxD;AACF;AAOA,SAAS,sBAAsB,QAAgB,SAAqC;AAClF,SAAO,gBAAgB,MAAM,KAAK,YAAY;AAChD;AAGA,SAAS,gBAAgB,cAAiD;AACxE,SAAO,aAAa,gBAAgB,SAAY,CAAC,IAAI,EAAE,aAAa,aAAa,YAAY;AAC/F;AAGA,eAAe,2BACbA,SACA,KACA,OAC6B;AAC7B,QAAM,aAAa,MAAM,oBAAoB,GAAG;AAChD,MAAI,CAAC,cAAc,WAAW,OAAO,WAAW,EAAG,QAAOA;AAC1D;AAAA,IACE,SAAS,WAAW,OAAO,MAAM,IAAI,KAAK,sBAAsB,WAAW,eAAe;AAAA,EAC5F;AACA,SAAO,2BAA2BA,SAAQ,UAAU;AACtD;AAEA,eAAe,cACb,QACA,cACA,SACwB;AAKxB,QAAM,aAAa,cAAc,MAAM,KAAK,MAAM,gBAAgB,MAAM,GAAG,OAAO;AAElF,UAAQ,mCAAmC,UAAU,EAAE;AAEvD,QAAM,eAAe,MAAM,yBAAyB,YAAY,MAAM;AACtE,QAAM,SAAS,MAAM,yBAAyB,YAAY,cAAc,OAAO;AAE/E,SAAO;AAAA,IACL,QAAQ;AAAA,IACR;AAAA,IACA,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,GAAG;AAAA,EACL;AACF;AAEA,eAAe,eACb,QACA,cACA,SACwB;AACxB,UAAQ,uCAAuC,MAAM,EAAE;AAEvD,QAAM,cAAc,MAAM,gBAAgB,MAAM;AAEhD,UAAQ,eAAe,YAAY,IAAI,EAAE;AAEzC,QAAM,eAAe,MAAM,yBAAyB,YAAY,MAAM,MAAM;AAC5E,QAAM,SAAS,MAAM,yBAAyB,QAAQ,cAAc,OAAO;AAE3E,SAAO;AAAA,IACL,QAAQ;AAAA,IACR;AAAA,IACA,YAAY,YAAY;AAAA,IACxB,SAAS;AAAA,IACT,GAAG;AAAA,EACL;AACF;AAiBA,eAAsB,sBAAsB,gBAAqD;AAC/F,QAAMA,UAAS,MAAM,yBAAyB,gBAAgB,cAAc;AAC5E,SAAO,EAAE,GAAGA,SAAQ,YAAY,2BAA2BA,OAAM,EAAE;AACrE;AAoBA,SAAS,2BAA2BA,SAAyC;AAC3E,QAAM,WAAW,IAAI,IAAkB,YAAYA,QAAO,MAAM,EAAE,IAAI,CAAC,UAAU,MAAM,QAAQ,CAAC;AAEhG,SAAO;AAAA,IACL,aAA2CA,QAAO,UAAU,EAAE;AAAA,MAAO,CAAC,CAAC,EAAE,MACvE,SAAS,IAAI,EAAE;AAAA,IACjB;AAAA,EACF;AACF;AAQA,eAAe,yBACb,UACA,QAC6B;AAI7B,QAAM,sBAAsB,MAAM,qBAAqB,QAAQ;AAE/D,QAAM,mBAAmB,qBAAqB,aAAa;AAC3D,QAAM,gBAAgB,qBAAqB;AAE3C,QAAM,EAAE,YAAY,YAAY,IAAI,MAAM,mBAAmB,QAAQ;AAErE,QAAMC,aAAYC,OAAK,KAAK,UAAU,gBAAgB;AACtD,UAAQ,uBAAuBD,UAAS,EAAE;AAE1C,QAAM,SAAS,MAAM,iBAAiBA,UAAS;AAC/C,QAAM,0BAA0B,UAAU,QAAQ,MAAM;AAExD,QAAM,gBAAgB,uBAAuB,QAAQ,WAAW;AAChE,QAAM,eAAe,sBAAsB,YAAY,eAAe,MAAM;AAC5E,mBAAiB,YAAY;AAI7B,QAAM,SAAS,MAAM,qBAAqB,UAAU,eAAe,MAAM;AACzE,eAAa,kBAAkB,OAAO,IAAI,CAAC,UAAU,4BAA4B,KAAK,CAAC;AAEvF,QAAM,sBAAsB,kBAAkB,MAAM,cAAc,QAAQ,CAAC;AAC3E,QAAM,cAAc,UAAU,mBAAmB,EAAE;AACnD,MAAI,cAAc,GAAG;AACnB,iBAAa,sBAAsB;AACnC,YAAQ,UAAU,WAAW,6BAA6B;AAAA,EAC5D;AAEA,SAAO;AACT;AAeA,eAAe,mBAAmB,UAA2C;AAC3E,QAAM,uBAAuBC,OAAK,KAAK,UAAU,qBAAqB;AACtE,QAAM,kBAAkBA,OAAK,KAAK,UAAU,gBAAgB;AAC5D,QAAM,sBAAsB,MAAM,WAAW,oBAAoB;AACjE,QAAM,iBAAiB,MAAM,WAAW,eAAe;AAEvD,QAAM,mBAAmB,sBACrB,MAAM,oBAAoB,oBAAoB,IAC9C;AACJ,MAAI,kBAAkB;AACpB;AAAA,MACE,6BAA6B,oBAAoB,KAAK,UAAU,gBAAgB,EAAE,MAAM;AAAA,IAC1F;AAAA,EACF;AACA,QAAM,aAA0B,mBAC5B,EAAE,GAAG,mBAAmB,GAAG,iBAAiB,IAC5C;AAEJ,QAAM,cAAc,iBAAiB,MAAM,eAAe,eAAe,IAAI;AAC7E,MAAI,aAAa;AACf,YAAQ,wBAAwB,eAAe,EAAE;AAAA,EACnD;AAEA,MAAI,uBAAuB,gBAAgB;AACzC,YAAQ,uBAAuB,UAAU,iBAAiB,EAAE,MAAM,uBAAuB;AAAA,EAC3F,OAAO;AACL,YAAQ,6DAA6D;AAAA,EACvE;AAEA,SAAO,EAAE,YAAY,YAAY;AACnC;AAGA,SAAS,kBACP,QACoC;AACpC,SAAO;AAAA,IACL,aAAyC,MAAM,EAAE;AAAA,MAAQ,CAAC,CAAC,SAAS,QAAQ,MAC1E,SAAS,SAAS,CAAC,CAAC,SAAS,SAAS,MAAM,CAAU,IAAI,CAAC;AAAA,IAC7D;AAAA,EACF;AACF;AAGA,IAAM,sBAA4C,IAAI,IAAI,UAAU,gBAAgB,MAAM,CAAC;AAG3F,IAAM,0BAA0B;AAiBhC,eAAe,0BACb,UACA,QACA,QACe;AACf,QAAM,eAAe,OAAO,IAAI,CAAC,UAAU,MAAM,EAAE,EAAE,OAAO,CAAC,OAAO,oBAAoB,IAAI,EAAE,CAAC;AAC/F,MAAI,aAAa,WAAW,EAAG;AAC/B,MAAI,MAAM,0BAA0B,QAAQ,EAAG;AAE/C,QAAM,IAAI,MAAM,wBAAwB,cAAc,MAAM,CAAC;AAC/D;AAEA,SAAS,wBAAwB,cAAyB,QAAwB;AAChF,QAAM,SAAS,aAAa,MAAM,GAAG,uBAAuB,EAAE,IAAI,CAAC,OAAO,KAAK,EAAE,EAAE;AACnF,QAAM,WAAW,aAAa,SAAS,OAAO;AAE9C,SAAO;AAAA,IACL,gBAAgB,MAAM,WAAW,aAAa,MAAM;AAAA,IAEpD,GAAG;AAAA,IACH,GAAI,WAAW,IAAI,CAAC,aAAa,QAAQ,OAAO,IAAI,CAAC;AAAA,IACrD;AAAA,EAIF,EAAE,KAAK,IAAI;AACb;AAaA,eAAe,qBACb,UACA,YACA,QACkB;AAClB,QAAM,eAAe,MAAM,WAAW,UAAU,UAAU;AAC1D,MAAI,aAAa,SAAS,GAAG;AAC3B,YAAQ,gBAAgB,aAAa,MAAM,0BAA0B;AACrE,WAAO;AAAA,EACT;AAEA,MAAI,MAAM,oBAAoB,UAAU,MAAM,GAAG;AAC/C;AAAA,MACE,4DAAuD,cAAc,MAAM;AAAA,IAC7E;AACA,WAAO;AAAA,EACT;AAEA,UAAQ,gBAAgB,MAAM,uEAAkE;AAChG,SAAO,CAAC;AACV;AAeA,SAAS,iBAAiB,OAA+D;AACvF,QAAM,QAAkB,UAAqB,MAAM,MAAM;AACzD,SAAO;AAAA,IACL,UAAU,MAAM,OAAO,WAAW;AAAA,IAClC,YAAY,MAAM,OAAO,CAAC,SAAS,CAAC,YAAY,IAAI,CAAC;AAAA,EACvD;AACF;AAoBA,SAAS,wBAAwB,OAAc,YAAuC;AACpF,QAAM,QAAQ,WAAW,IAAI,CAAC,SAAS,IAAI,IAAI,GAAG,EAAE,KAAK,IAAI;AAC7D,SACE,UAAU,MAAM,EAAE,WAAW,WAAW,MAAM,2CAC3C,KAAK;AAEZ;AASA,SAAS,uBAAuB,OAAc,WAAsC;AAClF,QAAM,QAAQ,UAAU,IAAI,CAAC,OAAO,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI;AACxD,SACE,UAAU,MAAM,EAAE,WAAW,UAAU,MAAM,0DAC/B,KAAK;AAEvB;AAGO,SAAS,4BAA4B,OAA6B;AACvE,QAAM,EAAE,UAAU,WAAW,IAAI,iBAAiB,KAAK;AACvD,MAAI,WAAW,SAAS,EAAG,MAAK,wBAAwB,OAAO,UAAU,CAAC;AAE1E,QAAM,eAAe,SAAS,QAAQ,CAAC,YAAY;AACjD,UAAM,cAAc,MAAM,OAAO,OAAO;AACxC,WAAO,cAAc,CAAC,EAAE,SAAS,YAAY,CAAC,IAAI,CAAC;AAAA,EACrD,CAAC;AAED,QAAM,SAAS;AAAA,IACb,aAAa;AAAA,MACX,CAAC,EAAE,SAAS,YAAY,MAAM,CAAC,SAAS,wBAAwB,WAAW,CAAC;AAAA,IAC9E;AAAA,EACF;AASA,QAAM,QAAQC;AAAA,IACZ,aAAa;AAAA,MAAQ,CAAC,EAAE,YAAY,MAClC,2BAA2B,WAAW,EAAE,IAAI,CAAC,QAAQ,IAAI,EAAE;AAAA,IAC7D;AAAA,EACF;AACA,QAAM,cAAc,MAAM,OAAO,CAAC,OAAO,MAAM,OAAc,MAAM;AACnE,QAAM,YAAY,MAAM,OAAO,CAAC,OAAO,EAAE,MAAM,OAAc,OAAO;AACpE,MAAI,UAAU,SAAS,EAAG,MAAK,uBAAuB,OAAO,SAAS,CAAC;AAEvE;AAAA,IACE,UAAU,MAAM,EAAE,SAAS,YAAY,MAAM,gBAAgB,aAAa,MAAM;AAAA,EAClF;AAEA,SAAO;AAAA,IACL,IAAI,MAAM;AAAA,IACV,MAAM,MAAM;AAAA,IACZ,aAAa,MAAM;AAAA,IACnB;AAAA,IACA;AAAA,IACA,YAAY,MAAM,cAAc;AAAA,EAClC;AACF;AAGA,SAAS,wBACP,aACsC;AACtC,QAAM,aAAa,aAA0C,WAAW,EACrE,IAAI,CAAC,CAAC,UAAU,WAAW,OAAO;AAAA,IACjC;AAAA;AAAA,IAEA,WAAW,eAAe,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,MAAM,OAAc,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE;AAAA,EAC3F,EAAE,EACD,OAAO,CAAC,EAAE,SAAS,MAAM,SAAS,SAAS,CAAC;AAC/C,SAAO;AAAA,IACL,WAAW,IAAI,CAAC,EAAE,UAAU,SAAS,MAAM,CAAC,UAAU,QAAQ,CAAU;AAAA,EAC1E;AACF;AAMA,SAAS,iBAAiBH,SAA4B,UAAiC;AACrF,SAAO,aAAa,yBAAyBA,QAAO,WAAW,QAAQ,MAAM;AAC/E;AASA,SAAS,0BACP,UACA,UACQ;AACR,QAAM,eAAeE,OAAK,KAAK,SAAS,MAAM,eAAe,aAAa;AAC1E,SACE,yBAAyB,SAAS,EAAE,MAAM,cAAc,QAAQ,KAAK,QAAQ,sHAEtE,cAAc,QAAQ,OAAO,YAAY;AAGpD;AAEO,SAAS,2BACdF,SACA,aACoB;AACpB,aAAW,YAAY,YAAY,QAAQ;AACzC,UAAM,gBAAgBA,QAAO,OAAO,SAAS,EAAE;AAI/C,UAAM,WAAW,eAAe,YAAY,SAAS;AAQrD,QAAI,SAAS,WAAW,QAAQ,CAAC,iBAAiBA,SAAQ,QAAQ,GAAG;AACnE,WAAK,0BAA0B,UAAU,QAAQ,CAAC;AAClD;AAAA,IACF;AAEA,UAAM,gBAAgB,qBAAqB,UAAU,eAAe,QAAQ;AAC5E,IAAAA,QAAO,OAAO,SAAS,EAAE,IAAI;AAK7B,cAAUA,QAAO,SAAS,cAAc,MAAM,SAAS,EAAE;AAEzD,0BAAsBA,SAAQ,UAAU,SAAS,MAAM;AAEvD,YAAQ,sBAAsB,SAAS,EAAE,eAAe,QAAQ,GAAG;AAAA,EACrE;AAEA,SAAOA;AACT;AAQA,SAAS,qBACP,UACA,eACA,UACe;AACf,SAAO;AAAA,IACL,IAAI,SAAS;AAAA,IACb,MAAM,eAAe,QAAQ,SAAS;AAAA,IACtC,aAAa,eAAe,eAAe,SAAS;AAAA,IACpD,aAAa,SAAS;AAAA,IACtB,GAAI,SAAS,0BAA0B,UAAa;AAAA,MAClD,uBAAuB,SAAS;AAAA,IAClC;AAAA,IACA,GAAI,SAAS,kBAAkB,UAAa,EAAE,eAAe,SAAS,cAAc;AAAA,IAEpF;AAAA,IAEA,QAAQ,eAAe;AAAA,IAEvB,eAAe,eAAe,iBAAiB,CAAC;AAAA,IAChD,UAAU,eAAe,YAAY,CAAC;AAAA,IACtC,cAAc,eAAe,gBAAgB,CAAC;AAAA,IAC9C,aAAa,eAAe,eAAe,CAAC;AAAA,IAE5C,MAAM,SAAS;AAAA,IAEf,OAAO;AAAA,IACP,GAAI,SAAS,cAAc,UAAa,EAAE,WAAW,SAAS,UAAU;AAAA,IACxE,GAAI,SAAS,WAAW,UAAa,EAAE,QAAQ,SAAS,OAAO;AAAA,EACjE;AACF;AAQA,SAAS,sBACPA,SACA,UACA,QACM;AAEN,MAAI,aAAa,sBAAuB;AACxC,MAAIA,QAAO,WAAW,QAAQ,EAAG;AAEjC,EAAAA,QAAO,WAAW,QAAQ,IAAI;AAAA,IAC5B,IAAI;AAAA,IACJ,aAAa;AAAA,IACb,aAAa;AAAA,IACb;AAAA,IACA,WAAW;AAAA,IACX,OAAO;AAAA,EACT;AACA,UAAQ,yBAAyB,QAAQ,aAAa,MAAM,GAAG;AACjE;","names":["os","unique","path","fs","os","path","fs","os","line","os","fs","path","fs","directoryExists","os","configLoadFailure","agentsDir","skillsDir","SKILL_IDS","AGENT_NAMES","AGENT_NAMES","SKILL_IDS","os","path","z","z","path","MODEL_NAMES","EFFORT_NAMES","z","MODEL_NAMES","EFFORT_NAMES","path","path","path","path","path","scopeLabel","path","os","CONTROL_CHAR_PATTERN","z","path","omit","partition","partition","isSkillAssignment","typedEntries","typedKeys","typedFromEntries","isAgentName","isSkillId","typedKeys","partition","typedEntries","typedFromEntries","omit","indexBy","omit","uniqueBy","os","path","path","groupBy","partition","unique","partition","groupBy","path","unique","scopeLabel","path","os","indexBy","uniqueBy","omit","groupBy","unique","typedEntries","groupBy","unique","typedKeys","path","path","matrix","path","path","path","path","path","NULL_BYTE_PATTERN","path","path","path","path","parseYaml","path","PLUGIN_MANIFEST_FILE","path","os","path","path","os","os","path","path","os","os","path","unique","parseYaml","path","parseYaml","parseYaml","parseYaml","agentsDir","path","directoryExists","skillsDir","createHash","os","path","path","pluginsDir","path","createHash","path","directoryExists","os","os","matrix","os","unique","path","os","os","os","directoryExists","os","path","z","path","SAFE_NAME_PATTERN","path","z","z","pluginsDir","path","os","z","path","os","path","z","os","line","z","path","cacheRoot","skillsDir","path","fg","directoryExists","path","skillsDir","fg","agentsDir","pluginsDir","allSkills","path","parseYaml","skillsDir","sourceDir","path","path","directoryExists","path","path","directoryExists","path","skillsDir","path","directoryExists","parseYaml","path","skillsDir","path","parseYaml","unique","uniqueBy","unique","uniqueBy","slug","groupBy","groupBy","validateSelection","matrix","isExclusiveCategory","os","matrix","skillsDir","path","unique"]}
|