agents-inc 0.156.0 → 0.158.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 +51 -0
- package/dist/{chunk-4A4L3YIW.js → chunk-2PN4QXON.js} +6 -7
- package/dist/chunk-2PN4QXON.js.map +1 -0
- package/dist/{chunk-QWVXOCXO.js → chunk-3NBXQSW2.js} +7 -9
- package/dist/{chunk-QWVXOCXO.js.map → chunk-3NBXQSW2.js.map} +1 -1
- package/dist/{chunk-WCAUUBHO.js → chunk-3PJLLBUS.js} +14597 -14536
- package/dist/chunk-3PJLLBUS.js.map +1 -0
- package/dist/{chunk-6RLV45HN.js → chunk-3Q2N7CSY.js} +6 -6
- package/dist/chunk-3Q2N7CSY.js.map +1 -0
- package/dist/{chunk-LJCNUP6M.js → chunk-4ABNXKAR.js} +2 -2
- package/dist/{chunk-D2CAV7MG.js → chunk-4DMFK67G.js} +2 -2
- package/dist/{chunk-MO5FGLVS.js → chunk-54QLV3OH.js} +11 -12
- package/dist/chunk-54QLV3OH.js.map +1 -0
- package/dist/{chunk-5F2YR5XV.js → chunk-6DBE562W.js} +15 -5
- package/dist/chunk-6DBE562W.js.map +1 -0
- package/dist/{chunk-RWOYPOMR.js → chunk-7Z4N4JWQ.js} +19 -245
- package/dist/chunk-7Z4N4JWQ.js.map +1 -0
- package/dist/{chunk-H6UTKTLK.js → chunk-DAUY2SB3.js} +98 -34
- package/dist/chunk-DAUY2SB3.js.map +1 -0
- package/dist/{chunk-2H7UWE2G.js → chunk-DP6YQFVO.js} +13 -12
- package/dist/chunk-DP6YQFVO.js.map +1 -0
- package/dist/{chunk-ILUVL7WM.js → chunk-DZD25NHW.js} +2 -2
- package/dist/{chunk-PCC4LBKB.js → chunk-EEAX7E2X.js} +2 -2
- package/dist/{chunk-IO5YBKHV.js → chunk-G6G2FT2G.js} +10 -8
- package/dist/chunk-G6G2FT2G.js.map +1 -0
- package/dist/{chunk-5QZAK6J7.js → chunk-H25VRR2T.js} +50 -18
- package/dist/chunk-H25VRR2T.js.map +1 -0
- package/dist/chunk-H2DHTJKW.js +1352 -0
- package/dist/chunk-H2DHTJKW.js.map +1 -0
- package/dist/{chunk-MHRC3KRX.js → chunk-H4CL23HG.js} +3 -3
- package/dist/chunk-H4CL23HG.js.map +1 -0
- package/dist/{chunk-F5T6TV4Z.js → chunk-IK6YOXZH.js} +40 -14
- package/dist/chunk-IK6YOXZH.js.map +1 -0
- package/dist/{chunk-HG4JPXJT.js → chunk-JG3B47P3.js} +23 -10
- package/dist/chunk-JG3B47P3.js.map +1 -0
- package/dist/{chunk-SY4X2LND.js → chunk-KUZBMEWR.js} +3 -3
- package/dist/{chunk-5OKLCVM4.js → chunk-KVVXINCJ.js} +3 -3
- package/dist/{chunk-PNMM5HNX.js → chunk-L4FHSOL5.js} +9 -10
- package/dist/chunk-L4FHSOL5.js.map +1 -0
- package/dist/{chunk-PMUABBPG.js → chunk-LKI3ENGQ.js} +9 -13
- package/dist/chunk-LKI3ENGQ.js.map +1 -0
- package/dist/{chunk-CLFHC2DK.js → chunk-OQB2CKBT.js} +17 -18
- package/dist/chunk-OQB2CKBT.js.map +1 -0
- package/dist/{chunk-HXKOIWLU.js → chunk-P6OKOH62.js} +2 -6
- package/dist/chunk-P6OKOH62.js.map +1 -0
- package/dist/{chunk-TNGMF4UX.js → chunk-PNRLBPGS.js} +12 -12
- package/dist/chunk-PNRLBPGS.js.map +1 -0
- package/dist/{chunk-Y5Y7XHVU.js → chunk-PZNXBORZ.js} +4 -4
- package/dist/{chunk-HTYH7CKN.js → chunk-Q7CAE5NN.js} +3 -3
- package/dist/{chunk-G47TDUK3.js → chunk-QNAMXQKF.js} +2 -2
- package/dist/{chunk-GS2NZ3GD.js → chunk-SJ4T5YLG.js} +5 -5
- package/dist/chunk-SJ4T5YLG.js.map +1 -0
- package/dist/{chunk-UMH2YZKG.js → chunk-TPQ5M3BW.js} +4 -6
- package/dist/{chunk-UMH2YZKG.js.map → chunk-TPQ5M3BW.js.map} +1 -1
- package/dist/{chunk-4G2YHZIM.js → chunk-TUXXBEBB.js} +4 -6
- package/dist/{chunk-4G2YHZIM.js.map → chunk-TUXXBEBB.js.map} +1 -1
- package/dist/{chunk-WFRTHH3A.js → chunk-TZRXWFF5.js} +3 -3
- package/dist/{chunk-TBOVYLQJ.js → chunk-VTIDLRNA.js} +2 -2
- package/dist/{chunk-OKH64JZE.js → chunk-WCZNQECQ.js} +2 -2
- package/dist/{chunk-ZUAZHDKP.js → chunk-WMVOJY6V.js} +277 -40
- package/dist/chunk-WMVOJY6V.js.map +1 -0
- package/dist/{chunk-YO2LTXB4.js → chunk-X52QUV4U.js} +115 -10
- package/dist/chunk-X52QUV4U.js.map +1 -0
- package/dist/{chunk-IXRZAHZF.js → chunk-XNYHMRVJ.js} +4 -4
- package/dist/{chunk-VPASBA7P.js → chunk-YXI3BTQQ.js} +2 -2
- package/dist/commands/build/marketplace.js +9 -12
- package/dist/commands/build/marketplace.js.map +1 -1
- package/dist/commands/build/plugins.js +9 -12
- package/dist/commands/build/plugins.js.map +1 -1
- package/dist/commands/compile.js +15 -19
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/doctor.js +75 -54
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +154 -109
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +68 -38
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/init.js +36 -39
- package/dist/commands/list.js +8 -10
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/new/marketplace.js +8 -11
- package/dist/commands/new/marketplace.js.map +1 -1
- package/dist/commands/search.js +10 -13
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/share.js +8 -10
- package/dist/commands/share.js.map +1 -1
- package/dist/commands/uninstall.js +39 -28
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +7 -10
- 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 -5
- package/dist/components/wizard/checkbox-grid.js +4 -4
- package/dist/components/wizard/domain-selection.js +9 -11
- package/dist/components/wizard/run-wizard-session.js +26 -28
- package/dist/components/wizard/scroll-affordance.js +2 -2
- package/dist/components/wizard/skill-agent-summary.js +5 -7
- package/dist/components/wizard/source-grid.js +5 -6
- package/dist/components/wizard/stack-selection.js +7 -9
- package/dist/components/wizard/step-agents.js +8 -10
- package/dist/components/wizard/step-build.js +7 -9
- package/dist/components/wizard/step-confirm.js +9 -11
- package/dist/components/wizard/step-sources.js +8 -10
- package/dist/components/wizard/step-stack.js +8 -10
- package/dist/components/wizard/summary-panel.js +8 -10
- package/dist/components/wizard/toast.js +2 -2
- package/dist/components/wizard/wizard-layout.js +12 -14
- package/dist/components/wizard/wizard-tabs.js +2 -4
- package/dist/components/wizard/wizard.js +25 -27
- package/dist/hooks/init.js +36 -39
- package/dist/hooks/init.js.map +1 -1
- package/dist/load-agent-defs-2VYAV5GL.js +13 -0
- package/dist/recompile-project-agents-NG5DCPHJ.js +17 -0
- package/dist/{source-loader-3DL3NYUX.js → source-loader-CO2FZ3OO.js} +4 -8
- package/dist/src/agents/_templates/agent.liquid +2 -2
- package/dist/stores/wizard-store.js +6 -6
- package/package.json +2 -4
- package/src/agents/_templates/agent.liquid +2 -2
- package/src/schemas/custom-metadata.schema.json +1 -1
- package/src/schemas/marketplace.schema.json +2 -1
- package/dist/chunk-2H7UWE2G.js.map +0 -1
- package/dist/chunk-4A4L3YIW.js.map +0 -1
- package/dist/chunk-5F2YR5XV.js.map +0 -1
- package/dist/chunk-5QZAK6J7.js.map +0 -1
- package/dist/chunk-6RLV45HN.js.map +0 -1
- package/dist/chunk-CLFHC2DK.js.map +0 -1
- package/dist/chunk-F2AMBBIA.js +0 -64
- package/dist/chunk-F2AMBBIA.js.map +0 -1
- package/dist/chunk-F5T6TV4Z.js.map +0 -1
- package/dist/chunk-GS2NZ3GD.js.map +0 -1
- package/dist/chunk-H6UTKTLK.js.map +0 -1
- package/dist/chunk-HG4JPXJT.js.map +0 -1
- package/dist/chunk-HXKOIWLU.js.map +0 -1
- package/dist/chunk-IO5YBKHV.js.map +0 -1
- package/dist/chunk-MHRC3KRX.js.map +0 -1
- package/dist/chunk-MO5FGLVS.js.map +0 -1
- package/dist/chunk-PMUABBPG.js.map +0 -1
- package/dist/chunk-PNMM5HNX.js.map +0 -1
- package/dist/chunk-RWOYPOMR.js.map +0 -1
- package/dist/chunk-TNGMF4UX.js.map +0 -1
- package/dist/chunk-VASLW636.js +0 -23
- package/dist/chunk-VASLW636.js.map +0 -1
- package/dist/chunk-WCAUUBHO.js.map +0 -1
- package/dist/chunk-WUQ3MTPF.js +0 -173
- package/dist/chunk-WUQ3MTPF.js.map +0 -1
- package/dist/chunk-XAXJWXI4.js +0 -1667
- package/dist/chunk-XAXJWXI4.js.map +0 -1
- package/dist/chunk-YO2LTXB4.js.map +0 -1
- package/dist/chunk-ZUAZHDKP.js.map +0 -1
- package/dist/copy-local-skills-NSUTBVLJ.js +0 -14
- package/dist/load-agent-defs-X4E57I2U.js +0 -15
- package/dist/loader-G6BFG2VA.js +0 -24
- package/dist/recompile-project-agents-JE4MM72I.js +0 -20
- package/dist/recompile-project-agents-JE4MM72I.js.map +0 -1
- package/dist/source-loader-3DL3NYUX.js.map +0 -1
- /package/dist/{chunk-LJCNUP6M.js.map → chunk-4ABNXKAR.js.map} +0 -0
- /package/dist/{chunk-D2CAV7MG.js.map → chunk-4DMFK67G.js.map} +0 -0
- /package/dist/{chunk-ILUVL7WM.js.map → chunk-DZD25NHW.js.map} +0 -0
- /package/dist/{chunk-PCC4LBKB.js.map → chunk-EEAX7E2X.js.map} +0 -0
- /package/dist/{chunk-SY4X2LND.js.map → chunk-KUZBMEWR.js.map} +0 -0
- /package/dist/{chunk-5OKLCVM4.js.map → chunk-KVVXINCJ.js.map} +0 -0
- /package/dist/{chunk-Y5Y7XHVU.js.map → chunk-PZNXBORZ.js.map} +0 -0
- /package/dist/{chunk-HTYH7CKN.js.map → chunk-Q7CAE5NN.js.map} +0 -0
- /package/dist/{chunk-G47TDUK3.js.map → chunk-QNAMXQKF.js.map} +0 -0
- /package/dist/{chunk-WFRTHH3A.js.map → chunk-TZRXWFF5.js.map} +0 -0
- /package/dist/{chunk-TBOVYLQJ.js.map → chunk-VTIDLRNA.js.map} +0 -0
- /package/dist/{chunk-OKH64JZE.js.map → chunk-WCZNQECQ.js.map} +0 -0
- /package/dist/{chunk-IXRZAHZF.js.map → chunk-XNYHMRVJ.js.map} +0 -0
- /package/dist/{chunk-VPASBA7P.js.map → chunk-YXI3BTQQ.js.map} +0 -0
- /package/dist/{copy-local-skills-NSUTBVLJ.js.map → load-agent-defs-2VYAV5GL.js.map} +0 -0
- /package/dist/{load-agent-defs-X4E57I2U.js.map → recompile-project-agents-NG5DCPHJ.js.map} +0 -0
- /package/dist/{loader-G6BFG2VA.js.map → source-loader-CO2FZ3OO.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/lib/operations/source/load-source.ts","../src/cli/lib/operations/project/detect-project.ts","../src/cli/lib/operations/project/detect-both-installations.ts","../src/cli/lib/config-gate/propagate.ts","../src/cli/lib/configuration/config-writer.ts","../src/cli/lib/config-gate/index.ts","../src/cli/lib/config-gate/classify.ts","../src/cli/lib/config-gate/deps.ts","../src/cli/lib/config-gate/pair-writer.ts","../src/cli/lib/config-gate/recompile.ts","../src/cli/lib/operations/project/write-project-config.ts","../src/cli/lib/operations/project/compile-agents-all-scopes.ts"],"sourcesContent":["import { loadSkillsMatrixFromSource, type SourceLoadResult } from \"../../loading/index.js\";\nimport type { SourceCaller } from \"../../configuration/index.js\";\nimport {\n enableBuffering,\n drainBuffer,\n disableBuffering,\n type StartupMessage,\n} from \"../../../utils/logger.js\";\n\nexport type LoadSourceOptions = {\n /** Whether this load may reach the init-time source rungs — see {@link SourceCaller}. */\n caller?: SourceCaller;\n sourceFlag?: string;\n projectDir: string;\n /** When true, enables message buffering and captures startup messages. Default: false. */\n captureStartupMessages?: boolean;\n};\n\nexport type LoadedSource = {\n sourceResult: SourceLoadResult;\n /** Empty array when captureStartupMessages is false. */\n startupMessages: StartupMessage[];\n};\n\n/**\n * Loads the skills matrix from a resolved source.\n *\n * When `captureStartupMessages` is true, wraps the load in buffer mode so\n * warn() calls during loading are captured instead of written to stderr.\n * The caller (init/edit) hands them to the wizard, which paints them as a band\n * above the step — stderr does not survive the wizard clearing the terminal.\n *\n * @throws {Error} If source resolution or fetching fails.\n */\nexport async function loadSource(options: LoadSourceOptions): Promise<LoadedSource> {\n const { caller, sourceFlag, projectDir, captureStartupMessages } = options;\n\n if (captureStartupMessages) {\n enableBuffering();\n }\n\n let sourceResult: SourceLoadResult;\n try {\n sourceResult = await loadSkillsMatrixFromSource({\n ...(caller !== undefined && { caller }),\n ...(sourceFlag !== undefined && { sourceFlag }),\n projectDir,\n });\n } catch (error) {\n if (captureStartupMessages) {\n disableBuffering();\n }\n throw error;\n }\n\n let startupMessages: StartupMessage[] = [];\n if (captureStartupMessages) {\n startupMessages = drainBuffer();\n disableBuffering();\n }\n\n return { sourceResult, startupMessages };\n}\n","import { detectInstallation, type Installation } from \"../../installation/index.js\";\nimport { ConfigLoadError, loadProjectConfig } from \"../../configuration/index.js\";\nimport type { ProjectConfig } from \"../../../types/index.js\";\n\nexport type DetectedProject = {\n installation: Installation;\n config: ProjectConfig | null;\n configPath: string | null;\n};\n\n/**\n * Detects an existing CLI installation and loads its project config.\n *\n * Uses detectInstallation() which checks project-level first, then falls back\n * to global. Returns the installation metadata plus the loaded config.\n *\n * Does NOT throw. Returns null when no installation is found OR when the config\n * file exists but is corrupt — the caller (doctor, edit) reports the resulting\n * null as a config/installation problem to the user. `compile` deliberately\n * does NOT use this wrapper: it detects scopes directly so it can hard-error on\n * a corrupt config instead of degrading to null.\n */\nexport async function detectProject(projectDir?: string): Promise<DetectedProject | null> {\n const resolvedDir = projectDir ?? process.cwd();\n\n let installation: Installation | null;\n try {\n installation = await detectInstallation(resolvedDir);\n } catch (error) {\n if (error instanceof ConfigLoadError) return null;\n throw error;\n }\n\n if (!installation) {\n return null;\n }\n\n const loaded = await loadProjectConfig(installation.projectDir);\n\n return {\n installation,\n config: loaded?.config ?? null,\n configPath: loaded?.configPath ?? null,\n };\n}\n","import {\n detectGlobalInstallation,\n detectProjectInstallation,\n isHomeDirectory,\n type Installation,\n} from \"../../installation/index.js\";\n\nexport type BothInstallations = {\n global: Installation | null;\n project: Installation | null;\n hasBoth: boolean;\n};\n\n/**\n * Detects both global and project installations.\n *\n * Skips project detection when projectDir is the home directory\n * to avoid double-compile. Returns a convenience `hasBoth` flag\n * used by callers to set scopeFilter on compile passes.\n */\nexport async function detectBothInstallations(projectDir: string): Promise<BothInstallations> {\n const global = await detectGlobalInstallation();\n\n const project = isHomeDirectory(projectDir) ? null : await detectProjectInstallation(projectDir);\n return { global, project, hasBoth: !!global && !!project };\n}\n","import fs from \"fs\";\nimport { isDeepEqual, unique } from \"remeda\";\nimport type {\n AgentDefinition,\n AgentName,\n Category,\n MergedSkillsMatrix,\n ProjectConfig,\n SkillAssignment,\n SkillId,\n StackAgentConfig,\n} from \"../../types\";\nimport type { AgentScopeConfig, SkillConfig } from \"../../types/config\";\nimport { getProjectConfigPath } from \"../installation/install-base-dir\";\nimport { loadProjectConfigFromDir } from \"../configuration/project-config\";\nimport { mergeConfigs, type AuthoritativeScope } from \"../configuration/config-merger\";\nimport {\n activeProjectAgentNames,\n isActiveAt,\n isGlobalTombstone,\n type ScopedEntry,\n} from \"../configuration/scope-predicates\";\nimport { generateConfigSource, type ConfigSourceOptions } from \"../configuration/config-writer\";\nimport {\n buildConfigTypesBackgroundData,\n type ConfigTypesExtras,\n deriveCategories,\n deriveDomains,\n regenerateConfigTypes,\n} from \"../configuration/config-types-writer\";\nimport { fileExists, writeFile } from \"../../utils/fs\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { verbose } from \"../../utils/logger\";\nimport { typedEntries, typedKeys } from \"../../utils/typed-object\";\nimport { GLOBAL_CONFIG_NAME, LOCAL_PSEUDO_CATEGORY } from \"../../consts\";\n\nexport async function writeConfigFile(\n config: ProjectConfig,\n configPath: string,\n options?: ConfigSourceOptions,\n): Promise<void> {\n const source = generateConfigSource(config, options);\n await writeFile(configPath, source);\n}\n\n/**\n * Deep-additive stack merge: appends any (agent, category, skill) triple present in\n * `incoming` but missing in `existing`. Never removes or overwrites existing entries\n * (including their `preloaded` flags). Returns a fresh stack object — inputs are not\n * mutated. `changed` is true iff at least one new agent, category, or skill assignment\n * was appended.\n */\nfunction additiveMergeStack(\n existing: Partial<Record<AgentName, StackAgentConfig>> | undefined,\n incoming: Partial<Record<AgentName, StackAgentConfig>> | undefined,\n): { stack: Partial<Record<AgentName, StackAgentConfig>>; changed: boolean } {\n const merged: Partial<Record<AgentName, StackAgentConfig>> = existing\n ? structuredClone(existing)\n : {};\n if (!incoming) return { stack: merged, changed: false };\n\n let changed = false;\n for (const [agentName, incomingAgentStack] of typedEntries<AgentName, StackAgentConfig>(\n incoming,\n )) {\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 (!incomingAgentStack) continue;\n\n const existingAgentStack = merged[agentName];\n if (!existingAgentStack) {\n merged[agentName] = structuredClone(incomingAgentStack);\n changed = true;\n continue;\n }\n\n if (mergeAgentCategories(existingAgentStack, incomingAgentStack)) {\n changed = true;\n }\n }\n\n return { stack: merged, changed };\n}\n\n/**\n * Mutates `existingAgentStack` in place by appending any category or skill assignment\n * from `incomingAgentStack` that is not already present. Returns true if anything was\n * appended. Caller must pass a cloned `existingAgentStack` — this function is only\n * called on the merged copy, never on the original input.\n */\nfunction mergeAgentCategories(\n existingAgentStack: StackAgentConfig,\n incomingAgentStack: StackAgentConfig,\n): boolean {\n let changed = false;\n for (const [category, incomingAssignments] of typedEntries<Category, SkillAssignment[]>(\n incomingAgentStack,\n )) {\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 (!incomingAssignments) continue;\n\n const existingAssignments = existingAgentStack[category];\n if (!existingAssignments) {\n existingAgentStack[category] = incomingAssignments.map((a) => ({ ...a }));\n changed = true;\n continue;\n }\n\n const existingIds = new Set(existingAssignments.map((a) => a.id));\n for (const assignment of incomingAssignments) {\n if (!existingIds.has(assignment.id)) {\n existingAssignments.push({ ...assignment });\n existingIds.add(assignment.id);\n changed = true;\n }\n }\n }\n return changed;\n}\n\n/**\n * Merges new global-scoped items into an existing global config.\n * Adds skills/agents that don't already exist. Never removes existing items.\n *\n * Exported for unit testing. See `mergeGlobalConfigs` describe block in\n * `local-installer.test.ts`.\n */\nexport function mergeGlobalConfigs(\n existing: ProjectConfig,\n incoming: ProjectConfig,\n): { config: ProjectConfig; changed: boolean } {\n const existingSkillIds = new Set(existing.skills.map((s) => s.id));\n const existingAgentNames = new Set(existing.agents.map((a) => a.name));\n\n const incomingActiveSkills = incoming.skills.filter((s) => !s.excluded);\n const incomingActiveAgents = incoming.agents.filter((a) => !a.excluded);\n const newSkills = incomingActiveSkills.filter((s) => !existingSkillIds.has(s.id));\n const newAgents = incomingActiveAgents.filter((a) => !existingAgentNames.has(a.name));\n\n const mergedSkills = [...existing.skills, ...newSkills];\n const mergedAgents = [...existing.agents, ...newAgents];\n\n // Per-agent stack merge policy: deep-additive. Project-context edits must NEVER remove\n // or overwrite global state; individual projects express their local view via tombstones\n // in the PROJECT config, not by rewriting the GLOBAL config (see commit 403df46:\n // \"never modify global config from project-level operations\").\n //\n // Merge rule per triple (agent, category, skill):\n // - agent absent in existing -> add from incoming\n // - category absent in existing -> add from incoming\n // - skill id absent in existing -> append from incoming\n // - everything already present -> keep existing as-is (including its preloaded flag)\n // Anything present only in `existing` is left untouched.\n const { stack: mergedStack, changed: stackChanged } = additiveMergeStack(\n existing.stack,\n incoming.stack,\n );\n\n // Merge selected domains (union, no duplicates)\n const mergedSelectedDomains = [\n ...new Set([...(existing.selectedDomains ?? []), ...(incoming.selectedDomains ?? [])]),\n ];\n\n // Marketplace identity (`marketplace`, `marketplaceName`) travels on the global partition of\n // `splitConfigByScope` but was previously lost here, leaving the global config with no\n // record of where its plugins came from. `uninstall` reads `config.marketplaceName` to build\n // the `<id>@<marketplace name>` registry key (getCliInstalledPluginKeys) — without it a global\n // uninstall silently owns nothing and leaves registered plugins behind.\n //\n // Precedence is FILL-ONLY: existing wins, incoming is used solely when the global config\n // has no value yet. Both fields are scalar but the merged config is multi-marketplace by\n // construction — this merge never removes skills, so after a second project init from a\n // different marketplace the skills array holds plugins from BOTH, and whichever label is\n // recorded orphans the other's registry key. Repointing is therefore never a strict\n // improvement, and doing it from a project context would silently rewrite global state on\n // behalf of every other registered project (commit 403df46). This also matches\n // `mergeConfigs`, which preserves `existingConfig.marketplaceName` on the home-root install\n // path. Changing global marketplace identity stays an explicit global-scope operation\n // (`init` run from ~), which writes the global config directly and bypasses this merge.\n const mergedMarketplaceName = existing.marketplaceName ?? incoming.marketplaceName;\n const mergedMarketplace = existing.marketplace ?? incoming.marketplace;\n\n // Newly-filled marketplace identity must mark the merge dirty: this flag becomes\n // `resolveEffectiveGlobalConfig`'s `changed`, which is the condition `writeFromProjectContext`\n // (lib/config-gate/index.ts) tests before calling `writeGlobalPair`, so a run whose only delta\n // is the now-known marketplace would otherwise skip the global write and drop the field again.\n const changed =\n newSkills.length > 0 ||\n newAgents.length > 0 ||\n stackChanged ||\n !isDeepEqual(existing.selectedDomains ?? [], mergedSelectedDomains) ||\n mergedMarketplaceName !== existing.marketplaceName ||\n mergedMarketplace !== existing.marketplace;\n\n return {\n config: {\n ...existing,\n skills: mergedSkills,\n agents: mergedAgents,\n stack: mergedStack,\n selectedDomains: mergedSelectedDomains,\n ...(mergedMarketplaceName !== undefined && { marketplaceName: mergedMarketplaceName }),\n ...(mergedMarketplace !== undefined && { marketplace: mergedMarketplace }),\n },\n changed,\n };\n}\n\n/**\n * The single normalization for every value compared against the global config's\n * `projects` array — the one written by {@link registerProjectPath}, the one the\n * gate's `deregister-project` mutation filters against, and the current-project\n * skip in {@link propagateGlobalChangesToProjects}. Symlinks are resolved, so an entry\n * stored under one of them matches byte-for-byte under the others. The two ends\n * normalizing differently is what left symlinked layouts (macOS `/tmp`, a\n * `~/dev/repo` pointing at `/data/repo`) registered forever after an uninstall.\n *\n * Throws when the directory does not exist. That is deliberate: a path that\n * cannot be resolved is an error, not a cue to fall back to a weaker\n * normalization — a second tier would reintroduce exactly the asymmetry this\n * helper exists to remove. The one caller that must survive it (`uninstall`'s\n * deregistration) already wraps the call in a warn-and-continue guard.\n */\nexport function normalizeProjectPath(projectDir: string): string {\n return fs.realpathSync(projectDir);\n}\n\n/**\n * Registers a project directory in the global config's `projects` array.\n * Paths are normalized via {@link normalizeProjectPath} to resolve symlinks.\n * Filters stale entries (where .claude-src/config.ts no longer exists).\n */\nasync function registerProjectPath(\n globalConfig: ProjectConfig,\n projectDir: string,\n): Promise<{ config: ProjectConfig; changed: boolean }> {\n const normalizedPath = normalizeProjectPath(projectDir);\n const existing = globalConfig.projects ?? [];\n\n // Filter stale entries\n const staleChecks = await Promise.all(\n existing.map(async (p) => ({\n path: p,\n hasConfig: await fileExists(getProjectConfigPath(p)),\n })),\n );\n const valid = staleChecks.filter((c) => c.hasConfig).map((c) => c.path);\n\n if (valid.includes(normalizedPath)) {\n const changed = valid.length !== existing.length;\n return { config: changed ? { ...globalConfig, projects: valid } : globalConfig, changed };\n }\n\n return { config: { ...globalConfig, projects: [...valid, normalizedPath] }, changed: true };\n}\n\nfunction isProjectScopedEntry(entry: ScopedEntry): boolean {\n return entry.scope === \"project\";\n}\n\n/** True when the global config still has an active (non-excluded) skill for this id. */\nfunction globalHasActiveSkill(globalConfig: ProjectConfig, id: SkillId): boolean {\n return globalConfig.skills.some((s) => s.id === id && isActiveAt(s, \"global\"));\n}\n\n/** True when the global config still has an active (non-excluded) agent for this name. */\nfunction globalHasActiveAgent(globalConfig: ProjectConfig, name: AgentName): boolean {\n return globalConfig.agents.some((a) => a.name === name && isActiveAt(a, \"global\"));\n}\n\n/**\n * Keeps a project's own skill entries when re-inlining fresh global data, dropping\n * tombstones that no longer correspond to a real global install.\n *\n * A tombstone (`scope === \"global\" && excluded`) only has meaning while the global entry\n * it masks still exists. Once the skill has been removed from the global config, the\n * tombstone is stale — carrying it forward would leave the project showing a masked\n * global item that no longer exists. Project-scoped entries are always retained.\n */\nfunction retainProjectOwnedSkills(\n skills: SkillConfig[],\n globalConfig: ProjectConfig,\n): SkillConfig[] {\n return skills.filter(\n (entry) =>\n isProjectScopedEntry(entry) ||\n (isGlobalTombstone(entry) && globalHasActiveSkill(globalConfig, entry.id)),\n );\n}\n\n/** Agent mirror of {@link retainProjectOwnedSkills}. */\nfunction retainProjectOwnedAgents(\n agents: AgentScopeConfig[],\n globalConfig: ProjectConfig,\n): AgentScopeConfig[] {\n return agents.filter(\n (entry) =>\n isProjectScopedEntry(entry) ||\n (isGlobalTombstone(entry) && globalHasActiveAgent(globalConfig, entry.name)),\n );\n}\n\n/**\n * Category a skill belongs to according to the MERGED matrix. `undefined` when the\n * matrix has no entry for the id (a user-authored local skill carries no matrix\n * record) or when the entry sits in the `local` pseudo-category — neither\n * participates in category rules, and neither may throw.\n */\nfunction categoryOfSkill(id: SkillId, matrix: MergedSkillsMatrix): Category | undefined {\n const category = matrix.skills[id]?.category;\n if (category === undefined || category === LOCAL_PSEUDO_CATEGORY) return undefined;\n return category;\n}\n\n/**\n * True when the merged matrix DECLARES this category as holding at most one skill.\n * Read from the matrix passed in rather than `defaultCategories` so a source repo's\n * category overrides are honoured.\n *\n * A category the matrix does not declare is deliberately NOT treated as exclusive.\n * The wizard's toggle handler defaults an undeclared one to exclusive\n * (`use-build-step-props.ts` uses `matrix.categories[categoryId]?.exclusive ?? true`),\n * but a rule that MASKS persisted entries must only fire on a flag the data\n * actually carries.\n */\nfunction isExclusiveCategory(category: Category, matrix: MergedSkillsMatrix): boolean {\n return matrix.categories[category]?.exclusive === true;\n}\n\n/** Categories occupied by an active project-scoped skill, per the merged matrix. */\nfunction activeProjectCategories(\n projectOwnedSkills: SkillConfig[],\n matrix: MergedSkillsMatrix,\n): Set<Category> {\n return new Set(\n projectOwnedSkills\n .filter((s) => isActiveAt(s, \"project\"))\n .map((s) => categoryOfSkill(s.id, matrix))\n .filter((category): category is Category => category !== undefined),\n );\n}\n\n/**\n * The collision that justifies masking a live global skill. Two kinds, both read from the\n * project's OWN entries: IDENTITY — the project owns the same id at project scope; CATEGORY —\n * the project owns a different active skill in the same category and the matrix declares that\n * category exclusive.\n *\n * Shared by the mask producer ({@link maskCollidingGlobalSkills}) and the self-heal that\n * removes a mask once its collision clears ({@link dropOrphanedDerivedMasks}), so the two can\n * never disagree about what a mask means.\n */\nfunction buildProjectCollisionTest(\n projectOwnedSkills: SkillConfig[],\n matrix: MergedSkillsMatrix,\n): (id: SkillId) => boolean {\n const ownedIds = new Set(\n projectOwnedSkills.filter((s) => isActiveAt(s, \"project\")).map((s) => s.id),\n );\n const occupiedExclusiveCategories = new Set(\n [...activeProjectCategories(projectOwnedSkills, matrix)].filter((category) =>\n isExclusiveCategory(category, matrix),\n ),\n );\n\n return (id) => {\n if (ownedIds.has(id)) return true;\n const category = categoryOfSkill(id, matrix);\n return category !== undefined && occupiedExclusiveCategories.has(category);\n };\n}\n\n/**\n * Drops a derived mask that no longer masks anything, so the global install becomes\n * visible again once the collision that produced it is gone.\n *\n * A derived mask and a user-authored tombstone are BYTE-IDENTICAL in config.ts — both are\n * `{ id, scope: \"global\", excluded: true }` — but the wizard can no longer mint\n * the second kind on its own: a project-scope deselect of a globally-installed skill is\n * refused, and a domain deselect only drops what the project owns. The one user route to a\n * global tombstone is the `s` scope toggle (G→P), which always pairs the tombstone with an\n * active project entry for the same id — an IDENTITY collision. So every bare mask is\n * machine-derived, and a single retention test suffices: keep it iff the collision that\n * would re-derive it is still there, in `required` and optional categories alike.\n */\nfunction dropOrphanedDerivedMasks(\n projectOwnedSkills: SkillConfig[],\n matrix: MergedSkillsMatrix,\n): SkillConfig[] {\n const collidesWithProjectOwnership = buildProjectCollisionTest(projectOwnedSkills, matrix);\n return projectOwnedSkills.filter(\n (entry) => !isGlobalTombstone(entry) || collidesWithProjectOwnership(entry.id),\n );\n}\n\n/**\n * Agent mirror of {@link dropOrphanedDerivedMasks}, identity collisions only: agents\n * have no categories, so the project-scoped sibling with the same name is the only thing a\n * mask can be justified by.\n */\nfunction dropOrphanedDerivedAgentMasks(projectOwnedAgents: AgentScopeConfig[]): AgentScopeConfig[] {\n const ownedNames = new Set(activeProjectAgentNames(projectOwnedAgents));\n return projectOwnedAgents.filter(\n (entry) => !isGlobalTombstone(entry) || ownedNames.has(entry.name),\n );\n}\n\n/**\n * Builds the tombstones that mask live global skills this project cannot show\n * alongside what it already owns at project scope. Two collision kinds, both keyed\n * against the SAME live global config:\n *\n * 1. IDENTITY — the project owns the same id at project scope. Without the\n * mask, `partitionInlinedConfigEntries` re-inlines the global copy as a SECOND\n * active entry, leaving one id active at BOTH scopes instead of rendering the\n * dual-scope `[P][G]` pair.\n * 2. CATEGORY — the project owns a DIFFERENT active skill in the same category and\n * the matrix declares that category exclusive. Reconciliation keyed on identity\n * alone cannot see this, so a project owning Vue plus a global install of React\n * ends up with two active skills in a category that permits one.\n *\n * The project-owned skill wins locally. This is DELIBERATELY ASYMMETRIC with the `s`\n * round trip, where a user-initiated radio swap in `toggleTechnology` refuses to displace a\n * globally-locked skill: there the user is actively trying to drop a shared install,\n * whereas here the collision is PUSHED IN by a global install landing on pre-existing\n * project state. Letting global win would silently uninstall the user's own skill.\n *\n * Tombstones are spread from the global entry so they carry the global install's\n * `origin`. A skill the project merely inherits (no active project-scope entry, no\n * exclusive-category collision) is skipped — it stays a single active global entry.\n * A skill the project already tombstones is skipped so re-running is idempotent.\n */\nfunction maskCollidingGlobalSkills(\n projectOwnedSkills: SkillConfig[],\n globalConfig: ProjectConfig,\n matrix: MergedSkillsMatrix,\n): SkillConfig[] {\n const collidesWithProjectOwnership = buildProjectCollisionTest(projectOwnedSkills, matrix);\n const alreadyTombstoned = new Set(projectOwnedSkills.filter(isGlobalTombstone).map((s) => s.id));\n\n return globalConfig.skills\n .filter(\n (globalEntry) =>\n isActiveAt(globalEntry, \"global\") &&\n collidesWithProjectOwnership(globalEntry.id) &&\n !alreadyTombstoned.has(globalEntry.id),\n )\n .map((globalEntry) => ({ ...globalEntry, excluded: true }));\n}\n\n/**\n * Agent mirror of {@link maskCollidingGlobalSkills}, identity collisions only.\n * Agents have no categories, so there is no grouping dimension to reconcile.\n */\nfunction maskCollidingGlobalAgents(\n projectOwnedAgents: AgentScopeConfig[],\n globalConfig: ProjectConfig,\n): AgentScopeConfig[] {\n const ownedNames = new Set(activeProjectAgentNames(projectOwnedAgents));\n const alreadyTombstoned = new Set(\n projectOwnedAgents.filter(isGlobalTombstone).map((a) => a.name),\n );\n\n return globalConfig.agents\n .filter(\n (globalEntry) =>\n isActiveAt(globalEntry, \"global\") &&\n ownedNames.has(globalEntry.name) &&\n !alreadyTombstoned.has(globalEntry.name),\n )\n .map((globalEntry) => ({ ...globalEntry, excluded: true }));\n}\n\n/**\n * Reconciles a project's OWN entries against the live global config, immediately\n * before the inlining writer merges the two.\n *\n * Applied at BOTH sites that write a project `config.ts` with `globalConfig` inlined:\n * `propagateGlobalChangesToProjects` (a global change fanning out to registered\n * projects) and the project-scope save branch of `writeScopedFromWizard` (an ordinary\n * project `init`/`edit` performed while the colliding skill is already active\n * globally). Either site alone can produce the malformed shape, so both must run it.\n *\n * Self-heal runs BEFORE masking on BOTH axes so a mask whose collision has cleared is\n * removed rather than immediately re-derived, and so masking's `alreadyTombstoned` guard\n * only sees tombstones that are still warranted.\n *\n * Masking is PROJECT-LOCAL: it is applied to the project split only. The global\n * config passed in is read, never rewritten — tombstones never belong in\n * `~/.claude-src/config.ts`.\n */\nexport function reconcileProjectSplitAgainstGlobal(\n projectSplit: ProjectConfig,\n globalConfig: ProjectConfig,\n matrix: MergedSkillsMatrix,\n): ProjectConfig {\n const healedSkills = dropOrphanedDerivedMasks(projectSplit.skills, matrix);\n const healedAgents = dropOrphanedDerivedAgentMasks(projectSplit.agents);\n return {\n ...projectSplit,\n skills: [...healedSkills, ...maskCollidingGlobalSkills(healedSkills, globalConfig, matrix)],\n agents: [...healedAgents, ...maskCollidingGlobalAgents(healedAgents, globalConfig)],\n };\n}\n\n/**\n * Computes the skill ids that this project inherited from global scope but that are\n * no longer active at global scope after the change being propagated — and that the\n * project does not own at project scope. These are the only ids that should be pruned\n * from the project's stack: a project-scoped agent may legitimately reference a\n * globally-installed skill, and once that skill is removed at global scope the\n * reference becomes dangling.\n *\n * `priorProjectSkills` is the project's pre-reconciliation (on-disk, inlined) skills.\n * A global skill that was just removed still appears here as a `scope: \"global\"`,\n * non-excluded entry, which is the signal we key on. Project-scoped skills and\n * user-authored local skills (which carry no SkillConfig entry at all) are never in\n * this set, so they are always preserved.\n */\nfunction computeRemovedGlobalSkillIds(\n priorProjectSkills: SkillConfig[],\n globalConfig: ProjectConfig,\n): Set<SkillId> {\n const activeGlobalIds = new Set(\n globalConfig.skills.filter((s) => isActiveAt(s, \"global\")).map((s) => s.id),\n );\n const projectOwnedIds = new Set(\n priorProjectSkills.filter((s) => isActiveAt(s, \"project\")).map((s) => s.id),\n );\n return new Set(\n priorProjectSkills\n .filter(\n (s) =>\n s.scope === \"global\" &&\n !s.excluded &&\n !activeGlobalIds.has(s.id) &&\n !projectOwnedIds.has(s.id),\n )\n .map((s) => s.id),\n );\n}\n\n/**\n * Prunes stack references to global skills that were just removed at global scope,\n * so a project-scoped agent stops referencing a skill that no longer exists anywhere.\n * Only ids in `removedGlobalSkillIds` are dropped — every other assignment is kept\n * verbatim, in order, with its `preloaded` flag untouched. Categories and agents left\n * empty by the pruning are removed. When nothing was removed, the stack is returned\n * unchanged so unaffected projects produce byte-identical config output.\n */\nfunction retainReconciledStack(\n stack: Record<string, StackAgentConfig> | undefined,\n removedGlobalSkillIds: Set<SkillId>,\n): Record<string, StackAgentConfig> | undefined {\n if (!stack || removedGlobalSkillIds.size === 0) return stack;\n\n const reconciled: Record<string, StackAgentConfig> = {};\n for (const [agent, agentStack] of Object.entries(stack)) {\n const reconciledAgentStack: StackAgentConfig = {};\n for (const [category, assignments] of 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 if (!assignments) continue;\n const kept = assignments.filter((assignment) => !removedGlobalSkillIds.has(assignment.id));\n if (kept.length > 0) reconciledAgentStack[category] = kept;\n }\n if (typedKeys<Category>(reconciledAgentStack).length > 0) {\n reconciled[agent] = reconciledAgentStack;\n }\n }\n return reconciled;\n}\n\n/** The registered projects one fan-out rewrote, and the ones it could not reach. */\nexport type PropagationResult = {\n updated: string[];\n skipped: string[];\n};\n\nexport type PropagationOptions = {\n /**\n * Whether each project's config-types.ts is rewritten alongside its config.ts.\n * False for a change that moves no type union — a project inlines the global\n * scalars into its config half, but no union is derived from them.\n */\n regenerateTypes?: boolean;\n};\n\n/**\n * The single writer for a project's config pair, used by BOTH sites that emit\n * one: the per-project propagation step below and the project branch of the\n * wizard write.\n *\n * `buildProjectTypesExtras` is fed the EFFECTIVE config — the project's own\n * reconciled rows plus the active global rows the writer is about to inline —\n * at both sites. The emitted config.ts names every one of those rows, so extras\n * derived from the project split alone declare fewer literals than the sibling\n * config.ts uses, and the pair stops type-checking against itself.\n */\nexport async function writeProjectConfigPair(\n projectDir: string,\n reconciledSplit: ProjectConfig,\n effectiveGlobal: ProjectConfig,\n matrix: MergedSkillsMatrix,\n agents: Partial<Record<AgentName, AgentDefinition>>,\n options: PropagationOptions = {},\n): Promise<void> {\n // Reconcile-before-both-writes: the two halves are derived from the same\n // reconciled data in the same call, so neither can describe a config the other\n // does not.\n await writeConfigFile(reconciledSplit, getProjectConfigPath(projectDir), {\n isProjectConfig: true,\n globalConfig: effectiveGlobal,\n });\n\n if (options.regenerateTypes === false) return;\n\n // Uses the same global-aware path for project types — emits\n // `import type { SkillId as GlobalSkillId, ... }` and extends with any\n // project-scoped items the project owns. Without this, a global-scope install\n // would overwrite the project's import-form types with the standalone/inlined\n // form.\n await regenerateConfigTypes(\n projectDir,\n Promise.resolve(buildConfigTypesBackgroundData(matrix, agents)),\n buildProjectTypesExtras(inlinedProjectView(reconciledSplit, effectiveGlobal), matrix),\n );\n}\n\n/**\n * The rows the inlining writer draws a project's config.ts from: the project's\n * own reconciled entries plus everything the global config contributes. Union\n * membership is decided downstream by `buildProjectTypesExtras`, which reads the\n * active entries — a tombstone's id always arrives via the live global row it\n * masks.\n */\nfunction inlinedProjectView(\n reconciledSplit: ProjectConfig,\n effectiveGlobal: ProjectConfig,\n): ProjectConfig {\n return {\n ...reconciledSplit,\n skills: [...effectiveGlobal.skills, ...reconciledSplit.skills],\n agents: [...effectiveGlobal.agents, ...reconciledSplit.agents],\n selectedDomains: unique([\n ...(effectiveGlobal.selectedDomains ?? []),\n ...(reconciledSplit.selectedDomains ?? []),\n ]),\n stack: { ...(effectiveGlobal.stack ?? {}), ...(reconciledSplit.stack ?? {}) },\n };\n}\n\n/**\n * Propagates global config changes to all registered project configs.\n * Updates each project's config-types.ts (type unions) and config.ts (inlined global data).\n * Skips stale project paths and the current project being installed.\n */\nexport async function propagateGlobalChangesToProjects(\n globalConfig: ProjectConfig,\n matrix: MergedSkillsMatrix,\n agents: Partial<Record<AgentName, AgentDefinition>>,\n currentProjectDir?: string,\n options: PropagationOptions = {},\n): Promise<PropagationResult> {\n const projects = globalConfig.projects ?? [];\n if (projects.length === 0) return { updated: [], skipped: [] };\n\n const currentNormalized = currentProjectDir ? normalizeProjectPath(currentProjectDir) : null;\n const updated: string[] = [];\n const skipped: string[] = [];\n\n for (const projectPath of projects) {\n // Skip the project currently being installed (it's already being written)\n if (currentNormalized && projectPath === currentNormalized) continue;\n\n const projectConfigPath = getProjectConfigPath(projectPath);\n if (!(await fileExists(projectConfigPath))) {\n skipped.push(projectPath);\n verbose(`Skipped propagation to ${projectPath} (config not found)`);\n continue;\n }\n\n try {\n const existingProject = await loadProjectConfigFromDir(projectPath);\n if (!existingProject?.config) {\n skipped.push(projectPath);\n continue;\n }\n\n const projectConfig = existingProject.config;\n\n // Derive project split: project-scoped entries plus tombstones that still\n // correspond to a live global install. Tombstones whose global entry has been\n // removed are dropped here so the project stops referencing a global item that\n // no longer exists. The stack is reconciled against the same\n // now-current global data so a project-scoped agent stops referencing a global\n // skill that was just removed at global scope. `projectConfig.skills` (pre-\n // reconciliation) is used to detect removed globals because the removed entry\n // is still present here as a `scope: \"global\"` reference.\n const removedGlobalSkillIds = computeRemovedGlobalSkillIds(\n projectConfig.skills,\n globalConfig,\n );\n const retained = retainReconciledStack(projectConfig.stack, removedGlobalSkillIds);\n const reconciledStack = retained === undefined ? {} : { stack: retained };\n const projectSplit = reconcileProjectSplitAgainstGlobal(\n {\n ...projectConfig,\n skills: retainProjectOwnedSkills(projectConfig.skills, globalConfig),\n agents: retainProjectOwnedAgents(projectConfig.agents, globalConfig),\n ...reconciledStack,\n },\n globalConfig,\n matrix,\n );\n\n await writeProjectConfigPair(projectPath, projectSplit, globalConfig, matrix, agents, {\n regenerateTypes: options.regenerateTypes ?? true,\n });\n\n updated.push(projectPath);\n verbose(`Propagated global changes to ${projectPath}`);\n } catch (error) {\n skipped.push(projectPath);\n verbose(`Failed to propagate to ${projectPath}: ${getErrorMessage(error)}`);\n }\n }\n\n return { updated, skipped };\n}\n\n/**\n * Prunes CLI-inlined global-scoped entries from every registered project after a\n * GLOBAL uninstall. Reuses {@link propagateGlobalChangesToProjects} with an\n * emptied global config so every global skill/agent reads as removed: project-\n * scoped entries are retained verbatim, inlined global rows and tombstones are\n * dropped, per-agent stack refs lose their global-only ids, and each project's\n * config-types.ts is regenerated.\n *\n * Call AFTER the global .claude-src manifest has been removed so the regenerated\n * project types fall back to the standalone form instead of importing from the\n * now-deleted global config-types.ts. Unreachable project dirs are reported in\n * `skipped`, never thrown.\n */\nexport async function pruneGlobalEntriesFromRegisteredProjects(\n globalConfig: ProjectConfig,\n matrix: MergedSkillsMatrix,\n agents: Partial<Record<AgentName, AgentDefinition>>,\n): Promise<{ updated: string[]; skipped: string[] }> {\n const emptiedGlobal: ProjectConfig = {\n ...globalConfig,\n skills: [],\n agents: [],\n };\n return propagateGlobalChangesToProjects(emptiedGlobal, matrix, agents);\n}\n\n/** What one resolution decided: the config to commit, and the two flags that gate the write. */\ntype ResolvedGlobalConfig = { config: ProjectConfig; changed: boolean };\n\n/**\n * Resolves the global config a project install should write, and registers this project's path.\n * `globalDataChanged` gates propagation; `changed` gates the write itself.\n *\n * `authority` is `mergeConfigs`' own word for how much of what it can see the session owns, and\n * it selects between the two resolutions below. Absent, or `\"owned\"`, keeps the standing\n * additive behaviour.\n */\nexport async function resolveEffectiveGlobalConfig(\n globalSplit: ProjectConfig,\n existingGlobalConfig: ProjectConfig | undefined,\n projectDir: string,\n authority?: AuthoritativeScope,\n): Promise<{ config: ProjectConfig; globalDataChanged: boolean; changed: boolean }> {\n const merged =\n authority === \"all\"\n ? matchGlobalToSession(globalSplit, existingGlobalConfig)\n : addSessionToGlobal(globalSplit, existingGlobalConfig);\n\n const registration = await registerProjectPath(merged.config, projectDir);\n return {\n config: registration.config,\n globalDataChanged: merged.changed,\n changed: merged.changed || registration.changed,\n };\n}\n\n/**\n * The standing resolution, and the one every caller but `edit --from` gets: the session's global\n * items are ADDED and nothing is taken away.\n *\n * A project install has asked nobody about the machine, so it may not decide for it (commit\n * 403df46, \"never modify global config from project-level operations\"). The `hasGlobalItems`\n * shortcut is part of that: a session carrying nothing global is not a statement that the global\n * install should be empty.\n */\nfunction addSessionToGlobal(\n globalSplit: ProjectConfig,\n existingGlobalConfig: ProjectConfig | undefined,\n): ResolvedGlobalConfig {\n const hasGlobalItems = globalSplit.skills.length > 0 || globalSplit.agents.length > 0;\n if (!hasGlobalItems) {\n return {\n config: existingGlobalConfig ?? { name: GLOBAL_CONFIG_NAME, skills: [], agents: [] },\n changed: false,\n };\n }\n\n if (!existingGlobalConfig) return { config: globalSplit, changed: true };\n return mergeGlobalConfigs(existingGlobalConfig, globalSplit);\n}\n\n/**\n * The resolution for a session that owns every scope it can see: the global config is made to\n * MATCH it, so a global entry the session left out is REMOVED rather than preserved.\n *\n * One caller reaches this — a confirmed `edit --from` — and it is not acting on its own\n * initiative: it states a whole roster, its plan showed every global removal under its own\n * heading, named every other registered project the removal reaches, and somebody answered yes.\n * Nothing else in the CLI may write the global config from a project, and this does not widen\n * that: the word arrives from the command, not from the shape of the data.\n *\n * `mergeConfigs` is what does it rather than a merge of this module's own, because \"absent from\n * the session means deselected\" is exactly what `authoritativeScope: \"all\"` already means at the\n * home root. It carries the global installation's identity, its stack fallback and its\n * `projects[]` registry across — a session's split says nothing about who the global\n * installation is or which projects read it, and the fan-out walks that registry.\n *\n * An empty session is a real answer here, so there is no `hasGlobalItems` shortcut: a\n * configuration that installs nothing globally removes what was.\n */\nfunction matchGlobalToSession(\n globalSplit: ProjectConfig,\n existingGlobalConfig: ProjectConfig | undefined,\n): ResolvedGlobalConfig {\n if (!existingGlobalConfig) return { config: globalSplit, changed: true };\n\n const config = mergeConfigs(globalSplit, existingGlobalConfig, { authoritativeScope: \"all\" });\n return { config, changed: !isDeepEqual(config, existingGlobalConfig) };\n}\n\n/** Category keys the emitted stack holds, across every agent it configures. */\nfunction stackCategories(stack: ProjectConfig[\"stack\"]): 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 return Object.values(stack ?? {}).flatMap((agentStack) => typedKeys<Category>(agentStack ?? {}));\n}\n\n/**\n * Derives the extras for regenerateConfigTypes so a project's config-types.ts declares every\n * literal its sibling config.ts holds — the two are written from the same config and must not\n * be able to disagree.\n *\n * ALL active (non-excluded) entries, not just project-scoped ones:\n * generateProjectConfigWithInlinedGlobal writes the active global rows into the project's own\n * config.ts verbatim, and the imported Global* unions cover those rows only for as long as the\n * global config still happens to contain them. A later global-scope run narrows those unions\n * and a project nobody touched stops type-checking (TS2322 on a skill id or domain, TS2353 on a\n * stack's category key).\n *\n * Domains and stack categories are read off the config's own arrays as well as derived from its\n * skill rows: `selectedDomains` is a wizard preference no skill row has to back, and neither it\n * nor a stack entry is pruned when the last skill that would derive it leaves.\n */\nexport function buildProjectTypesExtras(\n finalConfig: ProjectConfig,\n matrix: MergedSkillsMatrix,\n): Required<ConfigTypesExtras> {\n const activeSkills = finalConfig.skills.filter((s) => !s.excluded);\n const activeAgents = finalConfig.agents.filter((a) => !a.excluded);\n\n const extraSkillIds = unique(activeSkills.map((s) => s.id));\n const extraAgentNames = unique(activeAgents.map((a) => a.name));\n\n const extraCategories = unique([\n ...deriveCategories(extraSkillIds, matrix),\n ...stackCategories(finalConfig.stack),\n ]);\n const extraDomains = unique([\n ...deriveDomains(extraCategories, matrix),\n ...(finalConfig.selectedDomains ?? []),\n ]);\n\n return { extraSkillIds, extraAgentNames, extraDomains, extraCategories };\n}\n","import os from \"os\";\nimport path from \"path\";\nimport type { Category, ProjectConfig, SkillAssignment } from \"../../types\";\nimport { CLAUDE_SRC_DIR, DEFAULT_PLUGIN_NAME, GLOBAL_CONFIG_NAME } from \"../../consts\";\nimport { isSkillAssignment } from \"../../utils/type-guards\";\nimport { byCategoryDeclarationOrder, matrix } from \"../matrix/matrix-provider\";\nimport { assembleConfigTypesSource, STACK_AGENT_CONFIG_LOOSE_LINE } from \"./config-types-writer\";\n\n/**\n * This module renders config sources; it writes nothing. The partial-config\n * writer and the blank-global-pair creator that used to live here are\n * `writeProjectPartial` and `ensureBlankPair` in `config-gate/`, which is the\n * only code allowed to put either half of the pair on disk.\n */\n\nexport type ConfigSourceOptions = {\n /**\n * When true, generates a project config that imports and extends the global config.\n * The global config import path is resolved internally via `getGlobalConfigImportPath()`.\n */\n isProjectConfig?: boolean;\n\n /**\n * When provided alongside `isProjectConfig`, inlines global skills/agents directly\n * instead of generating `import globalConfig` and spread syntax.\n * Produces a self-contained, readable config snapshot.\n */\n globalConfig?: ProjectConfig;\n};\n\n/** Fields that are extracted into typed named variables below the export default */\nconst EXTRACTED_FIELDS = new Set([\"skills\", \"agents\", \"stack\", \"selectedDomains\"]);\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\nconst CANONICAL_FIELDS = new Set<string>(CANONICAL_FIELD_ORDER);\n\n/**\n * The cleaned record rebuilt in canonical order. A key the schema does not name\n * is passthrough data the writer has no order of its own to impose, so those\n * keep the order they arrived in, after every field the schema does name.\n */\nfunction canonicalizeFieldOrder(cleaned: Record<string, unknown>): Record<string, unknown> {\n const inSchemaOrder: [string, unknown][] = CANONICAL_FIELD_ORDER.filter(\n (key) => key in cleaned,\n ).map((key) => [key, cleaned[key]]);\n const passthrough = Object.entries(cleaned).filter(([key]) => !CANONICAL_FIELDS.has(key));\n\n return Object.fromEntries([...inSchemaOrder, ...passthrough]);\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(Object.entries(record).sort(([a], [b]) => compareKeys(a, b)));\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 matrix's\n * declaration order — the two orders the generator already builds a 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): Record<string, Record<string, unknown>> {\n const byDeclaration = byCategoryDeclarationOrder();\n const withCategoriesInOrder = Object.entries(stack).map(\n ([agent, categories]) => [agent, withKeysOrderedBy(categories, byDeclaration)] as const,\n );\n\n return withKeysOrderedBy(Object.fromEntries(withCategoriesInOrder), compareNamesInCodeUnitOrder);\n}\n\n/** One config entry as an indented array-element line. */\nfunction renderEntryLine(entry: unknown): string {\n return ` ${JSON.stringify(entry)},`;\n}\n\n/** One scalar field as an indented object-property line. */\nfunction renderScalarField(key: string, value: unknown): string {\n return ` ${JSON.stringify(key)}: ${JSON.stringify(value)},`;\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 * Generates a TypeScript config file source from a ProjectConfig object.\n * The export default sits at the top as a table of contents, with typed named\n * variables (skills, agents, stack, selectedDomains) declared below it.\n *\n * When `options.isProjectConfig` is true, the generated config imports from the global\n * config and spreads global arrays into skills, agents, and selectedDomains.\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 ordering of both the top-level fields\n * and the stack's own keys, so the emitted bytes are decided by the config's\n * values alone.\n */\nfunction cleanForEmission(\n config: ProjectConfig,\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 );\n cleaned.stack = canonicalizeStackOrder(compacted);\n }\n return canonicalizeFieldOrder(cleaned);\n}\n\nexport function generateConfigSource(config: ProjectConfig, options?: ConfigSourceOptions): string {\n if (options?.isProjectConfig && options.globalConfig) {\n return generateProjectConfigWithInlinedGlobal(\n cleanForEmission(config, { dropProjects: true }),\n cleanForEmission(options.globalConfig, { dropProjects: true }),\n );\n }\n\n if (options?.isProjectConfig) {\n return generateProjectConfigWithGlobalImport(\n cleanForEmission(config, { dropProjects: true }),\n getGlobalConfigImportPath(),\n );\n }\n\n return generateStandaloneConfig(cleanForEmission(config, { dropProjects: false }));\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 } = 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 // Build type imports based on what's used\n const typeImports = buildTypeImports({\n hasSkills,\n hasAgents,\n hasStack,\n hasSelectedDomains,\n });\n\n const lines: string[] = [`import type { ${typeImports} } from \"./config-types\";`];\n\n // Add named variable declarations above the export default\n if (hasSkills) {\n lines.push(``);\n lines.push(`const skills: SkillConfig[] = [`);\n lines.push(skills.map(renderEntryLine).join(\"\\n\"));\n lines.push(`];`);\n }\n\n if (hasAgents) {\n lines.push(``);\n lines.push(`const agents: AgentScopeConfig[] = [`);\n lines.push(agents.map(renderEntryLine).join(\"\\n\"));\n lines.push(`];`);\n }\n\n if (hasStack) {\n lines.push(``);\n const stackBody = JSON.stringify(stack, null, 2);\n lines.push(`const stack: Partial<Record<ProjectAgentName, StackAgentConfig>> = ${stackBody};`);\n }\n\n if (hasSelectedDomains) {\n lines.push(``);\n const items = selectedDomains.map((d) => JSON.stringify(d)).join(\", \");\n lines.push(`const selectedDomains: Domain[] = [${items}];`);\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 ]\n .filter((t): t is string => Boolean(t))\n .join(\", \");\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 } = extractConfigArrays(cleaned);\n\n const hasProjectDomains = selectedDomains.length > 0;\n const hasStack = stack != null && Object.keys(stack).length > 0;\n\n // Build type imports\n const typeImports = buildTypeImports({\n hasSkills: true, // Always present (spread from global)\n hasAgents: true, // Always present (spread from global)\n hasStack,\n hasSelectedDomains: hasProjectDomains,\n });\n\n const lines: string[] = [\n `import globalConfig from \"${importPath}\";`,\n `import type { ${typeImports} } from \"./config-types\";`,\n ];\n\n // Skills variable (always present with global spread)\n lines.push(``);\n const skillItems = skills.map(renderEntryLine).join(\"\\n\");\n lines.push(`const skills: SkillConfig[] = [`);\n lines.push(` ...globalConfig.skills,`);\n if (skillItems) lines.push(skillItems);\n lines.push(`];`);\n\n // Agents variable (always present with global spread)\n lines.push(``);\n const agentItems = agents.map(renderEntryLine).join(\"\\n\");\n lines.push(`const agents: AgentScopeConfig[] = [`);\n lines.push(` ...globalConfig.agents,`);\n if (agentItems) lines.push(agentItems);\n lines.push(`];`);\n\n // Stack variable (only if project has stack assignments)\n if (hasStack) {\n lines.push(``);\n const stackBody = JSON.stringify(stack, null, 2);\n lines.push(`const stack: Partial<Record<ProjectAgentName, StackAgentConfig>> = ${stackBody};`);\n }\n\n // Selected domains variable (only if project has selected domains)\n if (hasProjectDomains) {\n lines.push(``);\n const domainItems = selectedDomains.map(renderEntryLine).join(\"\\n\");\n lines.push(`const selectedDomains: Domain[] = [`);\n lines.push(` ...(globalConfig.selectedDomains ?? []),`);\n if (domainItems) lines.push(domainItems);\n lines.push(`];`);\n }\n\n // Build scalar fields (everything that isn't an extracted field or name)\n const scalarFields = Object.entries(cleaned)\n .filter(([key]) => !EXTRACTED_FIELDS.has(key) && key !== \"name\")\n .map(([key, value]) => renderScalarField(key, value))\n .join(\"\\n\");\n\n // Build export default (table of contents at bottom)\n const exportFields: string[] = [\n ` ...globalConfig,`,\n ` name: ${JSON.stringify(resolveProjectName(cleaned))},`,\n ` skills,`,\n ` agents,`,\n ...(hasStack ? [` stack,`] : []),\n ...(hasProjectDomains ? [` selectedDomains,`] : []),\n ...(scalarFields ? [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/** 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 ? cleaned.name : 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]) => projectAgentNames.has(agent)),\n )\n : undefined;\n\n return {\n globalSkills,\n globalAgents,\n projectSkills,\n projectAgents,\n filteredStack,\n selectedDomains: [...new Set([...global.selectedDomains, ...project.selectedDomains])],\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 */\nfunction mergeInlinedScalarFields(\n cleaned: Record<string, unknown>,\n cleanedGlobal: Record<string, unknown>,\n): [string, unknown][] {\n return Object.entries(canonicalizeFieldOrder({ ...cleanedGlobal, ...cleaned })).filter(\n ([key]) => !EXTRACTED_FIELDS.has(key) && key !== \"name\",\n );\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 { globalSkills, globalAgents, projectSkills, projectAgents, filteredStack } = 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 = 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[] = [`import type { ${typeImports} } from \"./config-types\";`];\n\n // Skills variable\n if (hasSkills) {\n lines.push(``);\n lines.push(`const skills: SkillConfig[] = [`);\n lines.push(\n ...(hasGlobalSkills ? [` // global`, ...globalSkills.map(renderEntryLine)] : []),\n ...(hasProjectSkills ? [` // project`, ...projectSkills.map(renderEntryLine)] : []),\n );\n lines.push(`];`);\n }\n\n // Agents variable\n if (hasAgents) {\n lines.push(``);\n lines.push(`const agents: AgentScopeConfig[] = [`);\n lines.push(\n ...(hasGlobalAgents ? [` // global`, ...globalAgents.map(renderEntryLine)] : []),\n ...(hasProjectAgents ? [` // project`, ...projectAgents.map(renderEntryLine)] : []),\n );\n lines.push(`];`);\n }\n\n // Stack variable (project agents only)\n if (hasStack) {\n lines.push(``);\n const stackBody = JSON.stringify(filteredStack, null, 2);\n lines.push(`const stack: Partial<Record<ProjectAgentName, StackAgentConfig>> = ${stackBody};`);\n }\n\n // Selected domains variable (merged global + project, deduplicated)\n if (hasSelectedDomains) {\n lines.push(``);\n const items = partition.selectedDomains.map((d) => JSON.stringify(d)).join(\", \");\n lines.push(`const selectedDomains: Domain[] = [${items}];`);\n }\n\n const scalarFields = mergeInlinedScalarFields(cleaned, cleanedGlobal);\n\n const exportFields: string[] = [\n ` name: ${JSON.stringify(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/** 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 * 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 */\nfunction compactAssignment(assignment: unknown): unknown {\n if (isSkillAssignment(assignment) && !carriesFlags(assignment)) return assignment.id;\n return assignment;\n}\n\n/**\n * True when the active matrix DECLARES this category as holding at most one skill. Read from the\n * matrix singleton so a source repo's category overrides are honoured.\n *\n * A category the matrix does not declare is deliberately NOT treated as exclusive, and that is a\n * real choice rather than a default: the wizard's toggle handler reads the same flag as\n * `?? true` (`components/hooks/use-build-step-props.ts`), so an undeclared category IS exclusive\n * while a selection is being made. A rule that REFUSES a write must only fire on a flag the data\n * actually carries. `buildProjectCollisionTest` (`config-gate/propagate.ts`) takes the same side\n * on the same reasoning, and `generateStackAgentConfig` (`config-types-writer.ts`) reads the flag\n * for the emitted union's `[]` suffix.\n */\nfunction isExclusiveCategory(category: string): boolean {\n // Boundary cast: category keys come from JSON-cleaned config data, not the Category union\n return matrix.categories[category as Category]?.exclusive === true;\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(category: string, assignments: unknown[]): unknown {\n const compacted = assignments.map(compactAssignment);\n if (!isExclusiveCategory(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\nfunction compactCategories(categories: Record<string, unknown[]>): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(categories)\n .filter(([, assignments]) => Array.isArray(assignments) && assignments.length > 0)\n .map(([category, assignments]) => [\n category,\n compactCategoryAssignments(category, assignments),\n ]),\n );\n}\n\nfunction compactStackAssignments(\n stack: Record<string, Record<string, unknown[]>>,\n): Record<string, Record<string, unknown>> {\n return Object.fromEntries(\n Object.entries(stack)\n .map(([agent, categories]) => [agent, compactCategories(categories)] as const)\n .filter(([, categories]) => Object.keys(categories).length > 0),\n );\n}\n\n/**\n * Returns the absolute path to the global .claude-src directory.\n * Used as the import path for project configs that extend global.\n */\nexport function getGlobalConfigImportPath(): string {\n return path.join(os.homedir(), CLAUDE_SRC_DIR);\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 \"./config-types\";\n\nexport default {\n \"name\": \"${GLOBAL_CONFIG_NAME}\",\n \"skills\": [],\n \"agents\": [],\n \"selectedDomains\": []\n} satisfies ProjectConfig;\\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: \"never\",\n agentName: \"never\",\n selectedAgentName: \"never\",\n projectAgentName: \"SelectedAgentName\",\n domain: \"never\",\n category: \"never\",\n stackAgentConfig: STACK_AGENT_CONFIG_LOOSE_LINE,\n });\n}\n","import os from \"os\";\nimport path from \"path\";\nimport type { ProjectConfig, SkillId } from \"../../types\";\nimport type { SkillConfig } from \"../../types/config\";\nimport type { AuthoritativeScope } from \"../configuration/config-merger\";\nimport { CLAUDE_SRC_DIR, CLI_INVOKE_COMMAND } from \"../../consts\";\nimport { ensureDir, writeFile } from \"../../utils/fs\";\nimport { verbose } from \"../../utils/logger\";\nimport { isHomeDirectory } from \"../installation/is-home-directory\";\nimport { getProjectConfigPath } from \"../installation/install-base-dir\";\nimport { loadProjectConfigFromDir } from \"../configuration/project-config\";\nimport { normalizeStackRecord } from \"../stacks/stacks-loader\";\nimport { isActiveAt } from \"../configuration/scope-predicates\";\nimport { splitConfigByScope } from \"../configuration/config-generator\";\nimport { generateConfigSource } from \"../configuration/config-writer\";\nimport {\n buildConfigTypesBackgroundData,\n regenerateConfigTypes,\n type ConfigTypesExtras,\n} from \"../configuration/config-types-writer\";\nimport {\n classifyGlobalChange,\n consequenceTier,\n tierPropagates,\n tierRegeneratesTypes,\n NO_CHANGES,\n type GlobalChangeSet,\n} from \"./classify.js\";\nimport { resolveGateDeps, type GateDeps, type LoadedGateDeps } from \"./deps.js\";\nimport { GlobalPairWriteViolation, withGateToken } from \"./gate-token.js\";\nimport {\n ensureBlankPair as ensureBlankPairInternal,\n writeGlobalConfigHalf,\n writeGlobalPair,\n writeGlobalTypesHalf,\n} from \"./pair-writer.js\";\nimport {\n buildProjectTypesExtras,\n mergeGlobalConfigs,\n normalizeProjectPath,\n propagateGlobalChangesToProjects,\n pruneGlobalEntriesFromRegisteredProjects,\n reconcileProjectSplitAgainstGlobal,\n resolveEffectiveGlobalConfig,\n writeProjectConfigPair,\n type PropagationResult,\n} from \"./propagate.js\";\nimport { NOTHING_RECOMPILED, recompilePropagated } from \"./recompile.js\";\nimport type { PropagatedRecompileSummary } from \"../operations/project/recompile-project-agents.js\";\n\nexport type { GateDeps } from \"./deps.js\";\nexport type { ConsequenceTier, GlobalChangeSet } from \"./classify.js\";\nexport { GlobalPairWriteViolation } from \"./gate-token.js\";\n\n/**\n * What one gated write did, for the caller to render.\n *\n * A write that propagates recompiles the propagated projects' agents itself:\n * both audited gaps in the previous contract (a project-context source\n * migration, a global uninstall) were instances of a caller forgetting to. A\n * report the caller may only log cannot go stale the same way, and per-project\n * failure isolation already lives in `recompilePropagatedProjectAgents`, so\n * internalizing the recompile adds no new failure mode.\n */\nexport type GateReport = {\n /** True when either half of the global pair was actually rewritten. */\n globalWritten: boolean;\n changes: GlobalChangeSet;\n propagated: PropagationResult;\n recompile: PropagatedRecompileSummary;\n};\n\n/**\n * The gate's public entry points are the ONLY code that mints the pair-write\n * privilege, and each one holds it across its whole consequence flow rather than\n * around the individual write.\n *\n * `pair-writer.ts` used to open the token inside each of its own functions, which\n * meant reaching that module by any route — a dynamic import, a re-export — came\n * with the privilege attached, and the runtime tripwire in `utils/fs.ts` had\n * nothing left to refuse. Moving the mint here inverts that: the private writers\n * REQUIRE a token they cannot produce, so authorization is a property of how the\n * write was ENTERED, which is exactly what the gate is meant to guarantee.\n *\n * The window is wider than the write itself — propagation and the recompile run\n * inside it too. That is accepted: everything in the window is the gate's own\n * code carrying out consequences the same entry already owes.\n *\n * Every entry below that writes or drives a write opens the token with\n * `withGateToken`, including `propagateGlobalRemoval`, which today reaches only\n * project pairs — the rule is \"a gate entry holds the privilege for its flow\",\n * not \"the ones whose current implementation happens to need it\".\n *\n * The one exception is `writeProjectPartial`. It refuses the home directory as its\n * first act and then writes a PROJECT's own config, which the tripwire never\n * guards; handing it the global-pair privilege would only blunt the refusal it\n * exists to make.\n */\n\n/** A write whose classification obliged nothing beyond the global pair. */\nconst NOTHING_PROPAGATED: PropagationResult = { updated: [], skipped: [] };\n\nfunction report(\n globalWritten: boolean,\n changes: GlobalChangeSet,\n propagated: PropagationResult = NOTHING_PROPAGATED,\n recompile: PropagatedRecompileSummary = NOTHING_RECOMPILED,\n): GateReport {\n return { globalWritten, changes, propagated, recompile };\n}\n\n/**\n * Carries out a classified global change's consequences: fan the change out to\n * every registered project, then recompile the ones it rewrote.\n *\n * `currentProjectDir` is excluded from the fan-out — its own pair is written by\n * the call that triggered this, and its agents are compiled by the command.\n */\nasync function applyConsequences(\n globalConfig: ProjectConfig,\n changes: GlobalChangeSet,\n deps: LoadedGateDeps,\n currentProjectDir?: string,\n): Promise<{ propagated: PropagationResult; recompile: PropagatedRecompileSummary }> {\n const tier = consequenceTier(changes);\n if (!tierPropagates(tier) || !globalConfig.projects?.length) {\n return { propagated: NOTHING_PROPAGATED, recompile: NOTHING_RECOMPILED };\n }\n\n const propagated = await propagateGlobalChangesToProjects(\n globalConfig,\n deps.matrix,\n deps.agents,\n currentProjectDir,\n { regenerateTypes: tierRegeneratesTypes(tier) },\n );\n if (propagated.updated.length > 0) {\n verbose(`Propagated global changes to ${propagated.updated.length} project(s)`);\n }\n\n const recompile = tierRegeneratesTypes(tier)\n ? await recompilePropagated(propagated.updated)\n : NOTHING_RECOMPILED;\n\n return { propagated, recompile };\n}\n\n/**\n * Loaders for a caller that holds no matrix of its own. Nothing is fetched\n * unless classification proves the write has consequences that read it, so a\n * registration-only mutation stays offline.\n *\n * `matrixOnly` + `skipExtraSources` are the offline policy the other config\n * readers already use: extra-source loading only annotates wizard UI tagging and\n * never changes the emitted config or types.\n */\nexport function lazyGateDeps(projectDir: string): GateDeps {\n return {\n loadMatrix: async () => {\n const { loadSkillsMatrixFromSource } = await import(\"../loading/source-loader.js\");\n const { matrix } = await loadSkillsMatrixFromSource({\n projectDir,\n skipExtraSources: true,\n matrixOnly: true,\n });\n return matrix;\n },\n loadAgents: async () => {\n const { loadAgentDefs } = await import(\"../operations/project/load-agent-defs.js\");\n return (await loadAgentDefs()).agents;\n },\n };\n}\n\nexport type WizardWriteArgs = {\n finalConfig: ProjectConfig;\n matrix: LoadedGateDeps[\"matrix\"];\n agents: LoadedGateDeps[\"agents\"];\n projectDir: string;\n projectConfigPath: string;\n projectInstallationExists: boolean;\n /**\n * How much of what it can see this session owns, from `mergeConfigs`' own vocabulary.\n *\n * Read by the PROJECT branch only, and only to decide whether the global config is made to\n * MATCH this session or merely absorb it. The home branch writes the whole global config from\n * `finalConfig` either way, and `undefined` (init) keeps the additive default.\n */\n authoritativeScope?: AuthoritativeScope;\n};\n\n/**\n * Writes config.ts and config-types.ts split by scope.\n * When installing into a project directory:\n * - Global config/types go to ~/.claude-src/\n * - Project config/types go to {projectDir}/.claude-src/ (with import from global)\n * When installing from home directory, writes a single standalone config.\n */\nexport async function writeScopedFromWizard(args: WizardWriteArgs): Promise<GateReport> {\n return withGateToken(async () => {\n const { finalConfig, matrix, agents, projectDir, projectConfigPath } = args;\n // os.homedir() at call time, so the path agrees with getGlobalConfigImportPath(),\n // which reaches the same home through globalInstallRoot()\n const homeDir = os.homedir();\n const deps: LoadedGateDeps = { matrix, agents };\n\n if (!isHomeDirectory(projectDir)) {\n return writeFromProjectContext(args, homeDir, deps);\n }\n\n // Installing from ~/ — write directly to global config (no import preamble)\n const priorGlobal = await loadProjectConfigFromDir(homeDir);\n const changes = classifyGlobalChange(priorGlobal?.config, finalConfig);\n const globalWritten = await writeGlobalPair(finalConfig, projectConfigPath, matrix, agents);\n\n const { propagated, recompile } = await applyConsequences(finalConfig, changes, deps);\n return report(globalWritten, changes, propagated, recompile);\n });\n}\n\nasync function writeFromProjectContext(\n args: WizardWriteArgs,\n homeDir: string,\n deps: LoadedGateDeps,\n): Promise<GateReport> {\n const { finalConfig, matrix, agents, projectDir, projectConfigPath } = args;\n\n // Installing from project — split by scope for project config generation.\n const { global: globalConfig, project: projectSplitConfig } = splitConfigByScope(finalConfig);\n const globalConfigPath = getProjectConfigPath(homeDir);\n\n // Merge new global-scoped items into the existing global config.\n // - Existing items are preserved (never removed from global during project init)\n // - New global items are added\n // - If no existing global config, write the full global split\n const existingGlobal = await loadProjectConfigFromDir(homeDir);\n const effective = await resolveEffectiveGlobalConfig(\n globalConfig,\n existingGlobal?.config,\n projectDir,\n args.authoritativeScope,\n );\n const effectiveGlobalConfig = effective.config;\n\n const changes = classifyGlobalChange(existingGlobal?.config, effectiveGlobalConfig);\n\n let globalWritten = false;\n if (effective.changed) {\n await ensureDir(path.dirname(globalConfigPath));\n globalWritten = await writeGlobalPair(effectiveGlobalConfig, globalConfigPath, matrix, agents);\n verbose(`Updated global config at ${globalConfigPath}`);\n } else {\n verbose(\"Global config unchanged, skipping write\");\n }\n\n const { propagated, recompile } = await applyConsequences(\n effectiveGlobalConfig,\n changes,\n deps,\n projectDir,\n );\n\n // Reconcile the project's own entries against the global config this write inlines.\n // Without it this branch hands the raw split straight to the inlining writer, so a\n // skill/agent the project owns at project scope AND a colliding live global install\n // both land as active entries in the same project config.\n const reconciledProjectConfig = reconcileProjectSplitAgainstGlobal(\n projectSplitConfig,\n effectiveGlobalConfig,\n matrix,\n );\n\n // Write project config if the project installation already exists OR if there are project-scoped items.\n // Skip only when no existing project installation AND no project-scoped items — creating an empty\n // project config with just `import globalConfig` and `{ ...globalConfig }` is pointless.\n const hasProjectItems =\n reconciledProjectConfig.skills.length > 0 || reconciledProjectConfig.agents.length > 0;\n\n if (args.projectInstallationExists || hasProjectItems) {\n await ensureDir(path.dirname(projectConfigPath));\n await writeProjectConfigPair(\n projectDir,\n reconciledProjectConfig,\n effectiveGlobalConfig,\n matrix,\n agents,\n );\n verbose(`Updated project config at ${projectConfigPath}`);\n } else {\n verbose(\n \"Skipped project config — no existing project installation and no project-scoped items\",\n );\n }\n\n return report(globalWritten, changes, propagated, recompile);\n}\n\n/**\n * Regenerates a single scope's config-types.ts from its persisted config,\n * matching the wizard write path's writer selection exactly:\n * - global scope (home dir): standalone unions narrowed to the config's entries\n * - project scope: import-and-extend form (falls back to standalone when no\n * global config-types.ts exists)\n *\n * Writes no config half at either scope: the config on disk is the input.\n * Returns whether a file was actually rewritten (always false at project scope,\n * where the writer does not report).\n */\nexport async function writeScopeConfigTypes(\n projectDir: string,\n config: ProjectConfig,\n deps: LoadedGateDeps,\n extras?: ConfigTypesExtras,\n): Promise<boolean> {\n return withGateToken(async () => {\n if (isHomeDirectory(projectDir)) {\n return writeGlobalTypesHalf(\n config,\n getProjectConfigPath(projectDir),\n deps.matrix,\n deps.agents,\n extras,\n );\n }\n\n await regenerateConfigTypes(\n projectDir,\n Promise.resolve(buildConfigTypesBackgroundData(deps.matrix, deps.agents)),\n extras ?? buildProjectTypesExtras(config, deps.matrix),\n );\n return false;\n });\n}\n\n/**\n * Regenerates a scope's config-types.ts from the config already on disk, which\n * is the truth and is never rewritten — the documented hand-edit workflow is\n * \"edit config.ts, then compile\", so the file the user edited must survive it.\n *\n * At the home directory the types are the standalone unions narrowed to that\n * config, and the fan-out is UNCONDITIONAL: a hand edit leaves no prior state to\n * diff against, so there is nothing to classify and the only safe assumption is\n * that every registered project's inlined copy is stale. At project and\n * marketplace directories the import-and-extend writer applies and nothing is\n * propagated — a project config is nobody else's input.\n */\nexport async function reconcileTypesFromDisk(\n projectDir: string,\n config: ProjectConfig,\n deps: LoadedGateDeps,\n options?: { extras?: ConfigTypesExtras; currentProjectDir?: string },\n): Promise<GateReport> {\n return withGateToken(async () => {\n const changes = classifyGlobalChange(undefined, config);\n const globalWritten = await writeScopeConfigTypes(projectDir, config, deps, options?.extras);\n\n if (!isHomeDirectory(projectDir)) return report(false, changes);\n if (!config.projects?.length) return report(globalWritten, changes);\n\n const propagated = await propagateGlobalChangesToProjects(\n config,\n deps.matrix,\n deps.agents,\n options?.currentProjectDir,\n );\n if (propagated.updated.length > 0) {\n verbose(`Propagated global changes to ${propagated.updated.length} project(s)`);\n }\n const recompile = await recompilePropagated(propagated.updated);\n\n return report(globalWritten, changes, propagated, recompile);\n });\n}\n\n/**\n * The transforms the gate will apply to the global config on a caller's behalf.\n *\n * A closed union rather than a caller-supplied function: every variant is\n * analysable and testable on its own, and no caller-authored transform runs\n * inside the only code allowed to write the pair.\n */\nexport type GlobalMutation =\n | { kind: \"migrate-skill-sources\"; sources: ReadonlyMap<SkillId, string> }\n | { kind: \"deregister-project\"; projectDir: string }\n | { kind: \"set-source\"; source: string; fallbackName: string };\n\n/** The migrated `origin` for an active-global entry, or the entry unchanged. */\nfunction withMigratedSource(\n skill: SkillConfig,\n migratedSources: ReadonlyMap<SkillId, string>,\n): SkillConfig {\n if (!isActiveAt(skill, \"global\")) return skill;\n const origin = migratedSources.get(skill.id);\n if (origin === undefined || origin === skill.origin) return skill;\n return { ...skill, origin };\n}\n\n/**\n * Rewrites `origin` on exactly the active-global entries listed in `migratedSources`,\n * returning every other entry — including global entries this session did not migrate —\n * identical by reference.\n */\nexport function applyMigratedGlobalSources(\n globalSkills: SkillConfig[],\n migratedSources: ReadonlyMap<SkillId, string>,\n): { skills: SkillConfig[]; changed: boolean } {\n const skills = globalSkills.map((skill) => withMigratedSource(skill, migratedSources));\n return { skills, changed: skills.some((skill, index) => skill !== globalSkills[index]) };\n}\n\n/**\n * The config a partial write commits: the scalars and arrays already on disk,\n * with the required fields filled. Mirrors what the partial writer has always\n * defaulted, so a scalar mutation cannot silently empty an install.\n */\nfunction fillRequiredFields(\n partial: Partial<ProjectConfig>,\n fallbackName: string | undefined,\n): ProjectConfig {\n const name = partial.name ?? fallbackName;\n if (!name) {\n throw new Error(\n `Cannot write config: no project config found. Run \\`${CLI_INVOKE_COMMAND} init\\` first.`,\n );\n }\n return { ...partial, name, skills: partial.skills ?? [], agents: partial.agents ?? [] };\n}\n\n/** Applies a mutation to the config on disk, or null when it is a no-op. */\nfunction applyMutation(\n mutation: GlobalMutation,\n current: Partial<ProjectConfig>,\n): Partial<ProjectConfig> | null {\n switch (mutation.kind) {\n case \"migrate-skill-sources\": {\n const { skills, changed } = applyMigratedGlobalSources(\n current.skills ?? [],\n mutation.sources,\n );\n return changed ? { ...current, skills } : null;\n }\n case \"deregister-project\": {\n const projects = current.projects ?? [];\n if (projects.length === 0) return null;\n const normalized = normalizeProjectPath(mutation.projectDir);\n const filtered = projects.filter((p) => p !== normalized);\n return filtered.length === projects.length ? null : { ...current, projects: filtered };\n }\n case \"set-source\":\n return { ...current, marketplace: mutation.source };\n default: {\n const _exhaustive: never = mutation;\n return _exhaustive;\n }\n }\n}\n\n/** The name a mutation invents when the global config has none yet. */\nfunction fallbackNameFor(mutation: GlobalMutation): string | undefined {\n return mutation.kind === \"set-source\" ? mutation.fallbackName : undefined;\n}\n\n/**\n * Applies a typed transform to the global config and carries out whatever its\n * classification obliges. No variant is exempt from classification by\n * construction: a source change propagates because project configs inline the\n * global scalars, and a deregistration does not because nothing inlines the\n * registration list.\n */\nexport async function mutateGlobal(mutation: GlobalMutation, deps: GateDeps): Promise<GateReport> {\n return withGateToken(async () => {\n const homeDir = os.homedir();\n // The full loader, not the scalar one: it normalizes every stack assignment\n // back to `SkillAssignment[]`. The writer compacts an exclusive category to its\n // bare value on the way out, and re-emitting that bare form without\n // normalization drops the category — so a scalar mutation would silently strip\n // every exclusive category from the global stack.\n const loadedGlobal = await loadProjectConfigFromDir(homeDir);\n if (!loadedGlobal) return report(false, NO_CHANGES);\n\n const current = loadedGlobal.config;\n const mutated = applyMutation(mutation, current);\n if (!mutated) return report(false, NO_CHANGES);\n\n const prior = fillRequiredFields(current, fallbackNameFor(mutation));\n const next = fillRequiredFields(mutated, fallbackNameFor(mutation));\n const changes = classifyGlobalChange(prior, next);\n\n const globalWritten = await writeGlobalConfigHalf(next, getProjectConfigPath(homeDir));\n if (!next.projects?.length) return report(globalWritten, changes);\n\n const loaded = await resolveGateDeps(deps, consequenceTier(changes));\n if (!loaded) return report(globalWritten, changes);\n\n const { propagated, recompile } = await applyConsequences(next, changes, loaded);\n return report(globalWritten, changes, propagated, recompile);\n });\n}\n\n/**\n * Prunes the CLI-inlined global entries from every registered project after a\n * GLOBAL uninstall, and recompiles their agents.\n *\n * Writes no pair: the pair this would derive from has just been deleted. That is\n * the reason this is its own entry rather than a flag on a writing one — the\n * removal case must not be reachable from a code path whose job is to write.\n *\n * Call AFTER the global manifest has been removed so the regenerated project\n * types fall back to the standalone form instead of importing from the\n * now-deleted global config-types.ts.\n */\nexport async function propagateGlobalRemoval(\n preRemovalGlobalConfig: ProjectConfig,\n deps: LoadedGateDeps,\n): Promise<GateReport> {\n return withGateToken(async () => {\n const changes = classifyGlobalChange(preRemovalGlobalConfig, {\n ...preRemovalGlobalConfig,\n skills: [],\n agents: [],\n });\n\n const propagated = await pruneGlobalEntriesFromRegisteredProjects(\n preRemovalGlobalConfig,\n deps.matrix,\n deps.agents,\n );\n const recompile = await recompilePropagated(propagated.updated);\n\n return report(false, changes, propagated, recompile);\n });\n}\n\n/**\n * Creates the blank global pair when none exists. No classification and no\n * fan-out: the registration list propagation reads lives in the file that was\n * just found absent, so a pair created here has no registered projects.\n */\nexport async function ensureBlankPair(): Promise<boolean> {\n return withGateToken(() => ensureBlankPairInternal());\n}\n\nexport type WriteProjectPartialOptions = {\n /** Name to invent when the partial has none. Absent → a missing name is an error. */\n fallbackName?: string;\n};\n\n/**\n * The partial with every stack assignment normalized back to `SkillAssignment[]`.\n *\n * Every caller of this entry reads the config with the LENIENT loader\n * (`loadProjectSourceConfig`), overlays one scalar, and hands the result back.\n * That loader passes the on-disk stack through untouched, and the writer emits an\n * exclusive category in its BARE form (`\"web-framework\": \"web-framework-react\"`,\n * no array) — so on a load / re-emit round trip `compactCategories`, which keeps\n * only non-empty arrays, drops the category and the user silently loses an\n * assignment they never touched.\n *\n * Normalizing at this boundary rather than inside the writer keeps the fix on the\n * one path that can present a denormalized stack: the full loader\n * (`loadProjectConfigFromDir`) already runs `normalizeStackRecord`, so every other\n * writer input arrives normalized.\n */\nfunction withNormalizedStack(partial: Partial<ProjectConfig>): Partial<ProjectConfig> {\n if (!partial.stack) return partial;\n return { ...partial, stack: normalizeStackRecord(partial.stack) };\n}\n\n/**\n * Writes a partial config to a PROJECT's `.claude-src/config.ts`, filling\n * required defaults. Refuses the home directory: the global pair's config half\n * may never be written without its types sibling and without classification.\n */\nexport async function writeProjectPartial(\n projectDir: string,\n partial: Partial<ProjectConfig>,\n options: WriteProjectPartialOptions = {},\n): Promise<void> {\n if (isHomeDirectory(projectDir)) {\n throw new GlobalPairWriteViolation(getProjectConfigPath(projectDir));\n }\n\n const configPath = getProjectConfigPath(projectDir);\n await ensureDir(path.join(projectDir, CLAUDE_SRC_DIR));\n await writeFile(\n configPath,\n generateConfigSource(fillRequiredFields(withNormalizedStack(partial), options.fallbackName)),\n );\n}\n\n/**\n * `normalizeProjectPath` is the single rule for any value compared against the\n * global config's `projects` array, so a reader that only wants to MATCH a\n * registration (never write one) gets it from here rather than reimplementing\n * `fs.realpathSync` and drifting from the rule the registrations were stored\n * under. It writes nothing, so exporting it hands out no privilege.\n */\nexport { mergeGlobalConfigs, normalizeProjectPath };\n","import { isDeepEqual } from \"remeda\";\nimport type { AgentName, ProjectConfig, SkillId } from \"../../types\";\nimport type { AgentScopeConfig, SkillConfig } from \"../../types/config\";\n\n/**\n * The work one global config write owes, decided from what actually moved\n * between the config on disk and the config being written.\n *\n * T1 — the generated type unions or the compiled agents are derived from what\n * changed: rewrite both halves of the pair, propagate to every registered\n * project, recompile those projects' agents.\n * T2 — a scalar the unions do not encode changed. Project configs inline the\n * global scalars verbatim, so the config half propagates; no union moves,\n * so no types are regenerated and no agent is recompiled.\n * T3 — only the `projects[]` registration list changed. Nothing is propagated,\n * and the matrix / agent definitions propagation would need are never\n * loaded.\n * T4 — nothing moved. No file is touched.\n */\nexport type ConsequenceTier = \"T1\" | \"T2\" | \"T3\" | \"T4\";\n\nexport type GlobalChangeSet = {\n skills: {\n added: SkillId[];\n removed: SkillId[];\n /**\n * Ids whose `origin` moved — the field's name on `SkillConfig`; this one keeps the\n * older word. Separate from `otherChanged` because the per-skill value decides the\n * reference form a compiled agent emits\n * (`<id>:<id>` for a marketplace-sourced skill, the bare id for an ejected\n * one), so a source change that skipped the recompile leaves every\n * registered project's agents naming a reference that no longer resolves.\n */\n sourceChanged: SkillId[];\n otherChanged: SkillId[];\n };\n agents: {\n added: AgentName[];\n removed: AgentName[];\n changed: AgentName[];\n };\n stackChanged: boolean;\n selectedDomainsChanged: boolean;\n /** Names of the inlined scalar fields that moved, in config key order. */\n scalarsChanged: string[];\n projectsChanged: boolean;\n};\n\n/** The identity element of {@link GlobalChangeSet} — nothing moved, so T4. */\nexport const NO_CHANGES: GlobalChangeSet = {\n skills: { added: [], removed: [], sourceChanged: [], otherChanged: [] },\n agents: { added: [], removed: [], changed: [] },\n stackChanged: false,\n selectedDomainsChanged: false,\n scalarsChanged: [],\n projectsChanged: false,\n};\n\n/** The four fields the config writer extracts into typed named variables. */\nconst EXTRACTED_FIELDS = new Set([\"skills\", \"agents\", \"stack\", \"selectedDomains\"]);\n\n/** The registration list — bookkeeping, never emitted into a project config. */\nconst REGISTRATION_FIELD = \"projects\";\n\n/**\n * Normalizes a config the way the writer does immediately before emission: a\n * JSON round-trip, so an explicitly-`undefined` field and an absent one compare\n * equal. Without it every write that merely reconstructs an object produces\n * phantom diffs.\n */\nfunction normalize(config: ProjectConfig): Record<string, unknown> {\n // Boundary cast: `JSON.parse` is typed `any`, and round-tripping an object\n // always yields one — the whole point of the call is that the result is the\n // same record with its undefined-valued keys gone.\n return JSON.parse(JSON.stringify(config)) as Record<string, unknown>;\n}\n\n/** Field value as the writer would emit it, or undefined when absent. */\nfunction field(config: Record<string, unknown>, key: string): unknown {\n return config[key];\n}\n\nfunction skillsById(config: Record<string, unknown>): Map<SkillId, SkillConfig> {\n const skills = (config.skills ?? []) as SkillConfig[];\n return new Map(skills.map((skill) => [skill.id, skill]));\n}\n\nfunction agentsByName(config: Record<string, unknown>): Map<AgentName, AgentScopeConfig> {\n const agents = (config.agents ?? []) as AgentScopeConfig[];\n return new Map(agents.map((agent) => [agent.name, agent]));\n}\n\n/** The scalar keys either side carries, in `next`-first order with `prev` extras appended. */\nfunction scalarKeys(prev: Record<string, unknown>, next: Record<string, unknown>): string[] {\n const isScalarKey = (key: string): boolean =>\n !EXTRACTED_FIELDS.has(key) && key !== REGISTRATION_FIELD;\n const nextKeys = Object.keys(next).filter(isScalarKey);\n const extraPrevKeys = Object.keys(prev).filter(\n (key) => isScalarKey(key) && !nextKeys.includes(key),\n );\n return [...nextKeys, ...extraPrevKeys];\n}\n\nfunction diffSkills(\n prev: Record<string, unknown>,\n next: Record<string, unknown>,\n): GlobalChangeSet[\"skills\"] {\n const before = skillsById(prev);\n const after = skillsById(next);\n\n const added = [...after.keys()].filter((id) => !before.has(id));\n const removed = [...before.keys()].filter((id) => !after.has(id));\n\n const sourceChanged: SkillId[] = [];\n const otherChanged: SkillId[] = [];\n for (const [id, afterEntry] of after) {\n const beforeEntry = before.get(id);\n if (!beforeEntry || isDeepEqual(beforeEntry, afterEntry)) continue;\n if (beforeEntry.origin !== afterEntry.origin) sourceChanged.push(id);\n else otherChanged.push(id);\n }\n\n return { added, removed, sourceChanged, otherChanged };\n}\n\nfunction diffAgents(\n prev: Record<string, unknown>,\n next: Record<string, unknown>,\n): GlobalChangeSet[\"agents\"] {\n const before = agentsByName(prev);\n const after = agentsByName(next);\n\n return {\n added: [...after.keys()].filter((name) => !before.has(name)),\n removed: [...before.keys()].filter((name) => !after.has(name)),\n changed: [...after.keys()].filter((name) => {\n const beforeEntry = before.get(name);\n return beforeEntry !== undefined && !isDeepEqual(beforeEntry, after.get(name));\n }),\n };\n}\n\n/**\n * Diffs the config on disk against the config about to be written. `prev` is\n * undefined when no global config exists yet, which every field reads as a\n * change from absent.\n */\nexport function classifyGlobalChange(\n prev: ProjectConfig | undefined,\n next: ProjectConfig,\n): GlobalChangeSet {\n const before = prev ? normalize(prev) : {};\n const after = normalize(next);\n\n return {\n skills: diffSkills(before, after),\n agents: diffAgents(before, after),\n stackChanged: !isDeepEqual(field(before, \"stack\"), field(after, \"stack\")),\n selectedDomainsChanged: !isDeepEqual(\n field(before, \"selectedDomains\"),\n field(after, \"selectedDomains\"),\n ),\n scalarsChanged: scalarKeys(before, after).filter(\n (key) => !isDeepEqual(field(before, key), field(after, key)),\n ),\n projectsChanged: !isDeepEqual(\n field(before, REGISTRATION_FIELD),\n field(after, REGISTRATION_FIELD),\n ),\n };\n}\n\n/** True when something the type unions or the compiled agents derive from moved. */\nfunction movesTypesOrCompiledAgents(changes: GlobalChangeSet): boolean {\n const { skills, agents } = changes;\n return (\n skills.added.length > 0 ||\n skills.removed.length > 0 ||\n skills.sourceChanged.length > 0 ||\n skills.otherChanged.length > 0 ||\n agents.added.length > 0 ||\n agents.removed.length > 0 ||\n agents.changed.length > 0 ||\n changes.stackChanged ||\n changes.selectedDomainsChanged\n );\n}\n\n/** The work tier a change set obliges. */\nexport function consequenceTier(changes: GlobalChangeSet): ConsequenceTier {\n if (movesTypesOrCompiledAgents(changes)) return \"T1\";\n if (changes.scalarsChanged.length > 0) return \"T2\";\n if (changes.projectsChanged) return \"T3\";\n return \"T4\";\n}\n\n/** True when the tier's consequences need the matrix and agent definitions. */\nexport function tierNeedsDeps(tier: ConsequenceTier): boolean {\n return tier === \"T1\" || tier === \"T2\";\n}\n\n/** True when the tier regenerates the types half and recompiles propagated agents. */\nexport function tierRegeneratesTypes(tier: ConsequenceTier): boolean {\n return tier === \"T1\";\n}\n\n/** True when the tier fans the change out to every registered project. */\nexport function tierPropagates(tier: ConsequenceTier): boolean {\n return tier === \"T1\" || tier === \"T2\";\n}\n","import type { AgentDefinition, AgentName, MergedSkillsMatrix } from \"../../types\";\nimport { tierNeedsDeps, tierRegeneratesTypes, type ConsequenceTier } from \"./classify.js\";\n\n/** The matrix and agent definitions propagation and type generation read. */\nexport type LoadedGateDeps = {\n matrix: MergedSkillsMatrix;\n agents: Partial<Record<AgentName, AgentDefinition>>;\n};\n\n/**\n * What a gate entry needs to carry out a write's consequences.\n *\n * The lazy form exists so a caller that cannot cheaply produce the matrix — an\n * offline uninstall, a deregistration — hands over loaders instead. Whether they\n * run is decided by classification: a registration-only or no-op write has no\n * consequences to carry out, so nothing is loaded and the write stays offline.\n */\nexport type GateDeps =\n | LoadedGateDeps\n | {\n loadMatrix: () => Promise<MergedSkillsMatrix>;\n loadAgents: () => Promise<Partial<Record<AgentName, AgentDefinition>>>;\n };\n\nfunction isLoaded(deps: GateDeps): deps is LoadedGateDeps {\n return \"matrix\" in deps;\n}\n\n/**\n * Resolves `deps` only when `tier` has consequences that read them. Returns null\n * otherwise, and the lazy loaders are never called.\n */\nexport async function resolveGateDeps(\n deps: GateDeps,\n tier: ConsequenceTier,\n): Promise<LoadedGateDeps | null> {\n if (!tierNeedsDeps(tier)) return null;\n if (isLoaded(deps)) return deps;\n\n // Agent definitions are read only where the types half is regenerated, so a\n // config-half-only tier never pays for loading them.\n const [matrix, agents] = await Promise.all([\n deps.loadMatrix(),\n tierRegeneratesTypes(tier) ? deps.loadAgents() : NO_AGENTS,\n ]);\n return { matrix, agents };\n}\n\n/** Agent definitions a tier that regenerates no types never reads. */\nconst NO_AGENTS: Promise<Partial<Record<AgentName, AgentDefinition>>> = Promise.resolve({});\n","import os from \"os\";\nimport path from \"path\";\nimport type { AgentDefinition, AgentName, MergedSkillsMatrix, ProjectConfig } from \"../../types\";\nimport { CLAUDE_SRC_DIR, STANDARD_FILES } from \"../../consts\";\nimport { ensureDir, fileExists, readFile, writeFile } from \"../../utils/fs\";\nimport { verbose } from \"../../utils/logger\";\nimport {\n generateBlankGlobalConfigSource,\n generateBlankGlobalConfigTypesSource,\n generateConfigSource,\n} from \"../configuration/config-writer\";\nimport {\n buildConfigTypesBackgroundData,\n generateConfigTypesSource,\n type ConfigTypesExtras,\n} from \"../configuration/config-types-writer\";\nimport { assertGateToken } from \"./gate-token.js\";\n\n/**\n * Nothing in this module MINTS the write privilege — every function below\n * REQUIRES it, and `writeIfChanged` is where that requirement is asserted. The\n * token is opened by the gate's public entry points in `index.ts`, each of which\n * wraps its whole consequence flow.\n *\n * That split is the point (D-309): a callee that opens the privilege on its own\n * behalf hands it to whoever reached it, so a caller that got past module\n * privacy — a dynamic import, a re-export added for convenience — arrived\n * already authorized and the runtime tripwire in `utils/fs.ts` waved it through.\n * Requiring the token instead makes reaching the private writer useless on its\n * own: the privilege belongs to the entry points, not to the writers.\n */\n\n/** Absolute paths of the two halves of the global config pair. */\nexport type GlobalPairPaths = {\n configPath: string;\n typesPath: string;\n};\n\n/**\n * Resolves the global pair's paths. `os.homedir()` at call time, so they agree\n * with every other home-dir reader and with test home mocks.\n */\nexport function globalPairPaths(): GlobalPairPaths {\n const dir = path.join(os.homedir(), CLAUDE_SRC_DIR);\n return {\n configPath: path.join(dir, STANDARD_FILES.CONFIG_TS),\n typesPath: path.join(dir, STANDARD_FILES.CONFIG_TYPES_TS),\n };\n}\n\n/** The types sibling of a config path — the two always share a directory. */\nexport function typesPathFor(configPath: string): string {\n return path.join(path.dirname(configPath), STANDARD_FILES.CONFIG_TYPES_TS);\n}\n\n/**\n * Writes `source` to `filePath` unless the file already holds exactly those\n * bytes. Both halves are derived from the same config on every write, so pair\n * coherence holds by derivation and the comparison only suppresses the mtime\n * churn a projects-only or scalar-only change would otherwise inflict on every\n * consumer watching these files. Returns true when the file was written.\n */\nasync function writeIfChanged(filePath: string, source: string): Promise<boolean> {\n assertGateToken(filePath);\n if ((await fileExists(filePath)) && (await readFile(filePath)) === source) return false;\n await writeFile(filePath, source);\n return true;\n}\n\n/**\n * Standalone (non-importing) type unions narrowed to `config`'s own entries,\n * widened by `extras` — the literals a just-created skill or agent needs before\n * it reaches the config.\n */\nfunction renderStandaloneTypes(\n config: ProjectConfig,\n matrix: MergedSkillsMatrix,\n agents: Partial<Record<AgentName, AgentDefinition>>,\n extras?: ConfigTypesExtras,\n): string {\n const data = buildConfigTypesBackgroundData(matrix, agents);\n return generateConfigTypesSource(\n data.matrix,\n data.agentNames,\n data.customAgentNames,\n extras,\n config,\n );\n}\n\n/**\n * Writes the config half of the pair at `configPath`. The global config never\n * takes the project writer's import/inline options — it is the file those\n * options resolve against.\n */\nexport async function writeGlobalConfigHalf(\n config: ProjectConfig,\n configPath: string,\n): Promise<boolean> {\n return writeIfChanged(configPath, generateConfigSource(config));\n}\n\n/** Writes the types half of the pair beside `configPath`. */\nexport async function writeGlobalTypesHalf(\n config: ProjectConfig,\n configPath: string,\n matrix: MergedSkillsMatrix,\n agents: Partial<Record<AgentName, AgentDefinition>>,\n extras?: ConfigTypesExtras,\n): Promise<boolean> {\n return writeIfChanged(\n typesPathFor(configPath),\n renderStandaloneTypes(config, matrix, agents, extras),\n );\n}\n\n/** Writes both halves from one config, so they cannot disagree. */\nexport async function writeGlobalPair(\n config: ProjectConfig,\n configPath: string,\n matrix: MergedSkillsMatrix,\n agents: Partial<Record<AgentName, AgentDefinition>>,\n): Promise<boolean> {\n const configWritten = await writeIfChanged(configPath, generateConfigSource(config));\n const typesWritten = await writeIfChanged(\n typesPathFor(configPath),\n renderStandaloneTypes(config, matrix, agents),\n );\n return configWritten || typesWritten;\n}\n\n/**\n * Creates a blank global pair at `~/.claude-src/` when none exists: `config.ts`\n * with empty arrays and `config-types.ts` with `never` unions. Returns true when\n * the files were created, false when they already existed.\n */\nexport async function ensureBlankPair(): Promise<boolean> {\n const { configPath, typesPath } = globalPairPaths();\n\n if (await fileExists(configPath)) {\n verbose(\"Global config already exists, skipping blank creation\");\n return false;\n }\n\n await ensureDir(path.dirname(configPath));\n\n await writeIfChanged(configPath, generateBlankGlobalConfigSource());\n await writeIfChanged(typesPath, generateBlankGlobalConfigTypesSource());\n\n verbose(`Created blank global config at ${path.dirname(configPath)}`);\n return true;\n}\n","import type { PropagatedRecompileSummary } from \"../operations/project/recompile-project-agents.js\";\n\n/** The summary of a fan-out that recompiled nothing, so callers render one shape. */\nexport const NOTHING_RECOMPILED: PropagatedRecompileSummary = {\n rewrittenCount: 0,\n unchangedCount: 0,\n failedCount: 0,\n warnings: [],\n};\n\n/**\n * Recompiles the agents of every project a global write propagated into.\n *\n * Imported lazily: `recompile-project-agents` lives in the operations layer,\n * which imports back into `installation`, so a static import here would form a\n * load-time cycle.\n * Per-project failure isolation lives in `recompilePropagatedProjectAgents` and\n * is unchanged by running it from inside the write.\n */\nexport async function recompilePropagated(\n projectDirs: string[],\n): Promise<PropagatedRecompileSummary> {\n if (projectDirs.length === 0) return NOTHING_RECOMPILED;\n\n const { recompilePropagatedProjectAgents } =\n await import(\"../operations/project/recompile-project-agents.js\");\n return recompilePropagatedProjectAgents(projectDirs);\n}\n","import path from \"path\";\nimport {\n buildAndMergeConfig,\n resolveInstallPaths,\n isHomeDirectory,\n} from \"../../installation/index.js\";\nimport type { SourceLoadResult } from \"../../loading/index.js\";\nimport type { AuthoritativeScope } from \"../../configuration/index.js\";\nimport {\n ensureBlankPair,\n writeScopedFromWizard,\n type GateReport,\n} from \"../../config-gate/index.js\";\nimport { loadAgentDefs, type AgentDefs } from \"./load-agent-defs.js\";\nimport { ensureDir } from \"../../../utils/fs.js\";\nimport type { ProjectConfig } from \"../../../types/index.js\";\nimport type { WizardResultV2 } from \"../../../components/wizard/wizard.js\";\n\nexport type ConfigWriteOptions = {\n wizardResult: WizardResultV2;\n sourceResult: SourceLoadResult;\n projectDir: string;\n sourceFlag?: string;\n /**\n * What {@link loadAgentDefs} answered, for a caller that has already asked it. Omitted, this\n * function asks for itself.\n *\n * It takes the WHOLE value rather than the roster inside it, so the only thing a caller can\n * hand over is what that one function produced. This used to be a bare\n * `Partial<Record<AgentName, AgentDefinition>>` — any map at all — which made \"a roster\n * different from the one the CLI would load\" a representable argument, and this function emits\n * the `AgentName` / `SelectedAgentName` unions from whatever it is given. Deleting the option\n * instead would cost `edit` a second uncached walk-and-parse of `src/agents/` per run, since\n * it needs `sourcePath` off the same value for its compile pass — one fact loaded twice, where\n * the second load is the one that can disagree.\n */\n agentDefs?: AgentDefs;\n /**\n * Authority of `cc edit`'s newConfig over absent entries:\n * `\"all\"` (global edit) drops any deselected entry, `\"owned\"` (project edit) drops deselected\n * project-owned entries only, `undefined` (init) keeps additive union-preserve.\n */\n authoritativeScope?: AuthoritativeScope;\n};\n\nexport type ConfigWriteResult = {\n config: ProjectConfig;\n configPath: string;\n wasMerged: boolean;\n existingConfigPath?: string;\n filesWritten: number;\n /**\n * What the gated write did: what moved in the global config, which registered\n * projects it fanned out to, and the recompile it drove in them. The caller\n * renders it; the work is already done.\n */\n propagation: GateReport;\n};\n\n/**\n * Builds, merges, and writes project configuration files.\n *\n * Handles the full config pipeline:\n * 1. buildAndMergeConfig() — generates config from wizard result, merges with existing\n * 2. loadAgentDefs() — the CLI's own sub-agent definitions, for config-types generation\n * 3. ensureBlankPair() — ensures the global config pair exists (when in project context)\n * 4. writeScopedFromWizard() — writes config.ts and config-types.ts split by scope,\n * fans global changes out to registered projects and recompiles their agents\n */\nexport async function writeProjectConfig(options: ConfigWriteOptions): Promise<ConfigWriteResult> {\n const { wizardResult, sourceResult, projectDir, sourceFlag } = options;\n const projectPaths = resolveInstallPaths(projectDir, \"project\");\n\n await ensureDir(path.dirname(projectPaths.configPath));\n\n // The marketplace is deliberately NOT consulted for this roster. It names the sub-agents the\n // emitted unions declare, and a marketplace-defined name in `AgentName` is one no compile pass\n // can honour: agent partials resolve through `getLocalAgentDefinitions`, which answers the\n // CLI's own root, and the generated `AGENT_NAMES` is built from that same directory. Reading\n // `sourceResult.sourcePath` here is what made `init` and `edit` emit two different files from\n // one config (owner ruling 2026-08-21).\n const { agents } = options.agentDefs ?? (await loadAgentDefs());\n\n const mergeResult = await buildAndMergeConfig(\n wizardResult,\n sourceResult,\n projectDir,\n sourceFlag,\n options.authoritativeScope,\n );\n const finalConfig = mergeResult.config;\n\n const isProjectContext = !isHomeDirectory(projectDir);\n\n if (isProjectContext) {\n await ensureBlankPair();\n }\n\n const propagation = await writeScopedFromWizard({\n finalConfig,\n matrix: sourceResult.matrix,\n agents,\n projectDir,\n projectConfigPath: projectPaths.configPath,\n projectInstallationExists: isProjectContext,\n // The same word the merger above took. It decides the config ROW there and the GLOBAL\n // config a project write commits here, and the two files disagree the moment it does not\n // reach both: a row preserved for a skill whose directory the removal diff deleted.\n ...(options.authoritativeScope !== undefined && {\n authoritativeScope: options.authoritativeScope,\n }),\n });\n\n return {\n config: finalConfig,\n configPath: projectPaths.configPath,\n wasMerged: mergeResult.merged,\n ...(mergeResult.existingConfigPath !== undefined && {\n existingConfigPath: mergeResult.existingConfigPath,\n }),\n filesWritten: isProjectContext ? 4 : 2,\n propagation,\n };\n}\n","import os from \"os\";\nimport { compileAgents, type CompilationResult } from \"./compile-agents.js\";\nimport { isHomeDirectory, resolveInstallPaths } from \"../../installation/index.js\";\nimport type { AgentName, SkillDefinitionMap, SkillScope } from \"../../../types/index.js\";\n\nexport type CompileAllScopesOptions = {\n /** Working directory of the command — a project root, or home for global context. */\n projectDir: string;\n sourcePath: string;\n skills: SkillDefinitionMap;\n agentScopeMap: Map<AgentName, SkillScope>;\n};\n\n/**\n * Compiles agents for every scope the current context owns.\n *\n * Home context: a single pass writing to the home agents directory.\n * Project context: a global pass (from home) then a project pass, each\n * filtered to its own scope so the project pass cannot overwrite global\n * agents with zero-skill versions. Results merge in pass order.\n */\nexport async function compileAgentsAllScopes(\n options: CompileAllScopesOptions,\n): Promise<CompilationResult> {\n const { projectDir, sourcePath, skills, agentScopeMap } = options;\n const base = { sourcePath, skills, agentScopeMap };\n\n if (isHomeDirectory(projectDir)) {\n return compileAgents({\n ...base,\n projectDir,\n outputDir: resolveInstallPaths(projectDir, \"project\").agentsDir,\n });\n }\n\n const globalResult = await compileAgents({\n ...base,\n projectDir: os.homedir(),\n outputDir: resolveInstallPaths(os.homedir(), \"global\").agentsDir,\n scopeFilter: \"global\",\n });\n const projectResult = await compileAgents({\n ...base,\n projectDir,\n outputDir: resolveInstallPaths(projectDir, \"project\").agentsDir,\n scopeFilter: \"project\",\n });\n return mergeCompilationResults(globalResult, projectResult);\n}\n\nfunction mergeCompilationResults(...results: CompilationResult[]): CompilationResult {\n return {\n compiled: results.flatMap((r) => r.compiled),\n rewritten: results.flatMap((r) => r.rewritten),\n failed: results.flatMap((r) => r.failed),\n warnings: results.flatMap((r) => r.warnings),\n };\n}\n"],"mappings":"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","names":["matrix","isExclusiveCategory","os","path","isDeepEqual","EXTRACTED_FIELDS","matrix","os","path","path","os","matrix","recompilePropagatedProjectAgents","loadSkillsMatrixFromSource","matrix","loadAgentDefs","os","path","ensureBlankPair","path","path","ensureBlankPair","os","os"]}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
getAgentDefinitions
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-WMVOJY6V.js";
|
|
5
5
|
import {
|
|
6
6
|
loadMergedAgents
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-3PJLLBUS.js";
|
|
8
8
|
|
|
9
9
|
// src/cli/lib/operations/project/load-agent-defs.ts
|
|
10
10
|
async function loadAgentDefs() {
|
|
@@ -20,4 +20,4 @@ async function loadAgentDefs() {
|
|
|
20
20
|
export {
|
|
21
21
|
loadAgentDefs
|
|
22
22
|
};
|
|
23
|
-
//# sourceMappingURL=chunk-
|
|
23
|
+
//# sourceMappingURL=chunk-H4CL23HG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/lib/operations/project/load-agent-defs.ts"],"sourcesContent":["import { getAgentDefinitions } from \"../../agents/index.js\";\nimport { loadMergedAgents } from \"../../loading/index.js\";\nimport type { AgentDefinition, AgentName, AgentSourcePaths } from \"../../../types/index.js\";\n\nexport type AgentDefs = {\n /**\n * The CLI's own sub-agent definitions — every `metadata.yaml` under its `src/agents/`, and\n * nothing a marketplace declares.\n */\n agents: Partial<Record<AgentName, AgentDefinition>>;\n /** The sourcePath used to load agent partials (for compilation). */\n sourcePath: string;\n /** Full agent source paths (agentsDir, sourcePath). */\n agentSourcePaths: AgentSourcePaths;\n};\n\n/**\n * The single definition of which sub-agents exist.\n *\n * Every path that emits the sub-agent unions in a `config-types.ts` derives its roster from here,\n * and so does every compile pass, because the answer has to be the same one: agent partials\n * resolve under {@link getAgentDefinitions}' local branch, and the generated `AGENT_NAMES` is\n * built by `scripts/generate-source-types.ts` from that same `src/agents/` directory. A roster\n * that included a marketplace's own sub-agents would put a literal in `AgentName` that nothing\n * downstream can honour (owner ruling 2026-08-21).\n *\n * It takes no arguments because there is nothing here for a caller to vary: agent partials\n * ship with the CLI, so {@link getAgentDefinitions} is always asked for its local branch.\n *\n * That local branch answers `sourcePath: PROJECT_ROOT`, so {@link loadMergedAgents} below is\n * handed the CLI's own root as its \"source\" and both of its sides read the same directory. The\n * merge is real and degenerate, which is why this used to be documented as \"CLI defaults plus\n * source overrides\" — a sentence describing an argument this function has not taken for some\n * time. The wiring was the intent; the sentence was the fossil.\n */\nexport async function loadAgentDefs(): Promise<AgentDefs> {\n const agentSourcePaths = await getAgentDefinitions();\n const agents = await loadMergedAgents(agentSourcePaths.sourcePath);\n\n return {\n agents,\n sourcePath: agentSourcePaths.sourcePath,\n agentSourcePaths,\n };\n}\n"],"mappings":";;;;;;;;;AAmCA,eAAsB,gBAAoC;AACxD,QAAM,mBAAmB,MAAM,oBAAoB;AACnD,QAAM,SAAS,MAAM,iBAAiB,iBAAiB,UAAU;AAEjE,SAAO;AAAA,IACL;AAAA,IACA,YAAY,iBAAiB;AAAA,IAC7B;AAAA,EACF;AACF;","names":[]}
|
|
@@ -2,28 +2,27 @@
|
|
|
2
2
|
import {
|
|
3
3
|
DOMAIN_ORDER,
|
|
4
4
|
deriveInstallMode,
|
|
5
|
+
disableBuffering,
|
|
6
|
+
drainBuffer,
|
|
7
|
+
enableBuffering,
|
|
5
8
|
getAvailableSkills,
|
|
6
9
|
getCellState,
|
|
7
10
|
getUnmetRequiredBy,
|
|
8
11
|
isActiveAt,
|
|
9
12
|
isGlobalTombstone,
|
|
10
13
|
isLocalOnlySkill,
|
|
11
|
-
isProjectOwned
|
|
12
|
-
} from "./chunk-WCAUUBHO.js";
|
|
13
|
-
import {
|
|
14
|
+
isProjectOwned,
|
|
14
15
|
warn
|
|
15
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-3PJLLBUS.js";
|
|
16
17
|
import {
|
|
17
18
|
getCategoryDomain,
|
|
18
19
|
getSkillById,
|
|
19
|
-
matrix
|
|
20
|
-
} from "./chunk-RWOYPOMR.js";
|
|
21
|
-
import {
|
|
20
|
+
matrix,
|
|
22
21
|
typedEntries,
|
|
23
22
|
typedFromEntries,
|
|
24
23
|
typedKeys,
|
|
25
24
|
typedValues
|
|
26
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-7Z4N4JWQ.js";
|
|
27
26
|
import {
|
|
28
27
|
CLI_INVOKE_COMMAND,
|
|
29
28
|
DEFAULT_PUBLIC_SOURCE_NAME,
|
|
@@ -32,7 +31,7 @@ import {
|
|
|
32
31
|
FALLBACK_DOMAIN,
|
|
33
32
|
INSTALL_MODES,
|
|
34
33
|
SKILL_CATEGORIES_PATH
|
|
35
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-G6G2FT2G.js";
|
|
36
35
|
|
|
37
36
|
// src/cli/stores/wizard-store.ts
|
|
38
37
|
import { create } from "zustand";
|
|
@@ -144,6 +143,16 @@ function toRemovedAgentRow(agent) {
|
|
|
144
143
|
}
|
|
145
144
|
|
|
146
145
|
// src/cli/lib/wizard/build-step-logic.ts
|
|
146
|
+
function validateBuildStep(categories, selections) {
|
|
147
|
+
const emptyRequired = categories.find(
|
|
148
|
+
(category) => category.required && !selections[category.id]?.length
|
|
149
|
+
);
|
|
150
|
+
if (!emptyRequired) return { valid: true };
|
|
151
|
+
return {
|
|
152
|
+
valid: false,
|
|
153
|
+
message: `No skills selected in ${emptyRequired.displayName} (required category)`
|
|
154
|
+
};
|
|
155
|
+
}
|
|
147
156
|
function buildCategoriesForDomain(domain, allSelections, installedSkillIds, skillConfigs) {
|
|
148
157
|
const categories = sortBy(
|
|
149
158
|
typedValues(matrix.categories).filter((cat) => cat.domain === domain),
|
|
@@ -309,6 +318,9 @@ var TOAST_MESSAGES = {
|
|
|
309
318
|
ALREADY_EJECTED_AT_GLOBAL: "Already exists as ejected skill at global scope",
|
|
310
319
|
GLOBAL_AGENTS_LOCKED: "Global agents cannot be changed from project scope"
|
|
311
320
|
};
|
|
321
|
+
function skillsLeftOutToast(count) {
|
|
322
|
+
return count === 1 ? "1 skill was left out \u2014 this source cannot place it" : `${count} skills were left out \u2014 this source cannot place them`;
|
|
323
|
+
}
|
|
312
324
|
function resolveEffectiveSource(...candidates) {
|
|
313
325
|
return candidates.find((source) => source !== void 0) ?? DEFAULT_PUBLIC_SOURCE_NAME;
|
|
314
326
|
}
|
|
@@ -409,13 +421,13 @@ function reconcileSkillConfigs(configs, added, removed, installedSkillConfigs, i
|
|
|
409
421
|
return result;
|
|
410
422
|
}
|
|
411
423
|
function agentHasProjectActive(configs, name) {
|
|
412
|
-
return configs.some((ac) => ac.name === name && ac
|
|
424
|
+
return configs.some((ac) => ac.name === name && isActiveAt(ac, "project"));
|
|
413
425
|
}
|
|
414
426
|
function agentHasGlobalActive(configs, name) {
|
|
415
|
-
return configs.some((ac) => ac.name === name && ac
|
|
427
|
+
return configs.some((ac) => ac.name === name && isActiveAt(ac, "global"));
|
|
416
428
|
}
|
|
417
429
|
function agentHasGlobalTombstone(configs, name) {
|
|
418
|
-
return configs.some((ac) => ac.name === name && ac
|
|
430
|
+
return configs.some((ac) => ac.name === name && isGlobalTombstone(ac));
|
|
419
431
|
}
|
|
420
432
|
function isDualScopeAgentPair(configs, name) {
|
|
421
433
|
return agentHasProjectActive(configs, name) && agentHasGlobalTombstone(configs, name);
|
|
@@ -770,7 +782,7 @@ var useWizardStore = create((set, get) => ({
|
|
|
770
782
|
selectedDomains: state.selectedDomains.filter((d) => d !== domain),
|
|
771
783
|
domainSelections: remainingSelections,
|
|
772
784
|
// Global-scope edit: no overlay, so deselecting a domain uninstalls its skills cleanly
|
|
773
|
-
// rather than tombstoning them in the global config
|
|
785
|
+
// rather than tombstoning them in the global config.
|
|
774
786
|
skillConfigs: applySkillRemoval(
|
|
775
787
|
state.skillConfigs,
|
|
776
788
|
removedSkillIds,
|
|
@@ -1075,6 +1087,18 @@ var useWizardStore = create((set, get) => ({
|
|
|
1075
1087
|
return rows;
|
|
1076
1088
|
}
|
|
1077
1089
|
}));
|
|
1090
|
+
function showWarningsAsToast(change) {
|
|
1091
|
+
enableBuffering();
|
|
1092
|
+
try {
|
|
1093
|
+
change();
|
|
1094
|
+
const warnings = drainBuffer();
|
|
1095
|
+
if (warnings.length > 0) {
|
|
1096
|
+
useWizardStore.getState().setToastMessage(skillsLeftOutToast(warnings.length));
|
|
1097
|
+
}
|
|
1098
|
+
} finally {
|
|
1099
|
+
disableBuffering();
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1078
1102
|
function hydrateWizardStore(options) {
|
|
1079
1103
|
useWizardStore.setState(createInitialState());
|
|
1080
1104
|
const { initialStep } = options;
|
|
@@ -1156,6 +1180,7 @@ export {
|
|
|
1156
1180
|
computeScopeDiff,
|
|
1157
1181
|
formatScopeTag,
|
|
1158
1182
|
deriveScopeBadges,
|
|
1183
|
+
validateBuildStep,
|
|
1159
1184
|
buildCategoriesForDomain,
|
|
1160
1185
|
orderDomains,
|
|
1161
1186
|
BUILT_IN_AGENT_GROUPS,
|
|
@@ -1165,6 +1190,7 @@ export {
|
|
|
1165
1190
|
getActiveStepFlow,
|
|
1166
1191
|
createInitialState,
|
|
1167
1192
|
useWizardStore,
|
|
1193
|
+
showWarningsAsToast,
|
|
1168
1194
|
hydrateWizardStore
|
|
1169
1195
|
};
|
|
1170
|
-
//# sourceMappingURL=chunk-
|
|
1196
|
+
//# sourceMappingURL=chunk-IK6YOXZH.js.map
|