agents-inc 0.159.0 → 0.161.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 +23 -0
- package/README.md +1 -1
- package/dist/{chunk-PEHYVSJG.js → chunk-264XDRU7.js} +2 -2
- package/dist/{chunk-WVKGO3Y5.js → chunk-2MPXMJ2O.js} +7 -7
- package/dist/{chunk-IO2DPRDS.js → chunk-3H42U56X.js} +2 -2
- package/dist/{chunk-FBRLHNUT.js → chunk-3M75HVIM.js} +3 -3
- package/dist/{chunk-YKRPWZ3G.js → chunk-3TM4FHTG.js} +2 -2
- package/dist/{chunk-5YOSLSQJ.js → chunk-5DWDT6GM.js} +115 -96
- package/dist/chunk-5DWDT6GM.js.map +1 -0
- package/dist/{chunk-4APXK7ZY.js → chunk-5MML3K36.js} +2 -2
- package/dist/{chunk-F35G42TF.js → chunk-6PVWDTEM.js} +12 -12
- package/dist/{chunk-VCUXNKOY.js → chunk-A2NA377T.js} +6 -6
- package/dist/{chunk-4RYWFQK7.js → chunk-ADDYIMWN.js} +3 -3
- package/dist/{chunk-V625APR6.js → chunk-AMZO4YJK.js} +10789 -18786
- package/dist/chunk-AMZO4YJK.js.map +1 -0
- package/dist/{chunk-4VMLCWLD.js → chunk-AO6DXJUK.js} +3 -3
- package/dist/{chunk-G7TYOPON.js → chunk-B3YSTZZC.js} +3 -3
- package/dist/{chunk-THLQS2AW.js → chunk-B7YTQVAF.js} +4 -4
- package/dist/{chunk-7Z4N4JWQ.js → chunk-BLGETWYI.js} +6 -113
- package/dist/chunk-BLGETWYI.js.map +1 -0
- package/dist/{chunk-ITEJARWI.js → chunk-BRHU6J3C.js} +3 -3
- package/dist/{chunk-AU5FS3QK.js → chunk-DGXW2ZFY.js} +3 -3
- package/dist/{chunk-LSSGS2QS.js → chunk-DHRW3MDM.js} +3 -3
- package/dist/{chunk-OJIQOVWB.js → chunk-DTCUZL7S.js} +2 -2
- package/dist/{chunk-SKDTGHCD.js → chunk-EEFTUZHZ.js} +5 -5
- package/dist/{chunk-BQJVHD6Y.js → chunk-EERGAAGE.js} +5 -10
- package/dist/chunk-EERGAAGE.js.map +1 -0
- package/dist/{chunk-Z6G24ROK.js → chunk-EQSMVZGS.js} +10 -10
- package/dist/{chunk-2Q65K6E3.js → chunk-EY7Z34Y4.js} +15 -15
- package/dist/{chunk-BNHD2GIB.js → chunk-F6LS2BQD.js} +11 -11
- package/dist/{chunk-SITF5EZM.js → chunk-HB3YIAFD.js} +2 -2
- package/dist/{chunk-GPZQCLZJ.js → chunk-LZPRLHUE.js} +9 -9
- package/dist/{chunk-YAHTF4NO.js → chunk-MED6GNV3.js} +288 -203
- package/dist/chunk-MED6GNV3.js.map +1 -0
- package/dist/chunk-N6CILY5A.js +35 -0
- package/dist/chunk-N6CILY5A.js.map +1 -0
- package/dist/{chunk-42PQKBVU.js → chunk-ODUACQLV.js} +6 -6
- package/dist/{chunk-VZRO7RYT.js → chunk-OI2H6M5I.js} +1 -103
- package/dist/chunk-OI2H6M5I.js.map +1 -0
- package/dist/{chunk-MPLWPWL4.js → chunk-QKMT6OOP.js} +2 -2
- package/dist/{chunk-WVBJRFFM.js → chunk-SX57ZIGM.js} +4 -4
- package/dist/{chunk-62XKTOUI.js → chunk-T4RVCFWN.js} +5 -15
- package/dist/chunk-T4RVCFWN.js.map +1 -0
- package/dist/{chunk-4VVKVOOP.js → chunk-UMYEY6BA.js} +2 -2
- package/dist/{chunk-X5PLVOJS.js → chunk-W2RXRWDB.js} +2 -2
- package/dist/{chunk-JV4P7BL4.js → chunk-WVCF7KFV.js} +5 -5
- package/dist/chunk-XA4SWA2Z.js +591 -0
- package/dist/chunk-XA4SWA2Z.js.map +1 -0
- package/dist/{chunk-LVA6XJGR.js → chunk-YOVUXONB.js} +9 -43
- package/dist/chunk-YOVUXONB.js.map +1 -0
- package/dist/chunk-YSQ76LWG.js +8734 -0
- package/dist/chunk-YSQ76LWG.js.map +1 -0
- package/dist/{chunk-Z6KROWH4.js → chunk-ZQZHDYHQ.js} +7 -7
- package/dist/commands/build/marketplace.js +8 -8
- package/dist/commands/build/plugins.js +8 -8
- package/dist/commands/compile.js +14 -14
- package/dist/commands/doctor.js +13 -13
- package/dist/commands/edit.js +45 -45
- package/dist/commands/eject.js +11 -11
- package/dist/commands/init.js +37 -37
- package/dist/commands/list.js +9 -9
- package/dist/commands/new/marketplace.js +8 -9
- package/dist/commands/new/marketplace.js.map +1 -1
- package/dist/commands/search.js +11 -11
- package/dist/commands/share.js +11 -10
- package/dist/commands/share.js.map +1 -1
- package/dist/commands/uninstall.js +12 -12
- package/dist/commands/update.js +7 -7
- package/dist/components/common/removal-plan-confirm.js +2 -2
- package/dist/components/common/select-list.js +2 -2
- package/dist/components/wizard/category-grid.js +4 -4
- package/dist/components/wizard/checkbox-grid.js +4 -4
- package/dist/components/wizard/domain-selection.js +10 -10
- package/dist/components/wizard/run-wizard-session.js +27 -27
- package/dist/components/wizard/scroll-affordance.js +2 -2
- package/dist/components/wizard/skill-agent-summary.js +6 -6
- package/dist/components/wizard/source-grid.js +5 -5
- package/dist/components/wizard/stack-selection.js +8 -8
- package/dist/components/wizard/step-agents.js +9 -9
- package/dist/components/wizard/step-build.js +8 -8
- package/dist/components/wizard/step-confirm.js +10 -10
- package/dist/components/wizard/step-sources.js +9 -9
- package/dist/components/wizard/step-stack.js +9 -9
- package/dist/components/wizard/summary-panel.js +9 -9
- package/dist/components/wizard/toast.js +2 -2
- package/dist/components/wizard/wizard-layout.js +13 -13
- package/dist/components/wizard/wizard-tabs.js +2 -2
- package/dist/components/wizard/wizard.js +26 -26
- package/dist/config-exports.js +1 -1
- package/dist/hooks/init.js +37 -37
- package/dist/load-agent-defs-LDSND43G.js +13 -0
- package/dist/recompile-project-agents-GQLODH24.js +17 -0
- package/dist/{source-loader-CC6ZWKTI.js → source-loader-TSF5VS6V.js} +5 -5
- package/dist/src/agents/_templates/methodologies/anti-over-engineering.liquid +14 -0
- package/dist/src/agents/_templates/methodologies/context-management.liquid +7 -154
- package/dist/src/agents/_templates/methodologies/investigation-requirements.liquid +12 -0
- package/dist/src/agents/_templates/methodologies/success-criteria.liquid +10 -0
- package/dist/stores/wizard-store.js +5 -5
- package/package.json +9 -4
- package/src/agents/_templates/methodologies/anti-over-engineering.liquid +14 -0
- package/src/agents/_templates/methodologies/context-management.liquid +7 -154
- package/src/agents/_templates/methodologies/investigation-requirements.liquid +12 -0
- package/src/agents/_templates/methodologies/success-criteria.liquid +10 -0
- package/dist/chunk-5KB4I5J7.js +0 -262
- package/dist/chunk-5KB4I5J7.js.map +0 -1
- package/dist/chunk-5YOSLSQJ.js.map +0 -1
- package/dist/chunk-62XKTOUI.js.map +0 -1
- package/dist/chunk-7Z4N4JWQ.js.map +0 -1
- package/dist/chunk-BQJVHD6Y.js.map +0 -1
- package/dist/chunk-LVA6XJGR.js.map +0 -1
- package/dist/chunk-NS5COBTT.js +0 -254
- package/dist/chunk-NS5COBTT.js.map +0 -1
- package/dist/chunk-V625APR6.js.map +0 -1
- package/dist/chunk-VZRO7RYT.js.map +0 -1
- package/dist/chunk-YAHTF4NO.js.map +0 -1
- package/dist/chunk-YVQSDBTK.js +0 -169
- package/dist/chunk-YVQSDBTK.js.map +0 -1
- package/dist/load-agent-defs-2H42B2OO.js +0 -13
- package/dist/recompile-project-agents-QIAMBCM4.js +0 -17
- /package/dist/{chunk-PEHYVSJG.js.map → chunk-264XDRU7.js.map} +0 -0
- /package/dist/{chunk-WVKGO3Y5.js.map → chunk-2MPXMJ2O.js.map} +0 -0
- /package/dist/{chunk-IO2DPRDS.js.map → chunk-3H42U56X.js.map} +0 -0
- /package/dist/{chunk-FBRLHNUT.js.map → chunk-3M75HVIM.js.map} +0 -0
- /package/dist/{chunk-YKRPWZ3G.js.map → chunk-3TM4FHTG.js.map} +0 -0
- /package/dist/{chunk-4APXK7ZY.js.map → chunk-5MML3K36.js.map} +0 -0
- /package/dist/{chunk-F35G42TF.js.map → chunk-6PVWDTEM.js.map} +0 -0
- /package/dist/{chunk-VCUXNKOY.js.map → chunk-A2NA377T.js.map} +0 -0
- /package/dist/{chunk-4RYWFQK7.js.map → chunk-ADDYIMWN.js.map} +0 -0
- /package/dist/{chunk-4VMLCWLD.js.map → chunk-AO6DXJUK.js.map} +0 -0
- /package/dist/{chunk-G7TYOPON.js.map → chunk-B3YSTZZC.js.map} +0 -0
- /package/dist/{chunk-THLQS2AW.js.map → chunk-B7YTQVAF.js.map} +0 -0
- /package/dist/{chunk-ITEJARWI.js.map → chunk-BRHU6J3C.js.map} +0 -0
- /package/dist/{chunk-AU5FS3QK.js.map → chunk-DGXW2ZFY.js.map} +0 -0
- /package/dist/{chunk-LSSGS2QS.js.map → chunk-DHRW3MDM.js.map} +0 -0
- /package/dist/{chunk-OJIQOVWB.js.map → chunk-DTCUZL7S.js.map} +0 -0
- /package/dist/{chunk-SKDTGHCD.js.map → chunk-EEFTUZHZ.js.map} +0 -0
- /package/dist/{chunk-Z6G24ROK.js.map → chunk-EQSMVZGS.js.map} +0 -0
- /package/dist/{chunk-2Q65K6E3.js.map → chunk-EY7Z34Y4.js.map} +0 -0
- /package/dist/{chunk-BNHD2GIB.js.map → chunk-F6LS2BQD.js.map} +0 -0
- /package/dist/{chunk-SITF5EZM.js.map → chunk-HB3YIAFD.js.map} +0 -0
- /package/dist/{chunk-GPZQCLZJ.js.map → chunk-LZPRLHUE.js.map} +0 -0
- /package/dist/{chunk-42PQKBVU.js.map → chunk-ODUACQLV.js.map} +0 -0
- /package/dist/{chunk-MPLWPWL4.js.map → chunk-QKMT6OOP.js.map} +0 -0
- /package/dist/{chunk-WVBJRFFM.js.map → chunk-SX57ZIGM.js.map} +0 -0
- /package/dist/{chunk-4VVKVOOP.js.map → chunk-UMYEY6BA.js.map} +0 -0
- /package/dist/{chunk-X5PLVOJS.js.map → chunk-W2RXRWDB.js.map} +0 -0
- /package/dist/{chunk-JV4P7BL4.js.map → chunk-WVCF7KFV.js.map} +0 -0
- /package/dist/{chunk-Z6KROWH4.js.map → chunk-ZQZHDYHQ.js.map} +0 -0
- /package/dist/{load-agent-defs-2H42B2OO.js.map → load-agent-defs-LDSND43G.js.map} +0 -0
- /package/dist/{recompile-project-agents-QIAMBCM4.js.map → recompile-project-agents-GQLODH24.js.map} +0 -0
- /package/dist/{source-loader-CC6ZWKTI.js.map → source-loader-TSF5VS6V.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
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"]}
|
package/dist/chunk-YVQSDBTK.js
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
orderDomains
|
|
4
|
-
} from "./chunk-LVA6XJGR.js";
|
|
5
|
-
import {
|
|
6
|
-
AGENT_NAMES,
|
|
7
|
-
execCommand,
|
|
8
|
-
getErrorMessage,
|
|
9
|
-
isScopePairCompatible,
|
|
10
|
-
seedAgentScope,
|
|
11
|
-
validateSelection
|
|
12
|
-
} from "./chunk-V625APR6.js";
|
|
13
|
-
import {
|
|
14
|
-
getCategoryDomain
|
|
15
|
-
} from "./chunk-7Z4N4JWQ.js";
|
|
16
|
-
import {
|
|
17
|
-
DEFAULT_PUBLIC_SOURCE_NAME
|
|
18
|
-
} from "./chunk-5KB4I5J7.js";
|
|
19
|
-
|
|
20
|
-
// src/cli/lib/seed/seed-to-wizard.ts
|
|
21
|
-
var KNOWN_AGENTS = new Set(AGENT_NAMES);
|
|
22
|
-
function sourceForSkill(skill) {
|
|
23
|
-
return skill?.availableSources?.find((s) => s.primary)?.name ?? DEFAULT_PUBLIC_SOURCE_NAME;
|
|
24
|
-
}
|
|
25
|
-
function addToDomainSelections(selections, domain, category, skillId) {
|
|
26
|
-
const categorySelections = selections[domain] ??= {};
|
|
27
|
-
const skillList = categorySelections[category] ??= [];
|
|
28
|
-
if (!skillList.includes(skillId)) skillList.push(skillId);
|
|
29
|
-
}
|
|
30
|
-
function addToAgentStack(stack, agent, category, assignment) {
|
|
31
|
-
const agentStack = stack[agent] ??= {};
|
|
32
|
-
const assignments = agentStack[category] ??= [];
|
|
33
|
-
assignments.push(assignment);
|
|
34
|
-
}
|
|
35
|
-
function toSkillAssignment(skillId, load) {
|
|
36
|
-
return { id: skillId, preloaded: load === "preloaded" };
|
|
37
|
-
}
|
|
38
|
-
function readAgentMap(agents) {
|
|
39
|
-
const known = /* @__PURE__ */ new Map();
|
|
40
|
-
const switchedOff = /* @__PURE__ */ new Set();
|
|
41
|
-
const unknown = [];
|
|
42
|
-
for (const [name, entry] of Object.entries(agents)) {
|
|
43
|
-
if (!KNOWN_AGENTS.has(name)) unknown.push(name);
|
|
44
|
-
else if (entry.on === false) switchedOff.add(name);
|
|
45
|
-
else known.set(name, entry);
|
|
46
|
-
}
|
|
47
|
-
return { known, switchedOff, unknown };
|
|
48
|
-
}
|
|
49
|
-
function agentScopeConfig(name, entry) {
|
|
50
|
-
return {
|
|
51
|
-
name,
|
|
52
|
-
scope: seedAgentScope(entry),
|
|
53
|
-
...entry?.model !== void 0 && { model: entry.model },
|
|
54
|
-
...entry?.effort !== void 0 && { effort: entry.effort }
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
function unwritableAssignmentsError(assignments) {
|
|
58
|
-
return [
|
|
59
|
-
"This configuration cannot be installed: a project-scoped skill never reaches a sub-agent that rests at global scope, so these assignments have nowhere to be written:",
|
|
60
|
-
...assignments.map(({ skillId, agent }) => ` ${skillId} -> ${agent}`),
|
|
61
|
-
"Re-share it with each sub-agent above pinned to the project, or each skill above at global scope."
|
|
62
|
-
].join("\n");
|
|
63
|
-
}
|
|
64
|
-
function seedToWizardResult(payload, matrix) {
|
|
65
|
-
const domainSelections = {};
|
|
66
|
-
const assignedStack = {};
|
|
67
|
-
const skills = [];
|
|
68
|
-
const skippedSkillIds = [];
|
|
69
|
-
const unwritable = [];
|
|
70
|
-
const agentNames = /* @__PURE__ */ new Set();
|
|
71
|
-
const agentMap = readAgentMap(payload.agents);
|
|
72
|
-
const skippedAgentNames = new Set(agentMap.unknown);
|
|
73
|
-
for (const [skillId, entry] of Object.entries(payload.skills)) {
|
|
74
|
-
const skill = matrix.skills[skillId];
|
|
75
|
-
const domain = skill?.category ? getCategoryDomain(skill.category) : void 0;
|
|
76
|
-
if (!skill?.category || !domain) {
|
|
77
|
-
skippedSkillIds.push(skillId);
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
const id = skillId;
|
|
81
|
-
const category = skill.category;
|
|
82
|
-
addToDomainSelections(domainSelections, domain, category, id);
|
|
83
|
-
skills.push({
|
|
84
|
-
id,
|
|
85
|
-
scope: entry.scope,
|
|
86
|
-
// "eject" is an origin in its own right; anything else names the marketplace it came from.
|
|
87
|
-
origin: entry.install === "eject" ? "eject" : sourceForSkill(skill)
|
|
88
|
-
});
|
|
89
|
-
for (const [agentName, load] of Object.entries(entry.assignments)) {
|
|
90
|
-
if (agentMap.switchedOff.has(agentName)) continue;
|
|
91
|
-
if (!KNOWN_AGENTS.has(agentName)) {
|
|
92
|
-
skippedAgentNames.add(agentName);
|
|
93
|
-
continue;
|
|
94
|
-
}
|
|
95
|
-
const agent = agentName;
|
|
96
|
-
if (!isScopePairCompatible(entry.scope, seedAgentScope(agentMap.known.get(agent)))) {
|
|
97
|
-
unwritable.push({ skillId: id, agent });
|
|
98
|
-
continue;
|
|
99
|
-
}
|
|
100
|
-
agentNames.add(agent);
|
|
101
|
-
addToAgentStack(assignedStack, agent, category, toSkillAssignment(id, load));
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
if (unwritable.length > 0) throw new Error(unwritableAssignmentsError(unwritable));
|
|
105
|
-
for (const [name, entry] of agentMap.known) {
|
|
106
|
-
if (entry.on === true) agentNames.add(name);
|
|
107
|
-
}
|
|
108
|
-
const selectedAgents = [...agentNames];
|
|
109
|
-
return {
|
|
110
|
-
result: {
|
|
111
|
-
skills,
|
|
112
|
-
selectedAgents,
|
|
113
|
-
agentConfigs: selectedAgents.map((name) => agentScopeConfig(name, agentMap.known.get(name))),
|
|
114
|
-
assignedStack,
|
|
115
|
-
selectedStackId: payload.stackId,
|
|
116
|
-
// Spread-conditional rather than passed through, because absent and present-holding-undefined
|
|
117
|
-
// are different files on disk: a config describing itself with no key is not one describing
|
|
118
|
-
// itself with an empty sentence, and the writer emits whichever key it is handed.
|
|
119
|
-
...payload.description !== void 0 && { description: payload.description },
|
|
120
|
-
domainSelections,
|
|
121
|
-
selectedDomains: orderDomains(Object.keys(domainSelections)),
|
|
122
|
-
// Nothing was dropped from a *saved config* — the skipped ids came off the wire and are
|
|
123
|
-
// reported to the user directly, so there is no config removal to explain.
|
|
124
|
-
unresolvableSkillIds: [],
|
|
125
|
-
cancelled: false,
|
|
126
|
-
// Revalidated here rather than taken on trust from the app that built the payload. That app
|
|
127
|
-
// validated against ITS catalog; this one skips ids it does not know and carries its own
|
|
128
|
-
// relationship rules, so a configuration that was consistent where it was authored can
|
|
129
|
-
// arrive with a requirement genuinely unmet. Running the same validator the wizard runs
|
|
130
|
-
// makes that this catalog's verdict on what it can install — reported through the spine
|
|
131
|
-
// `init` already has, beside the skips that explain it — rather than a fault in what was
|
|
132
|
-
// shared.
|
|
133
|
-
validation: validateSelection(skills.map((skill) => skill.id))
|
|
134
|
-
},
|
|
135
|
-
skippedSkillIds,
|
|
136
|
-
skippedAgentNames: [...skippedAgentNames]
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// src/cli/utils/open-url.ts
|
|
141
|
-
function browserOpenerCommand(platform, url) {
|
|
142
|
-
if (platform === "darwin") return { command: "open", args: [url] };
|
|
143
|
-
if (platform === "win32") return { command: "cmd", args: ["/c", "start", "", url] };
|
|
144
|
-
return { command: "xdg-open", args: [url] };
|
|
145
|
-
}
|
|
146
|
-
function openerRefusedMessage(command, exitCode) {
|
|
147
|
-
return `Could not open your browser \u2014 '${command}' exited ${exitCode}.`;
|
|
148
|
-
}
|
|
149
|
-
function openerUnavailableMessage(command, reason) {
|
|
150
|
-
return `Could not open your browser \u2014 '${command}' could not be run: ${reason}`;
|
|
151
|
-
}
|
|
152
|
-
async function openUrl(url) {
|
|
153
|
-
const { command, args } = browserOpenerCommand(process.platform, url);
|
|
154
|
-
try {
|
|
155
|
-
const result = await execCommand(command, args);
|
|
156
|
-
if (result.exitCode !== 0) {
|
|
157
|
-
return { ok: false, error: openerRefusedMessage(command, result.exitCode) };
|
|
158
|
-
}
|
|
159
|
-
return { ok: true };
|
|
160
|
-
} catch (error) {
|
|
161
|
-
return { ok: false, error: openerUnavailableMessage(command, getErrorMessage(error)) };
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
export {
|
|
166
|
-
seedToWizardResult,
|
|
167
|
-
openUrl
|
|
168
|
-
};
|
|
169
|
-
//# sourceMappingURL=chunk-YVQSDBTK.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/lib/seed/seed-to-wizard.ts","../src/cli/utils/open-url.ts"],"sourcesContent":["import { seedAgentScope } from \"@workspace/matrix\";\n\nimport { AGENT_NAMES } from \"../../types/agents.js\";\nimport { DEFAULT_PUBLIC_SOURCE_NAME } from \"../../consts.js\";\nimport { isScopePairCompatible } from \"../configuration/config-generator.js\";\nimport { getCategoryDomain } from \"../matrix/matrix-provider.js\";\nimport { validateSelection } from \"../matrix/matrix-resolver.js\";\nimport { orderDomains } from \"../wizard/domain-order.js\";\n\nimport type { WizardResultV2 } from \"../../components/wizard/wizard.js\";\nimport type { AgentName } from \"../../types/agents.js\";\nimport type { AgentScopeConfig, SkillConfig } from \"../../types/config.js\";\nimport type {\n Category,\n Domain,\n DomainSelections,\n MergedSkillsMatrix,\n ResolvedSkill,\n} from \"../../types/matrix.js\";\nimport type { SkillAssignment, SkillId } from \"../../types/skills.js\";\nimport type { StackAgentConfig } from \"../../types/stacks.js\";\nimport type { SeedAgent, SeedLoadState, SeedPayload } from \"@workspace/matrix/seed\";\n\nexport type SeedMapping = {\n result: WizardResultV2;\n /** Ids this matrix does not know. Reported, never fatal — see the decode policy. */\n skippedSkillIds: string[];\n skippedAgentNames: string[];\n};\n\nconst KNOWN_AGENTS = new Set<string>(AGENT_NAMES);\n\n/** A skill's primary source, or the default marketplace. Mirrors the wizard's own resolution. */\nfunction sourceForSkill(skill: ResolvedSkill | undefined): string {\n return skill?.availableSources?.find((s) => s.primary)?.name ?? DEFAULT_PUBLIC_SOURCE_NAME;\n}\n\nfunction addToDomainSelections(\n selections: DomainSelections,\n domain: Domain,\n category: Category,\n skillId: SkillId,\n): void {\n const categorySelections = (selections[domain] ??= {});\n const skillList = (categorySelections[category] ??= []);\n if (!skillList.includes(skillId)) skillList.push(skillId);\n}\n\n/**\n * The stack mirror of {@link addToDomainSelections}: one sub-agent's own category lists, appended\n * in payload order. A `(skill, sub-agent)` pair can only occur once — `skills` is keyed by id — so\n * there is nothing to de-duplicate here.\n */\nfunction addToAgentStack(\n stack: Partial<Record<AgentName, StackAgentConfig>>,\n agent: AgentName,\n category: Category,\n assignment: SkillAssignment,\n): void {\n const agentStack = (stack[agent] ??= {});\n const assignments = (agentStack[category] ??= []);\n assignments.push(assignment);\n}\n\n/** A load state is per `(skill, sub-agent)`; `preloaded` is the stack's word for the same thing. */\nfunction toSkillAssignment(skillId: SkillId, load: SeedLoadState): SkillAssignment {\n return { id: skillId, preloaded: load === \"preloaded\" };\n}\n\n/** The payload's `agents` map, split by what this catalog can do with each entry. */\ntype SeedAgentMap = {\n /** Known agents the map has something to say about, keyed by name. */\n known: Map<AgentName, SeedAgent>;\n /** Names explicitly switched off — dropped, and their assignment rows ignored with them. */\n switchedOff: Set<string>;\n /** Names this catalog does not know. Reported, never fatal — same policy as unknown skill ids. */\n unknown: string[];\n};\n\nfunction readAgentMap(agents: SeedPayload[\"agents\"]): SeedAgentMap {\n const known = new Map<AgentName, SeedAgent>();\n const switchedOff = new Set<string>();\n const unknown: string[] = [];\n\n for (const [name, entry] of Object.entries(agents)) {\n if (!KNOWN_AGENTS.has(name)) unknown.push(name);\n else if (entry.on === false) switchedOff.add(name);\n else known.set(name as AgentName, entry);\n }\n\n return { known, switchedOff, unknown };\n}\n\n/**\n * A sub-agent's own row. Model and effort ride along on the same terms as its scope — an absent\n * key means \"keep whatever the agent's metadata says\".\n */\nfunction agentScopeConfig(name: AgentName, entry: SeedAgent | undefined): AgentScopeConfig {\n return {\n name,\n scope: seedAgentScope(entry),\n ...(entry?.model !== undefined && { model: entry.model }),\n ...(entry?.effort !== undefined && { effort: entry.effort }),\n };\n}\n\n/** A `(skill, sub-agent)` assignment the config model has nowhere to write. */\ntype UnwritableAssignment = { skillId: SkillId; agent: AgentName };\n\n/**\n * Names every unwritable pair, not just the first: a sharer who fixes one only to be refused for\n * the next learns nothing the first message could not have told them. Both halves of each pair are\n * named because neither alone says what to change — the skill can move to global scope, or the\n * sub-agent can be pinned to the project, and only the sharer knows which they meant.\n */\nfunction unwritableAssignmentsError(assignments: UnwritableAssignment[]): string {\n return [\n \"This configuration cannot be installed: a project-scoped skill never reaches a sub-agent \" +\n \"that rests at global scope, so these assignments have nowhere to be written:\",\n ...assignments.map(({ skillId, agent }) => ` ${skillId} -> ${agent}`),\n \"Re-share it with each sub-agent above pinned to the project, or each skill above at global scope.\",\n ].join(\"\\n\");\n}\n\n/**\n * Turns a shared configuration into the shape the install pipeline already consumes, so\n * `init --from` reuses `writeProjectConfig` -> skill install -> `compileAgentsAllScopes`\n * unchanged rather than growing a second path that can drift from the wizard's.\n *\n * Unknown ids are skipped, never fatal. Payloads carry catalog slugs precisely so they survive\n * catalog churn: a config shared before a skill was renamed should still install everything else,\n * and failing the whole decode would make every rename retroactively break every shared id.\n *\n * A sub-agent reaches the roster two ways: named by a surviving skill's assignment, or switched on\n * in the `agents` map. The map is the only place a configuration can say anything about an agent\n * no skill mentions, which is what makes a bare (skill-less) agent shareable at all; it also\n * carries that agent's model and effort onto its `AgentScopeConfig`.\n *\n * The `assignments` map is per `(skill, sub-agent)` and carries a load state, so it decides three\n * things the wizard cannot express separately: which sub-agents are selected, which skills land in\n * each one's stack entry, and which of those preload. That is why the result carries an\n * `assignedStack` — the install pipeline's ownership rules broadcast every scope-compatible skill\n * to every selected agent, which would hand a bare sub-agent someone else's skills.\n *\n * An unwritable `(skill, sub-agent)` pair is the one thing here that IS fatal, and it is fatal for\n * the opposite reason to the skips: an unknown id is content this catalog does not have, while an\n * unwritable pair is content it has and cannot place. Because `assignedStack` replaces the derived\n * stack wholesale, no scope filter runs on these rows downstream — they reach the writers, which\n * put them in neither half of the split config and say nothing. Refusing at the decode is what\n * keeps a payload from installing as a quieter configuration than the one that was shared.\n */\nexport function seedToWizardResult(payload: SeedPayload, matrix: MergedSkillsMatrix): SeedMapping {\n const domainSelections: DomainSelections = {};\n const assignedStack: Partial<Record<AgentName, StackAgentConfig>> = {};\n const skills: SkillConfig[] = [];\n const skippedSkillIds: string[] = [];\n const unwritable: UnwritableAssignment[] = [];\n const agentNames = new Set<AgentName>();\n const agentMap = readAgentMap(payload.agents);\n const skippedAgentNames = new Set<string>(agentMap.unknown);\n\n for (const [skillId, entry] of Object.entries(payload.skills)) {\n const skill = matrix.skills[skillId as SkillId];\n const domain = skill?.category ? getCategoryDomain(skill.category) : undefined;\n\n if (!skill?.category || !domain) {\n skippedSkillIds.push(skillId);\n continue;\n }\n\n // Past the guard the matrix knows this id, and its category is a real one: the `local`\n // pseudo-category has no domain, so it left with the skips.\n const id = skillId as SkillId;\n const category = skill.category as Category;\n\n addToDomainSelections(domainSelections, domain, category, id);\n\n skills.push({\n id,\n scope: entry.scope,\n // \"eject\" is an origin in its own right; anything else names the marketplace it came from.\n origin: entry.install === \"eject\" ? \"eject\" : sourceForSkill(skill),\n });\n\n // Only assignments on skills that survived — an agent should not be switched on by a skill\n // this catalog cannot install.\n for (const [agentName, load] of Object.entries(entry.assignments)) {\n if (agentMap.switchedOff.has(agentName)) continue;\n if (!KNOWN_AGENTS.has(agentName)) {\n skippedAgentNames.add(agentName);\n continue;\n }\n\n const agent = agentName as AgentName;\n // Rows the decode was going to ignore anyway have already left, so what reaches here is a\n // pair the payload really asked for — and the config model's one rule about pairs applies.\n if (!isScopePairCompatible(entry.scope, seedAgentScope(agentMap.known.get(agent)))) {\n unwritable.push({ skillId: id, agent });\n continue;\n }\n\n agentNames.add(agent);\n // The assignment is the curation: this sub-agent holds this skill, at this load state, and\n // no sub-agent the payload did not name holds it at all.\n addToAgentStack(assignedStack, agent, category, toSkillAssignment(id, load));\n }\n }\n\n if (unwritable.length > 0) throw new Error(unwritableAssignmentsError(unwritable));\n\n // Bare agents: switched on by the map alone, with no skill to carry them in.\n for (const [name, entry] of agentMap.known) {\n if (entry.on === true) agentNames.add(name);\n }\n\n const selectedAgents = [...agentNames];\n\n return {\n result: {\n skills,\n selectedAgents,\n agentConfigs: selectedAgents.map((name) => agentScopeConfig(name, agentMap.known.get(name))),\n assignedStack,\n selectedStackId: payload.stackId,\n // Spread-conditional rather than passed through, because absent and present-holding-undefined\n // are different files on disk: a config describing itself with no key is not one describing\n // itself with an empty sentence, and the writer emits whichever key it is handed.\n ...(payload.description !== undefined && { description: payload.description }),\n domainSelections,\n selectedDomains: orderDomains(Object.keys(domainSelections) as Domain[]),\n // Nothing was dropped from a *saved config* — the skipped ids came off the wire and are\n // reported to the user directly, so there is no config removal to explain.\n unresolvableSkillIds: [],\n cancelled: false,\n // Revalidated here rather than taken on trust from the app that built the payload. That app\n // validated against ITS catalog; this one skips ids it does not know and carries its own\n // relationship rules, so a configuration that was consistent where it was authored can\n // arrive with a requirement genuinely unmet. Running the same validator the wizard runs\n // makes that this catalog's verdict on what it can install — reported through the spine\n // `init` already has, beside the skips that explain it — rather than a fault in what was\n // shared.\n validation: validateSelection(skills.map((skill) => skill.id)),\n },\n skippedSkillIds,\n skippedAgentNames: [...skippedAgentNames],\n };\n}\n","import { execCommand } from \"./exec.js\";\nimport { getErrorMessage } from \"./errors.js\";\n\n/** The shell-out one platform answers \"open this with whatever handles it\" with. */\nexport type OpenerCommand = { command: string; args: string[] };\n\n/**\n * Never a throw. A machine with no browser, no desktop session or no opener at all is a\n * legitimate place to run this CLI, so failing to open a link is something to say rather than\n * something to fail on — the same posture the seed boundaries take, and for the same reason:\n * the link is already printed by the time this runs, so nothing is lost by it not working.\n */\nexport type OpenUrlResult = { ok: true } | { ok: false; error: string };\n\n/**\n * The command a platform opens a link with.\n *\n * There is no dependency for this. All three are one-line shell-outs to something the operating\n * system already ships, and a package for it would be a fourth thing to keep current for no\n * behaviour this does not have.\n *\n * Windows goes through `cmd` because `start` is a shell builtin rather than a program, and the\n * empty string after it is its TITLE argument: without one, `start` reads the first quoted\n * argument it is given as the window title and opens nothing.\n */\nexport function browserOpenerCommand(platform: NodeJS.Platform, url: string): OpenerCommand {\n if (platform === \"darwin\") return { command: \"open\", args: [url] };\n if (platform === \"win32\") return { command: \"cmd\", args: [\"/c\", \"start\", \"\", url] };\n return { command: \"xdg-open\", args: [url] };\n}\n\nfunction openerRefusedMessage(command: string, exitCode: number): string {\n return `Could not open your browser — '${command}' exited ${exitCode}.`;\n}\n\nfunction openerUnavailableMessage(command: string, reason: string): string {\n return `Could not open your browser — '${command}' could not be run: ${reason}`;\n}\n\n/**\n * Hands a link to whatever this platform opens links with.\n *\n * The URL travels as its own argument rather than inside a command line: `execCommand` spawns\n * without a shell, so the argument vector is the whole of the injection guard — there is no\n * string for a link to break out of.\n */\nexport async function openUrl(url: string): Promise<OpenUrlResult> {\n const { command, args } = browserOpenerCommand(process.platform, url);\n\n try {\n const result = await execCommand(command, args);\n if (result.exitCode !== 0) {\n return { ok: false, error: openerRefusedMessage(command, result.exitCode) };\n }\n return { ok: true };\n } catch (error) {\n return { ok: false, error: openerUnavailableMessage(command, getErrorMessage(error)) };\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
loadAgentDefs
|
|
4
|
-
} from "./chunk-G7TYOPON.js";
|
|
5
|
-
import "./chunk-5YOSLSQJ.js";
|
|
6
|
-
import "./chunk-V625APR6.js";
|
|
7
|
-
import "./chunk-7Z4N4JWQ.js";
|
|
8
|
-
import "./chunk-5KB4I5J7.js";
|
|
9
|
-
import "./chunk-VZRO7RYT.js";
|
|
10
|
-
export {
|
|
11
|
-
loadAgentDefs
|
|
12
|
-
};
|
|
13
|
-
//# sourceMappingURL=load-agent-defs-2H42B2OO.js.map
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
recompilePropagatedProjectAgents,
|
|
4
|
-
recompileRegisteredProjectAgents
|
|
5
|
-
} from "./chunk-VCUXNKOY.js";
|
|
6
|
-
import "./chunk-G7TYOPON.js";
|
|
7
|
-
import "./chunk-5YOSLSQJ.js";
|
|
8
|
-
import "./chunk-4RYWFQK7.js";
|
|
9
|
-
import "./chunk-V625APR6.js";
|
|
10
|
-
import "./chunk-7Z4N4JWQ.js";
|
|
11
|
-
import "./chunk-5KB4I5J7.js";
|
|
12
|
-
import "./chunk-VZRO7RYT.js";
|
|
13
|
-
export {
|
|
14
|
-
recompilePropagatedProjectAgents,
|
|
15
|
-
recompileRegisteredProjectAgents
|
|
16
|
-
};
|
|
17
|
-
//# sourceMappingURL=recompile-project-agents-QIAMBCM4.js.map
|