@agents-inc/cli 0.45.0 → 0.47.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 +27 -0
- package/dist/{chunk-V43QDMYQ.js → chunk-2RQYJFKA.js} +2 -2
- package/dist/{chunk-ABE55TEU.js → chunk-3APMMQUA.js} +11 -3
- package/dist/chunk-3APMMQUA.js.map +1 -0
- package/dist/{chunk-KWWLPPHF.js → chunk-B4QYXVPZ.js} +2 -2
- package/dist/{chunk-473YHDYQ.js → chunk-C4QI54PN.js} +147 -52
- package/dist/chunk-C4QI54PN.js.map +1 -0
- package/dist/{chunk-CLHBKFHU.js → chunk-CJFWO46A.js} +2 -2
- package/dist/{chunk-M2XPTQDT.js → chunk-DC333ZDC.js} +4 -4
- package/dist/{chunk-M3AGB4TR.js → chunk-DVW6ASTO.js} +4 -4
- package/dist/{chunk-ARET3NYO.js → chunk-EZ46ZTAQ.js} +3 -3
- package/dist/{chunk-VTDEENSP.js → chunk-FMQ3A7W4.js} +5 -5
- package/dist/{chunk-VTDEENSP.js.map → chunk-FMQ3A7W4.js.map} +1 -1
- package/dist/{chunk-FVN5PFFY.js → chunk-FTD5Z6QD.js} +5 -1
- package/dist/chunk-FTD5Z6QD.js.map +1 -0
- package/dist/{chunk-YQFU2KZ5.js → chunk-FXQYEXLS.js} +3 -3
- package/dist/{chunk-ZECXM7LP.js → chunk-GFDGYQ6M.js} +3553 -3497
- package/dist/chunk-GFDGYQ6M.js.map +1 -0
- package/dist/chunk-HLTJK3XB.js +71 -0
- package/dist/chunk-HLTJK3XB.js.map +1 -0
- package/dist/{chunk-KVHLKPYB.js → chunk-HPJP3HFD.js} +7 -7
- package/dist/{chunk-KZNPPUQG.js → chunk-INKJBMPJ.js} +5 -3
- package/dist/chunk-INKJBMPJ.js.map +1 -0
- package/dist/{chunk-SBWMSNS2.js → chunk-IRJADQM7.js} +2 -2
- package/dist/{chunk-SYGEV3KV.js → chunk-JTTTXGHX.js} +4 -4
- package/dist/{chunk-ELRGSZHZ.js → chunk-JZHIF3K7.js} +5 -5
- package/dist/{chunk-OALQWRLG.js → chunk-KQ27IDYL.js} +2 -2
- package/dist/{chunk-OLZBZAW4.js → chunk-LJ5E4GXC.js} +2 -2
- package/dist/{chunk-SRFNNOLC.js → chunk-LNA6M2IE.js} +2 -2
- package/dist/{chunk-GUIRWCKI.js → chunk-M4P5YJ45.js} +3 -3
- package/dist/{chunk-3S4GIO4B.js → chunk-MVEYK55V.js} +2 -2
- package/dist/{chunk-HKRLWERR.js → chunk-N5OCAAXY.js} +2 -2
- package/dist/{chunk-YRVTXSXP.js → chunk-NRCKIHND.js} +9 -15
- package/dist/chunk-NRCKIHND.js.map +1 -0
- package/dist/{chunk-DAVOSI4M.js → chunk-OEJDFGAF.js} +5 -5
- package/dist/{chunk-ENWMWIHP.js → chunk-QR2TM4OY.js} +5 -12
- package/dist/chunk-QR2TM4OY.js.map +1 -0
- package/dist/{chunk-FYNMNY4P.js → chunk-SPSGZWTZ.js} +25 -12
- package/dist/chunk-SPSGZWTZ.js.map +1 -0
- package/dist/{chunk-3JRWNWBF.js → chunk-TBB3THSL.js} +38 -4
- package/dist/chunk-TBB3THSL.js.map +1 -0
- package/dist/chunk-TWDVLTU6.js +132 -0
- package/dist/chunk-TWDVLTU6.js.map +1 -0
- package/dist/{chunk-KCYNTAAF.js → chunk-VAQJLHUW.js} +12 -10
- package/dist/chunk-VAQJLHUW.js.map +1 -0
- package/dist/{chunk-F3O5YHSI.js → chunk-VSZ5GDET.js} +2 -2
- package/dist/{chunk-Q5BSIARS.js → chunk-XTRPYUWK.js} +15 -15
- package/dist/chunk-XTRPYUWK.js.map +1 -0
- package/dist/{chunk-WWSKP5SR.js → chunk-YTRFL3MR.js} +70 -24
- package/dist/chunk-YTRFL3MR.js.map +1 -0
- package/dist/{chunk-NTPHCNJO.js → chunk-ZWAL2ZY7.js} +2 -2
- package/dist/commands/build/marketplace.js +12 -126
- package/dist/commands/build/marketplace.js.map +1 -1
- package/dist/commands/build/plugins.js +5 -5
- package/dist/commands/build/stack.js +5 -5
- package/dist/commands/compile.js +6 -6
- package/dist/commands/config/get.js +4 -4
- package/dist/commands/config/index.js +5 -5
- package/dist/commands/config/path.js +4 -4
- package/dist/commands/config/set-project.js +4 -4
- package/dist/commands/config/show.js +5 -5
- package/dist/commands/config/unset-project.js +4 -4
- package/dist/commands/diff.js +4 -4
- package/dist/commands/doctor.js +4 -4
- package/dist/commands/edit.js +29 -29
- package/dist/commands/eject.js +19 -23
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/import/skill.js +5 -5
- package/dist/commands/info.js +5 -5
- package/dist/commands/init.js +30 -29
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/list.js +4 -4
- package/dist/commands/new/agent.js +52 -38
- package/dist/commands/new/agent.js.map +1 -1
- package/dist/commands/new/marketplace.js +252 -0
- package/dist/commands/new/marketplace.js.map +1 -0
- package/dist/commands/new/skill.js +35 -16
- package/dist/commands/new/skill.js.map +1 -1
- package/dist/commands/outdated.js +4 -4
- package/dist/commands/search.js +7 -7
- package/dist/commands/uninstall.js +6 -6
- package/dist/commands/update.js +6 -6
- package/dist/commands/validate.js +229 -19
- package/dist/commands/validate.js.map +1 -1
- package/dist/components/skill-search/skill-search.js +3 -3
- package/dist/components/wizard/category-grid.js +2 -2
- package/dist/components/wizard/category-grid.test.js +122 -2
- package/dist/components/wizard/category-grid.test.js.map +1 -1
- package/dist/components/wizard/checkbox-grid.js +3 -3
- package/dist/components/wizard/checkbox-grid.test.js +3 -3
- package/dist/components/wizard/domain-selection.js +9 -8
- package/dist/components/wizard/help-modal.js +2 -2
- package/dist/components/wizard/menu-item.js +1 -1
- package/dist/components/wizard/search-modal.js +2 -2
- package/dist/components/wizard/search-modal.test.js +2 -2
- package/dist/components/wizard/section-progress.js +2 -2
- package/dist/components/wizard/section-progress.test.js +2 -2
- package/dist/components/wizard/selection-card.js +2 -2
- package/dist/components/wizard/source-grid.js +3 -3
- package/dist/components/wizard/source-grid.test.js +3 -3
- package/dist/components/wizard/stack-selection.js +8 -9
- package/dist/components/wizard/step-agents.js +8 -7
- package/dist/components/wizard/step-agents.test.js +25 -20
- package/dist/components/wizard/step-agents.test.js.map +1 -1
- package/dist/components/wizard/step-build.js +8 -8
- package/dist/components/wizard/step-build.test.js +78 -46
- package/dist/components/wizard/step-build.test.js.map +1 -1
- package/dist/components/wizard/step-confirm.js +4 -4
- package/dist/components/wizard/step-confirm.test.js +8 -8
- package/dist/components/wizard/step-refine.js +2 -2
- package/dist/components/wizard/step-refine.test.js +2 -2
- package/dist/components/wizard/step-settings.js +5 -5
- package/dist/components/wizard/step-settings.test.js +8 -8
- package/dist/components/wizard/step-sources.js +10 -10
- package/dist/components/wizard/step-sources.test.js +11 -11
- package/dist/components/wizard/step-stack.js +12 -12
- package/dist/components/wizard/step-stack.test.js +27 -15
- package/dist/components/wizard/step-stack.test.js.map +1 -1
- package/dist/components/wizard/view-title.js +2 -2
- package/dist/components/wizard/wizard-layout.js +8 -8
- package/dist/components/wizard/wizard-tabs.js +2 -2
- package/dist/components/wizard/wizard-tabs.test.js +2 -2
- package/dist/components/wizard/wizard.js +25 -25
- package/dist/hooks/init.js +3 -5
- package/dist/hooks/init.js.map +1 -1
- package/dist/{source-manager-HXFXBZJU.js → source-manager-Q34LTUVM.js} +4 -4
- package/dist/src/agents/meta/documentor/examples.md +35 -36
- package/dist/src/agents/meta/documentor/workflow.md +91 -105
- package/dist/stores/wizard-store.js +5 -5
- package/dist/stores/wizard-store.test.js +48 -6
- package/dist/stores/wizard-store.test.js.map +1 -1
- package/package.json +1 -1
- package/src/agents/meta/documentor/examples.md +35 -36
- package/src/agents/meta/documentor/workflow.md +91 -105
- package/src/schemas/agent.schema.json +6 -0
- package/src/schemas/metadata.schema.json +7 -41
- package/src/schemas/project-config.schema.json +8 -4
- package/src/schemas/skills-matrix.schema.json +11 -298
- package/src/schemas/stacks.schema.json +2 -4
- package/dist/chunk-3JRWNWBF.js.map +0 -1
- package/dist/chunk-473YHDYQ.js.map +0 -1
- package/dist/chunk-5BDYODWP.js +0 -45
- package/dist/chunk-5BDYODWP.js.map +0 -1
- package/dist/chunk-ABE55TEU.js.map +0 -1
- package/dist/chunk-ENWMWIHP.js.map +0 -1
- package/dist/chunk-FVN5PFFY.js.map +0 -1
- package/dist/chunk-FYNMNY4P.js.map +0 -1
- package/dist/chunk-KCYNTAAF.js.map +0 -1
- package/dist/chunk-KZNPPUQG.js.map +0 -1
- package/dist/chunk-Q5BSIARS.js.map +0 -1
- package/dist/chunk-WWSKP5SR.js.map +0 -1
- package/dist/chunk-YRVTXSXP.js.map +0 -1
- package/dist/chunk-ZECXM7LP.js.map +0 -1
- package/dist/cli/defaults/agent-mappings.yaml +0 -215
- /package/dist/{chunk-V43QDMYQ.js.map → chunk-2RQYJFKA.js.map} +0 -0
- /package/dist/{chunk-KWWLPPHF.js.map → chunk-B4QYXVPZ.js.map} +0 -0
- /package/dist/{chunk-CLHBKFHU.js.map → chunk-CJFWO46A.js.map} +0 -0
- /package/dist/{chunk-M2XPTQDT.js.map → chunk-DC333ZDC.js.map} +0 -0
- /package/dist/{chunk-M3AGB4TR.js.map → chunk-DVW6ASTO.js.map} +0 -0
- /package/dist/{chunk-ARET3NYO.js.map → chunk-EZ46ZTAQ.js.map} +0 -0
- /package/dist/{chunk-YQFU2KZ5.js.map → chunk-FXQYEXLS.js.map} +0 -0
- /package/dist/{chunk-KVHLKPYB.js.map → chunk-HPJP3HFD.js.map} +0 -0
- /package/dist/{chunk-SBWMSNS2.js.map → chunk-IRJADQM7.js.map} +0 -0
- /package/dist/{chunk-SYGEV3KV.js.map → chunk-JTTTXGHX.js.map} +0 -0
- /package/dist/{chunk-ELRGSZHZ.js.map → chunk-JZHIF3K7.js.map} +0 -0
- /package/dist/{chunk-OALQWRLG.js.map → chunk-KQ27IDYL.js.map} +0 -0
- /package/dist/{chunk-OLZBZAW4.js.map → chunk-LJ5E4GXC.js.map} +0 -0
- /package/dist/{chunk-SRFNNOLC.js.map → chunk-LNA6M2IE.js.map} +0 -0
- /package/dist/{chunk-GUIRWCKI.js.map → chunk-M4P5YJ45.js.map} +0 -0
- /package/dist/{chunk-3S4GIO4B.js.map → chunk-MVEYK55V.js.map} +0 -0
- /package/dist/{chunk-HKRLWERR.js.map → chunk-N5OCAAXY.js.map} +0 -0
- /package/dist/{chunk-DAVOSI4M.js.map → chunk-OEJDFGAF.js.map} +0 -0
- /package/dist/{chunk-F3O5YHSI.js.map → chunk-VSZ5GDET.js.map} +0 -0
- /package/dist/{chunk-NTPHCNJO.js.map → chunk-ZWAL2ZY7.js.map} +0 -0
- /package/dist/{source-manager-HXFXBZJU.js.map → source-manager-Q34LTUVM.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
+
## [0.47.0] - 2026-02-25
|
|
13
|
+
|
|
14
|
+
**Custom domain support, source validation, wizard improvements, dead code cleanup**
|
|
15
|
+
|
|
16
|
+
- Domain field on skill metadata and agent YAML for custom marketplace support
|
|
17
|
+
- `validate --source` command for source repository validation
|
|
18
|
+
- Fix custom skill ID rejection in stacks validation
|
|
19
|
+
- Remove redundant verifyHash and legacy slash-in-skill-ID code
|
|
20
|
+
|
|
21
|
+
See [changelogs/0.47.0.md](./changelogs/0.47.0.md) for full details.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## [0.46.0] - 2026-02-24
|
|
26
|
+
|
|
27
|
+
**Custom extensibility, new commands, agent-mapping removal, wizard improvements**
|
|
28
|
+
|
|
29
|
+
- Custom extensibility foundation: runtime-extensible schemas for custom skills, agents, categories, and domains from private marketplaces
|
|
30
|
+
- Remove agent-mappings.yaml and skill-to-agent routing — all skills assigned to all selected agents
|
|
31
|
+
- Promote `eject templates` to first-class type, add `new marketplace` command, improve `new skill` and `new agent`
|
|
32
|
+
- Dynamic wizard domains/agents from merged matrix, fix stack domain preselection
|
|
33
|
+
- Fix plugin mode marketplace registration (strip `github:` prefix)
|
|
34
|
+
|
|
35
|
+
See [changelogs/0.46.0.md](./changelogs/0.46.0.md) for full details.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
12
39
|
## [0.45.0] - 2026-02-22
|
|
13
40
|
|
|
14
41
|
**Persist agent selection, skill relation validation, eject fix, test fixtures**
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
CLI_BIN_NAME,
|
|
4
4
|
DEFAULT_BRANDING
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-FTD5Z6QD.js";
|
|
6
6
|
import {
|
|
7
7
|
init_esm_shims
|
|
8
8
|
} from "./chunk-DHET7RCE.js";
|
|
@@ -67,4 +67,4 @@ export {
|
|
|
67
67
|
INFO_MESSAGES,
|
|
68
68
|
DRY_RUN_MESSAGES
|
|
69
69
|
};
|
|
70
|
-
//# sourceMappingURL=chunk-
|
|
70
|
+
//# sourceMappingURL=chunk-2RQYJFKA.js.map
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
CLI_COLORS,
|
|
7
7
|
SCROLL_VIEWPORT
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-FTD5Z6QD.js";
|
|
9
9
|
import {
|
|
10
10
|
init_esm_shims
|
|
11
11
|
} from "./chunk-DHET7RCE.js";
|
|
@@ -209,14 +209,21 @@ var CategorySection = ({
|
|
|
209
209
|
isLocked,
|
|
210
210
|
isFocused,
|
|
211
211
|
focusedOptionIndex,
|
|
212
|
-
showLabels
|
|
212
|
+
showLabels,
|
|
213
|
+
expertMode
|
|
213
214
|
}) => {
|
|
215
|
+
const selectedCount = options.filter((o) => o.selected).length;
|
|
216
|
+
const selectionCounter = expertMode ? null : category.exclusive ? `(${selectedCount} of 1)` : `(${selectedCount} selected)`;
|
|
214
217
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: isFirst ? 0 : 1, children: [
|
|
215
218
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
|
|
216
219
|
/* @__PURE__ */ jsx(Text, { dimColor: isLocked, color: isFocused ? "#fff" : "gray", children: category.displayName }),
|
|
217
220
|
category.required && /* @__PURE__ */ jsxs(Text, { color: isLocked ? CLI_COLORS.NEUTRAL : CLI_COLORS.ERROR, dimColor: isLocked, children: [
|
|
218
221
|
" ",
|
|
219
222
|
SYMBOL_REQUIRED
|
|
223
|
+
] }),
|
|
224
|
+
selectionCounter && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
225
|
+
" ",
|
|
226
|
+
selectionCounter
|
|
220
227
|
] })
|
|
221
228
|
] }),
|
|
222
229
|
/* @__PURE__ */ jsx(Box, { flexDirection: "row", flexWrap: "wrap", marginTop: 0, children: options.map((option, index) => /* @__PURE__ */ jsx(
|
|
@@ -360,6 +367,7 @@ var CategoryGrid = ({
|
|
|
360
367
|
isFocused: index === focusedRow,
|
|
361
368
|
focusedOptionIndex: focusedCol,
|
|
362
369
|
showLabels,
|
|
370
|
+
expertMode,
|
|
363
371
|
isFirst: index === 0
|
|
364
372
|
}
|
|
365
373
|
) }, category.id);
|
|
@@ -373,4 +381,4 @@ var CategoryGrid = ({
|
|
|
373
381
|
export {
|
|
374
382
|
CategoryGrid
|
|
375
383
|
};
|
|
376
|
-
//# sourceMappingURL=chunk-
|
|
384
|
+
//# sourceMappingURL=chunk-3APMMQUA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/components/wizard/category-grid.tsx","../src/cli/components/hooks/use-category-grid-input.ts"],"sourcesContent":["import React, { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { Box, type DOMElement, Text, measureElement } from \"ink\";\n\nimport { CLI_COLORS, SCROLL_VIEWPORT } from \"../../consts.js\";\nimport type { SkillId, Subcategory } from \"../../types/index.js\";\nimport { isSectionLocked, useCategoryGridInput } from \"../hooks/use-category-grid-input.js\";\nimport { useFocusedListItem } from \"../hooks/use-focused-list-item.js\";\n\nexport type OptionState = \"normal\" | \"recommended\" | \"discouraged\" | \"disabled\";\n\nexport type CategoryOption = {\n id: SkillId;\n label: string;\n state: OptionState;\n stateReason?: string;\n selected: boolean;\n local?: boolean;\n installed?: boolean;\n};\n\nexport type CategoryRow = {\n id: Subcategory;\n displayName: string;\n required: boolean;\n exclusive: boolean;\n options: CategoryOption[];\n};\n\nexport type CategoryGridProps = {\n categories: CategoryRow[];\n /** Available height in terminal lines for the scrollable viewport. 0 = no constraint. */\n availableHeight?: number;\n showLabels: boolean;\n expertMode: boolean;\n onToggle: (categoryId: Subcategory, technologyId: SkillId) => void;\n onToggleLabels: () => 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\nconst SYMBOL_REQUIRED = \"*\";\n\n/**\n * Priority order for skill states in the initial sort.\n * Lower numbers appear first. Selected skills are sorted above all states.\n */\nconst STATE_PRIORITY: Record<OptionState, number> = {\n recommended: 0,\n normal: 1,\n discouraged: 2,\n disabled: 3,\n};\n\n/**\n * Sort options by: selected first, then by state priority.\n * Within each group, original matrix order is preserved (stable sort).\n */\nconst stableSortByState = (options: CategoryOption[]): CategoryOption[] => {\n return [...options].sort((a, b) => {\n if (a.selected !== b.selected) return a.selected ? -1 : 1;\n return STATE_PRIORITY[a.state] - STATE_PRIORITY[b.state];\n });\n};\n\nconst findNextValidOption = (\n options: CategoryOption[],\n currentIndex: number,\n direction: 1 | -1,\n wrap = true,\n): number => {\n const length = options.length;\n if (length === 0) return currentIndex;\n\n let index = currentIndex + direction;\n\n if (wrap) {\n if (index < 0) index = length - 1;\n if (index >= length) index = 0;\n } else {\n if (index < 0) index = 0;\n if (index >= length) index = length - 1;\n }\n\n return index;\n};\n\ntype SkillTagProps = {\n option: CategoryOption;\n isFocused: boolean;\n isLocked: boolean;\n showLabels: boolean;\n};\n\nconst getCompatibilityLabel = (option: CategoryOption, isLocked: boolean): string | null => {\n if (option.selected) return \"(selected)\";\n if (isLocked || option.state === \"disabled\") return \"(disabled)\";\n if (option.state === \"recommended\") return \"(recommended)\";\n if (option.state === \"discouraged\") return \"(discouraged)\";\n return null;\n};\n\nconst SkillTag: React.FC<SkillTagProps> = ({ option, isFocused, isLocked, showLabels }) => {\n const getTextColor = (): string => {\n if (option.state === \"disabled\" && option.selected) return CLI_COLORS.PRIMARY;\n if (isLocked || option.state === \"disabled\") return CLI_COLORS.NEUTRAL;\n if (option.selected) return CLI_COLORS.PRIMARY;\n if (option.state === \"recommended\") return CLI_COLORS.UNFOCUSED;\n if (option.state === \"discouraged\") return CLI_COLORS.WARNING;\n\n return CLI_COLORS.NEUTRAL;\n };\n\n const getStateBorderColor = (): string => {\n if (option.state === \"disabled\" && option.selected) return CLI_COLORS.PRIMARY;\n if (isLocked || option.state === \"disabled\") return CLI_COLORS.NEUTRAL;\n if (option.selected) return CLI_COLORS.PRIMARY;\n if (option.state === \"recommended\") return CLI_COLORS.UNFOCUSED;\n if (option.state === \"discouraged\") return CLI_COLORS.WARNING;\n return CLI_COLORS.UNFOCUSED;\n };\n\n const textColor = getTextColor();\n const compatibilityLabel = showLabels ? getCompatibilityLabel(option, isLocked) : null;\n\n return (\n <Box\n marginRight={1}\n borderColor={isFocused ? getStateBorderColor() : CLI_COLORS.NEUTRAL}\n borderStyle=\"single\"\n flexShrink={0}\n >\n <>\n <Text color={textColor} bold dimColor={option.state === \"disabled\" && option.selected}>\n {\" \"}\n {option.label}{\" \"}\n </Text>\n {compatibilityLabel && <Text dimColor>{compatibilityLabel} </Text>}\n </>\n </Box>\n );\n};\n\ntype CategorySectionProps = {\n isFirst: boolean;\n category: CategoryRow;\n options: CategoryOption[];\n isLocked: boolean;\n isFocused: boolean;\n focusedOptionIndex: number;\n showLabels: boolean;\n expertMode: boolean;\n};\n\nconst CategorySection: React.FC<CategorySectionProps> = ({\n isFirst,\n category,\n options,\n isLocked,\n isFocused,\n focusedOptionIndex,\n showLabels,\n expertMode,\n}) => {\n const selectedCount = options.filter((o) => o.selected).length;\n\n const selectionCounter = expertMode\n ? null\n : category.exclusive\n ? `(${selectedCount} of 1)`\n : `(${selectedCount} selected)`;\n\n return (\n <Box flexDirection=\"column\" marginTop={isFirst ? 0 : 1}>\n <Box flexDirection=\"row\">\n <Text dimColor={isLocked} color={isFocused ? \"#fff\" : \"gray\"}>\n {category.displayName}\n </Text>\n {category.required && (\n <Text color={isLocked ? CLI_COLORS.NEUTRAL : CLI_COLORS.ERROR} dimColor={isLocked}>\n {\" \"}\n {SYMBOL_REQUIRED}\n </Text>\n )}\n {selectionCounter && <Text dimColor> {selectionCounter}</Text>}\n </Box>\n\n <Box flexDirection=\"row\" flexWrap=\"wrap\" marginTop={0}>\n {options.map((option, index) => (\n <SkillTag\n key={option.id}\n option={option}\n isFocused={isFocused && index === focusedOptionIndex && !isLocked}\n isLocked={isLocked}\n showLabels={showLabels}\n />\n ))}\n </Box>\n </Box>\n );\n};\n\ntype ProcessedCategory = CategoryRow & { sortedOptions: CategoryOption[] };\n\nexport const CategoryGrid: React.FC<CategoryGridProps> = ({\n categories,\n availableHeight = 0,\n showLabels,\n expertMode,\n onToggle,\n onToggleLabels,\n defaultFocusedRow = 0,\n defaultFocusedCol = 0,\n onFocusChange,\n}) => {\n // Cache the initial sort order per category so toggling selections does not reorder skills.\n // The ref resets when the component remounts (e.g., domain change via key={activeDomain}).\n const initialOrderRef = useRef<Map<string, SkillId[]>>(new Map());\n\n const processedCategories = useMemo(\n () =>\n categories.map((category) => {\n const cached = initialOrderRef.current.get(category.id);\n if (cached) {\n const orderMap = new Map(cached.map((id, idx) => [id, idx]));\n const sorted = [...category.options].sort((a, b) => {\n const aIdx = orderMap.get(a.id) ?? Infinity;\n const bIdx = orderMap.get(b.id) ?? Infinity;\n return aIdx - bIdx;\n });\n return { ...category, sortedOptions: sorted };\n }\n const sorted = stableSortByState(category.options);\n initialOrderRef.current.set(\n category.id,\n sorted.map((o) => o.id),\n );\n return { ...category, sortedOptions: sorted };\n }),\n [categories],\n );\n\n const getColCount = useCallback(\n (row: number): number => processedCategories[row]?.sortedOptions.length ?? 0,\n [processedCategories],\n );\n\n const isRowLocked = useCallback(\n (row: number): boolean => {\n const cat = processedCategories[row];\n return cat ? isSectionLocked(cat.id, categories) : false;\n },\n [processedCategories, categories],\n );\n\n const findValidCol = useCallback(\n (row: number, currentCol: number, direction: 1 | -1): number => {\n const options = processedCategories[row]?.sortedOptions || [];\n const catId = processedCategories[row]?.id;\n if (catId && isSectionLocked(catId, categories)) return currentCol;\n return findNextValidOption(options, currentCol, direction, true);\n },\n [processedCategories, categories],\n );\n\n const { focusedRow, focusedCol, setFocused, moveFocus } = useFocusedListItem(\n processedCategories.length,\n getColCount,\n {\n wrap: true,\n isRowLocked,\n findValidCol,\n onChange: onFocusChange,\n initialRow: defaultFocusedRow,\n initialCol: defaultFocusedCol,\n },\n );\n\n useCategoryGridInput({\n processedCategories,\n categories,\n focusedRow,\n focusedCol,\n setFocused,\n moveFocus,\n onToggle,\n onToggleLabels,\n });\n\n const sectionRefs = useRef<(DOMElement | null)[]>([]);\n const [sectionHeights, setSectionHeights] = useState<number[]>([]);\n const [scrollTopPx, setScrollTopPx] = useState(0);\n\n const setSectionRef = useCallback((index: number, el: DOMElement | null) => {\n sectionRefs.current[index] = el;\n }, []);\n\n useEffect(() => {\n const heights = sectionRefs.current.map((el) => {\n if (el) {\n const { height } = measureElement(el);\n return height;\n }\n return 0;\n });\n setSectionHeights((prev) => {\n if (prev.length === heights.length && prev.every((h, i) => h === heights[i])) {\n return prev;\n }\n return heights;\n });\n });\n\n const scrollEnabled = availableHeight > 0 && availableHeight >= SCROLL_VIEWPORT.MIN_VIEWPORT_ROWS;\n\n useEffect(() => {\n if (!scrollEnabled || sectionHeights.length === 0) return;\n\n let topOfFocused = 0;\n for (let i = 0; i < focusedRow; i++) {\n topOfFocused += sectionHeights[i] ?? 0;\n }\n const focusedHeight = sectionHeights[focusedRow] ?? 0;\n const bottomOfFocused = topOfFocused + focusedHeight;\n\n setScrollTopPx((prev) => {\n if (topOfFocused < prev) {\n return topOfFocused;\n }\n if (bottomOfFocused > prev + availableHeight) {\n return bottomOfFocused - availableHeight;\n }\n return prev;\n });\n }, [focusedRow, sectionHeights, scrollEnabled, availableHeight]);\n\n if (categories.length === 0) {\n return (\n <Box flexDirection=\"column\">\n <Text dimColor>No categories to display.</Text>\n </Box>\n );\n }\n\n const sectionElements = processedCategories.map((category, index) => {\n const isLocked = isSectionLocked(category.id, categories);\n\n return (\n <Box key={category.id} ref={(el) => setSectionRef(index, el)} flexShrink={0}>\n <CategorySection\n category={category}\n options={category.sortedOptions}\n isLocked={isLocked}\n isFocused={index === focusedRow}\n focusedOptionIndex={focusedCol}\n showLabels={showLabels}\n expertMode={expertMode}\n isFirst={index === 0}\n />\n </Box>\n );\n });\n\n // When no height constraint, render flat (tests, or before first measurement)\n if (!scrollEnabled) {\n return (\n <Box flexDirection=\"column\" flexGrow={1} overflow=\"hidden\">\n {sectionElements}\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" height={availableHeight} overflow=\"hidden\">\n <Box flexDirection=\"column\" marginTop={scrollTopPx > 0 ? -scrollTopPx : 0} flexShrink={0}>\n {sectionElements}\n </Box>\n </Box>\n );\n};\n","import { useCallback, useEffect, useRef } from \"react\";\nimport { useInput } from \"ink\";\n\nimport type { Subcategory, SkillId } from \"../../types/index.js\";\nimport type { CategoryOption, CategoryRow } from \"../wizard/category-grid.js\";\n\nconst FRAMEWORK_CATEGORY_ID = \"web-framework\";\n\n// Locked = non-framework section when no framework is selected\nexport const isSectionLocked = (categoryId: Subcategory, categories: CategoryRow[]): boolean => {\n if (categoryId === FRAMEWORK_CATEGORY_ID) {\n return false;\n }\n\n const frameworkCategory = categories.find((cat) => cat.id === FRAMEWORK_CATEGORY_ID);\n if (!frameworkCategory) return false;\n\n return !frameworkCategory.options.some((opt) => opt.selected);\n};\n\nexport const findValidStartColumn = (_options: CategoryOption[]): number => {\n return 0;\n};\n\n/** Find next unlocked section index (wrapping, direction: forward) */\nexport const findNextUnlockedIndex = (\n processed: { id: Subcategory; sortedOptions: CategoryOption[] }[],\n currentIndex: number,\n allCategories: CategoryRow[],\n): number => {\n const length = processed.length;\n if (length === 0) return currentIndex;\n\n let index = currentIndex;\n let attempts = 0;\n\n while (attempts < length) {\n index += 1;\n if (index >= length) index = 0;\n\n const category = processed[index];\n if (category && !isSectionLocked(category.id, allCategories)) {\n return index;\n }\n\n attempts++;\n }\n\n return currentIndex;\n};\n\ntype ProcessedCategory = CategoryRow & { sortedOptions: CategoryOption[] };\n\ntype UseCategoryGridInputOptions = {\n processedCategories: ProcessedCategory[];\n categories: CategoryRow[];\n focusedRow: number;\n focusedCol: number;\n setFocused: (row: number, col: number) => void;\n moveFocus: (direction: \"up\" | \"down\" | \"left\" | \"right\") => void;\n onToggle: (categoryId: Subcategory, technologyId: SkillId) => void;\n onToggleLabels: () => void;\n};\n\nexport function useCategoryGridInput({\n processedCategories,\n categories,\n focusedRow,\n focusedCol,\n setFocused,\n moveFocus,\n onToggle,\n onToggleLabels,\n}: UseCategoryGridInputOptions): void {\n const currentRow = processedCategories[focusedRow];\n const currentOptions = currentRow?.sortedOptions || [];\n const currentLocked = currentRow ? isSectionLocked(currentRow.id, categories) : false;\n\n // Adjust column when current row's options change externally (e.g. option becomes disabled)\n useEffect(() => {\n if (!currentRow) return;\n\n const maxCol = currentOptions.length - 1;\n if (focusedCol > maxCol) {\n const newCol = Math.max(0, maxCol);\n setFocused(focusedRow, newCol);\n }\n }, [focusedRow, currentOptions, focusedCol, setFocused, currentRow]);\n\n // Bounce off locked sections when a section becomes locked (e.g. framework deselected)\n useEffect(() => {\n if (currentRow && currentLocked) {\n const nextUnlocked = findNextUnlockedIndex(processedCategories, focusedRow, categories);\n if (nextUnlocked !== focusedRow) {\n const newRowOptions = processedCategories[nextUnlocked]?.sortedOptions || [];\n const newCol = findValidStartColumn(newRowOptions);\n setFocused(nextUnlocked, newCol);\n }\n }\n }, [currentRow, currentLocked, focusedRow, processedCategories, categories, setFocused]);\n\n // Store the latest handler in a ref so that the useInput effect never needs to\n // re-register on the event emitter. This avoids a stale-closure race condition\n // where, after a domain switch (CategoryGrid remount via key={activeDomain}),\n // the useInput effect may not yet have re-registered the updated handler when\n // the first keypress arrives — causing the first space press to be silently lost.\n type InputKey = {\n leftArrow: boolean;\n rightArrow: boolean;\n upArrow: boolean;\n downArrow: boolean;\n tab: boolean;\n shift: boolean;\n };\n\n const handlerRef = useRef<((input: string, key: InputKey) => void) | null>(null);\n handlerRef.current = (input: string, key: InputKey) => {\n if (key.tab && key.shift) {\n onToggleLabels();\n return;\n }\n\n if (key.tab && !key.shift) {\n const nextSection = findNextUnlockedIndex(processedCategories, focusedRow, categories);\n if (nextSection !== focusedRow) {\n const newRowOptions = processedCategories[nextSection]?.sortedOptions || [];\n const newCol = findValidStartColumn(newRowOptions);\n setFocused(nextSection, newCol);\n }\n return;\n }\n\n if (input === \"d\" || input === \"D\") {\n onToggleLabels();\n return;\n }\n\n if (input === \" \") {\n if (currentLocked) return;\n const currentOption = currentOptions[focusedCol];\n if (currentOption && currentOption.state !== \"disabled\") {\n onToggle(currentRow.id, currentOption.id);\n }\n return;\n }\n\n const isLeft = key.leftArrow || input === \"h\";\n const isRight = key.rightArrow || input === \"l\";\n const isUp = key.upArrow || input === \"k\";\n const isDown = key.downArrow || input === \"j\";\n\n if (isLeft) {\n if (currentLocked) return;\n moveFocus(\"left\");\n } else if (isRight) {\n if (currentLocked) return;\n moveFocus(\"right\");\n } else if (isUp) {\n moveFocus(\"up\");\n } else if (isDown) {\n moveFocus(\"down\");\n }\n };\n\n // Stable handler reference — never changes, so useInput's effect registers once\n const stableHandler = useCallback((input: string, key: InputKey) => {\n handlerRef.current?.(input, key);\n }, []);\n\n useInput(stableHandler);\n}\n"],"mappings":"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","names":["useCallback","useEffect","useRef","useRef","sorted","useCallback","useEffect"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
CLI_COLORS
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-FTD5Z6QD.js";
|
|
5
5
|
import {
|
|
6
6
|
init_esm_shims
|
|
7
7
|
} from "./chunk-DHET7RCE.js";
|
|
@@ -17,4 +17,4 @@ var ViewTitle = ({ children }) => {
|
|
|
17
17
|
export {
|
|
18
18
|
ViewTitle
|
|
19
19
|
};
|
|
20
|
-
//# sourceMappingURL=chunk-
|
|
20
|
+
//# sourceMappingURL=chunk-B4QYXVPZ.js.map
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
KEBAB_CASE_PATTERN
|
|
4
|
+
} from "./chunk-FTD5Z6QD.js";
|
|
2
5
|
import {
|
|
3
6
|
init_esm_shims
|
|
4
7
|
} from "./chunk-DHET7RCE.js";
|
|
@@ -90,7 +93,14 @@ async function copy(src, dest) {
|
|
|
90
93
|
// src/cli/lib/schemas.ts
|
|
91
94
|
init_esm_shims();
|
|
92
95
|
import { z } from "zod";
|
|
93
|
-
var
|
|
96
|
+
var customExtensions = {
|
|
97
|
+
categories: /* @__PURE__ */ new Set(),
|
|
98
|
+
domains: /* @__PURE__ */ new Set(),
|
|
99
|
+
agentNames: /* @__PURE__ */ new Set(),
|
|
100
|
+
skillIds: /* @__PURE__ */ new Set()
|
|
101
|
+
};
|
|
102
|
+
var DOMAIN_VALUES = ["web", "api", "cli", "mobile", "shared"];
|
|
103
|
+
var domainSchema = z.enum(DOMAIN_VALUES);
|
|
94
104
|
var skillSourceTypeSchema = z.enum([
|
|
95
105
|
"public",
|
|
96
106
|
"private",
|
|
@@ -144,7 +154,6 @@ var SUBCATEGORY_VALUES = [
|
|
|
144
154
|
"cli-testing"
|
|
145
155
|
];
|
|
146
156
|
var subcategorySchema = z.enum(SUBCATEGORY_VALUES);
|
|
147
|
-
var stackSubcategorySchema = z.enum(SUBCATEGORY_VALUES);
|
|
148
157
|
var agentNameSchema = z.enum([
|
|
149
158
|
"web-developer",
|
|
150
159
|
"api-developer",
|
|
@@ -264,15 +273,67 @@ var skillDisplayNameSchema = z.enum([
|
|
|
264
273
|
"context-management"
|
|
265
274
|
]);
|
|
266
275
|
var SKILL_ID_PATTERN = /^(web|api|cli|mobile|infra|meta|security)-.+-.+$/;
|
|
276
|
+
function isValidSkillId(id) {
|
|
277
|
+
return SKILL_ID_PATTERN.test(id) || customExtensions.skillIds.has(id);
|
|
278
|
+
}
|
|
267
279
|
var skillIdSchema = z.string().regex(
|
|
268
280
|
SKILL_ID_PATTERN,
|
|
269
281
|
"Must be a valid skill ID (e.g., 'web-framework-react')"
|
|
270
282
|
);
|
|
283
|
+
var extensibleDomainSchema = z.string().refine(
|
|
284
|
+
(val) => domainSchema.safeParse(val).success || customExtensions.domains.has(val),
|
|
285
|
+
{ message: "Must be a valid domain" }
|
|
286
|
+
);
|
|
287
|
+
var extensibleSkillIdSchema = z.string().refine(
|
|
288
|
+
(val) => skillIdSchema.safeParse(val).success || customExtensions.skillIds.has(val),
|
|
289
|
+
{ message: "Must be a valid skill ID" }
|
|
290
|
+
);
|
|
291
|
+
var extensibleSubcategorySchema = z.string().refine(
|
|
292
|
+
(val) => subcategorySchema.safeParse(val).success || customExtensions.categories.has(val),
|
|
293
|
+
{ message: "Must be a valid subcategory" }
|
|
294
|
+
);
|
|
295
|
+
var extensibleAgentNameSchema = z.string().refine(
|
|
296
|
+
(val) => agentNameSchema.safeParse(val).success || customExtensions.agentNames.has(val),
|
|
297
|
+
{ message: "Must be a valid agent name" }
|
|
298
|
+
);
|
|
299
|
+
function validateCategoryField(val, ctx) {
|
|
300
|
+
if (!val.category) return;
|
|
301
|
+
if (val.custom) {
|
|
302
|
+
if (!KEBAB_CASE_PATTERN.test(val.category)) {
|
|
303
|
+
ctx.addIssue({
|
|
304
|
+
code: "custom",
|
|
305
|
+
path: ["category"],
|
|
306
|
+
message: "Custom category must be kebab-case"
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
const result = categoryPathSchema.safeParse(val.category);
|
|
312
|
+
if (!result.success) {
|
|
313
|
+
for (const issue of result.error.issues) {
|
|
314
|
+
ctx.addIssue({ ...issue, path: ["category"] });
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
function validateExtensibleRecordKeys(builtinSet, extensionSet, label) {
|
|
319
|
+
return (val, ctx) => {
|
|
320
|
+
for (const key of Object.keys(val)) {
|
|
321
|
+
if (!builtinSet.has(key) && !extensionSet.has(key)) {
|
|
322
|
+
ctx.addIssue({
|
|
323
|
+
code: "custom",
|
|
324
|
+
path: [key],
|
|
325
|
+
message: `Invalid ${label} '${key}'.`
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
}
|
|
271
331
|
var categoryPathSchema = z.string().refine(
|
|
272
332
|
(val) => {
|
|
273
333
|
if (val === "local") return true;
|
|
274
334
|
if (/^(web|api|cli|mobile|infra|meta|security|shared)-.+$/.test(val)) return true;
|
|
275
|
-
|
|
335
|
+
if (subcategorySchema.safeParse(val).success) return true;
|
|
336
|
+
return customExtensions.categories.has(val);
|
|
276
337
|
},
|
|
277
338
|
{
|
|
278
339
|
message: "Must be a valid category path (e.g., 'web-framework', 'shared-testing', or 'local')"
|
|
@@ -298,7 +359,7 @@ var strictHooksRecordSchema = z.record(
|
|
|
298
359
|
z.array(strictAgentHookDefinitionSchema)
|
|
299
360
|
);
|
|
300
361
|
var skillAssignmentSchema = z.object({
|
|
301
|
-
id:
|
|
362
|
+
id: extensibleSkillIdSchema,
|
|
302
363
|
preloaded: z.boolean().optional(),
|
|
303
364
|
local: z.boolean().optional(),
|
|
304
365
|
path: z.string().optional()
|
|
@@ -309,14 +370,17 @@ var skillFrontmatterLoaderSchema = z.object({
|
|
|
309
370
|
model: modelNameSchema.optional()
|
|
310
371
|
});
|
|
311
372
|
var skillMetadataLoaderSchema = z.object({
|
|
312
|
-
|
|
373
|
+
// Field accepts any string; cross-field validation in superRefine enforces strict/custom rules
|
|
374
|
+
category: z.string().optional(),
|
|
313
375
|
categoryExclusive: z.boolean().optional(),
|
|
314
376
|
author: z.string().optional(),
|
|
315
377
|
tags: z.array(z.string()).optional(),
|
|
316
|
-
requires: z.array(
|
|
317
|
-
compatibleWith: z.array(
|
|
318
|
-
conflictsWith: z.array(
|
|
319
|
-
|
|
378
|
+
requires: z.array(extensibleSkillIdSchema).optional(),
|
|
379
|
+
compatibleWith: z.array(extensibleSkillIdSchema).optional(),
|
|
380
|
+
conflictsWith: z.array(extensibleSkillIdSchema).optional(),
|
|
381
|
+
domain: extensibleDomainSchema.optional(),
|
|
382
|
+
custom: z.boolean().optional()
|
|
383
|
+
}).passthrough().superRefine(validateCategoryField);
|
|
320
384
|
var pluginAuthorSchema = z.object({
|
|
321
385
|
name: z.string().min(1),
|
|
322
386
|
email: z.string().optional()
|
|
@@ -344,7 +408,7 @@ var pluginManifestValidationSchema = z.object({
|
|
|
344
408
|
hooks: z.union([z.string(), strictHooksRecordSchema]).optional()
|
|
345
409
|
}).strict();
|
|
346
410
|
var agentYamlConfigSchema = z.object({
|
|
347
|
-
id:
|
|
411
|
+
id: extensibleAgentNameSchema,
|
|
348
412
|
title: z.string(),
|
|
349
413
|
description: z.string(),
|
|
350
414
|
model: modelNameSchema.optional(),
|
|
@@ -352,24 +416,22 @@ var agentYamlConfigSchema = z.object({
|
|
|
352
416
|
disallowedTools: z.array(z.string()).optional(),
|
|
353
417
|
permissionMode: permissionModeSchema.optional(),
|
|
354
418
|
hooks: hooksRecordSchema.optional(),
|
|
355
|
-
outputFormat: z.string().optional()
|
|
419
|
+
outputFormat: z.string().optional(),
|
|
420
|
+
domain: extensibleDomainSchema.optional(),
|
|
421
|
+
custom: z.boolean().optional()
|
|
356
422
|
});
|
|
357
|
-
var skillAssignmentElementSchema = z.union([
|
|
358
|
-
var stackSubcategoryValues = new Set(
|
|
423
|
+
var skillAssignmentElementSchema = z.union([extensibleSkillIdSchema, skillAssignmentSchema]);
|
|
424
|
+
var stackSubcategoryValues = new Set(SUBCATEGORY_VALUES);
|
|
359
425
|
var stackAgentConfigSchema = z.record(
|
|
360
426
|
z.string(),
|
|
361
427
|
z.union([skillAssignmentElementSchema, z.array(skillAssignmentElementSchema)])
|
|
362
|
-
).superRefine(
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
});
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
});
|
|
428
|
+
).superRefine(
|
|
429
|
+
validateExtensibleRecordKeys(
|
|
430
|
+
stackSubcategoryValues,
|
|
431
|
+
customExtensions.categories,
|
|
432
|
+
"subcategory"
|
|
433
|
+
)
|
|
434
|
+
);
|
|
373
435
|
var projectConfigLoaderSchema = z.object({
|
|
374
436
|
version: z.literal("1").optional(),
|
|
375
437
|
/** Project/plugin name in kebab-case */
|
|
@@ -378,7 +440,7 @@ var projectConfigLoaderSchema = z.object({
|
|
|
378
440
|
/** Agent IDs to compile (e.g., ["web-developer", "api-developer"]) */
|
|
379
441
|
agents: z.array(z.string()).optional(),
|
|
380
442
|
/** Flat list of all skill IDs used by this project */
|
|
381
|
-
skills: z.array(
|
|
443
|
+
skills: z.array(extensibleSkillIdSchema).optional(),
|
|
382
444
|
/** Author handle (e.g., "@vince") */
|
|
383
445
|
author: z.string().optional(),
|
|
384
446
|
/** "local" = .claude/agents, "plugin" = .claude/plugins/ (DEFAULT_PLUGIN_NAME) */
|
|
@@ -386,7 +448,7 @@ var projectConfigLoaderSchema = z.object({
|
|
|
386
448
|
/** Whether expert mode (advanced/niche skills) was enabled in the wizard */
|
|
387
449
|
expertMode: z.boolean().optional(),
|
|
388
450
|
/** Selected domains from the wizard (persisted for edit mode restoration) */
|
|
389
|
-
domains: z.array(
|
|
451
|
+
domains: z.array(extensibleDomainSchema).optional(),
|
|
390
452
|
/** Selected agents from the wizard (persisted for edit mode restoration) */
|
|
391
453
|
selectedAgents: z.array(z.string()).optional(),
|
|
392
454
|
/** Agent-to-subcategory-to-skill mappings from selected stack (accepts same formats as stacks.yaml) */
|
|
@@ -415,6 +477,8 @@ var projectConfigValidationSchema = z.object({
|
|
|
415
477
|
expertMode: z.boolean().optional(),
|
|
416
478
|
/** Selected domains from the wizard (persisted for edit mode restoration) */
|
|
417
479
|
domains: z.array(domainSchema).optional(),
|
|
480
|
+
/** Selected agents from the wizard (persisted for edit mode restoration) */
|
|
481
|
+
selectedAgents: z.array(z.string()).optional(),
|
|
418
482
|
/** Agent-to-subcategory-to-skill mappings from selected stack */
|
|
419
483
|
stack: z.record(z.string(), stackAgentConfigSchema),
|
|
420
484
|
/** Skills source path or URL (e.g., "github:my-org/skills") */
|
|
@@ -425,14 +489,15 @@ var projectConfigValidationSchema = z.object({
|
|
|
425
489
|
agentsSource: z.string().optional()
|
|
426
490
|
});
|
|
427
491
|
var categoryDefinitionSchema = z.object({
|
|
428
|
-
id:
|
|
492
|
+
id: extensibleSubcategorySchema,
|
|
429
493
|
displayName: z.string(),
|
|
430
494
|
description: z.string(),
|
|
431
|
-
domain:
|
|
495
|
+
domain: extensibleDomainSchema.optional(),
|
|
432
496
|
exclusive: z.boolean(),
|
|
433
497
|
required: z.boolean(),
|
|
434
498
|
order: z.number(),
|
|
435
|
-
icon: z.string().optional()
|
|
499
|
+
icon: z.string().optional(),
|
|
500
|
+
custom: z.boolean().optional()
|
|
436
501
|
});
|
|
437
502
|
var skillRefInYaml = z.string();
|
|
438
503
|
var conflictRuleSchema = z.object({
|
|
@@ -465,11 +530,18 @@ var relationshipDefinitionsSchema = z.object({
|
|
|
465
530
|
requires: z.array(requireRuleSchema),
|
|
466
531
|
alternatives: z.array(alternativeGroupSchema)
|
|
467
532
|
});
|
|
533
|
+
var builtinSubcategoryValues = new Set(SUBCATEGORY_VALUES);
|
|
468
534
|
var skillsMatrixConfigSchema = z.object({
|
|
469
535
|
version: z.string(),
|
|
470
|
-
categories: z.record(
|
|
471
|
-
|
|
472
|
-
|
|
536
|
+
categories: z.record(z.string(), categoryDefinitionSchema).superRefine(
|
|
537
|
+
validateExtensibleRecordKeys(
|
|
538
|
+
builtinSubcategoryValues,
|
|
539
|
+
customExtensions.categories,
|
|
540
|
+
"category key"
|
|
541
|
+
)
|
|
542
|
+
),
|
|
543
|
+
relationships: relationshipDefinitionsSchema.optional(),
|
|
544
|
+
skillAliases: z.record(z.string(), extensibleSkillIdSchema).optional()
|
|
473
545
|
});
|
|
474
546
|
var localRawMetadataSchema = z.object({
|
|
475
547
|
/** Short name shown in the wizard grid (e.g., "my-custom-react") */
|
|
@@ -477,23 +549,28 @@ var localRawMetadataSchema = z.object({
|
|
|
477
549
|
/** One-line description for the wizard */
|
|
478
550
|
cliDescription: z.string().optional(),
|
|
479
551
|
/** Subcategory to place this skill in (e.g., "web-framework") */
|
|
480
|
-
|
|
552
|
+
// Field accepts any string; cross-field validation in superRefine enforces strict/custom rules
|
|
553
|
+
category: z.string().optional(),
|
|
481
554
|
/** If true, only one skill from this category can be selected */
|
|
482
555
|
categoryExclusive: z.boolean().optional(),
|
|
483
556
|
/** When an AI agent should invoke this skill */
|
|
484
557
|
usageGuidance: z.string().optional(),
|
|
485
558
|
tags: z.array(z.string()).optional(),
|
|
486
559
|
/** Framework skills this is compatible with (for Build step filtering) */
|
|
487
|
-
compatibleWith: z.array(
|
|
560
|
+
compatibleWith: z.array(extensibleSkillIdSchema).optional(),
|
|
488
561
|
/** Skills that cannot coexist with this one */
|
|
489
|
-
conflictsWith: z.array(
|
|
562
|
+
conflictsWith: z.array(extensibleSkillIdSchema).optional(),
|
|
490
563
|
/** Skills that must be selected before this one */
|
|
491
|
-
requires: z.array(
|
|
564
|
+
requires: z.array(extensibleSkillIdSchema).optional(),
|
|
492
565
|
/** Setup skills that must be installed first (e.g., env setup) */
|
|
493
|
-
requiresSetup: z.array(
|
|
566
|
+
requiresSetup: z.array(extensibleSkillIdSchema).optional(),
|
|
494
567
|
/** Usage skills this setup skill configures (inverse relationship) */
|
|
495
|
-
providesSetupFor: z.array(
|
|
496
|
-
|
|
568
|
+
providesSetupFor: z.array(extensibleSkillIdSchema).optional(),
|
|
569
|
+
/** Explicit domain assignment (overrides inference from category prefix) */
|
|
570
|
+
domain: extensibleDomainSchema.optional(),
|
|
571
|
+
/** True if this skill was created outside the CLI's built-in vocabulary */
|
|
572
|
+
custom: z.boolean().optional()
|
|
573
|
+
}).passthrough().superRefine(validateCategoryField);
|
|
497
574
|
var localSkillMetadataSchema = z.object({
|
|
498
575
|
forkedFrom: z.object({
|
|
499
576
|
/** Original skill ID before forking (e.g., "web-framework-react") */
|
|
@@ -552,12 +629,6 @@ var marketplaceSchema = z.object({
|
|
|
552
629
|
metadata: marketplaceMetadataSchema.optional(),
|
|
553
630
|
plugins: z.array(marketplacePluginSchema).min(1)
|
|
554
631
|
});
|
|
555
|
-
var defaultMappingsSchema = z.object({
|
|
556
|
-
/** Maps skill path patterns to the agent IDs that should receive them */
|
|
557
|
-
skillToAgents: z.record(z.string(), z.array(z.string())),
|
|
558
|
-
/** Maps agent IDs to skill ID prefixes they should receive by default */
|
|
559
|
-
agentSkillPrefixes: z.record(z.string(), z.array(z.string())).optional()
|
|
560
|
-
});
|
|
561
632
|
var permissionConfigSchema = z.object({
|
|
562
633
|
/** Tool names or patterns to explicitly allow */
|
|
563
634
|
allow: z.array(z.string()).optional(),
|
|
@@ -639,7 +710,6 @@ var projectSourceConfigValidationSchema = z.object({
|
|
|
639
710
|
stacksFile: z.string().optional(),
|
|
640
711
|
matrixFile: z.string().optional()
|
|
641
712
|
});
|
|
642
|
-
var KEBAB_CASE_PATTERN = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
|
|
643
713
|
var agentYamlGenerationSchema = z.object({
|
|
644
714
|
$schema: z.string().optional(),
|
|
645
715
|
id: z.string().min(1),
|
|
@@ -650,7 +720,9 @@ var agentYamlGenerationSchema = z.object({
|
|
|
650
720
|
disallowedTools: z.array(z.string()).optional(),
|
|
651
721
|
permissionMode: permissionModeSchema.optional(),
|
|
652
722
|
hooks: strictHooksRecordSchema.optional(),
|
|
653
|
-
outputFormat: z.string().optional()
|
|
723
|
+
outputFormat: z.string().optional(),
|
|
724
|
+
domain: extensibleDomainSchema.optional(),
|
|
725
|
+
custom: z.boolean().optional()
|
|
654
726
|
}).strict();
|
|
655
727
|
var agentFrontmatterValidationSchema = z.object({
|
|
656
728
|
/** Agent name in kebab-case (becomes the Task tool identifier) */
|
|
@@ -685,7 +757,7 @@ var skillFrontmatterValidationSchema = z.object({
|
|
|
685
757
|
}).strict();
|
|
686
758
|
var metadataValidationSchema = z.object({
|
|
687
759
|
/** Domain-prefixed subcategory (e.g., "web-framework") */
|
|
688
|
-
category:
|
|
760
|
+
category: extensibleSubcategorySchema,
|
|
689
761
|
categoryExclusive: z.boolean().optional(),
|
|
690
762
|
/** Author handle — must start with @ (e.g., "@vince") */
|
|
691
763
|
author: z.string().regex(/^@[a-z][a-z0-9-]*$/),
|
|
@@ -718,7 +790,11 @@ var metadataValidationSchema = z.object({
|
|
|
718
790
|
source: z.string().optional(),
|
|
719
791
|
/** ISO date of the fork */
|
|
720
792
|
date: z.string()
|
|
721
|
-
}).optional()
|
|
793
|
+
}).optional(),
|
|
794
|
+
/** Explicit domain assignment (overrides inference from category prefix) */
|
|
795
|
+
domain: extensibleDomainSchema.optional(),
|
|
796
|
+
/** True if this skill was created outside the CLI's built-in vocabulary */
|
|
797
|
+
custom: z.boolean().optional()
|
|
722
798
|
}).strict();
|
|
723
799
|
var stackSkillAssignmentSchema = z.object({
|
|
724
800
|
id: z.string().min(1),
|
|
@@ -799,6 +875,20 @@ function warnUnknownFields(parsed, expectedKeys, context) {
|
|
|
799
875
|
warn(`Unknown fields in ${context}: ${unknownKeys.join(", ")}`);
|
|
800
876
|
}
|
|
801
877
|
}
|
|
878
|
+
function extendSchemasWithCustomValues(options) {
|
|
879
|
+
for (const category of options.categories ?? []) {
|
|
880
|
+
customExtensions.categories.add(category);
|
|
881
|
+
}
|
|
882
|
+
for (const domain of options.domains ?? []) {
|
|
883
|
+
customExtensions.domains.add(domain);
|
|
884
|
+
}
|
|
885
|
+
for (const agentName of options.agentNames ?? []) {
|
|
886
|
+
customExtensions.agentNames.add(agentName);
|
|
887
|
+
}
|
|
888
|
+
for (const skillId of options.skillIds ?? []) {
|
|
889
|
+
customExtensions.skillIds.add(skillId);
|
|
890
|
+
}
|
|
891
|
+
}
|
|
802
892
|
|
|
803
893
|
export {
|
|
804
894
|
getErrorMessage,
|
|
@@ -817,9 +907,14 @@ export {
|
|
|
817
907
|
ensureDir,
|
|
818
908
|
remove,
|
|
819
909
|
copy,
|
|
910
|
+
DOMAIN_VALUES,
|
|
911
|
+
SUBCATEGORY_VALUES,
|
|
912
|
+
agentNameSchema,
|
|
820
913
|
skillDisplayNameSchema,
|
|
821
914
|
SKILL_ID_PATTERN,
|
|
915
|
+
isValidSkillId,
|
|
822
916
|
skillIdSchema,
|
|
917
|
+
extensibleDomainSchema,
|
|
823
918
|
categoryPathSchema,
|
|
824
919
|
hooksRecordSchema,
|
|
825
920
|
skillFrontmatterLoaderSchema,
|
|
@@ -833,7 +928,6 @@ export {
|
|
|
833
928
|
localSkillMetadataSchema,
|
|
834
929
|
stacksConfigSchema,
|
|
835
930
|
marketplaceSchema,
|
|
836
|
-
defaultMappingsSchema,
|
|
837
931
|
settingsFileSchema,
|
|
838
932
|
importedSkillMetadataSchema,
|
|
839
933
|
projectSourceConfigSchema,
|
|
@@ -844,6 +938,7 @@ export {
|
|
|
844
938
|
stackConfigValidationSchema,
|
|
845
939
|
formatZodErrors,
|
|
846
940
|
validateNestingDepth,
|
|
847
|
-
warnUnknownFields
|
|
941
|
+
warnUnknownFields,
|
|
942
|
+
extendSchemasWithCustomValues
|
|
848
943
|
};
|
|
849
|
-
//# sourceMappingURL=chunk-
|
|
944
|
+
//# sourceMappingURL=chunk-C4QI54PN.js.map
|