@claude-collective/cli 0.2.0 → 0.8.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.
Files changed (190) hide show
  1. package/CHANGELOG.md +178 -0
  2. package/README.md +1 -1
  3. package/dist/chunk-3HBTELJN.js +114 -0
  4. package/dist/chunk-3HBTELJN.js.map +1 -0
  5. package/dist/chunk-3ZCB5K33.js +54 -0
  6. package/dist/chunk-3ZCB5K33.js.map +1 -0
  7. package/dist/chunk-66UDJBF6.js +96 -0
  8. package/dist/chunk-66UDJBF6.js.map +1 -0
  9. package/dist/chunk-6LS7XO3H.js +31 -0
  10. package/dist/chunk-6LS7XO3H.js.map +1 -0
  11. package/dist/chunk-A3J6IAXK.js +57 -0
  12. package/dist/chunk-A3J6IAXK.js.map +1 -0
  13. package/dist/chunk-A65SBAAJ.js +69 -0
  14. package/dist/chunk-A65SBAAJ.js.map +1 -0
  15. package/dist/chunk-ALEPJ6YN.js +80 -0
  16. package/dist/chunk-ALEPJ6YN.js.map +1 -0
  17. package/dist/chunk-C4ZTIYFR.js +84 -0
  18. package/dist/chunk-C4ZTIYFR.js.map +1 -0
  19. package/dist/chunk-CIY5UBRB.js +453 -0
  20. package/dist/chunk-CIY5UBRB.js.map +1 -0
  21. package/dist/chunk-DHET7RCE.js +50 -0
  22. package/dist/chunk-DHET7RCE.js.map +1 -0
  23. package/dist/chunk-DHFFRMF6.js +31 -0
  24. package/dist/chunk-DHFFRMF6.js.map +1 -0
  25. package/dist/chunk-DKGL77IY.js +307 -0
  26. package/dist/chunk-DKGL77IY.js.map +1 -0
  27. package/dist/chunk-ED73HCW2.js +315 -0
  28. package/dist/chunk-ED73HCW2.js.map +1 -0
  29. package/dist/chunk-FNOYEXUE.js +308 -0
  30. package/dist/chunk-FNOYEXUE.js.map +1 -0
  31. package/dist/chunk-G2FBJOZG.js +141 -0
  32. package/dist/chunk-G2FBJOZG.js.map +1 -0
  33. package/dist/chunk-HNDT5QRB.js +120 -0
  34. package/dist/chunk-HNDT5QRB.js.map +1 -0
  35. package/dist/chunk-K7PTOVX4.js +158 -0
  36. package/dist/chunk-K7PTOVX4.js.map +1 -0
  37. package/dist/chunk-LQTST4WY.js +91 -0
  38. package/dist/chunk-LQTST4WY.js.map +1 -0
  39. package/dist/chunk-LVKRVFYR.js +54 -0
  40. package/dist/chunk-LVKRVFYR.js.map +1 -0
  41. package/dist/chunk-M7YCPFIX.js +108 -0
  42. package/dist/chunk-M7YCPFIX.js.map +1 -0
  43. package/dist/chunk-MJSFR562.js +57 -0
  44. package/dist/chunk-MJSFR562.js.map +1 -0
  45. package/dist/chunk-MMDXNZPF.js +69 -0
  46. package/dist/chunk-MMDXNZPF.js.map +1 -0
  47. package/dist/chunk-MYAVQ23U.js +356 -0
  48. package/dist/chunk-MYAVQ23U.js.map +1 -0
  49. package/dist/chunk-NGBFJJ7Q.js +124 -0
  50. package/dist/chunk-NGBFJJ7Q.js.map +1 -0
  51. package/dist/chunk-OLBOTK3O.js +64 -0
  52. package/dist/chunk-OLBOTK3O.js.map +1 -0
  53. package/dist/chunk-PPNTD5LO.js +330 -0
  54. package/dist/chunk-PPNTD5LO.js.map +1 -0
  55. package/dist/chunk-Q2LH2DAB.js +392 -0
  56. package/dist/chunk-Q2LH2DAB.js.map +1 -0
  57. package/dist/chunk-Q6DR5QUH.js +547 -0
  58. package/dist/chunk-Q6DR5QUH.js.map +1 -0
  59. package/dist/chunk-QESUUPOE.js +241 -0
  60. package/dist/chunk-QESUUPOE.js.map +1 -0
  61. package/dist/chunk-QGGSLMO3.js +607 -0
  62. package/dist/chunk-QGGSLMO3.js.map +1 -0
  63. package/dist/chunk-SEBPPFUW.js +478 -0
  64. package/dist/chunk-SEBPPFUW.js.map +1 -0
  65. package/dist/chunk-SYQ7R2JO.js +95 -0
  66. package/dist/chunk-SYQ7R2JO.js.map +1 -0
  67. package/dist/chunk-TOPAIL5W.js +22 -0
  68. package/dist/chunk-TOPAIL5W.js.map +1 -0
  69. package/dist/chunk-U4VYHKPM.js +110 -0
  70. package/dist/chunk-U4VYHKPM.js.map +1 -0
  71. package/dist/chunk-UOWHJ6BE.js +83 -0
  72. package/dist/chunk-UOWHJ6BE.js.map +1 -0
  73. package/dist/chunk-XKEG3SCV.js +86 -0
  74. package/dist/chunk-XKEG3SCV.js.map +1 -0
  75. package/dist/chunk-XY3XDVMI.js +15599 -0
  76. package/dist/chunk-XY3XDVMI.js.map +1 -0
  77. package/dist/chunk-Y3V43XCU.js +76 -0
  78. package/dist/chunk-Y3V43XCU.js.map +1 -0
  79. package/dist/chunk-YKXBGCFD.js +129 -0
  80. package/dist/chunk-YKXBGCFD.js.map +1 -0
  81. package/dist/cli-v2/defaults/agent-mappings.yaml +185 -0
  82. package/dist/commands/build/marketplace.js +254 -0
  83. package/dist/commands/build/marketplace.js.map +1 -0
  84. package/dist/commands/build/plugins.js +324 -0
  85. package/dist/commands/build/plugins.js.map +1 -0
  86. package/dist/commands/build/stack.js +169 -0
  87. package/dist/commands/build/stack.js.map +1 -0
  88. package/dist/commands/compile.js +461 -0
  89. package/dist/commands/compile.js.map +1 -0
  90. package/dist/commands/config/get.js +60 -0
  91. package/dist/commands/config/get.js.map +1 -0
  92. package/dist/commands/config/index.js +22 -0
  93. package/dist/commands/config/index.js.map +1 -0
  94. package/dist/commands/config/path.js +35 -0
  95. package/dist/commands/config/path.js.map +1 -0
  96. package/dist/commands/config/set-project.js +61 -0
  97. package/dist/commands/config/set-project.js.map +1 -0
  98. package/dist/commands/config/set.js +60 -0
  99. package/dist/commands/config/set.js.map +1 -0
  100. package/dist/commands/config/show.js +13 -0
  101. package/dist/commands/config/show.js.map +1 -0
  102. package/dist/commands/config/unset-project.js +57 -0
  103. package/dist/commands/config/unset-project.js.map +1 -0
  104. package/dist/commands/config/unset.js +56 -0
  105. package/dist/commands/config/unset.js.map +1 -0
  106. package/dist/commands/diff.js +755 -0
  107. package/dist/commands/diff.js.map +1 -0
  108. package/dist/commands/doctor.js +413 -0
  109. package/dist/commands/doctor.js.map +1 -0
  110. package/dist/commands/edit.js +254 -0
  111. package/dist/commands/edit.js.map +1 -0
  112. package/dist/commands/eject.js +208 -0
  113. package/dist/commands/eject.js.map +1 -0
  114. package/dist/commands/info.js +205 -0
  115. package/dist/commands/info.js.map +1 -0
  116. package/dist/commands/init.js +915 -0
  117. package/dist/commands/init.js.map +1 -0
  118. package/dist/commands/list.js +44 -0
  119. package/dist/commands/list.js.map +1 -0
  120. package/dist/commands/new/agent.js +230 -0
  121. package/dist/commands/new/agent.js.map +1 -0
  122. package/dist/commands/new/skill.js +204 -0
  123. package/dist/commands/new/skill.js.map +1 -0
  124. package/dist/commands/outdated.js +242 -0
  125. package/dist/commands/outdated.js.map +1 -0
  126. package/dist/commands/search.js +115 -0
  127. package/dist/commands/search.js.map +1 -0
  128. package/dist/commands/test-imports.js +92 -0
  129. package/dist/commands/test-imports.js.map +1 -0
  130. package/dist/commands/uninstall.js +309 -0
  131. package/dist/commands/uninstall.js.map +1 -0
  132. package/dist/commands/update.js +428 -0
  133. package/dist/commands/update.js.map +1 -0
  134. package/dist/commands/validate.js +375 -0
  135. package/dist/commands/validate.js.map +1 -0
  136. package/dist/commands/version/bump.js +95 -0
  137. package/dist/commands/version/bump.js.map +1 -0
  138. package/dist/commands/version/index.js +70 -0
  139. package/dist/commands/version/index.js.map +1 -0
  140. package/dist/commands/version/set.js +101 -0
  141. package/dist/commands/version/set.js.map +1 -0
  142. package/dist/commands/version/show.js +70 -0
  143. package/dist/commands/version/show.js.map +1 -0
  144. package/dist/components/common/confirm.js +9 -0
  145. package/dist/components/common/confirm.js.map +1 -0
  146. package/dist/components/common/message.js +24 -0
  147. package/dist/components/common/message.js.map +1 -0
  148. package/dist/components/common/spinner.js +14 -0
  149. package/dist/components/common/spinner.js.map +1 -0
  150. package/dist/components/wizard/category-grid.js +9 -0
  151. package/dist/components/wizard/category-grid.js.map +1 -0
  152. package/dist/components/wizard/category-grid.test.js +728 -0
  153. package/dist/components/wizard/category-grid.test.js.map +1 -0
  154. package/dist/components/wizard/section-progress.js +9 -0
  155. package/dist/components/wizard/section-progress.js.map +1 -0
  156. package/dist/components/wizard/section-progress.test.js +281 -0
  157. package/dist/components/wizard/section-progress.test.js.map +1 -0
  158. package/dist/components/wizard/step-approach.js +11 -0
  159. package/dist/components/wizard/step-approach.js.map +1 -0
  160. package/dist/components/wizard/step-build.js +15 -0
  161. package/dist/components/wizard/step-build.js.map +1 -0
  162. package/dist/components/wizard/step-build.test.js +729 -0
  163. package/dist/components/wizard/step-build.test.js.map +1 -0
  164. package/dist/components/wizard/step-confirm.js +9 -0
  165. package/dist/components/wizard/step-confirm.js.map +1 -0
  166. package/dist/components/wizard/step-refine.js +9 -0
  167. package/dist/components/wizard/step-refine.js.map +1 -0
  168. package/dist/components/wizard/step-refine.test.js +235 -0
  169. package/dist/components/wizard/step-refine.test.js.map +1 -0
  170. package/dist/components/wizard/step-stack-options.js +11 -0
  171. package/dist/components/wizard/step-stack-options.js.map +1 -0
  172. package/dist/components/wizard/step-stack.js +11 -0
  173. package/dist/components/wizard/step-stack.js.map +1 -0
  174. package/dist/components/wizard/wizard-tabs.js +11 -0
  175. package/dist/components/wizard/wizard-tabs.js.map +1 -0
  176. package/dist/components/wizard/wizard.js +20 -0
  177. package/dist/components/wizard/wizard.js.map +1 -0
  178. package/dist/hooks/init.js +41 -0
  179. package/dist/hooks/init.js.map +1 -0
  180. package/dist/index.js +10 -0
  181. package/dist/index.js.map +1 -0
  182. package/dist/magic-string.es-RGXYGAW3.js +1316 -0
  183. package/dist/magic-string.es-RGXYGAW3.js.map +1 -0
  184. package/dist/stores/wizard-store.js +10 -0
  185. package/dist/stores/wizard-store.js.map +1 -0
  186. package/dist/stores/wizard-store.test.js +405 -0
  187. package/dist/stores/wizard-store.test.js.map +1 -0
  188. package/package.json +44 -25
  189. package/dist/cli/index.js +0 -6314
  190. package/dist/cli/index.js.map +0 -1
@@ -0,0 +1,547 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ SectionProgress
4
+ } from "./chunk-LVKRVFYR.js";
5
+ import {
6
+ CategoryGrid
7
+ } from "./chunk-PPNTD5LO.js";
8
+ import {
9
+ init_esm_shims
10
+ } from "./chunk-DHET7RCE.js";
11
+
12
+ // src/cli-v2/components/wizard/step-build.tsx
13
+ init_esm_shims();
14
+ import { useState } from "react";
15
+ import { Box, Text, useInput } from "ink";
16
+
17
+ // src/cli-v2/lib/matrix-resolver.ts
18
+ init_esm_shims();
19
+ function resolveAlias(aliasOrId, matrix) {
20
+ return matrix.aliases[aliasOrId] || aliasOrId;
21
+ }
22
+ function isDisabled(skillId, currentSelections, matrix, options) {
23
+ if (options?.expertMode) {
24
+ return false;
25
+ }
26
+ const fullId = resolveAlias(skillId, matrix);
27
+ const skill = matrix.skills[fullId];
28
+ if (!skill) {
29
+ return false;
30
+ }
31
+ for (const selectedId of currentSelections) {
32
+ const selectedFullId = resolveAlias(selectedId, matrix);
33
+ if (skill.conflictsWith.some((c) => c.skillId === selectedFullId)) {
34
+ return true;
35
+ }
36
+ const selectedSkill = matrix.skills[selectedFullId];
37
+ if (selectedSkill && selectedSkill.conflictsWith.some((c) => c.skillId === fullId)) {
38
+ return true;
39
+ }
40
+ }
41
+ const resolvedSelections = currentSelections.map(
42
+ (s) => resolveAlias(s, matrix)
43
+ );
44
+ for (const requirement of skill.requires) {
45
+ if (requirement.needsAny) {
46
+ const hasAny = requirement.skillIds.some(
47
+ (reqId) => resolvedSelections.includes(reqId)
48
+ );
49
+ if (!hasAny) {
50
+ return true;
51
+ }
52
+ } else {
53
+ const hasAll = requirement.skillIds.every(
54
+ (reqId) => resolvedSelections.includes(reqId)
55
+ );
56
+ if (!hasAll) {
57
+ return true;
58
+ }
59
+ }
60
+ }
61
+ return false;
62
+ }
63
+ function getDisableReason(skillId, currentSelections, matrix) {
64
+ const fullId = resolveAlias(skillId, matrix);
65
+ const skill = matrix.skills[fullId];
66
+ if (!skill) {
67
+ return void 0;
68
+ }
69
+ const resolvedSelections = currentSelections.map(
70
+ (s) => resolveAlias(s, matrix)
71
+ );
72
+ for (const selectedId of resolvedSelections) {
73
+ const conflict = skill.conflictsWith.find((c) => c.skillId === selectedId);
74
+ if (conflict) {
75
+ const selectedSkill2 = matrix.skills[selectedId];
76
+ const selectedName = selectedSkill2?.name || selectedId;
77
+ return `${conflict.reason} (conflicts with ${selectedName})`;
78
+ }
79
+ const selectedSkill = matrix.skills[selectedId];
80
+ if (selectedSkill) {
81
+ const reverseConflict = selectedSkill.conflictsWith.find(
82
+ (c) => c.skillId === fullId
83
+ );
84
+ if (reverseConflict) {
85
+ const selectedName = selectedSkill.name;
86
+ return `${reverseConflict.reason} (conflicts with ${selectedName})`;
87
+ }
88
+ }
89
+ }
90
+ for (const requirement of skill.requires) {
91
+ if (requirement.needsAny) {
92
+ const hasAny = requirement.skillIds.some(
93
+ (reqId) => resolvedSelections.includes(reqId)
94
+ );
95
+ if (!hasAny) {
96
+ const requiredNames = requirement.skillIds.map((id) => matrix.skills[id]?.name || id).join(" or ");
97
+ return `${requirement.reason} (requires ${requiredNames})`;
98
+ }
99
+ } else {
100
+ const missingIds = requirement.skillIds.filter(
101
+ (reqId) => !resolvedSelections.includes(reqId)
102
+ );
103
+ if (missingIds.length > 0) {
104
+ const missingNames = missingIds.map((id) => matrix.skills[id]?.name || id).join(", ");
105
+ return `${requirement.reason} (requires ${missingNames})`;
106
+ }
107
+ }
108
+ }
109
+ return void 0;
110
+ }
111
+ function isDiscouraged(skillId, currentSelections, matrix) {
112
+ const fullId = resolveAlias(skillId, matrix);
113
+ const skill = matrix.skills[fullId];
114
+ if (!skill) {
115
+ return false;
116
+ }
117
+ const resolvedSelections = currentSelections.map(
118
+ (s) => resolveAlias(s, matrix)
119
+ );
120
+ for (const selectedId of resolvedSelections) {
121
+ const selectedSkill = matrix.skills[selectedId];
122
+ if (selectedSkill && selectedSkill.discourages.some((d) => d.skillId === fullId)) {
123
+ return true;
124
+ }
125
+ if (skill.discourages.some((d) => d.skillId === selectedId)) {
126
+ return true;
127
+ }
128
+ }
129
+ return false;
130
+ }
131
+ function getDiscourageReason(skillId, currentSelections, matrix) {
132
+ const fullId = resolveAlias(skillId, matrix);
133
+ const skill = matrix.skills[fullId];
134
+ if (!skill) {
135
+ return void 0;
136
+ }
137
+ const resolvedSelections = currentSelections.map(
138
+ (s) => resolveAlias(s, matrix)
139
+ );
140
+ for (const selectedId of resolvedSelections) {
141
+ const selectedSkill = matrix.skills[selectedId];
142
+ if (selectedSkill) {
143
+ const discourage = selectedSkill.discourages.find(
144
+ (d) => d.skillId === fullId
145
+ );
146
+ if (discourage) {
147
+ return discourage.reason;
148
+ }
149
+ }
150
+ const reverseDiscourage = skill.discourages.find(
151
+ (d) => d.skillId === selectedId
152
+ );
153
+ if (reverseDiscourage) {
154
+ return reverseDiscourage.reason;
155
+ }
156
+ }
157
+ return void 0;
158
+ }
159
+ function isRecommended(skillId, currentSelections, matrix) {
160
+ const fullId = resolveAlias(skillId, matrix);
161
+ const skill = matrix.skills[fullId];
162
+ if (!skill) {
163
+ return false;
164
+ }
165
+ const resolvedSelections = currentSelections.map(
166
+ (s) => resolveAlias(s, matrix)
167
+ );
168
+ for (const selectedId of resolvedSelections) {
169
+ const selectedSkill = matrix.skills[selectedId];
170
+ if (selectedSkill && selectedSkill.recommends.some((r) => r.skillId === fullId)) {
171
+ return true;
172
+ }
173
+ }
174
+ return false;
175
+ }
176
+ function getRecommendReason(skillId, currentSelections, matrix) {
177
+ const fullId = resolveAlias(skillId, matrix);
178
+ const skill = matrix.skills[fullId];
179
+ if (!skill) {
180
+ return void 0;
181
+ }
182
+ const resolvedSelections = currentSelections.map(
183
+ (s) => resolveAlias(s, matrix)
184
+ );
185
+ for (const selectedId of resolvedSelections) {
186
+ const selectedSkill = matrix.skills[selectedId];
187
+ if (selectedSkill) {
188
+ const recommendation = selectedSkill.recommends.find(
189
+ (r) => r.skillId === fullId
190
+ );
191
+ if (recommendation) {
192
+ return `${recommendation.reason} (recommended by ${selectedSkill.name})`;
193
+ }
194
+ }
195
+ }
196
+ return void 0;
197
+ }
198
+ function validateSelection(selections, matrix) {
199
+ const errors = [];
200
+ const warnings = [];
201
+ const resolvedSelections = selections.map((s) => resolveAlias(s, matrix));
202
+ for (let i = 0; i < resolvedSelections.length; i++) {
203
+ const skillA = matrix.skills[resolvedSelections[i]];
204
+ if (!skillA) continue;
205
+ for (let j = i + 1; j < resolvedSelections.length; j++) {
206
+ const skillBId = resolvedSelections[j];
207
+ const conflict = skillA.conflictsWith.find((c) => c.skillId === skillBId);
208
+ if (conflict) {
209
+ errors.push({
210
+ type: "conflict",
211
+ message: `${skillA.name} conflicts with ${matrix.skills[skillBId]?.name || skillBId}: ${conflict.reason}`,
212
+ skills: [skillA.id, skillBId]
213
+ });
214
+ }
215
+ }
216
+ }
217
+ for (const skillId of resolvedSelections) {
218
+ const skill = matrix.skills[skillId];
219
+ if (!skill) continue;
220
+ for (const requirement of skill.requires) {
221
+ if (requirement.needsAny) {
222
+ const hasAny = requirement.skillIds.some(
223
+ (reqId) => resolvedSelections.includes(reqId)
224
+ );
225
+ if (!hasAny) {
226
+ errors.push({
227
+ type: "missing_requirement",
228
+ message: `${skill.name} requires one of: ${requirement.skillIds.map((id) => matrix.skills[id]?.name || id).join(", ")}`,
229
+ skills: [skillId, ...requirement.skillIds]
230
+ });
231
+ }
232
+ } else {
233
+ const missingIds = requirement.skillIds.filter(
234
+ (reqId) => !resolvedSelections.includes(reqId)
235
+ );
236
+ if (missingIds.length > 0) {
237
+ errors.push({
238
+ type: "missing_requirement",
239
+ message: `${skill.name} requires: ${missingIds.map((id) => matrix.skills[id]?.name || id).join(", ")}`,
240
+ skills: [skillId, ...missingIds]
241
+ });
242
+ }
243
+ }
244
+ }
245
+ }
246
+ const categorySelections = /* @__PURE__ */ new Map();
247
+ for (const skillId of resolvedSelections) {
248
+ const skill = matrix.skills[skillId];
249
+ if (!skill) continue;
250
+ const existing = categorySelections.get(skill.category) || [];
251
+ existing.push(skillId);
252
+ categorySelections.set(skill.category, existing);
253
+ }
254
+ for (const [categoryId, skillIds] of categorySelections.entries()) {
255
+ if (skillIds.length > 1) {
256
+ const category = matrix.categories[categoryId];
257
+ if (category?.exclusive) {
258
+ errors.push({
259
+ type: "category_exclusive",
260
+ message: `Category "${category.name}" only allows one selection, but multiple selected: ${skillIds.map((id) => matrix.skills[id]?.name || id).join(", ")}`,
261
+ skills: skillIds
262
+ });
263
+ }
264
+ }
265
+ }
266
+ for (const skillId of resolvedSelections) {
267
+ const skill = matrix.skills[skillId];
268
+ if (!skill) continue;
269
+ for (const recommendation of skill.recommends) {
270
+ if (!resolvedSelections.includes(recommendation.skillId)) {
271
+ const recommendedSkill = matrix.skills[recommendation.skillId];
272
+ if (recommendedSkill) {
273
+ const hasConflict = recommendedSkill.conflictsWith.some(
274
+ (c) => resolvedSelections.includes(c.skillId)
275
+ );
276
+ if (!hasConflict) {
277
+ warnings.push({
278
+ type: "missing_recommendation",
279
+ message: `${skill.name} recommends ${recommendedSkill.name}: ${recommendation.reason}`,
280
+ skills: [skillId, recommendation.skillId]
281
+ });
282
+ }
283
+ }
284
+ }
285
+ }
286
+ }
287
+ for (const skillId of resolvedSelections) {
288
+ const skill = matrix.skills[skillId];
289
+ if (!skill || skill.providesSetupFor.length === 0) continue;
290
+ const hasUsageSkill = skill.providesSetupFor.some(
291
+ (usageId) => resolvedSelections.includes(usageId)
292
+ );
293
+ if (!hasUsageSkill) {
294
+ warnings.push({
295
+ type: "unused_setup",
296
+ message: `Setup skill "${skill.name}" selected but no corresponding usage skills: ${skill.providesSetupFor.map((id) => matrix.skills[id]?.name || id).join(", ")}`,
297
+ skills: [skillId, ...skill.providesSetupFor]
298
+ });
299
+ }
300
+ }
301
+ return {
302
+ valid: errors.length === 0,
303
+ errors,
304
+ warnings
305
+ };
306
+ }
307
+ function getAvailableSkills(categoryId, currentSelections, matrix, options) {
308
+ const skillOptions = [];
309
+ const resolvedSelections = currentSelections.map(
310
+ (s) => resolveAlias(s, matrix)
311
+ );
312
+ for (const skill of Object.values(matrix.skills)) {
313
+ if (skill.category !== categoryId) {
314
+ continue;
315
+ }
316
+ const disabled = isDisabled(skill.id, currentSelections, matrix, options);
317
+ const discouraged = !disabled && isDiscouraged(skill.id, currentSelections, matrix);
318
+ const recommended = !disabled && !discouraged && isRecommended(skill.id, currentSelections, matrix);
319
+ skillOptions.push({
320
+ id: skill.id,
321
+ alias: skill.alias,
322
+ name: skill.name,
323
+ description: skill.description,
324
+ disabled,
325
+ disabledReason: disabled ? getDisableReason(skill.id, currentSelections, matrix) : void 0,
326
+ discouraged,
327
+ discouragedReason: discouraged ? getDiscourageReason(skill.id, currentSelections, matrix) : void 0,
328
+ recommended,
329
+ recommendedReason: recommended ? getRecommendReason(skill.id, currentSelections, matrix) : void 0,
330
+ selected: resolvedSelections.includes(skill.id),
331
+ alternatives: skill.alternatives.map((a) => a.skillId)
332
+ });
333
+ }
334
+ return skillOptions;
335
+ }
336
+
337
+ // src/cli-v2/components/wizard/step-build.tsx
338
+ import { jsx, jsxs } from "react/jsx-runtime";
339
+ var MIN_DOMAINS_FOR_PROGRESS = 2;
340
+ function validateBuildStep(categories, selections) {
341
+ for (const category of categories) {
342
+ if (category.required) {
343
+ const categorySelections = selections[category.id] || [];
344
+ if (categorySelections.length === 0) {
345
+ return {
346
+ valid: false,
347
+ message: `Please select a ${category.name}`
348
+ };
349
+ }
350
+ }
351
+ }
352
+ return { valid: true };
353
+ }
354
+ function computeOptionState(skill) {
355
+ if (skill.disabled) {
356
+ return "disabled";
357
+ }
358
+ if (skill.discouraged) {
359
+ return "discouraged";
360
+ }
361
+ if (skill.recommended) {
362
+ return "recommended";
363
+ }
364
+ return "normal";
365
+ }
366
+ function getDisplayLabel(skill) {
367
+ const authorPattern = /\s*\(@[^)]+\)\s*$/;
368
+ return skill.name.replace(authorPattern, "");
369
+ }
370
+ function getStateReason(skill) {
371
+ if (skill.disabled && skill.disabledReason) {
372
+ return skill.disabledReason;
373
+ }
374
+ if (skill.discouraged && skill.discouragedReason) {
375
+ return skill.discouragedReason;
376
+ }
377
+ if (skill.recommended && skill.recommendedReason) {
378
+ return skill.recommendedReason;
379
+ }
380
+ return void 0;
381
+ }
382
+ function buildCategoriesForDomain(domain, allSelections, matrix, expertMode) {
383
+ const subcategories = Object.values(matrix.categories).filter((cat) => cat.domain === domain && cat.parent).sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
384
+ const categoryRows = subcategories.map((cat) => {
385
+ const skillOptions = getAvailableSkills(cat.id, allSelections, matrix, {
386
+ expertMode
387
+ });
388
+ const options = skillOptions.map((skill) => ({
389
+ id: skill.alias || skill.id,
390
+ // Use alias for selection tracking
391
+ label: getDisplayLabel(skill),
392
+ // Clean display name without author
393
+ state: computeOptionState(skill),
394
+ stateReason: getStateReason(skill),
395
+ selected: skill.selected
396
+ }));
397
+ return {
398
+ id: cat.id,
399
+ name: cat.name,
400
+ required: cat.required ?? false,
401
+ exclusive: cat.exclusive ?? true,
402
+ options
403
+ };
404
+ });
405
+ return categoryRows;
406
+ }
407
+ function getDomainDisplayName(domain) {
408
+ const displayNames = {
409
+ web: "Web",
410
+ api: "API",
411
+ cli: "CLI",
412
+ mobile: "Mobile",
413
+ shared: "Shared"
414
+ };
415
+ return displayNames[domain] || domain.charAt(0).toUpperCase() + domain.slice(1);
416
+ }
417
+ function countSelections(categories) {
418
+ let selected = 0;
419
+ let total = 0;
420
+ for (const category of categories) {
421
+ for (const option of category.options) {
422
+ if (option.state !== "disabled") {
423
+ total++;
424
+ if (option.selected) {
425
+ selected++;
426
+ }
427
+ }
428
+ }
429
+ }
430
+ return { selected, total };
431
+ }
432
+ var Header = ({ domain, selectionCount }) => {
433
+ return /* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", marginBottom: 1, children: [
434
+ /* @__PURE__ */ jsxs(Text, { bold: true, children: [
435
+ "Configure your ",
436
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: getDomainDisplayName(domain) }),
437
+ " ",
438
+ "stack:"
439
+ ] }),
440
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
441
+ selectionCount.selected,
442
+ "/",
443
+ selectionCount.total,
444
+ " selected"
445
+ ] })
446
+ ] });
447
+ };
448
+ var Footer = ({
449
+ showContinueHint,
450
+ validationError
451
+ }) => {
452
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
453
+ validationError && /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { color: "yellow", children: validationError }) }),
454
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
455
+ "\u2190",
456
+ "/",
457
+ "\u2192",
458
+ " options ",
459
+ "\u2191",
460
+ "/",
461
+ "\u2193",
462
+ " categories SPACE select TAB descriptions E expert ENTER continue ESC back"
463
+ ] })
464
+ ] });
465
+ };
466
+ var StepBuild = ({
467
+ matrix,
468
+ domain,
469
+ selectedDomains,
470
+ currentDomainIndex,
471
+ selections,
472
+ allSelections,
473
+ focusedRow,
474
+ focusedCol,
475
+ showDescriptions,
476
+ expertMode,
477
+ onToggle,
478
+ onFocusChange,
479
+ onToggleDescriptions,
480
+ onToggleExpertMode,
481
+ onContinue,
482
+ onBack
483
+ }) => {
484
+ const [validationError, setValidationError] = useState(
485
+ void 0
486
+ );
487
+ const categories = buildCategoriesForDomain(
488
+ domain,
489
+ allSelections,
490
+ matrix,
491
+ expertMode
492
+ );
493
+ const selectionCount = countSelections(categories);
494
+ const showProgress = selectedDomains.length >= MIN_DOMAINS_FOR_PROGRESS;
495
+ const isLastDomain = currentDomainIndex === selectedDomains.length - 1;
496
+ const nextDomain = isLastDomain ? void 0 : selectedDomains[currentDomainIndex + 1];
497
+ useInput((input, key) => {
498
+ if (key.return) {
499
+ const validation = validateBuildStep(categories, selections);
500
+ if (validation.valid) {
501
+ setValidationError(void 0);
502
+ onContinue();
503
+ } else {
504
+ setValidationError(validation.message);
505
+ }
506
+ } else if (key.escape) {
507
+ setValidationError(void 0);
508
+ onBack();
509
+ }
510
+ });
511
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
512
+ /* @__PURE__ */ jsx(Header, { domain, selectionCount }),
513
+ showProgress && /* @__PURE__ */ jsx(
514
+ SectionProgress,
515
+ {
516
+ label: "Domain",
517
+ current: getDomainDisplayName(domain),
518
+ index: currentDomainIndex + 1,
519
+ total: selectedDomains.length,
520
+ next: nextDomain ? getDomainDisplayName(nextDomain) : void 0
521
+ }
522
+ ),
523
+ /* @__PURE__ */ jsx(
524
+ CategoryGrid,
525
+ {
526
+ categories,
527
+ focusedRow,
528
+ focusedCol,
529
+ showDescriptions,
530
+ expertMode,
531
+ onToggle,
532
+ onFocusChange,
533
+ onToggleDescriptions,
534
+ onToggleExpertMode
535
+ }
536
+ ),
537
+ /* @__PURE__ */ jsx(Footer, { showContinueHint: true, validationError })
538
+ ] });
539
+ };
540
+
541
+ export {
542
+ validateSelection,
543
+ validateBuildStep,
544
+ getDisplayLabel,
545
+ StepBuild
546
+ };
547
+ //# sourceMappingURL=chunk-Q6DR5QUH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli-v2/components/wizard/step-build.tsx","../src/cli-v2/lib/matrix-resolver.ts"],"sourcesContent":["/**\n * StepBuild component - Main Build step for domain-based technology selection.\n *\n * Uses CategoryGrid for 2D grid selection and SectionProgress for multi-domain\n * progress indication. Replaces the old linear category->subcategory flow.\n *\n * This component is stateless - all state is managed via props from the parent\n * wizard component, following React's controlled component pattern.\n */\nimport React, { useState } from \"react\";\nimport { Box, Text, useInput } from \"ink\";\nimport type { MergedSkillsMatrix } from \"../../types-matrix.js\";\nimport { getAvailableSkills } from \"../../lib/matrix-resolver.js\";\nimport {\n CategoryGrid,\n type CategoryRow,\n type CategoryOption,\n type OptionState,\n} from \"./category-grid.js\";\nimport { SectionProgress } from \"./section-progress.js\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface StepBuildProps {\n /** Skills matrix for category/skill lookup */\n matrix: MergedSkillsMatrix;\n /** Current domain being configured (e.g., 'web', 'api') */\n domain: string;\n /** All selected domains (for progress indicator) */\n selectedDomains: string[];\n /** Current domain index (0-based) */\n currentDomainIndex: number;\n /** Current selections by subcategory */\n selections: Record<string, string[]>;\n /** All current selections (for state calculation across domains) */\n allSelections: string[];\n /** Grid focus state */\n focusedRow: number;\n focusedCol: number;\n /** UI toggles */\n showDescriptions: boolean;\n expertMode: boolean;\n /** Callbacks */\n onToggle: (subcategoryId: string, technologyId: string) => void;\n onFocusChange: (row: number, col: number) => void;\n onToggleDescriptions: () => void;\n onToggleExpertMode: () => void;\n onContinue: () => void;\n onBack: () => void;\n}\n\n// =============================================================================\n// Constants\n// =============================================================================\n\n/** Minimum number of domains to show progress indicator */\nconst MIN_DOMAINS_FOR_PROGRESS = 2;\n\n// =============================================================================\n// Validation\n// =============================================================================\n\nexport interface ValidationResult {\n valid: boolean;\n message?: string;\n}\n\n/**\n * Validate that required categories have at least one selection.\n */\nexport function validateBuildStep(\n categories: CategoryRow[],\n selections: Record<string, string[]>,\n): ValidationResult {\n for (const category of categories) {\n if (category.required) {\n const categorySelections = selections[category.id] || [];\n if (categorySelections.length === 0) {\n return {\n valid: false,\n message: `Please select a ${category.name}`,\n };\n }\n }\n }\n return { valid: true };\n}\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Compute option state from skill flags.\n */\nfunction computeOptionState(skill: {\n disabled: boolean;\n discouraged: boolean;\n recommended: boolean;\n}): OptionState {\n if (skill.disabled) {\n return \"disabled\";\n }\n if (skill.discouraged) {\n return \"discouraged\";\n }\n if (skill.recommended) {\n return \"recommended\";\n }\n return \"normal\";\n}\n\n/**\n * Get clean display label for a skill option.\n * Uses name with author suffix stripped for accurate display.\n * e.g., \"React (@vince)\" -> \"React\", \"SCSS Modules (@vince)\" -> \"SCSS Modules\"\n */\nexport function getDisplayLabel(skill: {\n alias?: string;\n name: string;\n}): string {\n // Strip author suffix like \" (@vince)\" from name\n // This preserves the original capitalization (e.g., \"SCSS Modules\" stays as-is)\n const authorPattern = /\\s*\\(@[^)]+\\)\\s*$/;\n return skill.name.replace(authorPattern, \"\");\n}\n\n/**\n * Get state reason from skill flags.\n */\nfunction getStateReason(skill: {\n disabled: boolean;\n disabledReason?: string;\n discouraged: boolean;\n discouragedReason?: string;\n recommended: boolean;\n recommendedReason?: string;\n}): string | undefined {\n if (skill.disabled && skill.disabledReason) {\n return skill.disabledReason;\n }\n if (skill.discouraged && skill.discouragedReason) {\n return skill.discouragedReason;\n }\n if (skill.recommended && skill.recommendedReason) {\n return skill.recommendedReason;\n }\n return undefined;\n}\n\n/**\n * Build CategoryRow[] from matrix for a specific domain.\n *\n * Filters subcategories by domain and builds options using getAvailableSkills.\n */\nfunction buildCategoriesForDomain(\n domain: string,\n allSelections: string[],\n matrix: MergedSkillsMatrix,\n expertMode: boolean,\n): CategoryRow[] {\n // Get subcategories for the current domain (categories with parent and matching domain)\n const subcategories = Object.values(matrix.categories)\n .filter((cat) => cat.domain === domain && cat.parent)\n .sort((a, b) => (a.order ?? 0) - (b.order ?? 0));\n\n // Build CategoryRow for each subcategory\n const categoryRows: CategoryRow[] = subcategories.map((cat) => {\n // Get available skills with computed states\n const skillOptions = getAvailableSkills(cat.id, allSelections, matrix, {\n expertMode,\n });\n\n // Map skills to CategoryOption[]\n const options: CategoryOption[] = skillOptions.map((skill) => ({\n id: skill.alias || skill.id, // Use alias for selection tracking\n label: getDisplayLabel(skill), // Clean display name without author\n state: computeOptionState(skill),\n stateReason: getStateReason(skill),\n selected: skill.selected,\n }));\n\n return {\n id: cat.id,\n name: cat.name,\n required: cat.required ?? false,\n exclusive: cat.exclusive ?? true,\n options,\n };\n });\n\n return categoryRows;\n}\n\n/**\n * Get display name for a domain.\n */\nfunction getDomainDisplayName(domain: string): string {\n const displayNames: Record<string, string> = {\n web: \"Web\",\n api: \"API\",\n cli: \"CLI\",\n mobile: \"Mobile\",\n shared: \"Shared\",\n };\n return (\n displayNames[domain] || domain.charAt(0).toUpperCase() + domain.slice(1)\n );\n}\n\n/**\n * Count selected options across categories.\n */\nfunction countSelections(categories: CategoryRow[]): {\n selected: number;\n total: number;\n} {\n let selected = 0;\n let total = 0;\n for (const category of categories) {\n for (const option of category.options) {\n if (option.state !== \"disabled\") {\n total++;\n if (option.selected) {\n selected++;\n }\n }\n }\n }\n return { selected, total };\n}\n\n// =============================================================================\n// Header Component (Domain info with selection count)\n// =============================================================================\n\ninterface HeaderProps {\n domain: string;\n selectionCount: { selected: number; total: number };\n}\n\nconst Header: React.FC<HeaderProps> = ({ domain, selectionCount }) => {\n return (\n <Box justifyContent=\"space-between\" marginBottom={1}>\n <Text bold>\n Configure your <Text color=\"cyan\">{getDomainDisplayName(domain)}</Text>{\" \"}\n stack:\n </Text>\n <Text dimColor>\n {selectionCount.selected}/{selectionCount.total} selected\n </Text>\n </Box>\n );\n};\n\n// =============================================================================\n// Footer Component (Keyboard Help)\n// =============================================================================\n\ninterface FooterProps {\n showContinueHint: boolean;\n validationError?: string;\n}\n\nconst Footer: React.FC<FooterProps> = ({\n showContinueHint,\n validationError,\n}) => {\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n {/* Validation error message */}\n {validationError && (\n <Box marginBottom={1}>\n <Text color=\"yellow\">{validationError}</Text>\n </Box>\n )}\n\n {/* Keyboard shortcuts help */}\n <Text dimColor>\n {\"\\u2190\"}/{\"\\u2192\"} options {\"\\u2191\"}/{\"\\u2193\"} categories SPACE\n select TAB descriptions E expert ENTER continue ESC back\n </Text>\n </Box>\n );\n};\n\n// =============================================================================\n// Main Component\n// =============================================================================\n\nexport const StepBuild: React.FC<StepBuildProps> = ({\n matrix,\n domain,\n selectedDomains,\n currentDomainIndex,\n selections,\n allSelections,\n focusedRow,\n focusedCol,\n showDescriptions,\n expertMode,\n onToggle,\n onFocusChange,\n onToggleDescriptions,\n onToggleExpertMode,\n onContinue,\n onBack,\n}) => {\n // Validation state for showing error messages\n const [validationError, setValidationError] = useState<string | undefined>(\n undefined,\n );\n\n // Build categories for the current domain\n const categories = buildCategoriesForDomain(\n domain,\n allSelections,\n matrix,\n expertMode,\n );\n\n // Selection count for header\n const selectionCount = countSelections(categories);\n\n // Multi-domain progress\n const showProgress = selectedDomains.length >= MIN_DOMAINS_FOR_PROGRESS;\n const isLastDomain = currentDomainIndex === selectedDomains.length - 1;\n const nextDomain = isLastDomain\n ? undefined\n : selectedDomains[currentDomainIndex + 1];\n\n // Handle keyboard input for Enter and Escape\n useInput((input, key) => {\n if (key.return) {\n // Validate before continuing\n const validation = validateBuildStep(categories, selections);\n if (validation.valid) {\n setValidationError(undefined);\n onContinue();\n } else {\n setValidationError(validation.message);\n }\n } else if (key.escape) {\n setValidationError(undefined);\n onBack();\n }\n });\n\n return (\n <Box flexDirection=\"column\">\n {/* Header with domain and selection count */}\n <Header domain={domain} selectionCount={selectionCount} />\n\n {/* Progress indicator for multi-domain */}\n {showProgress && (\n <SectionProgress\n label=\"Domain\"\n current={getDomainDisplayName(domain)}\n index={currentDomainIndex + 1}\n total={selectedDomains.length}\n next={nextDomain ? getDomainDisplayName(nextDomain) : undefined}\n />\n )}\n\n {/* Category grid */}\n <CategoryGrid\n categories={categories}\n focusedRow={focusedRow}\n focusedCol={focusedCol}\n showDescriptions={showDescriptions}\n expertMode={expertMode}\n onToggle={onToggle}\n onFocusChange={onFocusChange}\n onToggleDescriptions={onToggleDescriptions}\n onToggleExpertMode={onToggleExpertMode}\n />\n\n {/* Footer with keyboard hints */}\n <Footer showContinueHint validationError={validationError} />\n </Box>\n );\n};\n","import type {\n MergedSkillsMatrix,\n ResolvedSkill,\n SkillOption,\n SelectionValidation,\n ValidationError,\n ValidationWarning,\n} from \"../types-matrix\";\n\nexport function resolveAlias(\n aliasOrId: string,\n matrix: MergedSkillsMatrix,\n): string {\n return matrix.aliases[aliasOrId] || aliasOrId;\n}\n\nexport function getDependentSkills(\n skillId: string,\n currentSelections: string[],\n matrix: MergedSkillsMatrix,\n): string[] {\n const fullId = resolveAlias(skillId, matrix);\n const skill = matrix.skills[fullId];\n\n if (!skill) return [];\n\n const resolvedSelections = currentSelections.map((s) =>\n resolveAlias(s, matrix),\n );\n const dependents: string[] = [];\n\n for (const selectedId of resolvedSelections) {\n if (selectedId === fullId) continue;\n\n const selectedSkill = matrix.skills[selectedId];\n if (!selectedSkill) continue;\n\n for (const requirement of selectedSkill.requires) {\n if (requirement.needsAny) {\n const satisfiedReqs = requirement.skillIds.filter((reqId) =>\n resolvedSelections.includes(reqId),\n );\n if (satisfiedReqs.length === 1 && satisfiedReqs[0] === fullId) {\n dependents.push(selectedId);\n }\n } else {\n if (requirement.skillIds.includes(fullId)) {\n dependents.push(selectedId);\n }\n }\n }\n }\n\n return dependents;\n}\n\nexport interface SkillCheckOptions {\n expertMode?: boolean;\n}\n\nexport function isDisabled(\n skillId: string,\n currentSelections: string[],\n matrix: MergedSkillsMatrix,\n options?: SkillCheckOptions,\n): boolean {\n if (options?.expertMode) {\n return false;\n }\n\n const fullId = resolveAlias(skillId, matrix);\n const skill = matrix.skills[fullId];\n\n if (!skill) {\n return false;\n }\n\n for (const selectedId of currentSelections) {\n const selectedFullId = resolveAlias(selectedId, matrix);\n\n if (skill.conflictsWith.some((c) => c.skillId === selectedFullId)) {\n return true;\n }\n\n const selectedSkill = matrix.skills[selectedFullId];\n if (\n selectedSkill &&\n selectedSkill.conflictsWith.some((c) => c.skillId === fullId)\n ) {\n return true;\n }\n }\n\n const resolvedSelections = currentSelections.map((s) =>\n resolveAlias(s, matrix),\n );\n\n for (const requirement of skill.requires) {\n if (requirement.needsAny) {\n const hasAny = requirement.skillIds.some((reqId) =>\n resolvedSelections.includes(reqId),\n );\n if (!hasAny) {\n return true;\n }\n } else {\n const hasAll = requirement.skillIds.every((reqId) =>\n resolvedSelections.includes(reqId),\n );\n if (!hasAll) {\n return true;\n }\n }\n }\n\n return false;\n}\n\nexport function getDisableReason(\n skillId: string,\n currentSelections: string[],\n matrix: MergedSkillsMatrix,\n): string | undefined {\n const fullId = resolveAlias(skillId, matrix);\n const skill = matrix.skills[fullId];\n\n if (!skill) {\n return undefined;\n }\n\n const resolvedSelections = currentSelections.map((s) =>\n resolveAlias(s, matrix),\n );\n\n for (const selectedId of resolvedSelections) {\n const conflict = skill.conflictsWith.find((c) => c.skillId === selectedId);\n if (conflict) {\n const selectedSkill = matrix.skills[selectedId];\n const selectedName = selectedSkill?.name || selectedId;\n return `${conflict.reason} (conflicts with ${selectedName})`;\n }\n\n const selectedSkill = matrix.skills[selectedId];\n if (selectedSkill) {\n const reverseConflict = selectedSkill.conflictsWith.find(\n (c) => c.skillId === fullId,\n );\n if (reverseConflict) {\n const selectedName = selectedSkill.name;\n return `${reverseConflict.reason} (conflicts with ${selectedName})`;\n }\n }\n }\n\n for (const requirement of skill.requires) {\n if (requirement.needsAny) {\n const hasAny = requirement.skillIds.some((reqId) =>\n resolvedSelections.includes(reqId),\n );\n if (!hasAny) {\n const requiredNames = requirement.skillIds\n .map((id) => matrix.skills[id]?.name || id)\n .join(\" or \");\n return `${requirement.reason} (requires ${requiredNames})`;\n }\n } else {\n const missingIds = requirement.skillIds.filter(\n (reqId) => !resolvedSelections.includes(reqId),\n );\n if (missingIds.length > 0) {\n const missingNames = missingIds\n .map((id) => matrix.skills[id]?.name || id)\n .join(\", \");\n return `${requirement.reason} (requires ${missingNames})`;\n }\n }\n }\n\n return undefined;\n}\n\nexport function isDiscouraged(\n skillId: string,\n currentSelections: string[],\n matrix: MergedSkillsMatrix,\n): boolean {\n const fullId = resolveAlias(skillId, matrix);\n const skill = matrix.skills[fullId];\n\n if (!skill) {\n return false;\n }\n\n const resolvedSelections = currentSelections.map((s) =>\n resolveAlias(s, matrix),\n );\n\n for (const selectedId of resolvedSelections) {\n const selectedSkill = matrix.skills[selectedId];\n if (\n selectedSkill &&\n selectedSkill.discourages.some((d) => d.skillId === fullId)\n ) {\n return true;\n }\n\n if (skill.discourages.some((d) => d.skillId === selectedId)) {\n return true;\n }\n }\n\n return false;\n}\n\nexport function getDiscourageReason(\n skillId: string,\n currentSelections: string[],\n matrix: MergedSkillsMatrix,\n): string | undefined {\n const fullId = resolveAlias(skillId, matrix);\n const skill = matrix.skills[fullId];\n\n if (!skill) {\n return undefined;\n }\n\n const resolvedSelections = currentSelections.map((s) =>\n resolveAlias(s, matrix),\n );\n\n for (const selectedId of resolvedSelections) {\n const selectedSkill = matrix.skills[selectedId];\n if (selectedSkill) {\n const discourage = selectedSkill.discourages.find(\n (d) => d.skillId === fullId,\n );\n if (discourage) {\n return discourage.reason;\n }\n }\n\n const reverseDiscourage = skill.discourages.find(\n (d) => d.skillId === selectedId,\n );\n if (reverseDiscourage) {\n return reverseDiscourage.reason;\n }\n }\n\n return undefined;\n}\n\nexport function isRecommended(\n skillId: string,\n currentSelections: string[],\n matrix: MergedSkillsMatrix,\n): boolean {\n const fullId = resolveAlias(skillId, matrix);\n const skill = matrix.skills[fullId];\n\n if (!skill) {\n return false;\n }\n\n const resolvedSelections = currentSelections.map((s) =>\n resolveAlias(s, matrix),\n );\n\n for (const selectedId of resolvedSelections) {\n const selectedSkill = matrix.skills[selectedId];\n if (\n selectedSkill &&\n selectedSkill.recommends.some((r) => r.skillId === fullId)\n ) {\n return true;\n }\n }\n\n return false;\n}\n\nexport function getRecommendReason(\n skillId: string,\n currentSelections: string[],\n matrix: MergedSkillsMatrix,\n): string | undefined {\n const fullId = resolveAlias(skillId, matrix);\n const skill = matrix.skills[fullId];\n\n if (!skill) {\n return undefined;\n }\n\n const resolvedSelections = currentSelections.map((s) =>\n resolveAlias(s, matrix),\n );\n\n for (const selectedId of resolvedSelections) {\n const selectedSkill = matrix.skills[selectedId];\n if (selectedSkill) {\n const recommendation = selectedSkill.recommends.find(\n (r) => r.skillId === fullId,\n );\n if (recommendation) {\n return `${recommendation.reason} (recommended by ${selectedSkill.name})`;\n }\n }\n }\n\n return undefined;\n}\n\nexport function validateSelection(\n selections: string[],\n matrix: MergedSkillsMatrix,\n): SelectionValidation {\n const errors: ValidationError[] = [];\n const warnings: ValidationWarning[] = [];\n const resolvedSelections = selections.map((s) => resolveAlias(s, matrix));\n\n for (let i = 0; i < resolvedSelections.length; i++) {\n const skillA = matrix.skills[resolvedSelections[i]];\n if (!skillA) continue;\n\n for (let j = i + 1; j < resolvedSelections.length; j++) {\n const skillBId = resolvedSelections[j];\n const conflict = skillA.conflictsWith.find((c) => c.skillId === skillBId);\n if (conflict) {\n errors.push({\n type: \"conflict\",\n message: `${skillA.name} conflicts with ${matrix.skills[skillBId]?.name || skillBId}: ${conflict.reason}`,\n skills: [skillA.id, skillBId],\n });\n }\n }\n }\n\n for (const skillId of resolvedSelections) {\n const skill = matrix.skills[skillId];\n if (!skill) continue;\n\n for (const requirement of skill.requires) {\n if (requirement.needsAny) {\n const hasAny = requirement.skillIds.some((reqId) =>\n resolvedSelections.includes(reqId),\n );\n if (!hasAny) {\n errors.push({\n type: \"missing_requirement\",\n message: `${skill.name} requires one of: ${requirement.skillIds.map((id) => matrix.skills[id]?.name || id).join(\", \")}`,\n skills: [skillId, ...requirement.skillIds],\n });\n }\n } else {\n const missingIds = requirement.skillIds.filter(\n (reqId) => !resolvedSelections.includes(reqId),\n );\n if (missingIds.length > 0) {\n errors.push({\n type: \"missing_requirement\",\n message: `${skill.name} requires: ${missingIds.map((id) => matrix.skills[id]?.name || id).join(\", \")}`,\n skills: [skillId, ...missingIds],\n });\n }\n }\n }\n }\n\n const categorySelections = new Map<string, string[]>();\n for (const skillId of resolvedSelections) {\n const skill = matrix.skills[skillId];\n if (!skill) continue;\n\n const existing = categorySelections.get(skill.category) || [];\n existing.push(skillId);\n categorySelections.set(skill.category, existing);\n }\n\n for (const [categoryId, skillIds] of categorySelections.entries()) {\n if (skillIds.length > 1) {\n const category = matrix.categories[categoryId];\n if (category?.exclusive) {\n errors.push({\n type: \"category_exclusive\",\n message: `Category \"${category.name}\" only allows one selection, but multiple selected: ${skillIds.map((id) => matrix.skills[id]?.name || id).join(\", \")}`,\n skills: skillIds,\n });\n }\n }\n }\n\n for (const skillId of resolvedSelections) {\n const skill = matrix.skills[skillId];\n if (!skill) continue;\n\n for (const recommendation of skill.recommends) {\n if (!resolvedSelections.includes(recommendation.skillId)) {\n const recommendedSkill = matrix.skills[recommendation.skillId];\n if (recommendedSkill) {\n const hasConflict = recommendedSkill.conflictsWith.some((c) =>\n resolvedSelections.includes(c.skillId),\n );\n if (!hasConflict) {\n warnings.push({\n type: \"missing_recommendation\",\n message: `${skill.name} recommends ${recommendedSkill.name}: ${recommendation.reason}`,\n skills: [skillId, recommendation.skillId],\n });\n }\n }\n }\n }\n }\n\n for (const skillId of resolvedSelections) {\n const skill = matrix.skills[skillId];\n if (!skill || skill.providesSetupFor.length === 0) continue;\n\n const hasUsageSkill = skill.providesSetupFor.some((usageId) =>\n resolvedSelections.includes(usageId),\n );\n if (!hasUsageSkill) {\n warnings.push({\n type: \"unused_setup\",\n message: `Setup skill \"${skill.name}\" selected but no corresponding usage skills: ${skill.providesSetupFor.map((id) => matrix.skills[id]?.name || id).join(\", \")}`,\n skills: [skillId, ...skill.providesSetupFor],\n });\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\nexport function getAvailableSkills(\n categoryId: string,\n currentSelections: string[],\n matrix: MergedSkillsMatrix,\n options?: SkillCheckOptions,\n): SkillOption[] {\n const skillOptions: SkillOption[] = [];\n const resolvedSelections = currentSelections.map((s) =>\n resolveAlias(s, matrix),\n );\n\n for (const skill of Object.values(matrix.skills)) {\n if (skill.category !== categoryId) {\n continue;\n }\n\n const disabled = isDisabled(skill.id, currentSelections, matrix, options);\n const discouraged =\n !disabled && isDiscouraged(skill.id, currentSelections, matrix);\n const recommended =\n !disabled &&\n !discouraged &&\n isRecommended(skill.id, currentSelections, matrix);\n\n skillOptions.push({\n id: skill.id,\n alias: skill.alias,\n name: skill.name,\n description: skill.description,\n disabled,\n disabledReason: disabled\n ? getDisableReason(skill.id, currentSelections, matrix)\n : undefined,\n discouraged,\n discouragedReason: discouraged\n ? getDiscourageReason(skill.id, currentSelections, matrix)\n : undefined,\n recommended,\n recommendedReason: recommended\n ? getRecommendReason(skill.id, currentSelections, matrix)\n : undefined,\n selected: resolvedSelections.includes(skill.id),\n alternatives: skill.alternatives.map((a) => a.skillId),\n });\n }\n\n return skillOptions;\n}\n\nexport function getSkillsByCategory(\n categoryId: string,\n matrix: MergedSkillsMatrix,\n): ResolvedSkill[] {\n const skills: ResolvedSkill[] = [];\n\n for (const skill of Object.values(matrix.skills)) {\n if (skill.category === categoryId) {\n skills.push(skill);\n }\n }\n\n return skills;\n}\n\nexport function isCategoryAllDisabled(\n categoryId: string,\n currentSelections: string[],\n matrix: MergedSkillsMatrix,\n options?: SkillCheckOptions,\n): { disabled: boolean; reason?: string } {\n if (options?.expertMode) {\n return { disabled: false };\n }\n\n const skills = getSkillsByCategory(categoryId, matrix);\n\n if (skills.length === 0) {\n return { disabled: false };\n }\n\n const disabledSkills: Array<{ skillId: string; reason: string | undefined }> =\n [];\n\n for (const skill of skills) {\n if (isDisabled(skill.id, currentSelections, matrix, options)) {\n disabledSkills.push({\n skillId: skill.id,\n reason: getDisableReason(skill.id, currentSelections, matrix),\n });\n }\n }\n\n if (disabledSkills.length === skills.length) {\n const firstReason = disabledSkills[0]?.reason;\n const shortReason = firstReason?.split(\" (\")[0] || \"requirements not met\";\n return { disabled: true, reason: shortReason };\n }\n\n return { disabled: false };\n}\n\nexport function getSubcategories(\n parentCategoryId: string,\n matrix: MergedSkillsMatrix,\n): string[] {\n const subcategories: string[] = [];\n\n for (const category of Object.values(matrix.categories)) {\n if (category.parent === parentCategoryId) {\n subcategories.push(category.id);\n }\n }\n\n subcategories.sort((a, b) => {\n const catA = matrix.categories[a];\n const catB = matrix.categories[b];\n return (catA?.order ?? 0) - (catB?.order ?? 0);\n });\n\n return subcategories;\n}\n\nexport function getTopLevelCategories(matrix: MergedSkillsMatrix): string[] {\n const topLevel: string[] = [];\n\n for (const category of Object.values(matrix.categories)) {\n if (!category.parent) {\n topLevel.push(category.id);\n }\n }\n\n topLevel.sort((a, b) => {\n const catA = matrix.categories[a];\n const catB = matrix.categories[b];\n return (catA?.order ?? 0) - (catB?.order ?? 0);\n });\n\n return topLevel;\n}\n"],"mappings":"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","names":["selectedSkill"]}