@react-spa-scaffold/mcp 1.1.3 → 1.2.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.
Files changed (261) hide show
  1. package/README.md +19 -15
  2. package/dist/constants.d.ts +35 -0
  3. package/dist/constants.d.ts.map +1 -0
  4. package/dist/constants.js +35 -0
  5. package/dist/constants.js.map +1 -0
  6. package/dist/features/definitions/api.d.ts +3 -0
  7. package/dist/features/definitions/api.d.ts.map +1 -0
  8. package/dist/features/definitions/api.js +20 -0
  9. package/dist/features/definitions/api.js.map +1 -0
  10. package/dist/features/definitions/ci.d.ts +3 -0
  11. package/dist/features/definitions/ci.d.ts.map +1 -0
  12. package/dist/features/definitions/ci.js +25 -0
  13. package/dist/features/definitions/ci.js.map +1 -0
  14. package/dist/features/definitions/core.d.ts +3 -0
  15. package/dist/features/definitions/core.d.ts.map +1 -0
  16. package/dist/features/definitions/core.js +76 -0
  17. package/dist/features/definitions/core.js.map +1 -0
  18. package/dist/features/definitions/devtools.d.ts +3 -0
  19. package/dist/features/definitions/devtools.d.ts.map +1 -0
  20. package/dist/features/definitions/devtools.js +53 -0
  21. package/dist/features/definitions/devtools.js.map +1 -0
  22. package/dist/features/definitions/forms.d.ts +3 -0
  23. package/dist/features/definitions/forms.d.ts.map +1 -0
  24. package/dist/features/definitions/forms.js +32 -0
  25. package/dist/features/definitions/forms.js.map +1 -0
  26. package/dist/features/definitions/i18n.d.ts +3 -0
  27. package/dist/features/definitions/i18n.d.ts.map +1 -0
  28. package/dist/features/definitions/i18n.js +50 -0
  29. package/dist/features/definitions/i18n.js.map +1 -0
  30. package/dist/features/definitions/index.d.ts +15 -0
  31. package/dist/features/definitions/index.d.ts.map +1 -0
  32. package/dist/features/definitions/index.js +15 -0
  33. package/dist/features/definitions/index.js.map +1 -0
  34. package/dist/features/definitions/mobile.d.ts +3 -0
  35. package/dist/features/definitions/mobile.d.ts.map +1 -0
  36. package/dist/features/definitions/mobile.js +19 -0
  37. package/dist/features/definitions/mobile.js.map +1 -0
  38. package/dist/features/definitions/observability.d.ts +3 -0
  39. package/dist/features/definitions/observability.d.ts.map +1 -0
  40. package/dist/features/definitions/observability.js +21 -0
  41. package/dist/features/definitions/observability.js.map +1 -0
  42. package/dist/features/definitions/performance.d.ts +3 -0
  43. package/dist/features/definitions/performance.d.ts.map +1 -0
  44. package/dist/features/definitions/performance.js +28 -0
  45. package/dist/features/definitions/performance.js.map +1 -0
  46. package/dist/features/definitions/routing.d.ts +3 -0
  47. package/dist/features/definitions/routing.d.ts.map +1 -0
  48. package/dist/features/definitions/routing.js +25 -0
  49. package/dist/features/definitions/routing.js.map +1 -0
  50. package/dist/features/definitions/state.d.ts +3 -0
  51. package/dist/features/definitions/state.d.ts.map +1 -0
  52. package/dist/features/definitions/state.js +27 -0
  53. package/dist/features/definitions/state.js.map +1 -0
  54. package/dist/features/definitions/testing.d.ts +3 -0
  55. package/dist/features/definitions/testing.d.ts.map +1 -0
  56. package/dist/features/definitions/testing.js +56 -0
  57. package/dist/features/definitions/testing.js.map +1 -0
  58. package/dist/features/definitions/theming.d.ts +3 -0
  59. package/dist/features/definitions/theming.d.ts.map +1 -0
  60. package/dist/features/definitions/theming.js +27 -0
  61. package/dist/features/definitions/theming.js.map +1 -0
  62. package/dist/features/definitions/ui.d.ts +3 -0
  63. package/dist/features/definitions/ui.d.ts.map +1 -0
  64. package/dist/features/definitions/ui.js +44 -0
  65. package/dist/features/definitions/ui.js.map +1 -0
  66. package/dist/features/index.d.ts +3 -2
  67. package/dist/features/index.d.ts.map +1 -1
  68. package/dist/features/index.js +2 -1
  69. package/dist/features/index.js.map +1 -1
  70. package/dist/features/registry.d.ts +3 -9
  71. package/dist/features/registry.d.ts.map +1 -1
  72. package/dist/features/registry.js +3 -554
  73. package/dist/features/registry.js.map +1 -1
  74. package/dist/features/types.d.ts +17 -20
  75. package/dist/features/types.d.ts.map +1 -1
  76. package/dist/features/types.js +7 -1
  77. package/dist/features/types.js.map +1 -1
  78. package/dist/features/types.test.d.ts +5 -0
  79. package/dist/features/types.test.d.ts.map +1 -0
  80. package/dist/features/types.test.js +32 -0
  81. package/dist/features/types.test.js.map +1 -0
  82. package/dist/resources/docs.d.ts +2 -8
  83. package/dist/resources/docs.d.ts.map +1 -1
  84. package/dist/resources/docs.js +27 -49
  85. package/dist/resources/docs.js.map +1 -1
  86. package/dist/server.d.ts +2 -7
  87. package/dist/server.d.ts.map +1 -1
  88. package/dist/server.js +24 -57
  89. package/dist/server.js.map +1 -1
  90. package/dist/server.test.d.ts +2 -0
  91. package/dist/server.test.d.ts.map +1 -0
  92. package/dist/server.test.js +14 -0
  93. package/dist/server.test.js.map +1 -0
  94. package/dist/tools/get-example.d.ts +4 -15
  95. package/dist/tools/get-example.d.ts.map +1 -1
  96. package/dist/tools/get-example.js +3 -11
  97. package/dist/tools/get-example.js.map +1 -1
  98. package/dist/tools/get-example.test.d.ts +5 -0
  99. package/dist/tools/get-example.test.d.ts.map +1 -0
  100. package/dist/tools/get-example.test.js +63 -0
  101. package/dist/tools/get-example.test.js.map +1 -0
  102. package/dist/tools/get-features.d.ts +15 -14
  103. package/dist/tools/get-features.d.ts.map +1 -1
  104. package/dist/tools/get-features.js +12 -2
  105. package/dist/tools/get-features.js.map +1 -1
  106. package/dist/tools/get-features.test.d.ts +5 -0
  107. package/dist/tools/get-features.test.d.ts.map +1 -0
  108. package/dist/tools/get-features.test.js +45 -0
  109. package/dist/tools/get-features.test.js.map +1 -0
  110. package/dist/tools/get-file.d.ts +23 -0
  111. package/dist/tools/get-file.d.ts.map +1 -0
  112. package/dist/tools/get-file.js +53 -0
  113. package/dist/tools/get-file.js.map +1 -0
  114. package/dist/tools/get-file.test.d.ts +5 -0
  115. package/dist/tools/get-file.test.d.ts.map +1 -0
  116. package/dist/tools/get-file.test.js +63 -0
  117. package/dist/tools/get-file.test.js.map +1 -0
  118. package/dist/tools/get-scaffold.d.ts +8 -29
  119. package/dist/tools/get-scaffold.d.ts.map +1 -1
  120. package/dist/tools/get-scaffold.js +18 -24
  121. package/dist/tools/get-scaffold.js.map +1 -1
  122. package/dist/tools/get-scaffold.test.d.ts +5 -0
  123. package/dist/tools/get-scaffold.test.d.ts.map +1 -0
  124. package/dist/tools/get-scaffold.test.js +197 -0
  125. package/dist/tools/get-scaffold.test.js.map +1 -0
  126. package/dist/tools/index.d.ts +2 -0
  127. package/dist/tools/index.d.ts.map +1 -1
  128. package/dist/tools/index.js +1 -0
  129. package/dist/tools/index.js.map +1 -1
  130. package/dist/tools/registry.d.ts +13 -0
  131. package/dist/tools/registry.d.ts.map +1 -0
  132. package/dist/tools/registry.js +47 -0
  133. package/dist/tools/registry.js.map +1 -0
  134. package/dist/tools/types.d.ts +41 -0
  135. package/dist/tools/types.d.ts.map +1 -0
  136. package/dist/tools/types.js +8 -0
  137. package/dist/tools/types.js.map +1 -0
  138. package/dist/utils/cache.d.ts +25 -0
  139. package/dist/utils/cache.d.ts.map +1 -0
  140. package/dist/utils/cache.js +61 -0
  141. package/dist/utils/cache.js.map +1 -0
  142. package/dist/utils/docs.d.ts +1 -3
  143. package/dist/utils/docs.d.ts.map +1 -1
  144. package/dist/utils/docs.js +3 -8
  145. package/dist/utils/docs.js.map +1 -1
  146. package/dist/utils/docs.test.d.ts +5 -0
  147. package/dist/utils/docs.test.d.ts.map +1 -0
  148. package/dist/utils/docs.test.js +37 -0
  149. package/dist/utils/docs.test.js.map +1 -0
  150. package/dist/utils/errors.d.ts +8 -0
  151. package/dist/utils/errors.d.ts.map +1 -0
  152. package/dist/utils/errors.js +19 -0
  153. package/dist/utils/errors.js.map +1 -0
  154. package/dist/utils/examples/api-patterns.d.ts +3 -0
  155. package/dist/utils/examples/api-patterns.d.ts.map +1 -0
  156. package/dist/utils/examples/api-patterns.js +19 -0
  157. package/dist/utils/examples/api-patterns.js.map +1 -0
  158. package/dist/utils/examples/component-patterns.d.ts +3 -0
  159. package/dist/utils/examples/component-patterns.d.ts.map +1 -0
  160. package/dist/utils/examples/component-patterns.js +71 -0
  161. package/dist/utils/examples/component-patterns.js.map +1 -0
  162. package/dist/utils/examples/context-patterns.d.ts +3 -0
  163. package/dist/utils/examples/context-patterns.d.ts.map +1 -0
  164. package/dist/utils/examples/context-patterns.js +32 -0
  165. package/dist/utils/examples/context-patterns.js.map +1 -0
  166. package/dist/utils/examples/hook-patterns.d.ts +3 -0
  167. package/dist/utils/examples/hook-patterns.d.ts.map +1 -0
  168. package/dist/utils/examples/hook-patterns.js +55 -0
  169. package/dist/utils/examples/hook-patterns.js.map +1 -0
  170. package/dist/utils/examples/i18n-patterns.d.ts +3 -0
  171. package/dist/utils/examples/i18n-patterns.d.ts.map +1 -0
  172. package/dist/utils/examples/i18n-patterns.js +43 -0
  173. package/dist/utils/examples/i18n-patterns.js.map +1 -0
  174. package/dist/utils/examples/index.d.ts +12 -0
  175. package/dist/utils/examples/index.d.ts.map +1 -0
  176. package/dist/utils/examples/index.js +65 -0
  177. package/dist/utils/examples/index.js.map +1 -0
  178. package/dist/utils/examples/mobile-patterns.d.ts +3 -0
  179. package/dist/utils/examples/mobile-patterns.d.ts.map +1 -0
  180. package/dist/utils/examples/mobile-patterns.js +38 -0
  181. package/dist/utils/examples/mobile-patterns.js.map +1 -0
  182. package/dist/utils/examples/page-patterns.d.ts +3 -0
  183. package/dist/utils/examples/page-patterns.d.ts.map +1 -0
  184. package/dist/utils/examples/page-patterns.js +34 -0
  185. package/dist/utils/examples/page-patterns.js.map +1 -0
  186. package/dist/utils/examples/patterns.test.d.ts +6 -0
  187. package/dist/utils/examples/patterns.test.d.ts.map +1 -0
  188. package/dist/utils/examples/patterns.test.js +75 -0
  189. package/dist/utils/examples/patterns.test.js.map +1 -0
  190. package/dist/utils/examples/store-patterns.d.ts +3 -0
  191. package/dist/utils/examples/store-patterns.d.ts.map +1 -0
  192. package/dist/utils/examples/store-patterns.js +40 -0
  193. package/dist/utils/examples/store-patterns.js.map +1 -0
  194. package/dist/utils/examples/test-patterns.d.ts +3 -0
  195. package/dist/utils/examples/test-patterns.d.ts.map +1 -0
  196. package/dist/utils/examples/test-patterns.js +58 -0
  197. package/dist/utils/examples/test-patterns.js.map +1 -0
  198. package/dist/utils/examples/types.d.ts +17 -0
  199. package/dist/utils/examples/types.d.ts.map +1 -0
  200. package/dist/utils/examples/types.js +2 -0
  201. package/dist/utils/examples/types.js.map +1 -0
  202. package/dist/utils/examples/utility-patterns.d.ts +3 -0
  203. package/dist/utils/examples/utility-patterns.d.ts.map +1 -0
  204. package/dist/utils/examples/utility-patterns.js +77 -0
  205. package/dist/utils/examples/utility-patterns.js.map +1 -0
  206. package/dist/utils/index.d.ts +5 -3
  207. package/dist/utils/index.d.ts.map +1 -1
  208. package/dist/utils/index.js +5 -3
  209. package/dist/utils/index.js.map +1 -1
  210. package/dist/utils/paths.d.ts +13 -23
  211. package/dist/utils/paths.d.ts.map +1 -1
  212. package/dist/utils/paths.js +28 -39
  213. package/dist/utils/paths.js.map +1 -1
  214. package/dist/utils/paths.test.d.ts +2 -0
  215. package/dist/utils/paths.test.d.ts.map +1 -0
  216. package/dist/utils/paths.test.js +38 -0
  217. package/dist/utils/paths.test.js.map +1 -0
  218. package/dist/utils/scaffold/claude-md/index.d.ts +7 -0
  219. package/dist/utils/scaffold/claude-md/index.d.ts.map +1 -0
  220. package/dist/utils/scaffold/claude-md/index.js +23 -0
  221. package/dist/utils/scaffold/claude-md/index.js.map +1 -0
  222. package/dist/utils/scaffold/claude-md/sections.d.ts +16 -0
  223. package/dist/utils/scaffold/claude-md/sections.d.ts.map +1 -0
  224. package/dist/utils/scaffold/claude-md/sections.js +269 -0
  225. package/dist/utils/scaffold/claude-md/sections.js.map +1 -0
  226. package/dist/utils/scaffold/commands.d.ts +7 -0
  227. package/dist/utils/scaffold/commands.d.ts.map +1 -0
  228. package/dist/utils/scaffold/commands.js +19 -0
  229. package/dist/utils/scaffold/commands.js.map +1 -0
  230. package/dist/utils/scaffold/compute.d.ts +15 -0
  231. package/dist/utils/scaffold/compute.d.ts.map +1 -0
  232. package/dist/utils/scaffold/compute.js +63 -0
  233. package/dist/utils/scaffold/compute.js.map +1 -0
  234. package/dist/utils/scaffold/dependencies.d.ts +25 -0
  235. package/dist/utils/scaffold/dependencies.d.ts.map +1 -0
  236. package/dist/utils/scaffold/dependencies.js +101 -0
  237. package/dist/utils/scaffold/dependencies.js.map +1 -0
  238. package/dist/utils/scaffold/file-structure.d.ts +23 -0
  239. package/dist/utils/scaffold/file-structure.d.ts.map +1 -0
  240. package/dist/utils/scaffold/file-structure.js +62 -0
  241. package/dist/utils/scaffold/file-structure.js.map +1 -0
  242. package/dist/utils/scaffold/generators.d.ts +9 -0
  243. package/dist/utils/scaffold/generators.d.ts.map +1 -0
  244. package/dist/utils/scaffold/generators.js +121 -0
  245. package/dist/utils/scaffold/generators.js.map +1 -0
  246. package/dist/utils/scaffold/index.d.ts +10 -0
  247. package/dist/utils/scaffold/index.d.ts.map +1 -0
  248. package/dist/utils/scaffold/index.js +9 -0
  249. package/dist/utils/scaffold/index.js.map +1 -0
  250. package/package.json +2 -2
  251. package/templates/.github/workflows/release.yml +1 -1
  252. package/templates/e2e/tests/home.spec.ts +2 -2
  253. package/templates/e2e/tests/language.spec.ts +7 -3
  254. package/dist/utils/examples.d.ts +0 -27
  255. package/dist/utils/examples.d.ts.map +0 -1
  256. package/dist/utils/examples.js +0 -438
  257. package/dist/utils/examples.js.map +0 -1
  258. package/dist/utils/scaffold.d.ts +0 -59
  259. package/dist/utils/scaffold.d.ts.map +0 -1
  260. package/dist/utils/scaffold.js +0 -637
  261. package/dist/utils/scaffold.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"get-features.d.ts","sourceRoot":"","sources":["../../src/tools/get-features.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CACrE;AAED,wBAAgB,WAAW,IAAI,cAAc,EAAE,CAa9C;AAED,eAAO,MAAM,yBAAyB;;;;;;kBAqBlB,MAAM,EAAE;;CAE3B,CAAC"}
1
+ {"version":3,"file":"get-features.d.ts","sourceRoot":"","sources":["../../src/tools/get-features.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,qDAAqD;AACrD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,IAAI,cAAc,EAAE,CAW9C;AAED,4DAA4D;AAC5D,eAAO,MAAM,yBAAyB,EAAE,cAuBvC,CAAC"}
@@ -6,6 +6,17 @@
6
6
  * and present options to users.
7
7
  */
8
8
  import { FEATURES, FEATURE_IDS } from '../features/index.js';
9
+ /**
10
+ * Lists all available features for scaffolding.
11
+ *
12
+ * @returns Array of feature summaries with id, name, description, required flag, and includes
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * const features = getFeatures();
17
+ * // [{ id: 'core', name: 'Core', required: true, ... }, ...]
18
+ * ```
19
+ */
9
20
  export function getFeatures() {
10
21
  return FEATURE_IDS.map((id) => {
11
22
  const feature = FEATURES[id];
@@ -15,11 +26,10 @@ export function getFeatures() {
15
26
  description: feature.description,
16
27
  required: feature.required,
17
28
  includes: feature.includes,
18
- hasOptions: !!feature.options,
19
- options: feature.options,
20
29
  };
21
30
  });
22
31
  }
32
+ /** Tool definition for get_features - no input required. */
23
33
  export const getFeaturesToolDefinition = {
24
34
  name: 'get_features',
25
35
  description: `List all available feature modules for react-spa-scaffold project scaffolding.
@@ -1 +1 @@
1
- {"version":3,"file":"get-features.js","sourceRoot":"","sources":["../../src/tools/get-features.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAY7D,MAAM,UAAU,WAAW;IACzB,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,EAAkB,EAAE;QAC5C,MAAM,OAAO,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC7B,OAAO;YACL,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC;YACd,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,UAAU,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO;YAC7B,OAAO,EAAE,OAAO,CAAC,OAAO;SACzB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC,IAAI,EAAE,cAAc;IACpB,WAAW,EAAE;;;;;;;;;;;;;;;uEAewD;IACrE,WAAW,EAAE;QACX,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE,EAAE;QACd,QAAQ,EAAE,EAAc;KACzB;CACF,CAAC"}
1
+ {"version":3,"file":"get-features.js","sourceRoot":"","sources":["../../src/tools/get-features.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAY7D;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,EAAkB,EAAE;QAC5C,MAAM,OAAO,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC7B,OAAO;YACL,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC;YACd,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,QAAQ,EAAE,OAAO,CAAC,QAAQ;SAC3B,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,4DAA4D;AAC5D,MAAM,CAAC,MAAM,yBAAyB,GAAmB;IACvD,IAAI,EAAE,cAAc;IACpB,WAAW,EAAE;;;;;;;;;;;;;;;uEAewD;IACrE,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE,EAAE;QACd,QAAQ,EAAE,EAAE;KACb;CACF,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Tests for get_features tool
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=get-features.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-features.test.d.ts","sourceRoot":"","sources":["../../src/tools/get-features.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Tests for get_features tool
3
+ */
4
+ import { describe, it, expect } from 'vitest';
5
+ import { getFeatures } from './get-features.js';
6
+ import { FEATURE_IDS } from '../features/index.js';
7
+ describe('get_features tool', () => {
8
+ it('returns all feature IDs', () => {
9
+ const features = getFeatures();
10
+ expect(features).toHaveLength(FEATURE_IDS.length);
11
+ expect(features.map((f) => f.id)).toEqual(expect.arrayContaining([...FEATURE_IDS]));
12
+ });
13
+ it('returns core as required', () => {
14
+ const features = getFeatures();
15
+ const core = features.find((f) => f.id === 'core');
16
+ expect(core).toBeDefined();
17
+ expect(core?.required).toBe(true);
18
+ });
19
+ it('returns proper structure for each feature', () => {
20
+ const features = getFeatures();
21
+ for (const feature of features) {
22
+ expect(feature).toHaveProperty('id');
23
+ expect(feature).toHaveProperty('name');
24
+ expect(feature).toHaveProperty('description');
25
+ expect(feature).toHaveProperty('required');
26
+ expect(feature).toHaveProperty('includes');
27
+ expect(Array.isArray(feature.includes)).toBe(true);
28
+ }
29
+ });
30
+ it('mobile feature exists and is not required', () => {
31
+ const features = getFeatures();
32
+ const mobile = features.find((f) => f.id === 'mobile');
33
+ expect(mobile).toBeDefined();
34
+ expect(mobile?.required).toBe(false);
35
+ expect(mobile?.name).toBe('Mobile Support');
36
+ });
37
+ it('theming feature exists and is not required', () => {
38
+ const features = getFeatures();
39
+ const theming = features.find((f) => f.id === 'theming');
40
+ expect(theming).toBeDefined();
41
+ expect(theming?.required).toBe(false);
42
+ expect(theming?.name).toBe('Theming');
43
+ });
44
+ });
45
+ //# sourceMappingURL=get-features.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-features.test.js","sourceRoot":"","sources":["../../src/tools/get-features.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * get_file tool
3
+ *
4
+ * Fetches content of config or documentation files.
5
+ * Used for lazy loading after get_scaffold returns paths.
6
+ */
7
+ import { z } from 'zod';
8
+ import type { ToolDefinition } from './types.js';
9
+ /** Zod schema for get_file input - single source of truth. */
10
+ export declare const getFileSchema: z.ZodObject<{
11
+ path: z.ZodString;
12
+ }, z.core.$strip>;
13
+ export type GetFileInput = z.infer<typeof getFileSchema>;
14
+ export declare function getFile(input: GetFileInput): Promise<{
15
+ path: string;
16
+ content: string;
17
+ } | {
18
+ error: string;
19
+ hint: string;
20
+ }>;
21
+ /** Tool definition derived from Zod schema (Zod v4 native). */
22
+ export declare const getFileToolDefinition: ToolDefinition;
23
+ //# sourceMappingURL=get-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-file.d.ts","sourceRoot":"","sources":["../../src/tools/get-file.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAIjD,8DAA8D;AAC9D,eAAO,MAAM,aAAa;;iBAExB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEzD,wBAAsB,OAAO,CAAC,KAAK,EAAE,YAAY;UATX,MAAM;aAAW,MAAM;;;;GAgC5D;AAED,+DAA+D;AAC/D,eAAO,MAAM,qBAAqB,EAAE,cAYnC,CAAC"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * get_file tool
3
+ *
4
+ * Fetches content of config or documentation files.
5
+ * Used for lazy loading after get_scaffold returns paths.
6
+ */
7
+ import { readFile } from 'fs/promises';
8
+ import { z } from 'zod';
9
+ import { createCache } from '../utils/cache.js';
10
+ import { isPathWithinRoot, resolveTemplatePath } from '../utils/paths.js';
11
+ const fileCache = createCache();
12
+ /** Zod schema for get_file input - single source of truth. */
13
+ export const getFileSchema = z.object({
14
+ path: z.string().describe('File path from get_scaffold (configFiles or docs array)'),
15
+ });
16
+ export async function getFile(input) {
17
+ const { path: filePath } = input;
18
+ // Security: prevent path traversal
19
+ if (!isPathWithinRoot(filePath)) {
20
+ return {
21
+ error: 'Invalid path: must be within template directory',
22
+ hint: 'Use paths from get_scaffold configFiles or docs arrays',
23
+ };
24
+ }
25
+ try {
26
+ return await fileCache.getOrSet(filePath, async () => {
27
+ const fullPath = resolveTemplatePath(filePath);
28
+ const content = await readFile(fullPath, 'utf-8');
29
+ return { path: filePath, content };
30
+ });
31
+ }
32
+ catch {
33
+ return {
34
+ error: `File not found: ${filePath}`,
35
+ hint: 'Ensure MCP server runs from react-spa-scaffold directory',
36
+ };
37
+ }
38
+ }
39
+ /** Tool definition derived from Zod schema (Zod v4 native). */
40
+ export const getFileToolDefinition = {
41
+ name: 'get_file',
42
+ description: `Fetch content of a config or documentation file.
43
+
44
+ Use paths from \`get_scaffold\` response:
45
+ - \`configFiles\`: config file paths (e.g., "vite.config.ts")
46
+ - \`docs\`: documentation paths (e.g., "docs/ARCHITECTURE.md")
47
+
48
+ Examples:
49
+ - \`{ path: "vite.config.ts" }\`
50
+ - \`{ path: "docs/TESTING.md" }\``,
51
+ inputSchema: z.toJSONSchema(getFileSchema),
52
+ };
53
+ //# sourceMappingURL=get-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-file.js","sourceRoot":"","sources":["../../src/tools/get-file.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAI1E,MAAM,SAAS,GAAG,WAAW,EAAqC,CAAC;AAEnE,8DAA8D;AAC9D,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yDAAyD,CAAC;CACrF,CAAC,CAAC;AAIH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,KAAmB;IAC/C,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IAEjC,mCAAmC;IACnC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChC,OAAO;YACL,KAAK,EAAE,iDAAiD;YACxD,IAAI,EAAE,wDAAwD;SAC/D,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,OAAO,MAAM,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;YACnD,MAAM,QAAQ,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;YAC/C,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAClD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;QACrC,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,KAAK,EAAE,mBAAmB,QAAQ,EAAE;YACpC,IAAI,EAAE,0DAA0D;SACjE,CAAC;IACJ,CAAC;AACH,CAAC;AAED,+DAA+D;AAC/D,MAAM,CAAC,MAAM,qBAAqB,GAAmB;IACnD,IAAI,EAAE,UAAU;IAChB,WAAW,EAAE;;;;;;;;kCAQmB;IAChC,WAAW,EAAE,CAAC,CAAC,YAAY,CAAC,aAAa,CAAkC;CAC5E,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Tests for get_file tool
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=get-file.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-file.test.d.ts","sourceRoot":"","sources":["../../src/tools/get-file.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Tests for get_file tool
3
+ */
4
+ import { describe, it, expect } from 'vitest';
5
+ import { getFile, getFileSchema } from './get-file.js';
6
+ describe('get_file tool', () => {
7
+ describe('schema validation', () => {
8
+ it('accepts valid path', () => {
9
+ const result = getFileSchema.safeParse({ path: 'vite.config.ts' });
10
+ expect(result.success).toBe(true);
11
+ });
12
+ it('rejects missing path', () => {
13
+ const result = getFileSchema.safeParse({});
14
+ expect(result.success).toBe(false);
15
+ });
16
+ });
17
+ describe('file fetching', () => {
18
+ it('fetches config file content', async () => {
19
+ const result = await getFile({ path: 'vite.config.ts' });
20
+ expect(result).not.toHaveProperty('error');
21
+ expect(result).toHaveProperty('path', 'vite.config.ts');
22
+ expect(result).toHaveProperty('content');
23
+ expect(result.content).toContain('defineConfig');
24
+ });
25
+ it('fetches documentation file content', async () => {
26
+ const result = await getFile({ path: 'docs/ARCHITECTURE.md' });
27
+ expect(result).not.toHaveProperty('error');
28
+ expect(result).toHaveProperty('path', 'docs/ARCHITECTURE.md');
29
+ expect(result).toHaveProperty('content');
30
+ expect(result.content).toContain('#');
31
+ });
32
+ it('fetches .gitignore content', async () => {
33
+ const result = await getFile({ path: '.gitignore' });
34
+ expect(result).not.toHaveProperty('error');
35
+ expect(result).toHaveProperty('content');
36
+ expect(result.content).toContain('node_modules');
37
+ });
38
+ });
39
+ describe('security', () => {
40
+ it('rejects path traversal attempts', async () => {
41
+ const result = await getFile({ path: '../../../etc/passwd' });
42
+ expect(result).toHaveProperty('error');
43
+ expect(result.error).toContain('Invalid path');
44
+ });
45
+ it('rejects absolute paths outside root', async () => {
46
+ const result = await getFile({ path: '/etc/passwd' });
47
+ expect(result).toHaveProperty('error');
48
+ });
49
+ it('rejects embedded path traversal', async () => {
50
+ const result = await getFile({ path: 'docs/../../../etc/passwd' });
51
+ expect(result).toHaveProperty('error');
52
+ });
53
+ });
54
+ describe('error handling', () => {
55
+ it('returns error for non-existent file', async () => {
56
+ const result = await getFile({ path: 'nonexistent-file.xyz' });
57
+ expect(result).toHaveProperty('error');
58
+ expect(result.error).toContain('File not found');
59
+ expect(result).toHaveProperty('hint');
60
+ });
61
+ });
62
+ });
63
+ //# sourceMappingURL=get-file.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-file.test.js","sourceRoot":"","sources":["../../src/tools/get-file.test.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,8 @@
7
7
  */
8
8
  import { z } from 'zod';
9
9
  import { type CodeExample } from '../utils/index.js';
10
+ import type { ToolDefinition } from './types.js';
11
+ /** Zod schema for get_scaffold input - single source of truth. */
10
12
  export declare const getScaffoldSchema: z.ZodObject<{
11
13
  features: z.ZodArray<z.ZodString>;
12
14
  projectName: z.ZodOptional<z.ZodString>;
@@ -16,9 +18,9 @@ export type GetScaffoldInput = z.infer<typeof getScaffoldSchema>;
16
18
  export declare function getScaffold(input: GetScaffoldInput): Promise<{
17
19
  projectName: string;
18
20
  selectedFeatures: string[];
19
- resolvedFeatures: string[];
21
+ resolvedFeatures: import("../features/types.js").FeatureId[];
20
22
  featureDetails: {
21
- id: string;
23
+ id: import("../features/types.js").FeatureId;
22
24
  name: string;
23
25
  wasExplicitlySelected: boolean;
24
26
  wasAutoIncluded: boolean;
@@ -32,39 +34,16 @@ export declare function getScaffold(input: GetScaffoldInput): Promise<{
32
34
  engines: Record<string, string>;
33
35
  };
34
36
  fileStructure: string[];
35
- configFiles: Record<string, string>;
37
+ configFiles: string[];
36
38
  setupCommands: string[];
37
39
  claudeMd: string;
38
40
  viteEnvDts: string;
39
41
  envTs: string;
40
42
  routesTs: string | undefined;
41
- docs: Record<string, string>;
43
+ docs: string[];
42
44
  examples: Record<string, CodeExample[]> | undefined;
43
45
  instructions: string;
44
46
  }>;
45
- export declare const getScaffoldToolDefinition: {
46
- name: string;
47
- description: string;
48
- inputSchema: {
49
- type: "object";
50
- properties: {
51
- features: {
52
- type: "array";
53
- items: {
54
- type: "string";
55
- };
56
- description: string;
57
- };
58
- projectName: {
59
- type: "string";
60
- description: string;
61
- };
62
- includeExamples: {
63
- type: "boolean";
64
- description: string;
65
- };
66
- };
67
- required: string[];
68
- };
69
- };
47
+ /** Tool definition derived from Zod schema - single source of truth (Zod v4 native). */
48
+ export declare const getScaffoldToolDefinition: ToolDefinition;
70
49
  //# sourceMappingURL=get-scaffold.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"get-scaffold.d.ts","sourceRoot":"","sources":["../../src/tools/get-scaffold.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAmE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEtH,eAAO,MAAM,iBAAiB;;;;iBAuB5B,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAEjE,wBAAsB,WAAW,CAAC,KAAK,EAAE,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDxD;AAiBD,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;CA8BrC,CAAC"}
1
+ {"version":3,"file":"get-scaffold.d.ts","sourceRoot":"","sources":["../../src/tools/get-scaffold.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAmE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACtH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,kEAAkE;AAClE,eAAO,MAAM,iBAAiB;;;;iBAuB5B,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAEjE,wBAAsB,WAAW,CAAC,KAAK,EAAE,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDxD;AAmBD,wFAAwF;AACxF,eAAO,MAAM,yBAAyB,EAAE,cAoBvC,CAAC"}
@@ -8,6 +8,7 @@
8
8
  import { z } from 'zod';
9
9
  import { FEATURE_IDS, FEATURES } from '../features/index.js';
10
10
  import { computeScaffold, resolveFeatureDependencies, getFeatureExamples } from '../utils/index.js';
11
+ /** Zod schema for get_scaffold input - single source of truth. */
11
12
  export const getScaffoldSchema = z.object({
12
13
  features: z
13
14
  .array(z.string())
@@ -82,44 +83,37 @@ function generateInstructions(setupCommands, features) {
82
83
  const hasRouting = features.includes('routing');
83
84
  return `## Setup Instructions
84
85
 
85
- 1. Create project directory and initialize with provided \`packageJson\`
86
- 2. Create files from \`fileStructure\` using \`get_example\` patterns
87
- 3. Use provided content directly for: \`viteEnvDts\`, \`envTs\`${hasRouting ? ', `routesTs`' : ''}, \`claudeMd\`, \`docs\`
88
- 4. Run: ${setupCommands.join(' && ')}
86
+ 1. Create project with \`packageJson\`
87
+ 2. Use generated content: \`claudeMd\`, \`viteEnvDts\`, \`envTs\`${hasRouting ? ', `routesTs`' : ''}
88
+ 3. Fetch config files: \`get_file({ path: "..." })\` for each in \`configFiles\`
89
+ 4. Fetch docs: \`get_file({ path: "..." })\` for each in \`docs\`
90
+ 5. Create source files: \`get_example({ pattern: "..." })\`
91
+ 6. Run: ${setupCommands.join(' && ')}
89
92
 
90
93
  ## IMPORTANT
91
94
 
92
95
  Templates are written for ALL features. Remove imports, providers, and code for features not in \`resolvedFeatures\`.`;
93
96
  }
97
+ /** Tool definition derived from Zod schema - single source of truth (Zod v4 native). */
94
98
  export const getScaffoldToolDefinition = {
95
99
  name: 'get_scaffold',
96
100
  description: `Get complete scaffold information for a new react-spa-scaffold project.
97
101
 
98
- Returns package.json, file structure, config files, generated content (env.ts, routes.ts, CLAUDE.md), and setup commands.
102
+ Returns package.json, file structure paths, setup commands, and generated files.
103
+
104
+ **Lazy Loading**: \`configFiles\` and \`docs\` contain paths only.
105
+ Use \`get_file({ path: "..." })\` to fetch individual file content.
106
+
107
+ **Generated Content** (included directly):
108
+ - \`claudeMd\`: CLAUDE.md content
109
+ - \`viteEnvDts\`, \`envTs\`: TypeScript declarations
110
+ - \`routesTs\`: Route constants (if routing feature selected)
99
111
 
100
112
  IMPORTANT: Templates contain code for ALL features. Strip imports and code for features not in \`resolvedFeatures\`.
101
113
 
102
114
  Feature dependencies: theming → state (auto-included)
103
115
 
104
116
  Example: features: ["routing", "ui", "theming"] → resolvedFeatures: ["core", "routing", "ui", "theming", "state"]`,
105
- inputSchema: {
106
- type: 'object',
107
- properties: {
108
- features: {
109
- type: 'array',
110
- items: { type: 'string' },
111
- description: 'List of feature IDs to include',
112
- },
113
- projectName: {
114
- type: 'string',
115
- description: 'Name for the new project',
116
- },
117
- includeExamples: {
118
- type: 'boolean',
119
- description: 'Include code examples for patterns',
120
- },
121
- },
122
- required: ['features'],
123
- },
117
+ inputSchema: z.toJSONSchema(getScaffoldSchema),
124
118
  };
125
119
  //# sourceMappingURL=get-scaffold.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"get-scaffold.js","sourceRoot":"","sources":["../../src/tools/get-scaffold.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"get-scaffold.js","sourceRoot":"","sources":["../../src/tools/get-scaffold.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Tests for get_scaffold tool
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=get-scaffold.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-scaffold.test.d.ts","sourceRoot":"","sources":["../../src/tools/get-scaffold.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,197 @@
1
+ /**
2
+ * Tests for get_scaffold tool
3
+ */
4
+ import { describe, it, expect } from 'vitest';
5
+ import { getScaffold, getScaffoldSchema } from './get-scaffold.js';
6
+ describe('get_scaffold tool', () => {
7
+ it('always includes core feature', async () => {
8
+ const result = await getScaffold({ features: ['routing'] });
9
+ expect(result.resolvedFeatures).toContain('core');
10
+ });
11
+ it('rejects invalid features via schema', () => {
12
+ const result = getScaffoldSchema.safeParse({
13
+ features: ['invalid-feature'],
14
+ });
15
+ expect(result.success).toBe(false);
16
+ if (!result.success) {
17
+ expect(result.error.message).toContain('Invalid features');
18
+ }
19
+ });
20
+ it('only includes explicitly selected features (plus core)', async () => {
21
+ const result = await getScaffold({ features: ['ui'] });
22
+ expect(result.resolvedFeatures).not.toContain('state');
23
+ expect(result.resolvedFeatures).not.toContain('mobile');
24
+ expect(result.resolvedFeatures).toContain('ui');
25
+ expect(result.resolvedFeatures).toContain('core');
26
+ });
27
+ it('theming feature auto-includes state feature', async () => {
28
+ const result = await getScaffold({ features: ['theming'] });
29
+ expect(result.resolvedFeatures).toContain('theming');
30
+ expect(result.resolvedFeatures).toContain('state');
31
+ expect(result.resolvedFeatures).toContain('core');
32
+ });
33
+ it('marks auto-included features correctly', async () => {
34
+ const result = await getScaffold({ features: ['theming'] });
35
+ const themingDetail = result.featureDetails.find((f) => f.id === 'theming');
36
+ const stateDetail = result.featureDetails.find((f) => f.id === 'state');
37
+ const coreDetail = result.featureDetails.find((f) => f.id === 'core');
38
+ // Theming was explicitly selected
39
+ expect(themingDetail?.wasExplicitlySelected).toBe(true);
40
+ expect(themingDetail?.wasAutoIncluded).toBe(false);
41
+ // State was auto-included (dependency of theming)
42
+ expect(stateDetail?.wasExplicitlySelected).toBe(false);
43
+ expect(stateDetail?.wasAutoIncluded).toBe(true);
44
+ // Core is always auto-included
45
+ expect(coreDetail?.wasExplicitlySelected).toBe(false);
46
+ expect(coreDetail?.wasAutoIncluded).toBe(true);
47
+ });
48
+ it('includes theming files when theming feature is selected', async () => {
49
+ const result = await getScaffold({ features: ['theming'] });
50
+ expect(result.fileStructure).toContain('src/hooks/useThemeEffect.ts');
51
+ expect(result.fileStructure).toContain('src/components/shared/ThemeToggle/ThemeToggle.tsx');
52
+ });
53
+ it('excludes theming files when only ui is selected', async () => {
54
+ const result = await getScaffold({ features: ['ui'] });
55
+ expect(result.fileStructure).not.toContain('src/hooks/useThemeEffect.ts');
56
+ expect(result.fileStructure).not.toContain('src/components/shared/ThemeToggle/ThemeToggle.tsx');
57
+ });
58
+ it('includes mobile files when mobile feature is selected', async () => {
59
+ const result = await getScaffold({ features: ['mobile'] });
60
+ expect(result.fileStructure).toContain('src/contexts/mobileContext.tsx');
61
+ expect(result.fileStructure).toContain('src/hooks/useMediaQuery.ts');
62
+ expect(result.fileStructure).toContain('src/hooks/useTouchSizes.ts');
63
+ });
64
+ it('excludes mobile files when only core is selected', async () => {
65
+ const result = await getScaffold({ features: [] });
66
+ expect(result.fileStructure).not.toContain('src/contexts/mobileContext.tsx');
67
+ expect(result.fileStructure).not.toContain('src/hooks/useMediaQuery.ts');
68
+ });
69
+ it('returns valid package.json structure', async () => {
70
+ const result = await getScaffold({ features: ['routing'], projectName: 'test-app' });
71
+ expect(result.packageJson).toBeDefined();
72
+ expect(result.packageJson.name).toBe('test-app');
73
+ expect(result.packageJson.dependencies).toBeDefined();
74
+ expect(result.packageJson.devDependencies).toBeDefined();
75
+ expect(result.packageJson.scripts).toBeDefined();
76
+ });
77
+ it('includes react in core dependencies', async () => {
78
+ const result = await getScaffold({ features: [] });
79
+ expect(result.packageJson.dependencies).toHaveProperty('react');
80
+ expect(result.packageJson.dependencies).toHaveProperty('react-dom');
81
+ });
82
+ it('includes routing dependencies when routing feature selected', async () => {
83
+ const result = await getScaffold({ features: ['routing'] });
84
+ expect(result.packageJson.dependencies).toHaveProperty('react-router');
85
+ });
86
+ it('returns file structure', async () => {
87
+ const result = await getScaffold({ features: ['routing'] });
88
+ expect(Array.isArray(result.fileStructure)).toBe(true);
89
+ expect(result.fileStructure.length).toBeGreaterThan(0);
90
+ });
91
+ it('returns setup commands', async () => {
92
+ const result = await getScaffold({ features: ['routing'] });
93
+ expect(Array.isArray(result.setupCommands)).toBe(true);
94
+ expect(result.setupCommands).toContain('npm install');
95
+ });
96
+ it('uses default project name when not provided', async () => {
97
+ const result = await getScaffold({ features: [] });
98
+ expect(result.projectName).toBe('my-app');
99
+ });
100
+ it('marks explicitly selected features correctly', async () => {
101
+ const result = await getScaffold({ features: ['ui', 'state'] });
102
+ const stateDetail = result.featureDetails.find((f) => f.id === 'state');
103
+ const uiDetail = result.featureDetails.find((f) => f.id === 'ui');
104
+ expect(stateDetail?.wasExplicitlySelected).toBe(true);
105
+ expect(stateDetail?.wasAutoIncluded).toBe(false);
106
+ expect(uiDetail?.wasExplicitlySelected).toBe(true);
107
+ expect(uiDetail?.wasAutoIncluded).toBe(false);
108
+ });
109
+ it('includes CLAUDE.md in file structure', async () => {
110
+ const result = await getScaffold({ features: [] });
111
+ expect(result.fileStructure).toContain('CLAUDE.md');
112
+ });
113
+ it('returns claudeMd content', async () => {
114
+ const result = await getScaffold({ features: [], projectName: 'test-project' });
115
+ expect(result.claudeMd).toBeDefined();
116
+ expect(typeof result.claudeMd).toBe('string');
117
+ expect(result.claudeMd).toContain('# CLAUDE.md');
118
+ expect(result.claudeMd).toContain('test-project');
119
+ });
120
+ it('claudeMd includes testing section when testing feature selected', async () => {
121
+ const result = await getScaffold({ features: ['testing'] });
122
+ expect(result.claudeMd).toContain('## Testing');
123
+ expect(result.claudeMd).toContain('Vitest');
124
+ });
125
+ it('claudeMd excludes testing section when testing feature not selected', async () => {
126
+ const result = await getScaffold({ features: [] });
127
+ expect(result.claudeMd).not.toContain('## Testing');
128
+ });
129
+ it('claudeMd includes UI section only when ui feature selected', async () => {
130
+ const withUi = await getScaffold({ features: ['ui'] });
131
+ const withoutUi = await getScaffold({ features: [] });
132
+ expect(withUi.claudeMd).toContain('## UI Components');
133
+ expect(withoutUi.claudeMd).not.toContain('## UI Components');
134
+ });
135
+ it('claudeMd includes i18n section only when i18n feature selected', async () => {
136
+ const withI18n = await getScaffold({ features: ['i18n'] });
137
+ const withoutI18n = await getScaffold({ features: [] });
138
+ expect(withI18n.claudeMd).toContain('## Translations');
139
+ expect(withoutI18n.claudeMd).not.toContain('## Translations');
140
+ });
141
+ it('claudeMd includes mobile section only when mobile feature selected', async () => {
142
+ const withMobile = await getScaffold({ features: ['mobile'] });
143
+ const withoutMobile = await getScaffold({ features: [] });
144
+ expect(withMobile.claudeMd).toContain('## Mobile & Responsive Design');
145
+ expect(withMobile.claudeMd).toContain('MobileProvider');
146
+ expect(withoutMobile.claudeMd).not.toContain('## Mobile & Responsive Design');
147
+ });
148
+ it('claudeMd includes theming section only when theming feature selected', async () => {
149
+ const withTheming = await getScaffold({ features: ['theming'] });
150
+ const withoutTheming = await getScaffold({ features: [] });
151
+ expect(withTheming.claudeMd).toContain('## Theming');
152
+ expect(withTheming.claudeMd).toContain('usePreferencesStore');
153
+ expect(withoutTheming.claudeMd).not.toContain('## Theming');
154
+ });
155
+ it('claudeMd project structure shows contexts when mobile is selected', async () => {
156
+ const withMobile = await getScaffold({ features: ['mobile'] });
157
+ const withoutMobile = await getScaffold({ features: [] });
158
+ expect(withMobile.claudeMd).toContain('contexts/');
159
+ expect(withoutMobile.claudeMd).not.toContain('contexts/');
160
+ });
161
+ it('returns config files as paths array (lazy loading)', async () => {
162
+ const result = await getScaffold({ features: ['ui'] });
163
+ expect(Array.isArray(result.configFiles)).toBe(true);
164
+ expect(result.configFiles).toContain('components.json');
165
+ });
166
+ it('always includes .gitignore in fileStructure (core feature)', async () => {
167
+ const result = await getScaffold({ features: [] });
168
+ expect(result.fileStructure).toContain('.gitignore');
169
+ });
170
+ it('always includes .gitignore in configFiles array', async () => {
171
+ const result = await getScaffold({ features: [] });
172
+ expect(result.configFiles).toContain('.gitignore');
173
+ });
174
+ it('returns docs as paths array (lazy loading)', async () => {
175
+ const result = await getScaffold({ features: [] });
176
+ expect(Array.isArray(result.docs)).toBe(true);
177
+ expect(result.docs).toContain('docs/ARCHITECTURE.md');
178
+ expect(result.docs).not.toContain('docs/TESTING.md');
179
+ });
180
+ it('includes docs paths in structure', async () => {
181
+ const result = await getScaffold({ features: [] });
182
+ expect(result.fileStructure).toContain('docs/ARCHITECTURE.md');
183
+ expect(result.fileStructure).not.toContain('docs/TESTING.md');
184
+ });
185
+ it('adds feature-specific docs when feature selected', async () => {
186
+ const result = await getScaffold({ features: ['testing'] });
187
+ expect(result.fileStructure).toContain('docs/TESTING.md');
188
+ expect(result.docs).toContain('docs/TESTING.md');
189
+ });
190
+ it('instructions reference get_file for lazy loading', async () => {
191
+ const result = await getScaffold({ features: [] });
192
+ expect(result.instructions).toContain('get_file');
193
+ expect(result.instructions).toContain('configFiles');
194
+ expect(result.instructions).toContain('docs');
195
+ });
196
+ });
197
+ //# sourceMappingURL=get-scaffold.test.js.map