@claude-collective/cli 0.26.0 → 0.29.4
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 +125 -0
- package/README.md +47 -13
- package/config/stacks.yaml +330 -93
- package/dist/chunk-56ERY7H7.js +29 -0
- package/dist/chunk-56ERY7H7.js.map +1 -0
- package/dist/{chunk-OBXAY23Y.js → chunk-5I6VY2E7.js} +5 -5
- package/dist/chunk-5I6VY2E7.js.map +1 -0
- package/dist/{chunk-ZDREFYD2.js → chunk-5WIHSJRO.js} +234 -59
- package/dist/chunk-5WIHSJRO.js.map +1 -0
- package/dist/{chunk-GGFOD5PK.js → chunk-6F3ZKDVE.js} +122 -66
- package/dist/chunk-6F3ZKDVE.js.map +1 -0
- package/dist/{chunk-DBRUQQUF.js → chunk-7GHTQSWI.js} +5 -1
- package/dist/{chunk-DBRUQQUF.js.map → chunk-7GHTQSWI.js.map} +1 -1
- package/dist/chunk-7ICBJZV2.js +63 -0
- package/dist/chunk-7ICBJZV2.js.map +1 -0
- package/dist/{chunk-3X5D7RM5.js → chunk-7UKQZSWT.js} +15 -4
- package/dist/chunk-7UKQZSWT.js.map +1 -0
- package/dist/{chunk-F4RD5FYM.js → chunk-A4T4YSV4.js} +5 -2
- package/dist/chunk-A4T4YSV4.js.map +1 -0
- package/dist/{chunk-VVYNZZUX.js → chunk-AG5YGYJT.js} +9 -5
- package/dist/chunk-AG5YGYJT.js.map +1 -0
- package/dist/chunk-AJFSCLJ7.js +81 -0
- package/dist/chunk-AJFSCLJ7.js.map +1 -0
- package/dist/{chunk-NQJ47R4N.js → chunk-CQZAKMPJ.js} +66 -14
- package/dist/chunk-CQZAKMPJ.js.map +1 -0
- package/dist/chunk-DIRH4PDF.js +24 -0
- package/dist/chunk-DIRH4PDF.js.map +1 -0
- package/dist/{chunk-R7B63JAP.js → chunk-DUIYVKFK.js} +123 -86
- package/dist/chunk-DUIYVKFK.js.map +1 -0
- package/dist/chunk-EP6J44I4.js +142 -0
- package/dist/chunk-EP6J44I4.js.map +1 -0
- package/dist/{chunk-TDZE4TDG.js → chunk-EUPMWSM3.js} +92 -29
- package/dist/chunk-EUPMWSM3.js.map +1 -0
- package/dist/chunk-FUPBGSRA.js +66 -0
- package/dist/chunk-FUPBGSRA.js.map +1 -0
- package/dist/{chunk-U7HFKR74.js → chunk-FY5D4KIC.js} +5 -2
- package/dist/chunk-FY5D4KIC.js.map +1 -0
- package/dist/chunk-G5WXKKQM.js +233 -0
- package/dist/chunk-G5WXKKQM.js.map +1 -0
- package/dist/{chunk-KWYO3M5Q.js → chunk-GVVEPVR7.js} +25 -24
- package/dist/chunk-GVVEPVR7.js.map +1 -0
- package/dist/chunk-IFODQTCX.js +162 -0
- package/dist/chunk-IFODQTCX.js.map +1 -0
- package/dist/chunk-IQUBOWWU.js +366 -0
- package/dist/chunk-IQUBOWWU.js.map +1 -0
- package/dist/{chunk-ETCVEV3S.js → chunk-IRG52AN5.js} +242 -155
- package/dist/chunk-IRG52AN5.js.map +1 -0
- package/dist/chunk-MQAYAISQ.js +88 -0
- package/dist/chunk-MQAYAISQ.js.map +1 -0
- package/dist/{chunk-4357L7VK.js → chunk-N73GQTCK.js} +37 -104
- package/dist/chunk-N73GQTCK.js.map +1 -0
- package/dist/{chunk-H7SSBSPR.js → chunk-OA5RCL2L.js} +8 -5
- package/dist/chunk-OA5RCL2L.js.map +1 -0
- package/dist/{chunk-I3YYG5IO.js → chunk-PNXFJPXF.js} +3 -3
- package/dist/{chunk-MCTSHLAF.js → chunk-RI5QEK5W.js} +41 -14
- package/dist/chunk-RI5QEK5W.js.map +1 -0
- package/dist/chunk-RXC7AF7N.js +31 -0
- package/dist/chunk-RXC7AF7N.js.map +1 -0
- package/dist/{chunk-ETQ3BPGU.js → chunk-SSHG7MEE.js} +1252 -728
- package/dist/chunk-SSHG7MEE.js.map +1 -0
- package/dist/{chunk-4S4FCAA2.js → chunk-VTUPUKFD.js} +26 -31
- package/dist/chunk-VTUPUKFD.js.map +1 -0
- package/dist/{chunk-XENOESJZ.js → chunk-WLQUQXWO.js} +10 -67
- package/dist/chunk-WLQUQXWO.js.map +1 -0
- package/dist/chunk-WPED6CL3.js +105 -0
- package/dist/chunk-WPED6CL3.js.map +1 -0
- package/dist/{chunk-R5KJVI54.js → chunk-XPMEGGJK.js} +97 -76
- package/dist/chunk-XPMEGGJK.js.map +1 -0
- package/dist/chunk-XZKVOPCR.js +75 -0
- package/dist/chunk-XZKVOPCR.js.map +1 -0
- package/dist/{chunk-ZW2PELOH.js → chunk-ZX5DM4D5.js} +106 -69
- package/dist/chunk-ZX5DM4D5.js.map +1 -0
- package/dist/commands/build/marketplace.js +21 -20
- package/dist/commands/build/marketplace.js.map +1 -1
- package/dist/commands/build/plugins.js +7 -11
- package/dist/commands/build/plugins.js.map +1 -1
- package/dist/commands/build/stack.js +8 -13
- package/dist/commands/build/stack.js.map +1 -1
- package/dist/commands/compile.js +109 -135
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/config/get.js +4 -5
- package/dist/commands/config/get.js.map +1 -1
- package/dist/commands/config/index.js +5 -6
- package/dist/commands/config/index.js.map +1 -1
- package/dist/commands/config/path.js +4 -5
- package/dist/commands/config/path.js.map +1 -1
- package/dist/commands/config/set-project.js +4 -5
- package/dist/commands/config/set-project.js.map +1 -1
- package/dist/commands/config/show.js +5 -6
- package/dist/commands/config/unset-project.js +4 -5
- package/dist/commands/config/unset-project.js.map +1 -1
- package/dist/commands/diff.js +26 -11
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/doctor.js +13 -16
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +71 -42
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +34 -14
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/import/skill.js +93 -52
- package/dist/commands/import/skill.js.map +1 -1
- package/dist/commands/info.js +27 -9
- package/dist/commands/info.js.map +1 -1
- package/dist/commands/init.js +98 -48
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/list.js +10 -5
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/new/agent.js +8 -11
- package/dist/commands/new/agent.js.map +1 -1
- package/dist/commands/new/skill.js +17 -18
- package/dist/commands/new/skill.js.map +1 -1
- package/dist/commands/outdated.js +23 -9
- package/dist/commands/outdated.js.map +1 -1
- package/dist/commands/search.js +23 -20
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/uninstall.js +28 -21
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +30 -22
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/validate.js +103 -39
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/version/bump.js +4 -5
- package/dist/commands/version/bump.js.map +1 -1
- package/dist/commands/version/index.js +4 -5
- package/dist/commands/version/index.js.map +1 -1
- package/dist/commands/version/set.js +4 -5
- package/dist/commands/version/set.js.map +1 -1
- package/dist/commands/version/show.js +4 -5
- package/dist/commands/version/show.js.map +1 -1
- package/dist/components/common/confirm.test.js +2 -2
- package/dist/components/common/confirm.test.js.map +1 -1
- package/dist/components/skill-search/skill-search.js +4 -2
- package/dist/components/wizard/category-grid.js +3 -1
- package/dist/components/wizard/category-grid.test.js +63 -64
- package/dist/components/wizard/category-grid.test.js.map +1 -1
- package/dist/components/wizard/domain-selection.js +13 -0
- package/dist/components/wizard/help-modal.js +10 -0
- package/dist/components/wizard/help-modal.js.map +1 -0
- package/dist/components/wizard/menu-item.js +2 -1
- package/dist/components/wizard/search-modal.js +3 -1
- package/dist/components/wizard/search-modal.test.js +4 -2
- package/dist/components/wizard/search-modal.test.js.map +1 -1
- package/dist/components/wizard/section-progress.js +2 -1
- package/dist/components/wizard/section-progress.test.js +2 -1
- package/dist/components/wizard/section-progress.test.js.map +1 -1
- package/dist/components/wizard/source-grid.js +6 -2
- package/dist/components/wizard/source-grid.test.js +49 -45
- package/dist/components/wizard/source-grid.test.js.map +1 -1
- package/dist/components/wizard/stack-selection.js +15 -0
- package/dist/components/wizard/stack-selection.js.map +1 -0
- package/dist/components/wizard/step-approach.js +8 -6
- package/dist/components/wizard/step-approach.test.js +11 -9
- package/dist/components/wizard/step-approach.test.js.map +1 -1
- package/dist/components/wizard/step-build.js +9 -13
- package/dist/components/wizard/step-build.test.js +27 -45
- package/dist/components/wizard/step-build.test.js.map +1 -1
- package/dist/components/wizard/step-confirm.js +2 -1
- package/dist/components/wizard/step-confirm.test.js +6 -5
- package/dist/components/wizard/step-confirm.test.js.map +1 -1
- package/dist/components/wizard/step-refine.js +2 -1
- package/dist/components/wizard/step-refine.test.js +3 -2
- package/dist/components/wizard/step-refine.test.js.map +1 -1
- package/dist/components/wizard/step-settings.js +8 -6
- package/dist/components/wizard/step-settings.test.js +12 -10
- package/dist/components/wizard/step-settings.test.js.map +1 -1
- package/dist/components/wizard/step-sources.js +11 -9
- package/dist/components/wizard/step-sources.test.js +16 -15
- package/dist/components/wizard/step-sources.test.js.map +1 -1
- package/dist/components/wizard/step-stack.js +9 -6
- package/dist/components/wizard/step-stack.test.js +15 -12
- package/dist/components/wizard/step-stack.test.js.map +1 -1
- package/dist/components/wizard/view-title.js +2 -1
- package/dist/components/wizard/wizard-layout.js +7 -9
- package/dist/components/wizard/wizard-tabs.js +2 -1
- package/dist/components/wizard/wizard-tabs.test.js +2 -1
- package/dist/components/wizard/wizard-tabs.test.js.map +1 -1
- package/dist/components/wizard/wizard.js +26 -20
- package/dist/config/stacks.yaml +330 -93
- package/dist/hooks/init.js +3 -4
- package/dist/hooks/init.js.map +1 -1
- package/dist/source-manager-TV2YGPAN.js +15 -0
- package/dist/source-manager-TV2YGPAN.js.map +1 -0
- package/dist/stores/wizard-store.js +4 -3
- package/dist/stores/wizard-store.test.js +272 -25
- package/dist/stores/wizard-store.test.js.map +1 -1
- package/package.json +2 -1
- package/src/schemas/agent-frontmatter.schema.json +84 -0
- package/src/schemas/agent.schema.json +93 -0
- package/src/schemas/hooks.schema.json +47 -0
- package/src/schemas/marketplace.schema.json +119 -0
- package/src/schemas/metadata.schema.json +113 -0
- package/src/schemas/plugin.schema.json +130 -0
- package/src/schemas/project-config.schema.json +125 -0
- package/src/schemas/project-source-config.schema.json +81 -0
- package/src/schemas/skill-frontmatter.schema.json +42 -0
- package/src/schemas/skills-matrix.schema.json +467 -0
- package/src/schemas/stack.schema.json +191 -0
- package/src/schemas/stacks.schema.json +111 -0
- package/dist/chunk-3X5D7RM5.js.map +0 -1
- package/dist/chunk-4357L7VK.js.map +0 -1
- package/dist/chunk-4S4FCAA2.js.map +0 -1
- package/dist/chunk-7UPXT32F.js +0 -197
- package/dist/chunk-7UPXT32F.js.map +0 -1
- package/dist/chunk-ETCVEV3S.js.map +0 -1
- package/dist/chunk-ETQ3BPGU.js.map +0 -1
- package/dist/chunk-F4RD5FYM.js.map +0 -1
- package/dist/chunk-GGFOD5PK.js.map +0 -1
- package/dist/chunk-H7SSBSPR.js.map +0 -1
- package/dist/chunk-HWD32NP7.js +0 -19
- package/dist/chunk-HWD32NP7.js.map +0 -1
- package/dist/chunk-KWYO3M5Q.js.map +0 -1
- package/dist/chunk-MCTSHLAF.js.map +0 -1
- package/dist/chunk-NQJ47R4N.js.map +0 -1
- package/dist/chunk-O6ZTD7ZI.js +0 -70
- package/dist/chunk-O6ZTD7ZI.js.map +0 -1
- package/dist/chunk-OBXAY23Y.js.map +0 -1
- package/dist/chunk-R5KJVI54.js.map +0 -1
- package/dist/chunk-R7B63JAP.js.map +0 -1
- package/dist/chunk-TDZE4TDG.js.map +0 -1
- package/dist/chunk-TMED5DQ2.js +0 -210
- package/dist/chunk-TMED5DQ2.js.map +0 -1
- package/dist/chunk-U7HFKR74.js.map +0 -1
- package/dist/chunk-UEMRJI2K.js +0 -146
- package/dist/chunk-UEMRJI2K.js.map +0 -1
- package/dist/chunk-UNN7523L.js +0 -78
- package/dist/chunk-UNN7523L.js.map +0 -1
- package/dist/chunk-VVYNZZUX.js.map +0 -1
- package/dist/chunk-XENOESJZ.js.map +0 -1
- package/dist/chunk-ZDREFYD2.js.map +0 -1
- package/dist/chunk-ZW2PELOH.js.map +0 -1
- package/dist/source-manager-EYO3F2DV.js +0 -16
- /package/dist/{chunk-I3YYG5IO.js.map → chunk-PNXFJPXF.js.map} +0 -0
- /package/dist/{source-manager-EYO3F2DV.js.map → components/wizard/domain-selection.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/lib/agents/agent-fetcher.ts","../src/cli/lib/agents/agent-recompiler.ts","../src/cli/lib/agents/agent-plugin-compiler.ts","../src/cli/lib/agents/index.ts"],"sourcesContent":["import path from \"path\";\nimport { directoryExists } from \"../../utils/fs\";\nimport { verbose } from \"../../utils/logger\";\nimport { PROJECT_ROOT, DIRS, CLAUDE_DIR } from \"../../consts\";\nimport { fetchFromSource, type FetchOptions } from \"../loading\";\nimport type { AgentSourcePaths } from \"../../types\";\n\nexport type AgentDefinitionOptions = FetchOptions & {\n projectDir?: string;\n};\n\nexport async function getAgentDefinitions(\n remoteSource?: string,\n options: AgentDefinitionOptions = {},\n): Promise<AgentSourcePaths> {\n if (remoteSource) {\n return fetchAgentDefinitionsFromRemote(remoteSource, options);\n }\n return getLocalAgentDefinitions(options);\n}\n\nexport async function getLocalAgentDefinitions(\n options: AgentDefinitionOptions = {},\n): Promise<AgentSourcePaths> {\n const agentsDir = path.join(PROJECT_ROOT, DIRS.agents);\n let templatesDir = path.join(PROJECT_ROOT, DIRS.templates);\n\n if (!(await directoryExists(agentsDir))) {\n throw new Error(\n `Agent partials not found at '${agentsDir}'. Ensure the CLI is properly installed.`,\n );\n }\n\n if (options.projectDir) {\n const localTemplatesDir = path.join(options.projectDir, CLAUDE_DIR, \"templates\");\n if (await directoryExists(localTemplatesDir)) {\n verbose(`Using local templates from: ${localTemplatesDir}`);\n templatesDir = localTemplatesDir;\n }\n }\n\n if (!(await directoryExists(templatesDir))) {\n verbose(`Templates directory not found: ${templatesDir}`);\n }\n\n verbose(`Agent partials loaded from CLI: ${agentsDir}`);\n verbose(`Templates directory: ${templatesDir}`);\n\n return {\n agentsDir,\n templatesDir,\n sourcePath: PROJECT_ROOT,\n };\n}\n\nexport async function fetchAgentDefinitionsFromRemote(\n source: string,\n options: FetchOptions & { agentsDir?: string } = {},\n): Promise<AgentSourcePaths> {\n verbose(`Fetching agent partials from remote: ${source}`);\n\n const result = await fetchFromSource(source, {\n forceRefresh: options.forceRefresh,\n subdir: \"\",\n });\n\n const agentsDir = path.join(result.path, options.agentsDir ?? DIRS.agents);\n const templatesDir = path.join(agentsDir, \"_templates\");\n\n if (!(await directoryExists(agentsDir))) {\n throw new Error(`Agent partials not found at '${agentsDir}'`);\n }\n\n if (!(await directoryExists(templatesDir))) {\n verbose(`Templates directory not found: ${templatesDir}`);\n }\n\n verbose(`Agent partials fetched from: ${result.path}`);\n\n return {\n agentsDir,\n templatesDir,\n sourcePath: result.path,\n };\n}\n","import type { Liquid } from \"liquidjs\";\nimport path from \"path\";\nimport { parse as parseYaml } from \"yaml\";\n\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { STANDARD_FILES } from \"../../consts\";\nimport type {\n AgentConfig,\n AgentDefinition,\n AgentName,\n CompileAgentConfig,\n CompileConfig,\n ProjectConfig,\n SkillDefinition,\n SkillId,\n} from \"../../types\";\nimport { glob, writeFile, ensureDir, readFile, fileExists } from \"../../utils/fs\";\nimport { verbose } from \"../../utils/logger\";\nimport { typedEntries, typedKeys } from \"../../utils/typed-object\";\nimport { createLiquidEngine } from \"../compiler\";\nimport { loadProjectConfig, type LoadedProjectConfig } from \"../configuration\";\nimport { loadAllAgents, loadPluginSkills, loadProjectAgents } from \"../loading\";\nimport { getPluginAgentsDir } from \"../plugins\";\nimport { resolveAgents, buildSkillRefsFromConfig } from \"../resolver\";\nimport { projectConfigLoaderSchema } from \"../schemas\";\nimport { compileAgentForPlugin } from \"../stacks\";\n\nexport type RecompileAgentsOptions = {\n pluginDir: string;\n sourcePath: string;\n agents?: AgentName[];\n skills?: Partial<Record<SkillId, SkillDefinition>>;\n projectDir?: string;\n outputDir?: string;\n};\n\nexport type RecompileAgentsResult = {\n compiled: AgentName[];\n failed: AgentName[];\n warnings: string[];\n};\n\nasync function getExistingAgentNames(pluginDir: string): Promise<AgentName[]> {\n const agentsDir = getPluginAgentsDir(pluginDir);\n const files = await glob(\"*.md\", agentsDir);\n // Boundary cast: directory names from filesystem are agent names by convention\n return files.map((f) => path.basename(f, \".md\") as AgentName);\n}\n\n// Tries pluginDir/config.yaml (legacy) then pluginDir/.claude/config.yaml\nasync function loadConfigWithFallback(pluginDir: string): Promise<LoadedProjectConfig | null> {\n const legacyConfigPath = path.join(pluginDir, STANDARD_FILES.CONFIG_YAML);\n if (await fileExists(legacyConfigPath)) {\n try {\n const content = await readFile(legacyConfigPath);\n const parsed = parseYaml(content);\n const result = projectConfigLoaderSchema.safeParse(parsed);\n\n if (result.success) {\n verbose(`Loaded config.yaml from ${legacyConfigPath}`);\n return {\n // Loader schema validates field types but allows partial configs;\n // required field validation happens in validateProjectConfig()\n config: result.data as ProjectConfig,\n configPath: legacyConfigPath,\n };\n } else {\n verbose(`Invalid config.yaml at ${legacyConfigPath}: ${result.error.message}`);\n }\n } catch (error) {\n verbose(`Failed to parse config.yaml: ${error}`);\n }\n }\n\n // Fall back to project config location (.claude/config.yaml)\n return loadProjectConfig(pluginDir);\n}\n\ntype ResolveAgentNamesParams = {\n specifiedAgents?: AgentName[];\n projectConfig: ProjectConfig | null;\n allAgents: Record<AgentName, AgentDefinition>;\n outputDir?: string;\n pluginDir: string;\n};\n\nasync function resolveAgentNames(params: ResolveAgentNamesParams): Promise<AgentName[]> {\n const { specifiedAgents, projectConfig, allAgents, outputDir, pluginDir } = params;\n\n if (specifiedAgents) {\n return specifiedAgents;\n }\n\n if (projectConfig?.agents) {\n verbose(`Using agents from config.yaml: ${projectConfig.agents.join(\", \")}`);\n return projectConfig.agents;\n }\n\n if (outputDir) {\n const names = typedKeys<AgentName>(allAgents);\n verbose(`Using all available agents from source: ${names.join(\", \")}`);\n return names;\n }\n\n return getExistingAgentNames(pluginDir);\n}\n\ntype BuildCompileConfigParams = {\n agentNames: AgentName[];\n allAgents: Record<AgentName, AgentDefinition>;\n projectConfig: ProjectConfig | null;\n pluginDir: string;\n};\n\ntype BuildCompileConfigResult = {\n compileConfig: CompileConfig;\n warnings: string[];\n};\n\nfunction buildCompileConfig(params: BuildCompileConfigParams): BuildCompileConfigResult {\n const { agentNames, allAgents, projectConfig, pluginDir } = params;\n const warnings: string[] = [];\n\n // Store initialization: accumulator filled below for each agent in agentNames\n const compileAgents = {} as Record<AgentName, CompileAgentConfig>;\n for (const agentName of agentNames) {\n if (allAgents[agentName]) {\n const agentStack = projectConfig?.stack?.[agentName];\n compileAgents[agentName] = agentStack ? { skills: buildSkillRefsFromConfig(agentStack) } : {};\n } else {\n warnings.push(`Agent \"${agentName}\" not found in source definitions`);\n }\n }\n\n const compileConfig: CompileConfig = {\n name: projectConfig?.name || path.basename(pluginDir),\n description: projectConfig?.description || \"Recompiled plugin\",\n agents: compileAgents,\n };\n\n return { compileConfig, warnings };\n}\n\ntype CompileAndWriteParams = {\n resolvedAgents: Record<AgentName, AgentConfig>;\n agentsDir: string;\n sourcePath: string;\n engine: Liquid;\n installMode: ProjectConfig[\"installMode\"];\n};\n\nasync function compileAndWriteAgents(\n params: CompileAndWriteParams,\n result: RecompileAgentsResult,\n): Promise<void> {\n const { resolvedAgents, agentsDir, sourcePath, engine, installMode } = params;\n\n for (const [agentName, agent] of typedEntries<AgentName, AgentConfig>(resolvedAgents)) {\n try {\n const output = await compileAgentForPlugin(agentName, agent, sourcePath, engine, installMode);\n await writeFile(path.join(agentsDir, `${agentName}.md`), output);\n result.compiled.push(agentName);\n verbose(` Recompiled: ${agentName}`);\n } catch (error) {\n result.failed.push(agentName);\n result.warnings.push(`Failed to compile ${agentName}: ${getErrorMessage(error)}`);\n }\n }\n}\n\nexport async function recompileAgents(\n options: RecompileAgentsOptions,\n): Promise<RecompileAgentsResult> {\n const { pluginDir, sourcePath, skills: providedSkills, projectDir, outputDir } = options;\n\n const result: RecompileAgentsResult = {\n compiled: [],\n failed: [],\n warnings: [],\n };\n\n let loadedConfig = await loadConfigWithFallback(pluginDir);\n if (!loadedConfig && projectDir) {\n loadedConfig = await loadConfigWithFallback(projectDir);\n }\n const projectConfig = loadedConfig?.config ?? null;\n\n const builtinAgents = await loadAllAgents(sourcePath);\n const projectAgents = projectDir ? await loadProjectAgents(projectDir) : {};\n\n // Boundary cast: loadAllAgents returns Record<string, AgentDefinition>, agent dirs are AgentName by convention\n // Priority: project agents > built-in agents\n const allAgents = {\n ...builtinAgents,\n ...projectAgents,\n } as Record<AgentName, AgentDefinition>;\n\n const agentNames = await resolveAgentNames({\n specifiedAgents: options.agents,\n projectConfig,\n allAgents,\n outputDir,\n pluginDir,\n });\n\n if (agentNames.length === 0) {\n result.warnings.push(\"No agents found to recompile\");\n return result;\n }\n\n verbose(`Recompiling ${agentNames.length} agents in ${outputDir ?? pluginDir}`);\n\n const pluginSkills = providedSkills ?? (await loadPluginSkills(pluginDir));\n\n const { compileConfig, warnings } = buildCompileConfig({\n agentNames,\n allAgents,\n projectConfig,\n pluginDir,\n });\n result.warnings.push(...warnings);\n\n const engine = await createLiquidEngine(projectDir);\n const resolvedAgents = await resolveAgents(allAgents, pluginSkills, compileConfig, sourcePath);\n\n const agentsDir = outputDir ?? getPluginAgentsDir(pluginDir);\n await ensureDir(agentsDir);\n\n await compileAndWriteAgents(\n {\n resolvedAgents,\n agentsDir,\n sourcePath,\n engine,\n installMode: projectConfig?.installMode,\n },\n result,\n );\n\n return result;\n}\n","import path from \"path\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { readFile, ensureDir, glob, copy } from \"../../utils/fs\";\nimport { log, verbose, warn } from \"../../utils/logger\";\nimport {\n generateAgentPluginManifest,\n writePluginManifest,\n getPluginManifestPath,\n} from \"../plugins\";\nimport { computeStringHash, determinePluginVersion, writeContentHash } from \"../versioning\";\nimport { extractFrontmatter } from \"../../utils/frontmatter\";\nimport type { PluginManifest } from \"../../types\";\nimport { agentFrontmatterValidationSchema, formatZodErrors } from \"../schemas\";\n\nexport type AgentPluginOptions = {\n agentPath: string;\n outputDir: string;\n};\n\nexport type CompiledAgentPlugin = {\n pluginPath: string;\n manifest: PluginManifest;\n agentName: string;\n};\n\nfunction parseAgentFrontmatter(\n content: string,\n filePath: string,\n): { name: string; description: string } | null {\n const raw = extractFrontmatter(content);\n if (!raw) {\n return null;\n }\n\n const result = agentFrontmatterValidationSchema.safeParse(raw);\n if (!result.success) {\n warn(`Invalid agent frontmatter in ${filePath}: ${formatZodErrors(result.error.issues)}`);\n return null;\n }\n\n return { name: result.data.name, description: result.data.description };\n}\n\nexport async function compileAgentPlugin(\n options: AgentPluginOptions,\n): Promise<CompiledAgentPlugin> {\n const { agentPath, outputDir } = options;\n const fileName = path.basename(agentPath);\n\n const content = await readFile(agentPath);\n const frontmatter = parseAgentFrontmatter(content, agentPath);\n\n if (!frontmatter) {\n throw new Error(\n `Agent '${fileName}' has invalid or missing YAML frontmatter. ` +\n `Required fields: 'name' and 'description'. File: ${agentPath}`,\n );\n }\n\n const agentName = frontmatter.name;\n\n verbose(`Compiling agent plugin: ${agentName} from ${agentPath}`);\n\n const pluginDir = path.join(outputDir, `agent-${agentName}`);\n const agentsDir = path.join(pluginDir, \"agents\");\n\n await ensureDir(pluginDir);\n await ensureDir(agentsDir);\n\n const newHash = computeStringHash(content);\n const { version, contentHash } = await determinePluginVersion(\n newHash,\n pluginDir,\n getPluginManifestPath,\n );\n\n const manifest = generateAgentPluginManifest({\n agentName,\n description: frontmatter.description,\n version,\n });\n\n await writePluginManifest(pluginDir, manifest);\n\n await writeContentHash(pluginDir, contentHash, getPluginManifestPath);\n\n verbose(` Wrote plugin.json for ${agentName} (v${version})`);\n\n await copy(agentPath, path.join(agentsDir, `${agentName}.md`));\n verbose(` Copied agent ${fileName} -> agents/${agentName}.md`);\n\n return {\n pluginPath: pluginDir,\n manifest,\n agentName,\n };\n}\n\nexport async function compileAllAgentPlugins(\n agentsDir: string,\n outputDir: string,\n): Promise<CompiledAgentPlugin[]> {\n const results: CompiledAgentPlugin[] = [];\n\n const agentMdFiles = await glob(\"*.md\", agentsDir);\n\n for (const agentFile of agentMdFiles) {\n const agentPath = path.join(agentsDir, agentFile);\n\n try {\n const result = await compileAgentPlugin({\n agentPath,\n outputDir,\n });\n results.push(result);\n log(` [OK] agent-${result.agentName}`);\n } catch (error) {\n const errorMessage = getErrorMessage(error);\n warn(`Failed to compile agent from '${agentFile}': ${errorMessage}`);\n }\n }\n\n return results;\n}\n\nexport function printAgentCompilationSummary(results: CompiledAgentPlugin[]): void {\n log(`\\nCompiled ${results.length} agent plugins:`);\n for (const result of results) {\n log(` - agent-${result.agentName} (v${result.manifest.version})`);\n }\n}\n","export {\n type AgentDefinitionOptions,\n getAgentDefinitions,\n getLocalAgentDefinitions,\n fetchAgentDefinitionsFromRemote,\n} from \"./agent-fetcher\";\n\nexport {\n type RecompileAgentsOptions,\n type RecompileAgentsResult,\n recompileAgents,\n} from \"./agent-recompiler\";\n\nexport {\n type AgentPluginOptions,\n type CompiledAgentPlugin,\n compileAgentPlugin,\n compileAllAgentPlugins,\n printAgentCompilationSummary,\n} from \"./agent-plugin-compiler\";\n"],"mappings":"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","names":["path","path","path","path"]}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
ViewTitle
|
|
4
|
+
} from "./chunk-FY5D4KIC.js";
|
|
5
|
+
import {
|
|
6
|
+
MenuItem
|
|
7
|
+
} from "./chunk-OA5RCL2L.js";
|
|
8
|
+
import {
|
|
9
|
+
useWizardStore
|
|
10
|
+
} from "./chunk-IQUBOWWU.js";
|
|
11
|
+
import {
|
|
12
|
+
init_esm_shims
|
|
13
|
+
} from "./chunk-AWKZ5BDL.js";
|
|
14
|
+
|
|
15
|
+
// src/cli/components/wizard/stack-selection.tsx
|
|
16
|
+
init_esm_shims();
|
|
17
|
+
import { useState } from "react";
|
|
18
|
+
import { Box, Text, useInput } from "ink";
|
|
19
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
20
|
+
var INITIAL_FOCUSED_INDEX = 0;
|
|
21
|
+
var StackSelection = ({ matrix }) => {
|
|
22
|
+
const { selectStack, setStep, setStackAction, populateFromSkillIds, goBack } = useWizardStore();
|
|
23
|
+
const [focusedIndex, setFocusedIndex] = useState(INITIAL_FOCUSED_INDEX);
|
|
24
|
+
const stacks = matrix.suggestedStacks;
|
|
25
|
+
const stackCount = stacks.length;
|
|
26
|
+
useInput((input, key) => {
|
|
27
|
+
if (key.escape) {
|
|
28
|
+
goBack();
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (key.return && stackCount > 0) {
|
|
32
|
+
const focusedStack = stacks[focusedIndex];
|
|
33
|
+
if (focusedStack) {
|
|
34
|
+
selectStack(focusedStack.id);
|
|
35
|
+
setStackAction("customize");
|
|
36
|
+
const resolvedStack = matrix.suggestedStacks.find((s) => s.id === focusedStack.id);
|
|
37
|
+
if (resolvedStack) {
|
|
38
|
+
populateFromSkillIds(resolvedStack.allSkillIds, matrix.skills, matrix.categories);
|
|
39
|
+
}
|
|
40
|
+
setStep("build");
|
|
41
|
+
}
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (key.upArrow || input === "k") {
|
|
45
|
+
setFocusedIndex((prev) => Math.max(0, prev - 1));
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (key.downArrow || input === "j") {
|
|
49
|
+
setFocusedIndex((prev) => Math.min(stackCount - 1, prev + 1));
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
53
|
+
/* @__PURE__ */ jsx(ViewTitle, { children: "Select a stack" }),
|
|
54
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, children: stacks.map((stack, index) => /* @__PURE__ */ jsx(
|
|
55
|
+
MenuItem,
|
|
56
|
+
{
|
|
57
|
+
label: stack.name,
|
|
58
|
+
description: stack.description,
|
|
59
|
+
isFocused: index === focusedIndex
|
|
60
|
+
},
|
|
61
|
+
stack.id
|
|
62
|
+
)) }),
|
|
63
|
+
stackCount > 0 && /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
64
|
+
"\u2191",
|
|
65
|
+
"/",
|
|
66
|
+
"\u2193",
|
|
67
|
+
" navigate ENTER select ESC back"
|
|
68
|
+
] }) })
|
|
69
|
+
] });
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export {
|
|
73
|
+
StackSelection
|
|
74
|
+
};
|
|
75
|
+
//# sourceMappingURL=chunk-XZKVOPCR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/components/wizard/stack-selection.tsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport { Box, Text, useInput } from \"ink\";\nimport { useWizardStore } from \"../../stores/wizard-store.js\";\nimport type { MergedSkillsMatrix } from \"../../types/index.js\";\nimport { MenuItem } from \"./menu-item.js\";\nimport { ViewTitle } from \"./view-title.js\";\n\nconst INITIAL_FOCUSED_INDEX = 0;\n\nexport type StackSelectionProps = {\n matrix: MergedSkillsMatrix;\n};\n\nexport const StackSelection: React.FC<StackSelectionProps> = ({ matrix }) => {\n const { selectStack, setStep, setStackAction, populateFromSkillIds, goBack } = useWizardStore();\n const [focusedIndex, setFocusedIndex] = useState(INITIAL_FOCUSED_INDEX);\n\n const stacks = matrix.suggestedStacks;\n const stackCount = stacks.length;\n\n useInput((input, key) => {\n if (key.escape) {\n goBack();\n return;\n }\n\n if (key.return && stackCount > 0) {\n const focusedStack = stacks[focusedIndex];\n if (focusedStack) {\n selectStack(focusedStack.id);\n setStackAction(\"customize\");\n\n const resolvedStack = matrix.suggestedStacks.find((s) => s.id === focusedStack.id);\n if (resolvedStack) {\n populateFromSkillIds(resolvedStack.allSkillIds, matrix.skills, matrix.categories);\n }\n\n setStep(\"build\");\n }\n return;\n }\n\n if (key.upArrow || input === \"k\") {\n setFocusedIndex((prev) => Math.max(0, prev - 1));\n return;\n }\n if (key.downArrow || input === \"j\") {\n setFocusedIndex((prev) => Math.min(stackCount - 1, prev + 1));\n }\n });\n\n return (\n <Box flexDirection=\"column\">\n <ViewTitle>Select a stack</ViewTitle>\n <Box flexDirection=\"column\" marginTop={1}>\n {stacks.map((stack, index) => (\n <MenuItem\n key={stack.id}\n label={stack.name}\n description={stack.description}\n isFocused={index === focusedIndex}\n />\n ))}\n </Box>\n {stackCount > 0 && (\n <Box marginTop={1}>\n <Text dimColor>\n {\"\\u2191\"}/{\"\\u2193\"} navigate ENTER select ESC back\n </Text>\n </Box>\n )}\n </Box>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;AAAA;AAAA,SAAgB,gBAAgB;AAChC,SAAS,KAAK,MAAM,gBAAgB;AAoD9B,cAaI,YAbJ;AA9CN,IAAM,wBAAwB;AAMvB,IAAM,iBAAgD,CAAC,EAAE,OAAO,MAAM;AAC3E,QAAM,EAAE,aAAa,SAAS,gBAAgB,sBAAsB,OAAO,IAAI,eAAe;AAC9F,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,qBAAqB;AAEtE,QAAM,SAAS,OAAO;AACtB,QAAM,aAAa,OAAO;AAE1B,WAAS,CAAC,OAAO,QAAQ;AACvB,QAAI,IAAI,QAAQ;AACd,aAAO;AACP;AAAA,IACF;AAEA,QAAI,IAAI,UAAU,aAAa,GAAG;AAChC,YAAM,eAAe,OAAO,YAAY;AACxC,UAAI,cAAc;AAChB,oBAAY,aAAa,EAAE;AAC3B,uBAAe,WAAW;AAE1B,cAAM,gBAAgB,OAAO,gBAAgB,KAAK,CAAC,MAAM,EAAE,OAAO,aAAa,EAAE;AACjF,YAAI,eAAe;AACjB,+BAAqB,cAAc,aAAa,OAAO,QAAQ,OAAO,UAAU;AAAA,QAClF;AAEA,gBAAQ,OAAO;AAAA,MACjB;AACA;AAAA,IACF;AAEA,QAAI,IAAI,WAAW,UAAU,KAAK;AAChC,sBAAgB,CAAC,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,CAAC;AAC/C;AAAA,IACF;AACA,QAAI,IAAI,aAAa,UAAU,KAAK;AAClC,sBAAgB,CAAC,SAAS,KAAK,IAAI,aAAa,GAAG,OAAO,CAAC,CAAC;AAAA,IAC9D;AAAA,EACF,CAAC;AAED,SACE,qBAAC,OAAI,eAAc,UACjB;AAAA,wBAAC,aAAU,4BAAc;AAAA,IACzB,oBAAC,OAAI,eAAc,UAAS,WAAW,GACpC,iBAAO,IAAI,CAAC,OAAO,UAClB;AAAA,MAAC;AAAA;AAAA,QAEC,OAAO,MAAM;AAAA,QACb,aAAa,MAAM;AAAA,QACnB,WAAW,UAAU;AAAA;AAAA,MAHhB,MAAM;AAAA,IAIb,CACD,GACH;AAAA,IACC,aAAa,KACZ,oBAAC,OAAI,WAAW,GACd,+BAAC,QAAK,UAAQ,MACX;AAAA;AAAA,MAAS;AAAA,MAAE;AAAA,MAAS;AAAA,OACvB,GACF;AAAA,KAEJ;AAEJ;","names":[]}
|
|
@@ -1,19 +1,82 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
useModalState
|
|
4
|
+
} from "./chunk-DIRH4PDF.js";
|
|
2
5
|
import {
|
|
3
6
|
SearchModal
|
|
4
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-VTUPUKFD.js";
|
|
8
|
+
import {
|
|
9
|
+
useFocusedListItem
|
|
10
|
+
} from "./chunk-WPED6CL3.js";
|
|
11
|
+
import {
|
|
12
|
+
CLI_COLORS,
|
|
13
|
+
UI_SYMBOLS
|
|
14
|
+
} from "./chunk-IFODQTCX.js";
|
|
5
15
|
import {
|
|
6
16
|
init_esm_shims
|
|
7
17
|
} from "./chunk-AWKZ5BDL.js";
|
|
8
18
|
|
|
9
19
|
// src/cli/components/wizard/source-grid.tsx
|
|
10
20
|
init_esm_shims();
|
|
11
|
-
import { useCallback
|
|
21
|
+
import { useCallback as useCallback2 } from "react";
|
|
12
22
|
import { Box, Text, useInput } from "ink";
|
|
23
|
+
|
|
24
|
+
// src/cli/components/hooks/use-source-grid-search-modal.ts
|
|
25
|
+
init_esm_shims();
|
|
26
|
+
import { useCallback, useState } from "react";
|
|
27
|
+
function useSourceGridSearchModal({
|
|
28
|
+
rows,
|
|
29
|
+
onSearch,
|
|
30
|
+
onBind,
|
|
31
|
+
onSearchStateChange
|
|
32
|
+
}) {
|
|
33
|
+
const searchModal = useModalState();
|
|
34
|
+
const [searchResults, setSearchResults] = useState([]);
|
|
35
|
+
const [searchAlias, setSearchAlias] = useState("");
|
|
36
|
+
const resetSearch = useCallback(() => {
|
|
37
|
+
searchModal.close();
|
|
38
|
+
setSearchResults([]);
|
|
39
|
+
setSearchAlias("");
|
|
40
|
+
onSearchStateChange?.(false);
|
|
41
|
+
}, [onSearchStateChange, searchModal]);
|
|
42
|
+
const handleSearchTrigger = useCallback(
|
|
43
|
+
async (rowIndex) => {
|
|
44
|
+
const row = rows[rowIndex];
|
|
45
|
+
if (!row || !onSearch) return;
|
|
46
|
+
const alias = row.alias;
|
|
47
|
+
setSearchAlias(alias);
|
|
48
|
+
searchModal.open(rowIndex);
|
|
49
|
+
onSearchStateChange?.(true);
|
|
50
|
+
const results = await onSearch(alias);
|
|
51
|
+
setSearchResults(results);
|
|
52
|
+
},
|
|
53
|
+
[rows, onSearch, onSearchStateChange, searchModal]
|
|
54
|
+
);
|
|
55
|
+
const handleBind = useCallback(
|
|
56
|
+
(candidate) => {
|
|
57
|
+
onBind?.(candidate);
|
|
58
|
+
resetSearch();
|
|
59
|
+
},
|
|
60
|
+
[onBind, resetSearch]
|
|
61
|
+
);
|
|
62
|
+
const handleCloseSearch = useCallback(() => {
|
|
63
|
+
resetSearch();
|
|
64
|
+
}, [resetSearch]);
|
|
65
|
+
return {
|
|
66
|
+
searchModal: { isOpen: searchModal.isOpen },
|
|
67
|
+
searchResults,
|
|
68
|
+
searchAlias,
|
|
69
|
+
handleSearchTrigger,
|
|
70
|
+
handleBind,
|
|
71
|
+
handleCloseSearch
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// src/cli/components/wizard/source-grid.tsx
|
|
13
76
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
14
77
|
var SEARCH_PILL_LABEL = "\u2315 Search";
|
|
15
78
|
var SearchPill = ({ isFocused }) => {
|
|
16
|
-
const borderColor = isFocused ?
|
|
79
|
+
const borderColor = isFocused ? CLI_COLORS.UNFOCUSED : CLI_COLORS.NEUTRAL;
|
|
17
80
|
return /* @__PURE__ */ jsx(Box, { marginRight: 1, borderColor, borderStyle: "single", borderDimColor: !isFocused, children: /* @__PURE__ */ jsxs(Text, { dimColor: !isFocused, bold: isFocused, children: [
|
|
18
81
|
" ",
|
|
19
82
|
SEARCH_PILL_LABEL,
|
|
@@ -24,12 +87,16 @@ var SourceTag = ({
|
|
|
24
87
|
option,
|
|
25
88
|
isFocused
|
|
26
89
|
}) => {
|
|
27
|
-
const borderColor = option.selected ?
|
|
28
|
-
const textColor = option.selected ?
|
|
90
|
+
const borderColor = option.selected ? CLI_COLORS.PRIMARY : isFocused ? CLI_COLORS.UNFOCUSED : CLI_COLORS.NEUTRAL;
|
|
91
|
+
const textColor = option.selected ? CLI_COLORS.PRIMARY : void 0;
|
|
29
92
|
const isBold = isFocused || option.selected;
|
|
93
|
+
const symbol = option.selected ? UI_SYMBOLS.SELECTED : UI_SYMBOLS.UNSELECTED;
|
|
30
94
|
return /* @__PURE__ */ jsx(Box, { marginRight: 1, borderColor, borderStyle: "single", children: /* @__PURE__ */ jsxs(Text, { color: textColor, bold: isBold, children: [
|
|
95
|
+
" ",
|
|
96
|
+
/* @__PURE__ */ jsx(Text, { dimColor: !option.selected, children: symbol }),
|
|
31
97
|
" ",
|
|
32
98
|
option.label,
|
|
99
|
+
option.selected && /* @__PURE__ */ jsx(Text, { dimColor: true, children: " (active)" }),
|
|
33
100
|
" "
|
|
34
101
|
] }) });
|
|
35
102
|
};
|
|
@@ -60,52 +127,40 @@ var getNavigableCount = (row, showSearchPill) => {
|
|
|
60
127
|
};
|
|
61
128
|
var SourceGrid = ({
|
|
62
129
|
rows,
|
|
63
|
-
focusedRow,
|
|
64
|
-
focusedCol,
|
|
65
130
|
onSelect,
|
|
66
|
-
onFocusChange,
|
|
67
131
|
onSearch,
|
|
68
132
|
onBind,
|
|
69
|
-
onSearchStateChange
|
|
133
|
+
onSearchStateChange,
|
|
134
|
+
defaultFocusedRow = 0,
|
|
135
|
+
defaultFocusedCol = 0,
|
|
136
|
+
onFocusChange
|
|
70
137
|
}) => {
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
138
|
+
const {
|
|
139
|
+
searchModal,
|
|
140
|
+
searchResults,
|
|
141
|
+
searchAlias,
|
|
142
|
+
handleSearchTrigger,
|
|
143
|
+
handleBind,
|
|
144
|
+
handleCloseSearch
|
|
145
|
+
} = useSourceGridSearchModal({ rows, onSearch, onBind, onSearchStateChange });
|
|
74
146
|
const showSearchPill = !!onSearch;
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
if (!row || !onSearch) return;
|
|
80
|
-
const alias = row.alias;
|
|
81
|
-
setSearchAlias(alias);
|
|
82
|
-
setSearchingRow(rowIndex);
|
|
83
|
-
onSearchStateChange?.(true);
|
|
84
|
-
const results = await onSearch(alias);
|
|
85
|
-
setSearchResults(results);
|
|
86
|
-
},
|
|
87
|
-
[rows, onSearch, onSearchStateChange]
|
|
88
|
-
);
|
|
89
|
-
const handleBind = useCallback(
|
|
90
|
-
(candidate) => {
|
|
91
|
-
onBind?.(candidate);
|
|
92
|
-
setSearchingRow(null);
|
|
93
|
-
setSearchResults([]);
|
|
94
|
-
setSearchAlias("");
|
|
95
|
-
onSearchStateChange?.(false);
|
|
147
|
+
const getColCount = useCallback2(
|
|
148
|
+
(row) => {
|
|
149
|
+
const rowData = rows[row];
|
|
150
|
+
return rowData ? getNavigableCount(rowData, showSearchPill) : 0;
|
|
96
151
|
},
|
|
97
|
-
[
|
|
152
|
+
[rows, showSearchPill]
|
|
98
153
|
);
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
154
|
+
const { focusedRow, focusedCol, moveFocus } = useFocusedListItem(rows.length, getColCount, {
|
|
155
|
+
wrap: true,
|
|
156
|
+
onChange: onFocusChange,
|
|
157
|
+
initialRow: defaultFocusedRow,
|
|
158
|
+
initialCol: defaultFocusedCol
|
|
159
|
+
});
|
|
105
160
|
useInput(
|
|
106
|
-
|
|
161
|
+
useCallback2(
|
|
107
162
|
(input, key) => {
|
|
108
|
-
if (
|
|
163
|
+
if (searchModal.isOpen) return;
|
|
109
164
|
if (input === " ") {
|
|
110
165
|
const currentRow = rows[focusedRow];
|
|
111
166
|
if (!currentRow) return;
|
|
@@ -126,31 +181,13 @@ var SourceGrid = ({
|
|
|
126
181
|
const isUp = key.upArrow;
|
|
127
182
|
const isDown = key.downArrow;
|
|
128
183
|
if (isLeft) {
|
|
129
|
-
|
|
130
|
-
if (!currentRow) return;
|
|
131
|
-
const length = getNavigableCount(currentRow, showSearchPill);
|
|
132
|
-
const newCol = focusedCol <= 0 ? length - 1 : focusedCol - 1;
|
|
133
|
-
onFocusChange(focusedRow, newCol);
|
|
184
|
+
moveFocus("left");
|
|
134
185
|
} else if (isRight) {
|
|
135
|
-
|
|
136
|
-
if (!currentRow) return;
|
|
137
|
-
const length = getNavigableCount(currentRow, showSearchPill);
|
|
138
|
-
const newCol = focusedCol >= length - 1 ? 0 : focusedCol + 1;
|
|
139
|
-
onFocusChange(focusedRow, newCol);
|
|
186
|
+
moveFocus("right");
|
|
140
187
|
} else if (isUp) {
|
|
141
|
-
|
|
142
|
-
const newRow = focusedRow <= 0 ? length - 1 : focusedRow - 1;
|
|
143
|
-
const newRowData = rows[newRow];
|
|
144
|
-
const maxCol = newRowData ? getNavigableCount(newRowData, showSearchPill) - 1 : 0;
|
|
145
|
-
const newCol = Math.min(focusedCol, maxCol);
|
|
146
|
-
onFocusChange(newRow, Math.max(0, newCol));
|
|
188
|
+
moveFocus("up");
|
|
147
189
|
} else if (isDown) {
|
|
148
|
-
|
|
149
|
-
const newRow = focusedRow >= length - 1 ? 0 : focusedRow + 1;
|
|
150
|
-
const newRowData = rows[newRow];
|
|
151
|
-
const maxCol = newRowData ? getNavigableCount(newRowData, showSearchPill) - 1 : 0;
|
|
152
|
-
const newCol = Math.min(focusedCol, maxCol);
|
|
153
|
-
onFocusChange(newRow, Math.max(0, newCol));
|
|
190
|
+
moveFocus("down");
|
|
154
191
|
}
|
|
155
192
|
},
|
|
156
193
|
[
|
|
@@ -158,10 +195,10 @@ var SourceGrid = ({
|
|
|
158
195
|
focusedRow,
|
|
159
196
|
focusedCol,
|
|
160
197
|
onSelect,
|
|
161
|
-
onFocusChange,
|
|
162
198
|
showSearchPill,
|
|
163
|
-
|
|
164
|
-
handleSearchTrigger
|
|
199
|
+
searchModal.isOpen,
|
|
200
|
+
handleSearchTrigger,
|
|
201
|
+
moveFocus
|
|
165
202
|
]
|
|
166
203
|
)
|
|
167
204
|
);
|
|
@@ -179,7 +216,7 @@ var SourceGrid = ({
|
|
|
179
216
|
},
|
|
180
217
|
row.skillId
|
|
181
218
|
)),
|
|
182
|
-
|
|
219
|
+
searchModal.isOpen && /* @__PURE__ */ jsx(
|
|
183
220
|
SearchModal,
|
|
184
221
|
{
|
|
185
222
|
results: searchResults,
|
|
@@ -194,4 +231,4 @@ var SourceGrid = ({
|
|
|
194
231
|
export {
|
|
195
232
|
SourceGrid
|
|
196
233
|
};
|
|
197
|
-
//# sourceMappingURL=chunk-
|
|
234
|
+
//# sourceMappingURL=chunk-ZX5DM4D5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/components/wizard/source-grid.tsx","../src/cli/components/hooks/use-source-grid-search-modal.ts"],"sourcesContent":["import React, { useCallback } from \"react\";\nimport { Box, Text, useInput } from \"ink\";\nimport type { BoundSkillCandidate, SkillAlias, SkillId } from \"../../types/index.js\";\nimport { CLI_COLORS, UI_SYMBOLS } from \"../../consts.js\";\nimport { useFocusedListItem } from \"../hooks/use-focused-list-item.js\";\nimport { useSourceGridSearchModal } from \"../hooks/use-source-grid-search-modal.js\";\nimport { SearchModal } from \"./search-modal.js\";\n\nconst SEARCH_PILL_LABEL = \"\\u2315 Search\";\n\nexport type SourceOption = {\n id: string;\n label: string;\n selected: boolean;\n installed: boolean;\n};\n\nexport type SourceRow = {\n skillId: SkillId;\n displayName: string;\n alias: SkillAlias;\n options: SourceOption[];\n};\n\nexport type SourceGridProps = {\n rows: SourceRow[];\n onSelect: (skillId: SkillId, sourceId: string) => void;\n onSearch?: (alias: SkillAlias) => Promise<BoundSkillCandidate[]>;\n onBind?: (candidate: BoundSkillCandidate) => void;\n onSearchStateChange?: (active: boolean) => void;\n /** Optional initial focus row (default: 0). Use with React `key` to reset. */\n defaultFocusedRow?: number;\n /** Optional initial focus col (default: 0). Use with React `key` to reset. */\n defaultFocusedCol?: number;\n /** Optional callback fired whenever the focused position changes */\n onFocusChange?: (row: number, col: number) => void;\n};\n\ntype SearchPillProps = {\n isFocused: boolean;\n};\n\nconst SearchPill: React.FC<SearchPillProps> = ({ isFocused }) => {\n const borderColor = isFocused ? CLI_COLORS.UNFOCUSED : CLI_COLORS.NEUTRAL;\n\n return (\n <Box marginRight={1} borderColor={borderColor} borderStyle=\"single\" borderDimColor={!isFocused}>\n <Text dimColor={!isFocused} bold={isFocused}>\n {\" \"}\n {SEARCH_PILL_LABEL}{\" \"}\n </Text>\n </Box>\n );\n};\n\ntype SourceSectionProps = {\n row: SourceRow;\n isFocused: boolean;\n focusedOptionIndex: number;\n showSearchPill: boolean;\n};\n\nconst SourceTag: React.FC<{ option: SourceOption; isFocused: boolean }> = ({\n option,\n isFocused,\n}) => {\n const borderColor = option.selected\n ? CLI_COLORS.PRIMARY\n : isFocused\n ? CLI_COLORS.UNFOCUSED\n : CLI_COLORS.NEUTRAL;\n const textColor = option.selected ? CLI_COLORS.PRIMARY : undefined;\n const isBold = isFocused || option.selected;\n const symbol = option.selected ? UI_SYMBOLS.SELECTED : UI_SYMBOLS.UNSELECTED;\n\n return (\n <Box marginRight={1} borderColor={borderColor} borderStyle=\"single\">\n <Text color={textColor} bold={isBold}>\n {\" \"}\n <Text dimColor={!option.selected}>{symbol}</Text> {option.label}\n {option.selected && <Text dimColor> (active)</Text>}{\" \"}\n </Text>\n </Box>\n );\n};\n\nconst SourceSection: React.FC<SourceSectionProps> = ({\n row,\n isFocused,\n focusedOptionIndex,\n showSearchPill,\n}) => {\n const searchPillIndex = row.options.length;\n\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n <Box flexDirection=\"row\">\n <Text>{row.displayName}</Text>\n </Box>\n\n <Box flexDirection=\"row\" flexWrap=\"wrap\" marginTop={0}>\n {row.options.map((option, index) => (\n <SourceTag\n key={option.id}\n option={option}\n isFocused={isFocused && index === focusedOptionIndex}\n />\n ))}\n {showSearchPill && (\n <SearchPill isFocused={isFocused && focusedOptionIndex === searchPillIndex} />\n )}\n </Box>\n </Box>\n );\n};\n\n/** Total navigable columns for a row (options + search pill if applicable) */\nconst getNavigableCount = (row: SourceRow, showSearchPill: boolean): number => {\n return row.options.length + (showSearchPill ? 1 : 0);\n};\n\nexport const SourceGrid: React.FC<SourceGridProps> = ({\n rows,\n onSelect,\n onSearch,\n onBind,\n onSearchStateChange,\n defaultFocusedRow = 0,\n defaultFocusedCol = 0,\n onFocusChange,\n}) => {\n const {\n searchModal,\n searchResults,\n searchAlias,\n handleSearchTrigger,\n handleBind,\n handleCloseSearch,\n } = useSourceGridSearchModal({ rows, onSearch, onBind, onSearchStateChange });\n\n const showSearchPill = !!onSearch;\n\n const getColCount = useCallback(\n (row: number): number => {\n const rowData = rows[row];\n return rowData ? getNavigableCount(rowData, showSearchPill) : 0;\n },\n [rows, showSearchPill],\n );\n\n const { focusedRow, focusedCol, moveFocus } = useFocusedListItem(rows.length, getColCount, {\n wrap: true,\n onChange: onFocusChange,\n initialRow: defaultFocusedRow,\n initialCol: defaultFocusedCol,\n });\n\n useInput(\n useCallback(\n (\n input: string,\n key: {\n leftArrow: boolean;\n rightArrow: boolean;\n upArrow: boolean;\n downArrow: boolean;\n return: boolean;\n },\n ) => {\n // Don't handle grid input while search modal is open\n if (searchModal.isOpen) return;\n\n if (input === \" \") {\n const currentRow = rows[focusedRow];\n if (!currentRow) return;\n // Space on search pill triggers search\n if (showSearchPill && focusedCol === currentRow.options.length) {\n void handleSearchTrigger(focusedRow);\n return;\n }\n // Space on a source option toggles selection\n if (focusedCol < currentRow.options.length) {\n const currentOption = currentRow.options[focusedCol];\n if (currentOption) {\n onSelect(currentRow.skillId, currentOption.id);\n }\n }\n return;\n }\n\n const isLeft = key.leftArrow;\n const isRight = key.rightArrow;\n const isUp = key.upArrow;\n const isDown = key.downArrow;\n\n if (isLeft) {\n moveFocus(\"left\");\n } else if (isRight) {\n moveFocus(\"right\");\n } else if (isUp) {\n moveFocus(\"up\");\n } else if (isDown) {\n moveFocus(\"down\");\n }\n },\n [\n rows,\n focusedRow,\n focusedCol,\n onSelect,\n showSearchPill,\n searchModal.isOpen,\n handleSearchTrigger,\n moveFocus,\n ],\n ),\n );\n\n if (rows.length === 0) {\n return (\n <Box flexDirection=\"column\">\n <Text dimColor>No skills to display.</Text>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\">\n {rows.map((row, rowIndex) => (\n <SourceSection\n key={row.skillId}\n row={row}\n isFocused={rowIndex === focusedRow}\n focusedOptionIndex={focusedCol}\n showSearchPill={showSearchPill}\n />\n ))}\n {searchModal.isOpen && (\n <SearchModal\n results={searchResults}\n alias={searchAlias}\n onBind={handleBind}\n onClose={handleCloseSearch}\n />\n )}\n </Box>\n );\n};\n","import { useCallback, useState } from \"react\";\nimport type { BoundSkillCandidate, SkillAlias } from \"../../types/index.js\";\nimport { useModalState } from \"./use-modal-state.js\";\nimport type { SourceRow } from \"../wizard/source-grid.js\";\n\ntype UseSourceGridSearchModalOptions = {\n rows: SourceRow[];\n onSearch?: (alias: SkillAlias) => Promise<BoundSkillCandidate[]>;\n onBind?: (candidate: BoundSkillCandidate) => void;\n onSearchStateChange?: (active: boolean) => void;\n};\n\ntype UseSourceGridSearchModalResult = {\n searchModal: { isOpen: boolean };\n searchResults: BoundSkillCandidate[];\n searchAlias: string;\n handleSearchTrigger: (rowIndex: number) => Promise<void>;\n handleBind: (candidate: BoundSkillCandidate) => void;\n handleCloseSearch: () => void;\n};\n\nexport function useSourceGridSearchModal({\n rows,\n onSearch,\n onBind,\n onSearchStateChange,\n}: UseSourceGridSearchModalOptions): UseSourceGridSearchModalResult {\n const searchModal = useModalState<number>();\n const [searchResults, setSearchResults] = useState<BoundSkillCandidate[]>([]);\n const [searchAlias, setSearchAlias] = useState(\"\");\n\n const resetSearch = useCallback(() => {\n searchModal.close();\n setSearchResults([]);\n setSearchAlias(\"\");\n onSearchStateChange?.(false);\n }, [onSearchStateChange, searchModal]);\n\n const handleSearchTrigger = useCallback(\n async (rowIndex: number) => {\n const row = rows[rowIndex];\n if (!row || !onSearch) return;\n\n const alias = row.alias;\n setSearchAlias(alias);\n searchModal.open(rowIndex);\n onSearchStateChange?.(true);\n\n const results = await onSearch(alias);\n setSearchResults(results);\n },\n [rows, onSearch, onSearchStateChange, searchModal],\n );\n\n const handleBind = useCallback(\n (candidate: BoundSkillCandidate) => {\n onBind?.(candidate);\n resetSearch();\n },\n [onBind, resetSearch],\n );\n\n const handleCloseSearch = useCallback(() => {\n resetSearch();\n }, [resetSearch]);\n\n return {\n searchModal: { isOpen: searchModal.isOpen },\n searchResults,\n searchAlias,\n handleSearchTrigger,\n handleBind,\n handleCloseSearch,\n };\n}\n"],"mappings":"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","names":["useCallback","useCallback"]}
|
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
BaseCommand
|
|
4
|
-
|
|
5
|
-
} from "../../chunk-OBXAY23Y.js";
|
|
3
|
+
BaseCommand
|
|
4
|
+
} from "../../chunk-5I6VY2E7.js";
|
|
6
5
|
import {
|
|
7
6
|
ensureDir,
|
|
7
|
+
getErrorMessage,
|
|
8
8
|
glob,
|
|
9
9
|
pluginManifestSchema,
|
|
10
|
-
|
|
10
|
+
readFileSafe,
|
|
11
11
|
setVerbose,
|
|
12
12
|
verbose,
|
|
13
13
|
warn,
|
|
14
14
|
writeFile
|
|
15
|
-
} from "../../chunk-
|
|
15
|
+
} from "../../chunk-5WIHSJRO.js";
|
|
16
16
|
import {
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
DEFAULT_PLUGIN_NAME,
|
|
18
|
+
DEFAULT_VERSION,
|
|
19
|
+
MAX_PLUGIN_FILE_SIZE
|
|
20
|
+
} from "../../chunk-IFODQTCX.js";
|
|
19
21
|
import {
|
|
20
22
|
init_esm_shims
|
|
21
23
|
} from "../../chunk-AWKZ5BDL.js";
|
|
@@ -41,7 +43,7 @@ var CATEGORY_PATTERNS = [
|
|
|
41
43
|
{ pattern: /^mobile-/, category: "mobile" },
|
|
42
44
|
{ pattern: /^security-/, category: "security" }
|
|
43
45
|
];
|
|
44
|
-
function
|
|
46
|
+
function inferCategoryFromPluginName(pluginName) {
|
|
45
47
|
for (const { pattern, category } of CATEGORY_PATTERNS) {
|
|
46
48
|
if (pattern.test(pluginName)) {
|
|
47
49
|
return category;
|
|
@@ -52,14 +54,15 @@ function inferCategory(pluginName) {
|
|
|
52
54
|
async function readPluginManifest(pluginDir) {
|
|
53
55
|
const manifestPath = path.join(pluginDir, PLUGIN_MANIFEST_PATH);
|
|
54
56
|
try {
|
|
55
|
-
const content = await
|
|
57
|
+
const content = await readFileSafe(manifestPath, MAX_PLUGIN_FILE_SIZE);
|
|
56
58
|
return pluginManifestSchema.parse(JSON.parse(content));
|
|
57
|
-
} catch {
|
|
59
|
+
} catch (error) {
|
|
60
|
+
verbose(`Failed to read plugin manifest at '${manifestPath}': ${getErrorMessage(error)}`);
|
|
58
61
|
return null;
|
|
59
62
|
}
|
|
60
63
|
}
|
|
61
|
-
function
|
|
62
|
-
const category =
|
|
64
|
+
function convertManifestToMarketplacePlugin(manifest, pluginRoot, pluginDirName) {
|
|
65
|
+
const category = inferCategoryFromPluginName(manifest.name);
|
|
63
66
|
const plugin = {
|
|
64
67
|
name: manifest.name,
|
|
65
68
|
source: `./${pluginRoot}/${pluginDirName}`,
|
|
@@ -83,10 +86,10 @@ async function generateMarketplace(pluginsDir, options) {
|
|
|
83
86
|
const pluginDir = path.join(pluginsDir, pluginDirName);
|
|
84
87
|
const manifest = await readPluginManifest(pluginDir);
|
|
85
88
|
if (!manifest) {
|
|
86
|
-
warn(`Could not read plugin manifest: ${manifestFile}`);
|
|
89
|
+
warn(`Could not read plugin manifest: '${manifestFile}'`);
|
|
87
90
|
continue;
|
|
88
91
|
}
|
|
89
|
-
const plugin =
|
|
92
|
+
const plugin = convertManifestToMarketplacePlugin(
|
|
90
93
|
manifest,
|
|
91
94
|
options.pluginRoot.replace(/^\.\//, ""),
|
|
92
95
|
pluginDirName
|
|
@@ -117,7 +120,8 @@ async function generateMarketplace(pluginsDir, options) {
|
|
|
117
120
|
}
|
|
118
121
|
async function writeMarketplace(outputPath, marketplace) {
|
|
119
122
|
await ensureDir(path.dirname(outputPath));
|
|
120
|
-
const content = JSON.stringify(marketplace, null, 2)
|
|
123
|
+
const content = `${JSON.stringify(marketplace, null, 2)}
|
|
124
|
+
`;
|
|
121
125
|
await writeFile(outputPath, content);
|
|
122
126
|
}
|
|
123
127
|
function getMarketplaceStats(marketplace) {
|
|
@@ -135,7 +139,6 @@ function getMarketplaceStats(marketplace) {
|
|
|
135
139
|
// src/cli/commands/build/marketplace.ts
|
|
136
140
|
var DEFAULT_PLUGINS_DIR = "dist/plugins";
|
|
137
141
|
var DEFAULT_OUTPUT_FILE = ".claude-plugin/marketplace.json";
|
|
138
|
-
var DEFAULT_NAME = "claude-collective";
|
|
139
142
|
var DEFAULT_DESCRIPTION = "Community skills and stacks for Claude Code";
|
|
140
143
|
var DEFAULT_OWNER_NAME = "Claude Collective";
|
|
141
144
|
var DEFAULT_OWNER_EMAIL = "hello@claude-collective.com";
|
|
@@ -162,7 +165,7 @@ var BuildMarketplace = class _BuildMarketplace extends BaseCommand {
|
|
|
162
165
|
}),
|
|
163
166
|
name: Flags.string({
|
|
164
167
|
description: "Marketplace name",
|
|
165
|
-
default:
|
|
168
|
+
default: DEFAULT_PLUGIN_NAME
|
|
166
169
|
}),
|
|
167
170
|
version: Flags.string({
|
|
168
171
|
description: "Marketplace version",
|
|
@@ -237,9 +240,7 @@ var BuildMarketplace = class _BuildMarketplace extends BaseCommand {
|
|
|
237
240
|
this.log("");
|
|
238
241
|
} catch (error) {
|
|
239
242
|
this.log("Generation failed");
|
|
240
|
-
this.
|
|
241
|
-
exit: EXIT_CODES.ERROR
|
|
242
|
-
});
|
|
243
|
+
this.handleError(error);
|
|
243
244
|
}
|
|
244
245
|
}
|
|
245
246
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/cli/commands/build/marketplace.ts","../../../src/cli/lib/marketplace-generator.ts"],"sourcesContent":["import { Flags } from \"@oclif/core\";\nimport path from \"path\";\nimport { sortBy } from \"remeda\";\nimport { BaseCommand } from \"../../base-command\";\nimport { setVerbose } from \"../../utils/logger\";\nimport {\n generateMarketplace,\n writeMarketplace,\n getMarketplaceStats,\n} from \"../../lib/marketplace-generator\";\nimport { EXIT_CODES } from \"../../lib/exit-codes\";\nimport { DEFAULT_VERSION } from \"../../consts\";\n\nconst DEFAULT_PLUGINS_DIR = \"dist/plugins\";\nconst DEFAULT_OUTPUT_FILE = \".claude-plugin/marketplace.json\";\nconst DEFAULT_NAME = \"claude-collective\";\nconst DEFAULT_DESCRIPTION = \"Community skills and stacks for Claude Code\";\nconst DEFAULT_OWNER_NAME = \"Claude Collective\";\nconst DEFAULT_OWNER_EMAIL = \"hello@claude-collective.com\";\n\nexport default class BuildMarketplace extends BaseCommand {\n static summary = \"Generate marketplace.json from built plugins (requires skills repo)\";\n\n static description =\n \"Generate marketplace.json from built plugins. This command scans the plugins directory and generates a marketplace manifest file.\";\n\n static examples = [\n \"<%= config.bin %> <%= command.id %>\",\n \"<%= config.bin %> <%= command.id %> --plugins-dir dist/stacks\",\n \"<%= config.bin %> <%= command.id %> --output .claude-plugin/market.json\",\n \"<%= config.bin %> <%= command.id %> --name my-marketplace --version 2.0.0\",\n ];\n\n static flags = {\n ...BaseCommand.baseFlags,\n \"plugins-dir\": Flags.string({\n char: \"p\",\n description: \"Plugins directory\",\n default: DEFAULT_PLUGINS_DIR,\n }),\n output: Flags.string({\n char: \"o\",\n description: \"Output file\",\n default: DEFAULT_OUTPUT_FILE,\n }),\n name: Flags.string({\n description: \"Marketplace name\",\n default: DEFAULT_NAME,\n }),\n version: Flags.string({\n description: \"Marketplace version\",\n default: DEFAULT_VERSION,\n }),\n description: Flags.string({\n description: \"Marketplace description\",\n default: DEFAULT_DESCRIPTION,\n }),\n \"owner-name\": Flags.string({\n description: \"Owner name\",\n default: DEFAULT_OWNER_NAME,\n }),\n \"owner-email\": Flags.string({\n description: \"Owner email\",\n default: DEFAULT_OWNER_EMAIL,\n }),\n verbose: Flags.boolean({\n char: \"v\",\n description: \"Enable verbose logging\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(BuildMarketplace);\n\n setVerbose(flags.verbose);\n\n const projectRoot = process.cwd();\n const pluginsDir = path.resolve(projectRoot, flags[\"plugins-dir\"]);\n const outputPath = path.resolve(projectRoot, flags.output);\n\n this.log(\"\");\n this.log(\"Generating marketplace.json\");\n this.log(` Plugins directory: ${pluginsDir}`);\n this.log(` Output file: ${outputPath}`);\n this.log(\"\");\n\n try {\n this.log(\"Scanning plugins...\");\n\n const marketplace = await generateMarketplace(pluginsDir, {\n name: flags.name,\n version: flags.version,\n description: flags.description,\n ownerName: flags[\"owner-name\"],\n ownerEmail: flags[\"owner-email\"],\n pluginRoot: `./${flags[\"plugins-dir\"]}`,\n });\n\n const stats = getMarketplaceStats(marketplace);\n this.log(`Found ${stats.total} plugins`);\n\n this.log(\"\");\n this.log(\"Category breakdown:\");\n const sortedCategories = sortBy(Object.entries(stats.byCategory), ([, count]) => -count);\n for (const [category, count] of sortedCategories) {\n this.log(` ${category}: ${count}`);\n }\n\n this.log(\"Writing marketplace.json...\");\n await writeMarketplace(outputPath, marketplace);\n this.log(`Wrote ${outputPath}`);\n\n this.log(\"\");\n this.log(\"Sample plugins:\");\n const sampleSize = 5;\n for (const plugin of marketplace.plugins.slice(0, sampleSize)) {\n const version = plugin.version ? `v${plugin.version}` : \"\";\n const category = plugin.category ? `[${plugin.category}]` : \"\";\n this.log(` ${plugin.name} ${version} ${category}`);\n if (plugin.description) {\n this.log(` ${plugin.description}`);\n }\n }\n if (marketplace.plugins.length > sampleSize) {\n this.log(` ... and ${marketplace.plugins.length - sampleSize} more`);\n }\n\n this.log(\"\");\n this.logSuccess(`Marketplace generated with ${stats.total} plugins!`);\n this.log(\"\");\n } catch (error) {\n this.log(\"Generation failed\");\n this.error(error instanceof Error ? error.message : String(error), {\n exit: EXIT_CODES.ERROR,\n });\n }\n }\n}\n","import path from \"path\";\nimport { sortBy } from \"remeda\";\nimport { readFile, writeFile, glob, ensureDir } from \"../utils/fs\";\nimport { verbose, warn } from \"../utils/logger\";\nimport type { Marketplace, MarketplacePlugin, PluginManifest } from \"../types\";\nimport { pluginManifestSchema } from \"./schemas\";\n\nconst PLUGIN_MANIFEST_PATH = \".claude-plugin/plugin.json\";\nconst MARKETPLACE_SCHEMA_URL = \"https://anthropic.com/claude-code/marketplace.schema.json\";\n\n/**\n * Category patterns for marketplace plugins.\n *\n * Plugin names match skill IDs directly (e.g., \"web-framework-react\").\n * The category is the first segment of the ID:\n * - web-* -> web\n * - api-* -> api\n * - cli-* -> cli\n * - meta-* -> methodology\n * - infra-* -> infra\n * - mobile-* -> mobile\n * - security-* -> security\n */\nconst CATEGORY_PATTERNS: Array<{ pattern: RegExp; category: string }> = [\n { pattern: /^web-/, category: \"web\" },\n { pattern: /^api-/, category: \"api\" },\n { pattern: /^cli-/, category: \"cli\" },\n { pattern: /^meta-/, category: \"methodology\" },\n { pattern: /^infra-/, category: \"infra\" },\n { pattern: /^mobile-/, category: \"mobile\" },\n { pattern: /^security-/, category: \"security\" },\n];\n\nexport type MarketplaceOptions = {\n name: string;\n version?: string;\n description?: string;\n ownerName: string;\n ownerEmail?: string;\n pluginRoot: string;\n};\n\nfunction inferCategory(pluginName: string): string | undefined {\n for (const { pattern, category } of CATEGORY_PATTERNS) {\n if (pattern.test(pluginName)) {\n return category;\n }\n }\n return undefined;\n}\n\nasync function readPluginManifest(pluginDir: string): Promise<PluginManifest | null> {\n const manifestPath = path.join(pluginDir, PLUGIN_MANIFEST_PATH);\n\n try {\n const content = await readFile(manifestPath);\n return pluginManifestSchema.parse(JSON.parse(content));\n } catch {\n return null;\n }\n}\n\nfunction toMarketplacePlugin(\n manifest: PluginManifest,\n pluginRoot: string,\n pluginDirName: string,\n): MarketplacePlugin {\n const category = inferCategory(manifest.name);\n\n const plugin: MarketplacePlugin = {\n name: manifest.name,\n source: `./${pluginRoot}/${pluginDirName}`,\n description: manifest.description,\n version: manifest.version,\n author: manifest.author,\n keywords: manifest.keywords,\n };\n\n if (category) {\n plugin.category = category;\n }\n\n return plugin;\n}\n\nexport async function generateMarketplace(\n pluginsDir: string,\n options: MarketplaceOptions,\n): Promise<Marketplace> {\n verbose(`Scanning plugins directory: ${pluginsDir}`);\n\n const manifestFiles = await glob(`**/${PLUGIN_MANIFEST_PATH}`, pluginsDir);\n verbose(`Found ${manifestFiles.length} plugin manifests`);\n\n const plugins: MarketplacePlugin[] = [];\n\n for (const manifestFile of manifestFiles) {\n const pluginDirName = manifestFile.split(\"/\")[0];\n const pluginDir = path.join(pluginsDir, pluginDirName);\n\n const manifest = await readPluginManifest(pluginDir);\n if (!manifest) {\n warn(`Could not read plugin manifest: ${manifestFile}`);\n continue;\n }\n\n const plugin = toMarketplacePlugin(\n manifest,\n options.pluginRoot.replace(/^\\.\\//, \"\"),\n pluginDirName,\n );\n plugins.push(plugin);\n verbose(` [OK] ${plugin.name}`);\n }\n\n const sortedPlugins = sortBy(plugins, (p) => p.name);\n\n const marketplace: Marketplace = {\n $schema: MARKETPLACE_SCHEMA_URL,\n name: options.name,\n version: options.version ?? \"1.0.0\",\n owner: {\n name: options.ownerName,\n },\n metadata: {\n pluginRoot: options.pluginRoot,\n },\n plugins: sortedPlugins,\n };\n\n if (options.description) {\n marketplace.description = options.description;\n }\n\n if (options.ownerEmail) {\n marketplace.owner.email = options.ownerEmail;\n }\n\n return marketplace;\n}\n\nexport async function writeMarketplace(\n outputPath: string,\n marketplace: Marketplace,\n): Promise<void> {\n await ensureDir(path.dirname(outputPath));\n const content = JSON.stringify(marketplace, null, 2) + \"\\n\";\n await writeFile(outputPath, content);\n}\n\nexport function getMarketplaceStats(marketplace: Marketplace): {\n total: number;\n byCategory: Record<string, number>;\n} {\n const byCategory: Record<string, number> = {};\n\n for (const plugin of marketplace.plugins) {\n const category = plugin.category ?? \"uncategorized\";\n byCategory[category] = (byCategory[category] ?? 0) + 1;\n }\n\n return {\n total: marketplace.plugins.length,\n byCategory,\n };\n}\n"],"mappings":"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","names":["path","sortBy","path","sortBy"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/cli/commands/build/marketplace.ts","../../../src/cli/lib/marketplace-generator.ts"],"sourcesContent":["import { Flags } from \"@oclif/core\";\nimport path from \"path\";\nimport { sortBy } from \"remeda\";\n\nimport { BaseCommand } from \"../../base-command\";\nimport { setVerbose } from \"../../utils/logger\";\nimport {\n generateMarketplace,\n writeMarketplace,\n getMarketplaceStats,\n} from \"../../lib/marketplace-generator\";\nimport { DEFAULT_PLUGIN_NAME, DEFAULT_VERSION } from \"../../consts\";\n\nconst DEFAULT_PLUGINS_DIR = \"dist/plugins\";\nconst DEFAULT_OUTPUT_FILE = \".claude-plugin/marketplace.json\";\nconst DEFAULT_DESCRIPTION = \"Community skills and stacks for Claude Code\";\nconst DEFAULT_OWNER_NAME = \"Claude Collective\";\nconst DEFAULT_OWNER_EMAIL = \"hello@claude-collective.com\";\n\nexport default class BuildMarketplace extends BaseCommand {\n static summary = \"Generate marketplace.json from built plugins (requires skills repo)\";\n\n static description =\n \"Generate marketplace.json from built plugins. This command scans the plugins directory and generates a marketplace manifest file.\";\n\n static examples = [\n \"<%= config.bin %> <%= command.id %>\",\n \"<%= config.bin %> <%= command.id %> --plugins-dir dist/stacks\",\n \"<%= config.bin %> <%= command.id %> --output .claude-plugin/market.json\",\n \"<%= config.bin %> <%= command.id %> --name my-marketplace --version 2.0.0\",\n ];\n\n static flags = {\n ...BaseCommand.baseFlags,\n \"plugins-dir\": Flags.string({\n char: \"p\",\n description: \"Plugins directory\",\n default: DEFAULT_PLUGINS_DIR,\n }),\n output: Flags.string({\n char: \"o\",\n description: \"Output file\",\n default: DEFAULT_OUTPUT_FILE,\n }),\n name: Flags.string({\n description: \"Marketplace name\",\n default: DEFAULT_PLUGIN_NAME,\n }),\n version: Flags.string({\n description: \"Marketplace version\",\n default: DEFAULT_VERSION,\n }),\n description: Flags.string({\n description: \"Marketplace description\",\n default: DEFAULT_DESCRIPTION,\n }),\n \"owner-name\": Flags.string({\n description: \"Owner name\",\n default: DEFAULT_OWNER_NAME,\n }),\n \"owner-email\": Flags.string({\n description: \"Owner email\",\n default: DEFAULT_OWNER_EMAIL,\n }),\n verbose: Flags.boolean({\n char: \"v\",\n description: \"Enable verbose logging\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(BuildMarketplace);\n\n setVerbose(flags.verbose);\n\n const projectRoot = process.cwd();\n const pluginsDir = path.resolve(projectRoot, flags[\"plugins-dir\"]);\n const outputPath = path.resolve(projectRoot, flags.output);\n\n this.log(\"\");\n this.log(\"Generating marketplace.json\");\n this.log(` Plugins directory: ${pluginsDir}`);\n this.log(` Output file: ${outputPath}`);\n this.log(\"\");\n\n try {\n this.log(\"Scanning plugins...\");\n\n const marketplace = await generateMarketplace(pluginsDir, {\n name: flags.name,\n version: flags.version,\n description: flags.description,\n ownerName: flags[\"owner-name\"],\n ownerEmail: flags[\"owner-email\"],\n pluginRoot: `./${flags[\"plugins-dir\"]}`,\n });\n\n const stats = getMarketplaceStats(marketplace);\n this.log(`Found ${stats.total} plugins`);\n\n this.log(\"\");\n this.log(\"Category breakdown:\");\n const sortedCategories = sortBy(Object.entries(stats.byCategory), ([, count]) => -count);\n for (const [category, count] of sortedCategories) {\n this.log(` ${category}: ${count}`);\n }\n\n this.log(\"Writing marketplace.json...\");\n await writeMarketplace(outputPath, marketplace);\n this.log(`Wrote ${outputPath}`);\n\n this.log(\"\");\n this.log(\"Sample plugins:\");\n const sampleSize = 5;\n for (const plugin of marketplace.plugins.slice(0, sampleSize)) {\n const version = plugin.version ? `v${plugin.version}` : \"\";\n const category = plugin.category ? `[${plugin.category}]` : \"\";\n this.log(` ${plugin.name} ${version} ${category}`);\n if (plugin.description) {\n this.log(` ${plugin.description}`);\n }\n }\n if (marketplace.plugins.length > sampleSize) {\n this.log(` ... and ${marketplace.plugins.length - sampleSize} more`);\n }\n\n this.log(\"\");\n this.logSuccess(`Marketplace generated with ${stats.total} plugins!`);\n this.log(\"\");\n } catch (error) {\n this.log(\"Generation failed\");\n this.handleError(error);\n }\n }\n}\n","import path from \"path\";\nimport { sortBy } from \"remeda\";\n\nimport { MAX_PLUGIN_FILE_SIZE } from \"../consts\";\nimport { getErrorMessage } from \"../utils/errors\";\nimport { readFileSafe, writeFile, glob, ensureDir } from \"../utils/fs\";\nimport { verbose, warn } from \"../utils/logger\";\nimport type { Marketplace, MarketplacePlugin, PluginManifest } from \"../types\";\nimport { pluginManifestSchema } from \"./schemas\";\n\nconst PLUGIN_MANIFEST_PATH = \".claude-plugin/plugin.json\";\nconst MARKETPLACE_SCHEMA_URL = \"https://anthropic.com/claude-code/marketplace.schema.json\";\n\n/**\n * Category patterns for marketplace plugins.\n *\n * Plugin names match skill IDs directly (e.g., \"web-framework-react\").\n * The category is the first segment of the ID:\n * - web-* -> web\n * - api-* -> api\n * - cli-* -> cli\n * - meta-* -> methodology\n * - infra-* -> infra\n * - mobile-* -> mobile\n * - security-* -> security\n */\nconst CATEGORY_PATTERNS: Array<{ pattern: RegExp; category: string }> = [\n { pattern: /^web-/, category: \"web\" },\n { pattern: /^api-/, category: \"api\" },\n { pattern: /^cli-/, category: \"cli\" },\n { pattern: /^meta-/, category: \"methodology\" },\n { pattern: /^infra-/, category: \"infra\" },\n { pattern: /^mobile-/, category: \"mobile\" },\n { pattern: /^security-/, category: \"security\" },\n];\n\ntype MarketplaceOptions = {\n name: string;\n version?: string;\n description?: string;\n ownerName: string;\n ownerEmail?: string;\n pluginRoot: string;\n};\n\nfunction inferCategoryFromPluginName(pluginName: string): string | undefined {\n for (const { pattern, category } of CATEGORY_PATTERNS) {\n if (pattern.test(pluginName)) {\n return category;\n }\n }\n return undefined;\n}\n\nasync function readPluginManifest(pluginDir: string): Promise<PluginManifest | null> {\n const manifestPath = path.join(pluginDir, PLUGIN_MANIFEST_PATH);\n\n try {\n const content = await readFileSafe(manifestPath, MAX_PLUGIN_FILE_SIZE);\n return pluginManifestSchema.parse(JSON.parse(content));\n } catch (error) {\n verbose(`Failed to read plugin manifest at '${manifestPath}': ${getErrorMessage(error)}`);\n return null;\n }\n}\n\nfunction convertManifestToMarketplacePlugin(\n manifest: PluginManifest,\n pluginRoot: string,\n pluginDirName: string,\n): MarketplacePlugin {\n const category = inferCategoryFromPluginName(manifest.name);\n\n const plugin: MarketplacePlugin = {\n name: manifest.name,\n source: `./${pluginRoot}/${pluginDirName}`,\n description: manifest.description,\n version: manifest.version,\n author: manifest.author,\n keywords: manifest.keywords,\n };\n\n if (category) {\n plugin.category = category;\n }\n\n return plugin;\n}\n\nexport async function generateMarketplace(\n pluginsDir: string,\n options: MarketplaceOptions,\n): Promise<Marketplace> {\n verbose(`Scanning plugins directory: ${pluginsDir}`);\n\n const manifestFiles = await glob(`**/${PLUGIN_MANIFEST_PATH}`, pluginsDir);\n verbose(`Found ${manifestFiles.length} plugin manifests`);\n\n const plugins: MarketplacePlugin[] = [];\n\n for (const manifestFile of manifestFiles) {\n const pluginDirName = manifestFile.split(\"/\")[0];\n const pluginDir = path.join(pluginsDir, pluginDirName);\n\n const manifest = await readPluginManifest(pluginDir);\n if (!manifest) {\n warn(`Could not read plugin manifest: '${manifestFile}'`);\n continue;\n }\n\n const plugin = convertManifestToMarketplacePlugin(\n manifest,\n options.pluginRoot.replace(/^\\.\\//, \"\"),\n pluginDirName,\n );\n plugins.push(plugin);\n verbose(` [OK] ${plugin.name}`);\n }\n\n const sortedPlugins = sortBy(plugins, (p) => p.name);\n\n const marketplace: Marketplace = {\n $schema: MARKETPLACE_SCHEMA_URL,\n name: options.name,\n version: options.version ?? \"1.0.0\",\n owner: {\n name: options.ownerName,\n },\n metadata: {\n pluginRoot: options.pluginRoot,\n },\n plugins: sortedPlugins,\n };\n\n if (options.description) {\n marketplace.description = options.description;\n }\n\n if (options.ownerEmail) {\n marketplace.owner.email = options.ownerEmail;\n }\n\n return marketplace;\n}\n\nexport async function writeMarketplace(\n outputPath: string,\n marketplace: Marketplace,\n): Promise<void> {\n await ensureDir(path.dirname(outputPath));\n const content = `${JSON.stringify(marketplace, null, 2)}\\n`;\n await writeFile(outputPath, content);\n}\n\nexport function getMarketplaceStats(marketplace: Marketplace): {\n total: number;\n byCategory: Record<string, number>;\n} {\n const byCategory: Record<string, number> = {};\n\n for (const plugin of marketplace.plugins) {\n const category = plugin.category ?? \"uncategorized\";\n byCategory[category] = (byCategory[category] ?? 0) + 1;\n }\n\n return {\n total: marketplace.plugins.length,\n byCategory,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA,SAAS,aAAa;AACtB,OAAOA,WAAU;AACjB,SAAS,UAAAC,eAAc;;;ACFvB;AAAA,OAAO,UAAU;AACjB,SAAS,cAAc;AASvB,IAAM,uBAAuB;AAC7B,IAAM,yBAAyB;AAe/B,IAAM,oBAAkE;AAAA,EACtE,EAAE,SAAS,SAAS,UAAU,MAAM;AAAA,EACpC,EAAE,SAAS,SAAS,UAAU,MAAM;AAAA,EACpC,EAAE,SAAS,SAAS,UAAU,MAAM;AAAA,EACpC,EAAE,SAAS,UAAU,UAAU,cAAc;AAAA,EAC7C,EAAE,SAAS,WAAW,UAAU,QAAQ;AAAA,EACxC,EAAE,SAAS,YAAY,UAAU,SAAS;AAAA,EAC1C,EAAE,SAAS,cAAc,UAAU,WAAW;AAChD;AAWA,SAAS,4BAA4B,YAAwC;AAC3E,aAAW,EAAE,SAAS,SAAS,KAAK,mBAAmB;AACrD,QAAI,QAAQ,KAAK,UAAU,GAAG;AAC5B,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAe,mBAAmB,WAAmD;AACnF,QAAM,eAAe,KAAK,KAAK,WAAW,oBAAoB;AAE9D,MAAI;AACF,UAAM,UAAU,MAAM,aAAa,cAAc,oBAAoB;AACrE,WAAO,qBAAqB,MAAM,KAAK,MAAM,OAAO,CAAC;AAAA,EACvD,SAAS,OAAO;AACd,YAAQ,sCAAsC,YAAY,MAAM,gBAAgB,KAAK,CAAC,EAAE;AACxF,WAAO;AAAA,EACT;AACF;AAEA,SAAS,mCACP,UACA,YACA,eACmB;AACnB,QAAM,WAAW,4BAA4B,SAAS,IAAI;AAE1D,QAAM,SAA4B;AAAA,IAChC,MAAM,SAAS;AAAA,IACf,QAAQ,KAAK,UAAU,IAAI,aAAa;AAAA,IACxC,aAAa,SAAS;AAAA,IACtB,SAAS,SAAS;AAAA,IAClB,QAAQ,SAAS;AAAA,IACjB,UAAU,SAAS;AAAA,EACrB;AAEA,MAAI,UAAU;AACZ,WAAO,WAAW;AAAA,EACpB;AAEA,SAAO;AACT;AAEA,eAAsB,oBACpB,YACA,SACsB;AACtB,UAAQ,+BAA+B,UAAU,EAAE;AAEnD,QAAM,gBAAgB,MAAM,KAAK,MAAM,oBAAoB,IAAI,UAAU;AACzE,UAAQ,SAAS,cAAc,MAAM,mBAAmB;AAExD,QAAM,UAA+B,CAAC;AAEtC,aAAW,gBAAgB,eAAe;AACxC,UAAM,gBAAgB,aAAa,MAAM,GAAG,EAAE,CAAC;AAC/C,UAAM,YAAY,KAAK,KAAK,YAAY,aAAa;AAErD,UAAM,WAAW,MAAM,mBAAmB,SAAS;AACnD,QAAI,CAAC,UAAU;AACb,WAAK,oCAAoC,YAAY,GAAG;AACxD;AAAA,IACF;AAEA,UAAM,SAAS;AAAA,MACb;AAAA,MACA,QAAQ,WAAW,QAAQ,SAAS,EAAE;AAAA,MACtC;AAAA,IACF;AACA,YAAQ,KAAK,MAAM;AACnB,YAAQ,UAAU,OAAO,IAAI,EAAE;AAAA,EACjC;AAEA,QAAM,gBAAgB,OAAO,SAAS,CAAC,MAAM,EAAE,IAAI;AAEnD,QAAM,cAA2B;AAAA,IAC/B,SAAS;AAAA,IACT,MAAM,QAAQ;AAAA,IACd,SAAS,QAAQ,WAAW;AAAA,IAC5B,OAAO;AAAA,MACL,MAAM,QAAQ;AAAA,IAChB;AAAA,IACA,UAAU;AAAA,MACR,YAAY,QAAQ;AAAA,IACtB;AAAA,IACA,SAAS;AAAA,EACX;AAEA,MAAI,QAAQ,aAAa;AACvB,gBAAY,cAAc,QAAQ;AAAA,EACpC;AAEA,MAAI,QAAQ,YAAY;AACtB,gBAAY,MAAM,QAAQ,QAAQ;AAAA,EACpC;AAEA,SAAO;AACT;AAEA,eAAsB,iBACpB,YACA,aACe;AACf,QAAM,UAAU,KAAK,QAAQ,UAAU,CAAC;AACxC,QAAM,UAAU,GAAG,KAAK,UAAU,aAAa,MAAM,CAAC,CAAC;AAAA;AACvD,QAAM,UAAU,YAAY,OAAO;AACrC;AAEO,SAAS,oBAAoB,aAGlC;AACA,QAAM,aAAqC,CAAC;AAE5C,aAAW,UAAU,YAAY,SAAS;AACxC,UAAM,WAAW,OAAO,YAAY;AACpC,eAAW,QAAQ,KAAK,WAAW,QAAQ,KAAK,KAAK;AAAA,EACvD;AAEA,SAAO;AAAA,IACL,OAAO,YAAY,QAAQ;AAAA,IAC3B;AAAA,EACF;AACF;;;AD5JA,IAAM,sBAAsB;AAC5B,IAAM,sBAAsB;AAC5B,IAAM,sBAAsB;AAC5B,IAAM,qBAAqB;AAC3B,IAAM,sBAAsB;AAE5B,IAAqB,mBAArB,MAAqB,0BAAyB,YAAY;AAAA,EACxD,OAAO,UAAU;AAAA,EAEjB,OAAO,cACL;AAAA,EAEF,OAAO,WAAW;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EAEA,OAAO,QAAQ;AAAA,IACb,GAAG,YAAY;AAAA,IACf,eAAe,MAAM,OAAO;AAAA,MAC1B,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AAAA,IACD,QAAQ,MAAM,OAAO;AAAA,MACnB,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AAAA,IACD,MAAM,MAAM,OAAO;AAAA,MACjB,aAAa;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AAAA,IACD,SAAS,MAAM,OAAO;AAAA,MACpB,aAAa;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AAAA,IACD,aAAa,MAAM,OAAO;AAAA,MACxB,aAAa;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AAAA,IACD,cAAc,MAAM,OAAO;AAAA,MACzB,aAAa;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AAAA,IACD,eAAe,MAAM,OAAO;AAAA,MAC1B,aAAa;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AAAA,IACD,SAAS,MAAM,QAAQ;AAAA,MACrB,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,MAAqB;AACzB,UAAM,EAAE,MAAM,IAAI,MAAM,KAAK,MAAM,iBAAgB;AAEnD,eAAW,MAAM,OAAO;AAExB,UAAM,cAAc,QAAQ,IAAI;AAChC,UAAM,aAAaC,MAAK,QAAQ,aAAa,MAAM,aAAa,CAAC;AACjE,UAAM,aAAaA,MAAK,QAAQ,aAAa,MAAM,MAAM;AAEzD,SAAK,IAAI,EAAE;AACX,SAAK,IAAI,6BAA6B;AACtC,SAAK,IAAI,wBAAwB,UAAU,EAAE;AAC7C,SAAK,IAAI,kBAAkB,UAAU,EAAE;AACvC,SAAK,IAAI,EAAE;AAEX,QAAI;AACF,WAAK,IAAI,qBAAqB;AAE9B,YAAM,cAAc,MAAM,oBAAoB,YAAY;AAAA,QACxD,MAAM,MAAM;AAAA,QACZ,SAAS,MAAM;AAAA,QACf,aAAa,MAAM;AAAA,QACnB,WAAW,MAAM,YAAY;AAAA,QAC7B,YAAY,MAAM,aAAa;AAAA,QAC/B,YAAY,KAAK,MAAM,aAAa,CAAC;AAAA,MACvC,CAAC;AAED,YAAM,QAAQ,oBAAoB,WAAW;AAC7C,WAAK,IAAI,SAAS,MAAM,KAAK,UAAU;AAEvC,WAAK,IAAI,EAAE;AACX,WAAK,IAAI,qBAAqB;AAC9B,YAAM,mBAAmBC,QAAO,OAAO,QAAQ,MAAM,UAAU,GAAG,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,KAAK;AACvF,iBAAW,CAAC,UAAU,KAAK,KAAK,kBAAkB;AAChD,aAAK,IAAI,KAAK,QAAQ,KAAK,KAAK,EAAE;AAAA,MACpC;AAEA,WAAK,IAAI,6BAA6B;AACtC,YAAM,iBAAiB,YAAY,WAAW;AAC9C,WAAK,IAAI,SAAS,UAAU,EAAE;AAE9B,WAAK,IAAI,EAAE;AACX,WAAK,IAAI,iBAAiB;AAC1B,YAAM,aAAa;AACnB,iBAAW,UAAU,YAAY,QAAQ,MAAM,GAAG,UAAU,GAAG;AAC7D,cAAM,UAAU,OAAO,UAAU,IAAI,OAAO,OAAO,KAAK;AACxD,cAAM,WAAW,OAAO,WAAW,IAAI,OAAO,QAAQ,MAAM;AAC5D,aAAK,IAAI,KAAK,OAAO,IAAI,IAAI,OAAO,IAAI,QAAQ,EAAE;AAClD,YAAI,OAAO,aAAa;AACtB,eAAK,IAAI,OAAO,OAAO,WAAW,EAAE;AAAA,QACtC;AAAA,MACF;AACA,UAAI,YAAY,QAAQ,SAAS,YAAY;AAC3C,aAAK,IAAI,aAAa,YAAY,QAAQ,SAAS,UAAU,OAAO;AAAA,MACtE;AAEA,WAAK,IAAI,EAAE;AACX,WAAK,WAAW,8BAA8B,MAAM,KAAK,WAAW;AACpE,WAAK,IAAI,EAAE;AAAA,IACb,SAAS,OAAO;AACd,WAAK,IAAI,mBAAmB;AAC5B,WAAK,YAAY,KAAK;AAAA,IACxB;AAAA,EACF;AACF;","names":["path","sortBy","path","sortBy"]}
|
|
@@ -2,23 +2,21 @@
|
|
|
2
2
|
import {
|
|
3
3
|
compileAllAgentPlugins,
|
|
4
4
|
printAgentCompilationSummary
|
|
5
|
-
} from "../../chunk-
|
|
5
|
+
} from "../../chunk-XPMEGGJK.js";
|
|
6
6
|
import {
|
|
7
|
-
BaseCommand
|
|
8
|
-
|
|
9
|
-
} from "../../chunk-OBXAY23Y.js";
|
|
7
|
+
BaseCommand
|
|
8
|
+
} from "../../chunk-5I6VY2E7.js";
|
|
10
9
|
import {
|
|
11
10
|
compileAllSkillPlugins,
|
|
12
11
|
compileSkillPlugin,
|
|
13
12
|
printCompilationSummary
|
|
14
|
-
} from "../../chunk-
|
|
13
|
+
} from "../../chunk-SSHG7MEE.js";
|
|
15
14
|
import {
|
|
16
15
|
setVerbose
|
|
17
|
-
} from "../../chunk-
|
|
18
|
-
import "../../chunk-HWD32NP7.js";
|
|
16
|
+
} from "../../chunk-5WIHSJRO.js";
|
|
19
17
|
import {
|
|
20
18
|
DIRS
|
|
21
|
-
} from "../../chunk-
|
|
19
|
+
} from "../../chunk-IFODQTCX.js";
|
|
22
20
|
import {
|
|
23
21
|
init_esm_shims
|
|
24
22
|
} from "../../chunk-AWKZ5BDL.js";
|
|
@@ -105,9 +103,7 @@ var BuildPlugins = class _BuildPlugins extends BaseCommand {
|
|
|
105
103
|
this.logSuccess("Plugin compilation complete!");
|
|
106
104
|
} catch (error) {
|
|
107
105
|
this.log("Compilation failed");
|
|
108
|
-
this.
|
|
109
|
-
exit: EXIT_CODES.ERROR
|
|
110
|
-
});
|
|
106
|
+
this.handleError(error);
|
|
111
107
|
}
|
|
112
108
|
}
|
|
113
109
|
};
|