@agents-inc/cli 0.35.0 → 0.41.1
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 +103 -0
- package/config/skills-matrix.yaml +124 -132
- package/config/stacks.yaml +687 -687
- package/dist/{chunk-BLLXNFWP.js → chunk-2D6LKRHW.js} +2 -2
- package/dist/{chunk-KWF6D7ZP.js → chunk-342YB6TQ.js} +27 -19
- package/dist/chunk-342YB6TQ.js.map +1 -0
- package/dist/{chunk-OGXSTJP2.js → chunk-423MJ6DT.js} +66 -36
- package/dist/chunk-423MJ6DT.js.map +1 -0
- package/dist/{chunk-5LPPIT6H.js → chunk-4LT6RXMY.js} +4 -4
- package/dist/{chunk-LFHZBF6N.js → chunk-4SYXPG7L.js} +4 -3
- package/dist/chunk-4SYXPG7L.js.map +1 -0
- package/dist/{chunk-CXWPUVA7.js → chunk-4UTPJXUX.js} +9 -9
- package/dist/{chunk-CEWNZQMH.js → chunk-5TMB53BV.js} +9 -3
- package/dist/chunk-5TMB53BV.js.map +1 -0
- package/dist/chunk-7FBM7V3E.js +144 -0
- package/dist/chunk-7FBM7V3E.js.map +1 -0
- package/dist/chunk-ACVJVYMC.js +111 -0
- package/dist/chunk-ACVJVYMC.js.map +1 -0
- package/dist/{chunk-YN35L5NE.js → chunk-AH7XHAKN.js} +12 -12
- package/dist/chunk-AH7XHAKN.js.map +1 -0
- package/dist/{chunk-5YNZJ5TP.js → chunk-AVVYFEMF.js} +2 -2
- package/dist/{chunk-U36YCEBK.js → chunk-BFISETQG.js} +32 -23
- package/dist/chunk-BFISETQG.js.map +1 -0
- package/dist/{chunk-YCS7GF6Y.js → chunk-BK7TANUV.js} +6 -2
- package/dist/chunk-BK7TANUV.js.map +1 -0
- package/dist/{chunk-OGJ7DFCL.js → chunk-DV4ALU5I.js} +6 -6
- package/dist/{chunk-NJ775OJ4.js → chunk-FHBICUXB.js} +7 -7
- package/dist/chunk-FHBICUXB.js.map +1 -0
- package/dist/{chunk-OKILA27U.js → chunk-GEDWVX6Y.js} +87 -100
- package/dist/chunk-GEDWVX6Y.js.map +1 -0
- package/dist/{chunk-DC5AK3LW.js → chunk-GG4BSB6S.js} +5 -11
- package/dist/chunk-GG4BSB6S.js.map +1 -0
- package/dist/{chunk-BPD4VUAU.js → chunk-H6H3COI5.js} +5 -5
- package/dist/{chunk-AQQVSNUX.js → chunk-K77I4XGL.js} +20 -6
- package/dist/chunk-K77I4XGL.js.map +1 -0
- package/dist/chunk-KC2SIUIA.js +46 -0
- package/dist/chunk-KC2SIUIA.js.map +1 -0
- package/dist/{chunk-HTTPKSL6.js → chunk-KXM7KOPE.js} +2 -2
- package/dist/{chunk-GGHH3KR2.js → chunk-LJRP4SWY.js} +6 -5
- package/dist/chunk-LJRP4SWY.js.map +1 -0
- package/dist/{chunk-PKUIO2Z7.js → chunk-MNPPGIZQ.js} +8 -8
- package/dist/chunk-MNPPGIZQ.js.map +1 -0
- package/dist/{chunk-IG7CUREJ.js → chunk-NYP5SB2V.js} +2 -2
- package/dist/{chunk-JXMRTHDT.js → chunk-NZYKDVRL.js} +2 -2
- package/dist/{chunk-XNQJBQ5X.js → chunk-PURJZ72D.js} +2 -2
- package/dist/{chunk-VEZ2GZEK.js → chunk-R52N7DBG.js} +2 -2
- package/dist/chunk-SILUTTV7.js +113 -0
- package/dist/chunk-SILUTTV7.js.map +1 -0
- package/dist/{chunk-YIKBNGE3.js → chunk-TJAZ7QCF.js} +7 -7
- package/dist/chunk-TJAZ7QCF.js.map +1 -0
- package/dist/{chunk-WMVGRAFB.js → chunk-TTXV55NQ.js} +235 -117
- package/dist/chunk-TTXV55NQ.js.map +1 -0
- package/dist/{chunk-ZE355C6C.js → chunk-UKTYDNWJ.js} +9 -4
- package/dist/chunk-UKTYDNWJ.js.map +1 -0
- package/dist/{chunk-YPJKOM42.js → chunk-WS6OQIEN.js} +2 -2
- package/dist/{chunk-OI4WBRC7.js → chunk-XJXJZ2MJ.js} +113 -150
- package/dist/chunk-XJXJZ2MJ.js.map +1 -0
- package/dist/chunk-YLJYAQSG.js +210 -0
- package/dist/chunk-YLJYAQSG.js.map +1 -0
- package/dist/{chunk-MZB3GGOH.js → chunk-YRVTXSXP.js} +1 -2
- package/dist/chunk-YRVTXSXP.js.map +1 -0
- package/dist/{chunk-XYCN2GCV.js → chunk-ZLHGJSRK.js} +3 -3
- package/dist/cli/defaults/agent-mappings.yaml +16 -72
- package/dist/commands/build/marketplace.js +3 -3
- package/dist/commands/build/plugins.js +5 -5
- package/dist/commands/build/stack.js +5 -5
- package/dist/commands/compile.js +14 -18
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/config/get.js +8 -8
- package/dist/commands/config/get.js.map +1 -1
- package/dist/commands/config/index.js +5 -5
- package/dist/commands/config/path.js +4 -4
- package/dist/commands/config/set-project.js +7 -7
- package/dist/commands/config/set-project.js.map +1 -1
- package/dist/commands/config/show.js +5 -5
- package/dist/commands/config/unset-project.js +5 -5
- package/dist/commands/config/unset-project.js.map +1 -1
- package/dist/commands/diff.js +12 -9
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/doctor.js +8 -7
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +35 -29
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +6 -6
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/import/skill.js +16 -16
- package/dist/commands/import/skill.js.map +1 -1
- package/dist/commands/info.js +7 -6
- package/dist/commands/info.js.map +1 -1
- package/dist/commands/init.js +42 -31
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/list.js +6 -5
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/new/agent.js +5 -5
- package/dist/commands/new/skill.js +12 -9
- package/dist/commands/new/skill.js.map +1 -1
- package/dist/commands/outdated.js +8 -5
- package/dist/commands/outdated.js.map +1 -1
- package/dist/commands/search.js +7 -7
- package/dist/commands/uninstall.js +122 -103
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +8 -7
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/validate.js +5 -5
- package/dist/commands/version/bump.js +4 -4
- package/dist/commands/version/index.js +4 -4
- package/dist/commands/version/set.js +4 -4
- package/dist/commands/version/show.js +4 -4
- package/dist/components/skill-search/skill-search.js +3 -3
- package/dist/components/wizard/category-grid.js +3 -3
- package/dist/components/wizard/category-grid.test.js +79 -58
- package/dist/components/wizard/category-grid.test.js.map +1 -1
- package/dist/components/wizard/checkbox-grid.js +10 -0
- package/dist/components/wizard/checkbox-grid.test.js +270 -0
- package/dist/components/wizard/checkbox-grid.test.js.map +1 -0
- package/dist/components/wizard/domain-selection.js +7 -5
- package/dist/components/wizard/help-modal.js +2 -2
- package/dist/components/wizard/menu-item.js +2 -2
- 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/source-grid.js +4 -4
- package/dist/components/wizard/source-grid.test.js +4 -4
- package/dist/components/wizard/stack-selection.js +9 -8
- package/dist/components/wizard/step-agents.js +16 -0
- package/dist/components/wizard/step-agents.js.map +1 -0
- package/dist/components/wizard/step-agents.test.js +190 -0
- package/dist/components/wizard/step-agents.test.js.map +1 -0
- package/dist/components/wizard/step-build.js +10 -9
- package/dist/components/wizard/step-build.test.js +56 -53
- package/dist/components/wizard/step-build.test.js.map +1 -1
- package/dist/components/wizard/step-confirm.js +3 -3
- package/dist/components/wizard/step-confirm.test.js +19 -12
- package/dist/components/wizard/step-confirm.test.js.map +1 -1
- 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 +11 -10
- 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 +12 -10
- package/dist/components/wizard/step-stack.test.js +19 -19
- 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 -7
- package/dist/components/wizard/wizard-tabs.js +2 -2
- package/dist/components/wizard/wizard-tabs.test.js +6 -4
- package/dist/components/wizard/wizard-tabs.test.js.map +1 -1
- package/dist/components/wizard/wizard.js +27 -24
- package/dist/config/skills-matrix.yaml +124 -132
- package/dist/config/stacks.yaml +687 -687
- package/dist/hooks/init.js +3 -3
- package/dist/{source-manager-PTK4P6BF.js → source-manager-PPABS6BC.js} +4 -4
- package/dist/source-manager-PPABS6BC.js.map +1 -0
- package/dist/stores/wizard-store.js +5 -4
- package/dist/stores/wizard-store.test.js +336 -136
- package/dist/stores/wizard-store.test.js.map +1 -1
- package/package.json +1 -1
- package/src/schemas/agent.schema.json +3 -3
- package/src/schemas/metadata.schema.json +55 -15
- package/src/schemas/project-config.schema.json +42 -2
- package/src/schemas/project-source-config.schema.json +5 -5
- package/src/schemas/skills-matrix.schema.json +103 -104
- package/src/schemas/stack.schema.json +1 -1
- package/src/schemas/stacks.schema.json +41 -1
- package/dist/chunk-AQQVSNUX.js.map +0 -1
- package/dist/chunk-CEWNZQMH.js.map +0 -1
- package/dist/chunk-DC5AK3LW.js.map +0 -1
- package/dist/chunk-GGHH3KR2.js.map +0 -1
- package/dist/chunk-KWF6D7ZP.js.map +0 -1
- package/dist/chunk-LFHZBF6N.js.map +0 -1
- package/dist/chunk-MZB3GGOH.js.map +0 -1
- package/dist/chunk-NJ775OJ4.js.map +0 -1
- package/dist/chunk-NVQEHRJY.js +0 -120
- package/dist/chunk-NVQEHRJY.js.map +0 -1
- package/dist/chunk-OGXSTJP2.js.map +0 -1
- package/dist/chunk-OI4WBRC7.js.map +0 -1
- package/dist/chunk-OKILA27U.js.map +0 -1
- package/dist/chunk-PKUIO2Z7.js.map +0 -1
- package/dist/chunk-U36YCEBK.js.map +0 -1
- package/dist/chunk-UFUQUFV6.js +0 -256
- package/dist/chunk-UFUQUFV6.js.map +0 -1
- package/dist/chunk-WMVGRAFB.js.map +0 -1
- package/dist/chunk-YCS7GF6Y.js.map +0 -1
- package/dist/chunk-YIKBNGE3.js.map +0 -1
- package/dist/chunk-YN35L5NE.js.map +0 -1
- package/dist/chunk-ZE355C6C.js.map +0 -1
- /package/dist/{chunk-BLLXNFWP.js.map → chunk-2D6LKRHW.js.map} +0 -0
- /package/dist/{chunk-5LPPIT6H.js.map → chunk-4LT6RXMY.js.map} +0 -0
- /package/dist/{chunk-CXWPUVA7.js.map → chunk-4UTPJXUX.js.map} +0 -0
- /package/dist/{chunk-5YNZJ5TP.js.map → chunk-AVVYFEMF.js.map} +0 -0
- /package/dist/{chunk-OGJ7DFCL.js.map → chunk-DV4ALU5I.js.map} +0 -0
- /package/dist/{chunk-BPD4VUAU.js.map → chunk-H6H3COI5.js.map} +0 -0
- /package/dist/{chunk-HTTPKSL6.js.map → chunk-KXM7KOPE.js.map} +0 -0
- /package/dist/{chunk-IG7CUREJ.js.map → chunk-NYP5SB2V.js.map} +0 -0
- /package/dist/{chunk-JXMRTHDT.js.map → chunk-NZYKDVRL.js.map} +0 -0
- /package/dist/{chunk-XNQJBQ5X.js.map → chunk-PURJZ72D.js.map} +0 -0
- /package/dist/{chunk-VEZ2GZEK.js.map → chunk-R52N7DBG.js.map} +0 -0
- /package/dist/{chunk-YPJKOM42.js.map → chunk-WS6OQIEN.js.map} +0 -0
- /package/dist/{chunk-XYCN2GCV.js.map → chunk-ZLHGJSRK.js.map} +0 -0
- /package/dist/{source-manager-PTK4P6BF.js.map → components/wizard/checkbox-grid.js.map} +0 -0
|
@@ -20,6 +20,7 @@ var PLUGIN_MANIFEST_DIR = ".claude-plugin";
|
|
|
20
20
|
var PLUGIN_MANIFEST_FILE = "plugin.json";
|
|
21
21
|
var DEFAULT_PLUGIN_NAME = "agents-inc";
|
|
22
22
|
var CACHE_DIR = path.join(os.homedir(), ".cache", DEFAULT_PLUGIN_NAME);
|
|
23
|
+
var CLI_BIN_NAME = "agentsinc";
|
|
23
24
|
var SKILLS_MATRIX_PATH = "config/skills-matrix.yaml";
|
|
24
25
|
var STACKS_FILE_PATH = "config/stacks.yaml";
|
|
25
26
|
var SKILLS_DIR_PATH = "src/skills";
|
|
@@ -126,6 +127,7 @@ var DEFAULT_BRANDING = {
|
|
|
126
127
|
NAME: "Agents Inc.",
|
|
127
128
|
TAGLINE: "AI-powered development tools"
|
|
128
129
|
};
|
|
130
|
+
var DEFAULT_PUBLIC_SOURCE_NAME = "Agents Inc";
|
|
129
131
|
var CLI_COLORS = {
|
|
130
132
|
PRIMARY: "cyan",
|
|
131
133
|
SUCCESS: "green",
|
|
@@ -136,7 +138,7 @@ var CLI_COLORS = {
|
|
|
136
138
|
FOCUS: "cyan",
|
|
137
139
|
UNFOCUSED: "white"
|
|
138
140
|
};
|
|
139
|
-
var DEFAULT_SCRATCH_DOMAINS = ["web", "
|
|
141
|
+
var DEFAULT_SCRATCH_DOMAINS = ["web", "api", "mobile"];
|
|
140
142
|
var DEFAULT_PRESELECTED_SKILLS = [
|
|
141
143
|
"meta-methodology-anti-over-engineering",
|
|
142
144
|
"meta-methodology-context-management",
|
|
@@ -155,6 +157,7 @@ export {
|
|
|
155
157
|
PLUGIN_MANIFEST_FILE,
|
|
156
158
|
DEFAULT_PLUGIN_NAME,
|
|
157
159
|
CACHE_DIR,
|
|
160
|
+
CLI_BIN_NAME,
|
|
158
161
|
SKILLS_MATRIX_PATH,
|
|
159
162
|
STACKS_FILE_PATH,
|
|
160
163
|
SKILLS_DIR_PATH,
|
|
@@ -182,8 +185,9 @@ export {
|
|
|
182
185
|
MAX_MARKETPLACE_PLUGINS,
|
|
183
186
|
SCROLL_VIEWPORT,
|
|
184
187
|
DEFAULT_BRANDING,
|
|
188
|
+
DEFAULT_PUBLIC_SOURCE_NAME,
|
|
185
189
|
CLI_COLORS,
|
|
186
190
|
DEFAULT_SCRATCH_DOMAINS,
|
|
187
191
|
DEFAULT_PRESELECTED_SKILLS
|
|
188
192
|
};
|
|
189
|
-
//# sourceMappingURL=chunk-
|
|
193
|
+
//# sourceMappingURL=chunk-BK7TANUV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/consts.ts"],"sourcesContent":["import path from \"path\";\nimport os from \"os\";\nimport { fileURLToPath } from \"url\";\nimport type { Domain, SkillId } from \"./types/index.js\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n// After tsup build, dist/ is flat, so we go up one level from dist/ to get CLI root\n// In development (src/cli/consts.ts), we go up two levels\nconst isInDist = __dirname.includes(\"/dist\");\nconst CLI_ROOT = isInDist ? path.resolve(__dirname, \"..\") : path.resolve(__dirname, \"../..\");\nexport const PROJECT_ROOT = CLI_ROOT;\n\nexport const CLAUDE_DIR = \".claude\";\nexport const CLAUDE_SRC_DIR = \".claude-src\";\nexport const PLUGINS_SUBDIR = \"plugins\";\nexport const PLUGIN_MANIFEST_DIR = \".claude-plugin\";\nexport const PLUGIN_MANIFEST_FILE = \"plugin.json\";\nexport const DEFAULT_PLUGIN_NAME = \"agents-inc\";\n\nexport const CACHE_DIR = path.join(os.homedir(), \".cache\", DEFAULT_PLUGIN_NAME);\n\nexport const CLI_BIN_NAME = \"agentsinc\";\n\nexport const SKILLS_MATRIX_PATH = \"config/skills-matrix.yaml\";\nexport const STACKS_FILE_PATH = \"config/stacks.yaml\";\nexport const SKILLS_DIR_PATH = \"src/skills\";\nexport const LOCAL_SKILLS_PATH = \".claude/skills\";\nexport const ARCHIVED_SKILLS_DIR_NAME = \"_archived\";\n\nexport const DIRS = {\n agents: \"src/agents\",\n skills: \"src/skills\",\n stacks: \"src/stacks\",\n templates: \"src/agents/_templates\",\n commands: \"src/commands\",\n} as const;\n\nexport const STANDARD_FILES = {\n SKILL_MD: \"SKILL.md\",\n METADATA_YAML: \"metadata.yaml\",\n METADATA_JSON: \"metadata.json\",\n CONFIG_YAML: \"config.yaml\",\n SKILLS_MATRIX_YAML: \"skills-matrix.yaml\",\n AGENT_YAML: \"agent.yaml\",\n PLUGIN_JSON: \"plugin.json\",\n CLAUDE_MD: \"CLAUDE.md\",\n REFERENCE_MD: \"reference.md\",\n INTRO_MD: \"intro.md\",\n WORKFLOW_MD: \"workflow.md\",\n EXAMPLES_MD: \"examples.md\",\n OUTPUT_FORMAT_MD: \"output-format.md\",\n CRITICAL_REQUIREMENTS_MD: \"critical-requirements.md\",\n CRITICAL_REMINDERS_MD: \"critical-reminders.md\",\n} as const;\n\nexport const STANDARD_DIRS = {\n EXAMPLES: \"examples\",\n SCRIPTS: \"scripts\",\n SKILLS: \"skills\",\n} as const;\n\nexport const DEFAULT_VERSION = \"1.0.0\";\n\n// \"0.0.0\" indicates no version was explicitly set\nexport const DEFAULT_DISPLAY_VERSION = \"0.0.0\";\n\n// JSON Schema URLs for yaml-language-server $schema comments.\n// Uses raw.githubusercontent.com so schemas resolve without requiring the CLI as a dependency.\nconst SCHEMA_PKG_PREFIX = \"https://raw.githubusercontent.com/agents-inc/cli/main/src/schemas\";\n\nexport const SCHEMA_PATHS = {\n agent: `${SCHEMA_PKG_PREFIX}/agent.schema.json`,\n metadata: `${SCHEMA_PKG_PREFIX}/metadata.schema.json`,\n marketplace: `${SCHEMA_PKG_PREFIX}/marketplace.schema.json`,\n projectConfig: `${SCHEMA_PKG_PREFIX}/project-config.schema.json`,\n projectSourceConfig: `${SCHEMA_PKG_PREFIX}/project-source-config.schema.json`,\n skillsMatrix: `${SCHEMA_PKG_PREFIX}/skills-matrix.schema.json`,\n stacks: `${SCHEMA_PKG_PREFIX}/stacks.schema.json`,\n} as const;\n\n/** Generates a yaml-language-server schema comment for the top of YAML files. */\nexport function yamlSchemaComment(schemaPath: string): string {\n return `# yaml-language-server: $schema=${schemaPath}`;\n}\n\nexport const YAML_FORMATTING = {\n INDENT: 2,\n LINE_WIDTH: 120,\n /** lineWidth: 0 disables wrapping — used for metadata files */\n LINE_WIDTH_NONE: 0,\n} as const;\n\nexport const UI_SYMBOLS = {\n CHECKBOX_CHECKED: \"[x]\",\n CHECKBOX_UNCHECKED: \"[ ]\",\n CHEVRON: \"\\u276F\",\n CHEVRON_SPACER: \" \",\n SELECTED: \"\\u2713\",\n UNSELECTED: \"\\u25CB\",\n CURRENT: \"\\u25CF\",\n SKIPPED: \"\\u2013\",\n DISCOURAGED: \"!\",\n DISABLED: \"\\u2013\",\n SCROLL_UP: \"\\u25B2\",\n SCROLL_DOWN: \"\\u25BC\",\n} as const;\n\nexport const UI_LAYOUT = {\n MAX_VISIBLE_RESULTS: 10,\n DESCRIPTION_WIDTH: 30,\n COPIED_MESSAGE_TIMEOUT_MS: 2000,\n FALLBACK_MESSAGE_TIMEOUT_MS: 3000,\n} as const;\n\nexport const GITHUB_SOURCE = {\n HTTPS_PREFIX: \"https://github.com/\",\n GITHUB_PREFIX: \"github:\",\n GH_PREFIX: \"gh:\",\n} as const;\n\nexport const DEFAULT_SKILLS_SUBDIR = \"skills\";\n\nexport const HASH_PREFIX_LENGTH = 7;\n\n/** Hex chars from SHA-256 hash used in cache directory names (64 bits of collision resistance) */\nexport const CACHE_HASH_LENGTH = 16;\n\n/** Max chars of human-readable prefix in cache directory names (for debugging) */\nexport const CACHE_READABLE_PREFIX_LENGTH = 32;\n\n// File size limits for parsing boundaries (DoS prevention)\nconst ONE_MB = 1024 * 1024;\nexport const MAX_MARKETPLACE_FILE_SIZE = 10 * ONE_MB;\nexport const MAX_PLUGIN_FILE_SIZE = ONE_MB;\nexport const MAX_CONFIG_FILE_SIZE = ONE_MB;\n\nexport const MAX_JSON_NESTING_DEPTH = 10;\nexport const MAX_MARKETPLACE_PLUGINS = 10_000;\n\nexport const SCROLL_VIEWPORT = {\n /** Height of the \"N more above\" scroll indicator */\n SCROLL_INDICATOR_HEIGHT: 1,\n /** Estimated lines per category name row (including top margin) */\n CATEGORY_NAME_LINES: 2,\n /** Margin between category sections (marginTop on CategorySection) */\n CATEGORY_MARGIN_LINES: 1,\n /** Minimum rows to show at least 1 category before enabling scroll */\n MIN_VIEWPORT_ROWS: 5,\n /** Minimum terminal height to show the wizard at all */\n MIN_TERMINAL_HEIGHT: 15,\n} as const;\n\nexport const DEFAULT_BRANDING = {\n NAME: \"Agents Inc.\",\n TAGLINE: \"AI-powered development tools\",\n} as const;\n\n/** Fallback name for the default public marketplace when marketplace.json is unavailable */\nexport const DEFAULT_PUBLIC_SOURCE_NAME = \"Agents Inc\";\n\nexport const CLI_COLORS = {\n PRIMARY: \"cyan\",\n SUCCESS: \"green\",\n ERROR: \"red\",\n WARNING: \"yellow\",\n INFO: \"blue\",\n NEUTRAL: \"gray\",\n FOCUS: \"cyan\",\n UNFOCUSED: \"white\",\n} as const;\n\n/** Default domains pre-selected when \"Start from scratch\" is chosen (all except CLI) */\nexport const DEFAULT_SCRATCH_DOMAINS: readonly Domain[] = [\"web\", \"api\", \"mobile\"];\n\nexport const DEFAULT_PRESELECTED_SKILLS: readonly SkillId[] = [\n \"meta-methodology-anti-over-engineering\",\n \"meta-methodology-context-management\",\n \"meta-methodology-improvement-protocol\",\n \"meta-methodology-investigation-requirements\",\n \"meta-methodology-success-criteria\",\n \"meta-methodology-write-verification\",\n];\n"],"mappings":"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","names":[]}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
getDomainsFromStack
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-YRVTXSXP.js";
|
|
5
5
|
import {
|
|
6
6
|
ViewTitle
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-KXM7KOPE.js";
|
|
8
8
|
import {
|
|
9
9
|
MenuItem
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-WS6OQIEN.js";
|
|
11
11
|
import {
|
|
12
12
|
useWizardStore
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-423MJ6DT.js";
|
|
14
14
|
import {
|
|
15
15
|
DEFAULT_SCRATCH_DOMAINS
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-BK7TANUV.js";
|
|
17
17
|
import {
|
|
18
18
|
init_esm_shims
|
|
19
19
|
} from "./chunk-DHET7RCE.js";
|
|
@@ -106,4 +106,4 @@ var StackSelection = ({ matrix, onCancel }) => {
|
|
|
106
106
|
export {
|
|
107
107
|
StackSelection
|
|
108
108
|
};
|
|
109
|
-
//# sourceMappingURL=chunk-
|
|
109
|
+
//# sourceMappingURL=chunk-DV4ALU5I.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
BaseCommand
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-2D6LKRHW.js";
|
|
5
5
|
import {
|
|
6
6
|
DEFAULT_SOURCE,
|
|
7
7
|
SOURCE_ENV_VAR,
|
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
loadProjectSourceConfig,
|
|
11
11
|
resolveAgentsSource,
|
|
12
12
|
resolveSource
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-TTXV55NQ.js";
|
|
14
14
|
import {
|
|
15
15
|
DEFAULT_BRANDING
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-BK7TANUV.js";
|
|
17
17
|
import {
|
|
18
18
|
init_esm_shims
|
|
19
19
|
} from "./chunk-DHET7RCE.js";
|
|
@@ -66,15 +66,15 @@ ${DEFAULT_BRANDING.NAME} Configuration
|
|
|
66
66
|
const projectConfigPath = getProjectConfigPath(projectDir);
|
|
67
67
|
this.log(` 2. Project config:`);
|
|
68
68
|
this.log(` ${projectConfigPath}`);
|
|
69
|
-
if (projectConfig?.source || projectConfig?.marketplace || projectConfig?.
|
|
69
|
+
if (projectConfig?.source || projectConfig?.marketplace || projectConfig?.agentsSource) {
|
|
70
70
|
if (projectConfig?.source) {
|
|
71
71
|
this.log(` source: ${projectConfig.source}`);
|
|
72
72
|
}
|
|
73
73
|
if (projectConfig?.marketplace) {
|
|
74
74
|
this.log(` marketplace: ${projectConfig.marketplace}`);
|
|
75
75
|
}
|
|
76
|
-
if (projectConfig?.
|
|
77
|
-
this.log(`
|
|
76
|
+
if (projectConfig?.agentsSource) {
|
|
77
|
+
this.log(` agentsSource: ${projectConfig.agentsSource}`);
|
|
78
78
|
}
|
|
79
79
|
} else {
|
|
80
80
|
this.log(` (not configured)`);
|
|
@@ -90,4 +90,4 @@ ${DEFAULT_BRANDING.NAME} Configuration
|
|
|
90
90
|
export {
|
|
91
91
|
ConfigShow
|
|
92
92
|
};
|
|
93
|
-
//# sourceMappingURL=chunk-
|
|
93
|
+
//# sourceMappingURL=chunk-FHBICUXB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/config/show.ts"],"sourcesContent":["import { BaseCommand } from \"../../base-command.js\";\nimport { DEFAULT_BRANDING } from \"../../consts.js\";\nimport {\n resolveSource,\n resolveAgentsSource,\n loadProjectSourceConfig,\n getProjectConfigPath,\n formatOrigin,\n DEFAULT_SOURCE,\n SOURCE_ENV_VAR,\n} from \"../../lib/configuration/index.js\";\n\nexport default class ConfigShow extends BaseCommand {\n static summary = \"Show current effective configuration\";\n static description =\n \"Display the current effective configuration with all layers (env, project, default)\";\n\n static flags = {\n ...BaseCommand.baseFlags,\n };\n\n async run(): Promise<void> {\n await this.parse(ConfigShow);\n\n const projectDir = process.cwd();\n\n this.log(`\\n${DEFAULT_BRANDING.NAME} Configuration\\n`);\n\n const resolved = await resolveSource(undefined, projectDir);\n\n this.log(\"Source:\");\n this.log(` ${resolved.source}`);\n this.log(` (from ${formatOrigin(\"source\", resolved.sourceOrigin)})`);\n this.log(\"\");\n\n this.log(\"Marketplace:\");\n if (resolved.marketplace) {\n this.log(` ${resolved.marketplace}`);\n } else {\n this.log(` (not configured)`);\n }\n this.log(\"\");\n\n const agentsResolved = await resolveAgentsSource(undefined, projectDir);\n this.log(\"Agents Source:\");\n if (agentsResolved.agentsSource) {\n this.log(` ${agentsResolved.agentsSource}`);\n this.log(` (from ${formatOrigin(\"agents\", agentsResolved.agentsSourceOrigin)})`);\n } else {\n this.log(` (not configured - using local CLI)`);\n }\n this.log(\"\");\n\n this.log(\"Configuration Layers:\");\n this.log(\"\");\n\n const envValue = process.env[SOURCE_ENV_VAR];\n this.log(` 1. Environment (${SOURCE_ENV_VAR}):`);\n if (envValue) {\n this.log(` ${envValue}`);\n } else {\n this.log(` (not set)`);\n }\n\n const projectConfig = await loadProjectSourceConfig(projectDir);\n const projectConfigPath = getProjectConfigPath(projectDir);\n this.log(` 2. Project config:`);\n this.log(` ${projectConfigPath}`);\n if (projectConfig?.source || projectConfig?.marketplace || projectConfig?.agentsSource) {\n if (projectConfig?.source) {\n this.log(` source: ${projectConfig.source}`);\n }\n if (projectConfig?.marketplace) {\n this.log(` marketplace: ${projectConfig.marketplace}`);\n }\n if (projectConfig?.agentsSource) {\n this.log(` agentsSource: ${projectConfig.agentsSource}`);\n }\n } else {\n this.log(` (not configured)`);\n }\n\n this.log(` 3. Default:`);\n this.log(` ${DEFAULT_SOURCE}`);\n\n this.log(\"\");\n this.log(\"Precedence: flag > env > project > default\");\n this.log(\"\");\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAYA,IAAqB,aAArB,MAAqB,oBAAmB,YAAY;AAAA,EAClD,OAAO,UAAU;AAAA,EACjB,OAAO,cACL;AAAA,EAEF,OAAO,QAAQ;AAAA,IACb,GAAG,YAAY;AAAA,EACjB;AAAA,EAEA,MAAM,MAAqB;AACzB,UAAM,KAAK,MAAM,WAAU;AAE3B,UAAM,aAAa,QAAQ,IAAI;AAE/B,SAAK,IAAI;AAAA,EAAK,iBAAiB,IAAI;AAAA,CAAkB;AAErD,UAAM,WAAW,MAAM,cAAc,QAAW,UAAU;AAE1D,SAAK,IAAI,SAAS;AAClB,SAAK,IAAI,KAAK,SAAS,MAAM,EAAE;AAC/B,SAAK,IAAI,WAAW,aAAa,UAAU,SAAS,YAAY,CAAC,GAAG;AACpE,SAAK,IAAI,EAAE;AAEX,SAAK,IAAI,cAAc;AACvB,QAAI,SAAS,aAAa;AACxB,WAAK,IAAI,KAAK,SAAS,WAAW,EAAE;AAAA,IACtC,OAAO;AACL,WAAK,IAAI,oBAAoB;AAAA,IAC/B;AACA,SAAK,IAAI,EAAE;AAEX,UAAM,iBAAiB,MAAM,oBAAoB,QAAW,UAAU;AACtE,SAAK,IAAI,gBAAgB;AACzB,QAAI,eAAe,cAAc;AAC/B,WAAK,IAAI,KAAK,eAAe,YAAY,EAAE;AAC3C,WAAK,IAAI,WAAW,aAAa,UAAU,eAAe,kBAAkB,CAAC,GAAG;AAAA,IAClF,OAAO;AACL,WAAK,IAAI,sCAAsC;AAAA,IACjD;AACA,SAAK,IAAI,EAAE;AAEX,SAAK,IAAI,uBAAuB;AAChC,SAAK,IAAI,EAAE;AAEX,UAAM,WAAW,QAAQ,IAAI,cAAc;AAC3C,SAAK,IAAI,qBAAqB,cAAc,IAAI;AAChD,QAAI,UAAU;AACZ,WAAK,IAAI,QAAQ,QAAQ,EAAE;AAAA,IAC7B,OAAO;AACL,WAAK,IAAI,gBAAgB;AAAA,IAC3B;AAEA,UAAM,gBAAgB,MAAM,wBAAwB,UAAU;AAC9D,UAAM,oBAAoB,qBAAqB,UAAU;AACzD,SAAK,IAAI,sBAAsB;AAC/B,SAAK,IAAI,QAAQ,iBAAiB,EAAE;AACpC,QAAI,eAAe,UAAU,eAAe,eAAe,eAAe,cAAc;AACtF,UAAI,eAAe,QAAQ;AACzB,aAAK,IAAI,gBAAgB,cAAc,MAAM,EAAE;AAAA,MACjD;AACA,UAAI,eAAe,aAAa;AAC9B,aAAK,IAAI,qBAAqB,cAAc,WAAW,EAAE;AAAA,MAC3D;AACA,UAAI,eAAe,cAAc;AAC/B,aAAK,IAAI,sBAAsB,cAAc,YAAY,EAAE;AAAA,MAC7D;AAAA,IACF,OAAO;AACL,WAAK,IAAI,uBAAuB;AAAA,IAClC;AAEA,SAAK,IAAI,eAAe;AACxB,SAAK,IAAI,QAAQ,cAAc,EAAE;AAEjC,SAAK,IAAI,EAAE;AACX,SAAK,IAAI,4CAA4C;AACrD,SAAK,IAAI,EAAE;AAAA,EACb;AACF;","names":[]}
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
useFocusedListItem
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-GG4BSB6S.js";
|
|
5
5
|
import {
|
|
6
6
|
CLI_COLORS,
|
|
7
7
|
SCROLL_VIEWPORT
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-BK7TANUV.js";
|
|
9
9
|
import {
|
|
10
10
|
init_esm_shims
|
|
11
11
|
} from "./chunk-DHET7RCE.js";
|
|
12
12
|
|
|
13
13
|
// src/cli/components/wizard/category-grid.tsx
|
|
14
14
|
init_esm_shims();
|
|
15
|
-
import { useCallback as useCallback2, useEffect as useEffect2, useMemo, useRef, useState } from "react";
|
|
15
|
+
import { useCallback as useCallback2, useEffect as useEffect2, useMemo, useRef as useRef2, useState } from "react";
|
|
16
16
|
import { Box, Text, measureElement } from "ink";
|
|
17
17
|
|
|
18
18
|
// src/cli/components/hooks/use-category-grid-input.ts
|
|
19
19
|
init_esm_shims();
|
|
20
|
-
import { useCallback, useEffect } from "react";
|
|
20
|
+
import { useCallback, useEffect, useRef } from "react";
|
|
21
21
|
import { useInput } from "ink";
|
|
22
|
-
var FRAMEWORK_CATEGORY_ID = "framework";
|
|
22
|
+
var FRAMEWORK_CATEGORY_ID = "web-framework";
|
|
23
23
|
var isSectionLocked = (categoryId, categories) => {
|
|
24
24
|
if (categoryId === FRAMEWORK_CATEGORY_ID) {
|
|
25
25
|
return false;
|
|
@@ -55,7 +55,7 @@ function useCategoryGridInput({
|
|
|
55
55
|
setFocused,
|
|
56
56
|
moveFocus,
|
|
57
57
|
onToggle,
|
|
58
|
-
|
|
58
|
+
onToggleLabels
|
|
59
59
|
}) {
|
|
60
60
|
const currentRow = processedCategories[focusedRow];
|
|
61
61
|
const currentOptions = currentRow?.sortedOptions || [];
|
|
@@ -78,65 +78,53 @@ function useCategoryGridInput({
|
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
}, [currentRow, currentLocked, focusedRow, processedCategories, categories, setFocused]);
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
currentOptions,
|
|
129
|
-
currentRow,
|
|
130
|
-
currentLocked,
|
|
131
|
-
processedCategories,
|
|
132
|
-
categories,
|
|
133
|
-
onToggle,
|
|
134
|
-
onToggleDescriptions,
|
|
135
|
-
setFocused,
|
|
136
|
-
moveFocus
|
|
137
|
-
]
|
|
138
|
-
)
|
|
139
|
-
);
|
|
81
|
+
const handlerRef = useRef(null);
|
|
82
|
+
handlerRef.current = (input, key) => {
|
|
83
|
+
if (key.tab && key.shift) {
|
|
84
|
+
onToggleLabels();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (key.tab && !key.shift) {
|
|
88
|
+
const nextSection = findNextUnlockedIndex(processedCategories, focusedRow, categories);
|
|
89
|
+
if (nextSection !== focusedRow) {
|
|
90
|
+
const newRowOptions = processedCategories[nextSection]?.sortedOptions || [];
|
|
91
|
+
const newCol = findValidStartColumn(newRowOptions);
|
|
92
|
+
setFocused(nextSection, newCol);
|
|
93
|
+
}
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (input === "d" || input === "D") {
|
|
97
|
+
onToggleLabels();
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (input === " ") {
|
|
101
|
+
if (currentLocked) return;
|
|
102
|
+
const currentOption = currentOptions[focusedCol];
|
|
103
|
+
if (currentOption && currentOption.state !== "disabled") {
|
|
104
|
+
onToggle(currentRow.id, currentOption.id);
|
|
105
|
+
}
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const isLeft = key.leftArrow || input === "h";
|
|
109
|
+
const isRight = key.rightArrow || input === "l";
|
|
110
|
+
const isUp = key.upArrow || input === "k";
|
|
111
|
+
const isDown = key.downArrow || input === "j";
|
|
112
|
+
if (isLeft) {
|
|
113
|
+
if (currentLocked) return;
|
|
114
|
+
moveFocus("left");
|
|
115
|
+
} else if (isRight) {
|
|
116
|
+
if (currentLocked) return;
|
|
117
|
+
moveFocus("right");
|
|
118
|
+
} else if (isUp) {
|
|
119
|
+
moveFocus("up");
|
|
120
|
+
} else if (isDown) {
|
|
121
|
+
moveFocus("down");
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
const stableHandler = useCallback((input, key) => {
|
|
125
|
+
handlerRef.current?.(input, key);
|
|
126
|
+
}, []);
|
|
127
|
+
useInput(stableHandler);
|
|
140
128
|
}
|
|
141
129
|
|
|
142
130
|
// src/cli/components/wizard/category-grid.tsx
|
|
@@ -167,13 +155,14 @@ var findNextValidOption = (options, currentIndex, direction, wrap = true) => {
|
|
|
167
155
|
}
|
|
168
156
|
return index;
|
|
169
157
|
};
|
|
170
|
-
var
|
|
171
|
-
if (
|
|
172
|
-
if (state === "
|
|
173
|
-
if (state === "
|
|
158
|
+
var getCompatibilityLabel = (option, isLocked) => {
|
|
159
|
+
if (option.selected) return "(selected)";
|
|
160
|
+
if (isLocked || option.state === "disabled") return "(disabled)";
|
|
161
|
+
if (option.state === "recommended") return "(recommended)";
|
|
162
|
+
if (option.state === "discouraged") return "(discouraged)";
|
|
174
163
|
return null;
|
|
175
164
|
};
|
|
176
|
-
var SkillTag = ({ option, isFocused, isLocked }) => {
|
|
165
|
+
var SkillTag = ({ option, isFocused, isLocked, showLabels }) => {
|
|
177
166
|
const getTextColor = () => {
|
|
178
167
|
if (isLocked || option.state === "disabled") return CLI_COLORS.NEUTRAL;
|
|
179
168
|
if (option.selected) return CLI_COLORS.PRIMARY;
|
|
@@ -190,7 +179,7 @@ var SkillTag = ({ option, isFocused, isLocked }) => {
|
|
|
190
179
|
};
|
|
191
180
|
const isBold = isFocused || option.selected;
|
|
192
181
|
const textColor = getTextColor();
|
|
193
|
-
const
|
|
182
|
+
const compatibilityLabel = showLabels ? getCompatibilityLabel(option, isLocked) : null;
|
|
194
183
|
return /* @__PURE__ */ jsx(
|
|
195
184
|
Box,
|
|
196
185
|
{
|
|
@@ -198,18 +187,17 @@ var SkillTag = ({ option, isFocused, isLocked }) => {
|
|
|
198
187
|
borderColor: isFocused ? getStateBorderColor() : CLI_COLORS.NEUTRAL,
|
|
199
188
|
borderStyle: "single",
|
|
200
189
|
borderDimColor: !isFocused,
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
/* @__PURE__ */ jsx(Text, { backgroundColor: CLI_COLORS.NEUTRAL, children: " L " }),
|
|
205
|
-
" "
|
|
206
|
-
] }),
|
|
207
|
-
option.label,
|
|
208
|
-
stateSuffix && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
190
|
+
flexShrink: 0,
|
|
191
|
+
children: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
192
|
+
/* @__PURE__ */ jsxs(Text, { color: textColor, bold: isBold, dimColor: false, children: [
|
|
209
193
|
" ",
|
|
210
|
-
|
|
194
|
+
option.label,
|
|
195
|
+
" "
|
|
211
196
|
] }),
|
|
212
|
-
|
|
197
|
+
compatibilityLabel && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
198
|
+
compatibilityLabel,
|
|
199
|
+
" "
|
|
200
|
+
] })
|
|
213
201
|
] })
|
|
214
202
|
}
|
|
215
203
|
);
|
|
@@ -220,7 +208,7 @@ var CategorySection = ({
|
|
|
220
208
|
isLocked,
|
|
221
209
|
isFocused,
|
|
222
210
|
focusedOptionIndex,
|
|
223
|
-
|
|
211
|
+
showLabels
|
|
224
212
|
}) => {
|
|
225
213
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
226
214
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
|
|
@@ -230,31 +218,30 @@ var CategorySection = ({
|
|
|
230
218
|
SYMBOL_REQUIRED
|
|
231
219
|
] })
|
|
232
220
|
] }),
|
|
233
|
-
/* @__PURE__ */ jsx(Box, { flexDirection: "row", flexWrap: "wrap", marginTop: 0, children: options.map((option, index) => /* @__PURE__ */
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
] }, option.id)) })
|
|
221
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "row", flexWrap: "wrap", marginTop: 0, children: options.map((option, index) => /* @__PURE__ */ jsx(
|
|
222
|
+
SkillTag,
|
|
223
|
+
{
|
|
224
|
+
option,
|
|
225
|
+
isFocused: isFocused && index === focusedOptionIndex && !isLocked,
|
|
226
|
+
isLocked,
|
|
227
|
+
showLabels
|
|
228
|
+
},
|
|
229
|
+
option.id
|
|
230
|
+
)) })
|
|
244
231
|
] });
|
|
245
232
|
};
|
|
246
233
|
var CategoryGrid = ({
|
|
247
234
|
categories,
|
|
248
235
|
availableHeight = 0,
|
|
249
|
-
|
|
236
|
+
showLabels,
|
|
250
237
|
expertMode,
|
|
251
238
|
onToggle,
|
|
252
|
-
|
|
239
|
+
onToggleLabels,
|
|
253
240
|
defaultFocusedRow = 0,
|
|
254
241
|
defaultFocusedCol = 0,
|
|
255
242
|
onFocusChange
|
|
256
243
|
}) => {
|
|
257
|
-
const initialOrderRef =
|
|
244
|
+
const initialOrderRef = useRef2(/* @__PURE__ */ new Map());
|
|
258
245
|
const processedCategories = useMemo(
|
|
259
246
|
() => categories.map((category) => {
|
|
260
247
|
const cached = initialOrderRef.current.get(category.id);
|
|
@@ -316,9 +303,9 @@ var CategoryGrid = ({
|
|
|
316
303
|
setFocused,
|
|
317
304
|
moveFocus,
|
|
318
305
|
onToggle,
|
|
319
|
-
|
|
306
|
+
onToggleLabels
|
|
320
307
|
});
|
|
321
|
-
const sectionRefs =
|
|
308
|
+
const sectionRefs = useRef2([]);
|
|
322
309
|
const [sectionHeights, setSectionHeights] = useState([]);
|
|
323
310
|
const [scrollTopPx, setScrollTopPx] = useState(0);
|
|
324
311
|
const setSectionRef = useCallback2((index, el) => {
|
|
@@ -371,7 +358,7 @@ var CategoryGrid = ({
|
|
|
371
358
|
isLocked,
|
|
372
359
|
isFocused: index === focusedRow,
|
|
373
360
|
focusedOptionIndex: focusedCol,
|
|
374
|
-
|
|
361
|
+
showLabels
|
|
375
362
|
}
|
|
376
363
|
) }, category.id);
|
|
377
364
|
});
|
|
@@ -384,4 +371,4 @@ var CategoryGrid = ({
|
|
|
384
371
|
export {
|
|
385
372
|
CategoryGrid
|
|
386
373
|
};
|
|
387
|
-
//# sourceMappingURL=chunk-
|
|
374
|
+
//# sourceMappingURL=chunk-GEDWVX6Y.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 (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 // Normal unselected: muted color to clearly contrast with selected (cyan) skills\n return CLI_COLORS.NEUTRAL;\n };\n\n const getStateBorderColor = (): string => {\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 isBold = isFocused || option.selected;\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 borderDimColor={!isFocused}\n flexShrink={0}\n >\n <>\n <Text color={textColor} bold={isBold} dimColor={false}>\n {\" \"}\n {option.label}{\" \"}\n </Text>\n {compatibilityLabel && <Text dimColor>{compatibilityLabel} </Text>}\n </>\n </Box>\n );\n};\n\ntype CategorySectionProps = {\n category: CategoryRow;\n options: CategoryOption[];\n isLocked: boolean;\n isFocused: boolean;\n focusedOptionIndex: number;\n showLabels: boolean;\n};\n\nconst CategorySection: React.FC<CategorySectionProps> = ({\n category,\n options,\n isLocked,\n isFocused,\n focusedOptionIndex,\n showLabels,\n}) => {\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n <Box flexDirection=\"row\">\n <Text dimColor={isLocked}>{category.displayName}</Text>\n {category.required && (\n <Text color={isLocked ? CLI_COLORS.NEUTRAL : CLI_COLORS.ERROR} dimColor={isLocked}>\n {\" \"}\n {SYMBOL_REQUIRED}\n </Text>\n )}\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 />\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"]}
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
|
|
6
6
|
// src/cli/components/hooks/use-focused-list-item.ts
|
|
7
7
|
init_esm_shims();
|
|
8
|
-
import { useState, useCallback,
|
|
8
|
+
import { useState, useCallback, useRef } from "react";
|
|
9
9
|
function useFocusedListItem(rowCount, getColCount, options = {}) {
|
|
10
10
|
const {
|
|
11
11
|
wrap = true,
|
|
@@ -19,17 +19,11 @@ function useFocusedListItem(rowCount, getColCount, options = {}) {
|
|
|
19
19
|
const [focusedRow, setFocusedRow] = useState(initialRow);
|
|
20
20
|
const [focusedCol, setFocusedCol] = useState(initialCol);
|
|
21
21
|
const focusedRowRef = useRef(focusedRow);
|
|
22
|
+
focusedRowRef.current = focusedRow;
|
|
22
23
|
const focusedColRef = useRef(focusedCol);
|
|
24
|
+
focusedColRef.current = focusedCol;
|
|
23
25
|
const onChangeRef = useRef(onChange);
|
|
24
|
-
|
|
25
|
-
focusedRowRef.current = focusedRow;
|
|
26
|
-
}, [focusedRow]);
|
|
27
|
-
useEffect(() => {
|
|
28
|
-
focusedColRef.current = focusedCol;
|
|
29
|
-
}, [focusedCol]);
|
|
30
|
-
useEffect(() => {
|
|
31
|
-
onChangeRef.current = onChange;
|
|
32
|
-
}, [onChange]);
|
|
26
|
+
onChangeRef.current = onChange;
|
|
33
27
|
const applyFocus = useCallback((row, col) => {
|
|
34
28
|
setFocusedRow(row);
|
|
35
29
|
setFocusedCol(col);
|
|
@@ -102,4 +96,4 @@ function useFocusedListItem(rowCount, getColCount, options = {}) {
|
|
|
102
96
|
export {
|
|
103
97
|
useFocusedListItem
|
|
104
98
|
};
|
|
105
|
-
//# sourceMappingURL=chunk-
|
|
99
|
+
//# sourceMappingURL=chunk-GG4BSB6S.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/components/hooks/use-focused-list-item.ts"],"sourcesContent":["import { useState, useCallback, useRef } from \"react\";\n\ntype Direction = \"up\" | \"down\" | \"left\" | \"right\";\n\ntype UseFocusedListItemOptions = {\n /** Wrap around when reaching boundaries (default: true) */\n wrap?: boolean;\n /** Returns true if a row should be skipped during vertical navigation */\n isRowLocked?: (row: number) => boolean;\n /** Custom column finder for skipping disabled items on horizontal nav.\n * Receives the row, current column, and direction (+1 right, -1 left).\n * Should return the next valid column index. */\n findValidCol?: (row: number, currentCol: number, direction: 1 | -1) => number;\n /** Called after vertical navigation to adjust the clamped column\n * (e.g. to skip disabled items). Returns the adjusted column index. */\n adjustCol?: (row: number, clampedCol: number) => number;\n /** Called whenever focused position changes */\n onChange?: (row: number, col: number) => void;\n /** Initial row index (default: 0) */\n initialRow?: number;\n /** Initial col index (default: 0) */\n initialCol?: number;\n};\n\ntype UseFocusedListItemResult = {\n focusedRow: number;\n focusedCol: number;\n setFocused: (row: number, col: number) => void;\n moveFocus: (direction: Direction) => void;\n};\n\n/**\n * 2D grid focus management: tracks (row, col) position and handles\n * directional movement with wrapping, column clamping, row locking,\n * and optional disabled-column skipping.\n */\nexport function useFocusedListItem(\n rowCount: number,\n getColCount: (row: number) => number,\n options: UseFocusedListItemOptions = {},\n): UseFocusedListItemResult {\n const {\n wrap = true,\n isRowLocked,\n findValidCol,\n adjustCol,\n onChange,\n initialRow = 0,\n initialCol = 0,\n } = options;\n\n const [focusedRow, setFocusedRow] = useState(initialRow);\n const [focusedCol, setFocusedCol] = useState(initialCol);\n\n // Refs for stable callback access without stale closures.\n // Synced during render (not via useEffect) to prevent a timing gap where\n // the ref holds stale values when an input event arrives between render\n // and effect execution (e.g. after a domain-switch remount).\n const focusedRowRef = useRef(focusedRow);\n focusedRowRef.current = focusedRow;\n\n const focusedColRef = useRef(focusedCol);\n focusedColRef.current = focusedCol;\n\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n const applyFocus = useCallback((row: number, col: number) => {\n setFocusedRow(row);\n setFocusedCol(col);\n onChangeRef.current?.(row, col);\n }, []);\n\n const setFocused = applyFocus;\n\n const findNextUnlockedRow = useCallback(\n (fromRow: number, direction: 1 | -1): number => {\n if (!isRowLocked || rowCount === 0) {\n if (wrap) {\n return (fromRow + direction + rowCount) % rowCount;\n }\n const next = fromRow + direction;\n return Math.max(0, Math.min(rowCount - 1, next));\n }\n\n let index = fromRow;\n let attempts = 0;\n\n while (attempts < rowCount) {\n index += direction;\n\n if (wrap) {\n if (index < 0) index = rowCount - 1;\n if (index >= rowCount) index = 0;\n } else {\n if (index < 0) index = 0;\n if (index >= rowCount) index = rowCount - 1;\n }\n\n if (!isRowLocked(index)) {\n return index;\n }\n\n attempts++;\n }\n\n return fromRow;\n },\n [rowCount, wrap, isRowLocked],\n );\n\n const moveFocus = useCallback(\n (direction: Direction) => {\n const currentRow = focusedRowRef.current;\n const currentCol = focusedColRef.current;\n\n if (direction === \"left\" || direction === \"right\") {\n const colCount = getColCount(currentRow);\n if (colCount === 0) return;\n\n const step = direction === \"right\" ? 1 : -1;\n\n if (findValidCol) {\n const newCol = findValidCol(currentRow, currentCol, step);\n applyFocus(currentRow, newCol);\n } else if (wrap) {\n const newCol = (currentCol + step + colCount) % colCount;\n applyFocus(currentRow, newCol);\n } else {\n const newCol = Math.max(0, Math.min(colCount - 1, currentCol + step));\n applyFocus(currentRow, newCol);\n }\n } else {\n const step = direction === \"down\" ? 1 : -1;\n const newRow = findNextUnlockedRow(currentRow, step);\n const newRowColCount = getColCount(newRow);\n let finalCol = Math.min(currentCol, Math.max(0, newRowColCount - 1));\n\n if (adjustCol) {\n finalCol = adjustCol(newRow, finalCol);\n }\n\n applyFocus(newRow, finalCol);\n }\n },\n [getColCount, wrap, findValidCol, adjustCol, findNextUnlockedRow, applyFocus],\n );\n\n return { focusedRow, focusedCol, setFocused, moveFocus };\n}\n"],"mappings":";;;;;;AAAA;AAAA,SAAS,UAAU,aAAa,cAAc;AAoCvC,SAAS,mBACd,UACA,aACA,UAAqC,CAAC,GACZ;AAC1B,QAAM;AAAA,IACJ,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa;AAAA,IACb,aAAa;AAAA,EACf,IAAI;AAEJ,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,UAAU;AACvD,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,UAAU;AAMvD,QAAM,gBAAgB,OAAO,UAAU;AACvC,gBAAc,UAAU;AAExB,QAAM,gBAAgB,OAAO,UAAU;AACvC,gBAAc,UAAU;AAExB,QAAM,cAAc,OAAO,QAAQ;AACnC,cAAY,UAAU;AAEtB,QAAM,aAAa,YAAY,CAAC,KAAa,QAAgB;AAC3D,kBAAc,GAAG;AACjB,kBAAc,GAAG;AACjB,gBAAY,UAAU,KAAK,GAAG;AAAA,EAChC,GAAG,CAAC,CAAC;AAEL,QAAM,aAAa;AAEnB,QAAM,sBAAsB;AAAA,IAC1B,CAAC,SAAiB,cAA8B;AAC9C,UAAI,CAAC,eAAe,aAAa,GAAG;AAClC,YAAI,MAAM;AACR,kBAAQ,UAAU,YAAY,YAAY;AAAA,QAC5C;AACA,cAAM,OAAO,UAAU;AACvB,eAAO,KAAK,IAAI,GAAG,KAAK,IAAI,WAAW,GAAG,IAAI,CAAC;AAAA,MACjD;AAEA,UAAI,QAAQ;AACZ,UAAI,WAAW;AAEf,aAAO,WAAW,UAAU;AAC1B,iBAAS;AAET,YAAI,MAAM;AACR,cAAI,QAAQ,EAAG,SAAQ,WAAW;AAClC,cAAI,SAAS,SAAU,SAAQ;AAAA,QACjC,OAAO;AACL,cAAI,QAAQ,EAAG,SAAQ;AACvB,cAAI,SAAS,SAAU,SAAQ,WAAW;AAAA,QAC5C;AAEA,YAAI,CAAC,YAAY,KAAK,GAAG;AACvB,iBAAO;AAAA,QACT;AAEA;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,UAAU,MAAM,WAAW;AAAA,EAC9B;AAEA,QAAM,YAAY;AAAA,IAChB,CAAC,cAAyB;AACxB,YAAM,aAAa,cAAc;AACjC,YAAM,aAAa,cAAc;AAEjC,UAAI,cAAc,UAAU,cAAc,SAAS;AACjD,cAAM,WAAW,YAAY,UAAU;AACvC,YAAI,aAAa,EAAG;AAEpB,cAAM,OAAO,cAAc,UAAU,IAAI;AAEzC,YAAI,cAAc;AAChB,gBAAM,SAAS,aAAa,YAAY,YAAY,IAAI;AACxD,qBAAW,YAAY,MAAM;AAAA,QAC/B,WAAW,MAAM;AACf,gBAAM,UAAU,aAAa,OAAO,YAAY;AAChD,qBAAW,YAAY,MAAM;AAAA,QAC/B,OAAO;AACL,gBAAM,SAAS,KAAK,IAAI,GAAG,KAAK,IAAI,WAAW,GAAG,aAAa,IAAI,CAAC;AACpE,qBAAW,YAAY,MAAM;AAAA,QAC/B;AAAA,MACF,OAAO;AACL,cAAM,OAAO,cAAc,SAAS,IAAI;AACxC,cAAM,SAAS,oBAAoB,YAAY,IAAI;AACnD,cAAM,iBAAiB,YAAY,MAAM;AACzC,YAAI,WAAW,KAAK,IAAI,YAAY,KAAK,IAAI,GAAG,iBAAiB,CAAC,CAAC;AAEnE,YAAI,WAAW;AACb,qBAAW,UAAU,QAAQ,QAAQ;AAAA,QACvC;AAEA,mBAAW,QAAQ,QAAQ;AAAA,MAC7B;AAAA,IACF;AAAA,IACA,CAAC,aAAa,MAAM,cAAc,WAAW,qBAAqB,UAAU;AAAA,EAC9E;AAEA,SAAO,EAAE,YAAY,YAAY,YAAY,UAAU;AACzD;","names":[]}
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-7SOPVGDV.js";
|
|
5
5
|
import {
|
|
6
6
|
ViewTitle
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-KXM7KOPE.js";
|
|
8
8
|
import {
|
|
9
9
|
useKeyboardNavigation
|
|
10
10
|
} from "./chunk-KUV24B5M.js";
|
|
@@ -16,14 +16,14 @@ import {
|
|
|
16
16
|
addSource,
|
|
17
17
|
getSourceSummary,
|
|
18
18
|
removeSource
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-TTXV55NQ.js";
|
|
20
20
|
import {
|
|
21
21
|
getErrorMessage,
|
|
22
22
|
verbose
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-XJXJZ2MJ.js";
|
|
24
24
|
import {
|
|
25
25
|
CLI_COLORS
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-BK7TANUV.js";
|
|
27
27
|
import {
|
|
28
28
|
init_esm_shims
|
|
29
29
|
} from "./chunk-DHET7RCE.js";
|
|
@@ -232,4 +232,4 @@ var StepSettings = ({ projectDir, onClose }) => {
|
|
|
232
232
|
export {
|
|
233
233
|
StepSettings
|
|
234
234
|
};
|
|
235
|
-
//# sourceMappingURL=chunk-
|
|
235
|
+
//# sourceMappingURL=chunk-H6H3COI5.js.map
|
|
@@ -11,14 +11,28 @@ function useMeasuredHeight() {
|
|
|
11
11
|
const ref = useRef(null);
|
|
12
12
|
const [measuredHeight, setMeasuredHeight] = useState(0);
|
|
13
13
|
const { stdout } = useStdout();
|
|
14
|
+
const measure = () => {
|
|
15
|
+
if (ref.current) {
|
|
16
|
+
const { height } = measureElement(ref.current);
|
|
17
|
+
setMeasuredHeight((prev) => prev !== height ? height : prev);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
14
20
|
useEffect(() => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
21
|
+
measure();
|
|
22
|
+
});
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
const RETRY_DELAYS_MS = [0, 16, 50];
|
|
25
|
+
const timers = [];
|
|
26
|
+
for (const delay of RETRY_DELAYS_MS) {
|
|
27
|
+
timers.push(setTimeout(measure, delay));
|
|
28
|
+
}
|
|
29
|
+
return () => {
|
|
30
|
+
for (const timer of timers) {
|
|
31
|
+
clearTimeout(timer);
|
|
19
32
|
}
|
|
20
33
|
};
|
|
21
|
-
|
|
34
|
+
}, []);
|
|
35
|
+
useEffect(() => {
|
|
22
36
|
stdout.on("resize", measure);
|
|
23
37
|
return () => {
|
|
24
38
|
stdout.off("resize", measure);
|
|
@@ -30,4 +44,4 @@ function useMeasuredHeight() {
|
|
|
30
44
|
export {
|
|
31
45
|
useMeasuredHeight
|
|
32
46
|
};
|
|
33
|
-
//# sourceMappingURL=chunk-
|
|
47
|
+
//# sourceMappingURL=chunk-K77I4XGL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/components/hooks/use-measured-height.ts"],"sourcesContent":["import { useRef, useState, useEffect } from \"react\";\nimport { type DOMElement, measureElement, useStdout } from \"ink\";\n\n/**\n * Measures the computed height of a Box element using Ink's Yoga layout engine.\n *\n * Returns a ref to attach to a Box with `flexGrow={1}` and the measured height.\n * The Box must be inside a parent chain with a constrained height (e.g., an\n * explicit `height` prop on an ancestor) so Yoga can compute the remaining space.\n *\n * Returns 0 before the first layout pass. Re-measures on terminal resize.\n */\nexport function useMeasuredHeight(): {\n ref: React.Ref<DOMElement>;\n measuredHeight: number;\n} {\n const ref = useRef<DOMElement>(null);\n const [measuredHeight, setMeasuredHeight] = useState(0);\n const { stdout } = useStdout();\n\n const measure = () => {\n if (ref.current) {\n const { height } = measureElement(ref.current);\n setMeasuredHeight((prev) => (prev !== height ? height : prev));\n }\n };\n\n // Re-measure after every render so late-mounted refs (e.g., Sources\n // step switching from \"choice\" to \"customize\" view) get picked up.\n // The state setter avoids unnecessary updates when height is unchanged.\n useEffect(() => {\n measure();\n });\n\n // Yoga may not have computed the layout on the first render, so\n // measureElement() returns 0. Retry with increasing delays to give\n // Yoga time to resolve the full flex constraint chain.\n useEffect(() => {\n const RETRY_DELAYS_MS = [0, 16, 50];\n const timers: ReturnType<typeof setTimeout>[] = [];\n\n for (const delay of RETRY_DELAYS_MS) {\n timers.push(setTimeout(measure, delay));\n }\n\n return () => {\n for (const timer of timers) {\n clearTimeout(timer);\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n stdout.on(\"resize\", measure);\n return () => {\n stdout.off(\"resize\", measure);\n };\n }, [stdout]);\n\n return { ref, measuredHeight };\n}\n"],"mappings":";;;;;;AAAA;AAAA,SAAS,QAAQ,UAAU,iBAAiB;AAC5C,SAA0B,gBAAgB,iBAAiB;AAWpD,SAAS,oBAGd;AACA,QAAM,MAAM,OAAmB,IAAI;AACnC,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAS,CAAC;AACtD,QAAM,EAAE,OAAO,IAAI,UAAU;AAE7B,QAAM,UAAU,MAAM;AACpB,QAAI,IAAI,SAAS;AACf,YAAM,EAAE,OAAO,IAAI,eAAe,IAAI,OAAO;AAC7C,wBAAkB,CAAC,SAAU,SAAS,SAAS,SAAS,IAAK;AAAA,IAC/D;AAAA,EACF;AAKA,YAAU,MAAM;AACd,YAAQ;AAAA,EACV,CAAC;AAKD,YAAU,MAAM;AACd,UAAM,kBAAkB,CAAC,GAAG,IAAI,EAAE;AAClC,UAAM,SAA0C,CAAC;AAEjD,eAAW,SAAS,iBAAiB;AACnC,aAAO,KAAK,WAAW,SAAS,KAAK,CAAC;AAAA,IACxC;AAEA,WAAO,MAAM;AACX,iBAAW,SAAS,QAAQ;AAC1B,qBAAa,KAAK;AAAA,MACpB;AAAA,IACF;AAAA,EAEF,GAAG,CAAC,CAAC;AAEL,YAAU,MAAM;AACd,WAAO,GAAG,UAAU,OAAO;AAC3B,WAAO,MAAM;AACX,aAAO,IAAI,UAAU,OAAO;AAAA,IAC9B;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAEX,SAAO,EAAE,KAAK,eAAe;AAC/B;","names":[]}
|