@eide/uniformgen 0.1.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 (299) hide show
  1. package/README.md +356 -0
  2. package/dist/auth/credentials.d.ts +58 -0
  3. package/dist/auth/credentials.d.ts.map +1 -0
  4. package/dist/auth/credentials.js +107 -0
  5. package/dist/cli.d.ts +3 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +563 -0
  8. package/dist/commands/init.d.ts +11 -0
  9. package/dist/commands/init.d.ts.map +1 -0
  10. package/dist/commands/init.js +113 -0
  11. package/dist/commands/login.d.ts +9 -0
  12. package/dist/commands/login.d.ts.map +1 -0
  13. package/dist/commands/login.js +158 -0
  14. package/dist/commands/logout.d.ts +5 -0
  15. package/dist/commands/logout.d.ts.map +1 -0
  16. package/dist/commands/logout.js +13 -0
  17. package/dist/commands/push.d.ts +13 -0
  18. package/dist/commands/push.d.ts.map +1 -0
  19. package/dist/commands/push.js +328 -0
  20. package/dist/commands/scaffold.d.ts +19 -0
  21. package/dist/commands/scaffold.d.ts.map +1 -0
  22. package/dist/commands/scaffold.js +366 -0
  23. package/dist/commands/seed.d.ts +20 -0
  24. package/dist/commands/seed.d.ts.map +1 -0
  25. package/dist/commands/seed.js +380 -0
  26. package/dist/commands/select-project.d.ts +10 -0
  27. package/dist/commands/select-project.d.ts.map +1 -0
  28. package/dist/commands/select-project.js +277 -0
  29. package/dist/commands/setup.d.ts +5 -0
  30. package/dist/commands/setup.d.ts.map +1 -0
  31. package/dist/commands/setup.js +51 -0
  32. package/dist/commands/sync.d.ts +13 -0
  33. package/dist/commands/sync.d.ts.map +1 -0
  34. package/dist/commands/sync.js +318 -0
  35. package/dist/commands/whoami.d.ts +5 -0
  36. package/dist/commands/whoami.d.ts.map +1 -0
  37. package/dist/commands/whoami.js +31 -0
  38. package/dist/config/load-config.d.ts +6 -0
  39. package/dist/config/load-config.d.ts.map +1 -0
  40. package/dist/config/load-config.js +103 -0
  41. package/dist/config/settings.d.ts +20 -0
  42. package/dist/config/settings.d.ts.map +1 -0
  43. package/dist/config/settings.js +64 -0
  44. package/dist/config/types.d.ts +152 -0
  45. package/dist/config/types.d.ts.map +1 -0
  46. package/dist/config/types.js +94 -0
  47. package/dist/fetcher/fetch-schemas.d.ts +140 -0
  48. package/dist/fetcher/fetch-schemas.d.ts.map +1 -0
  49. package/dist/fetcher/fetch-schemas.js +223 -0
  50. package/dist/fetcher/fetch-workflows.d.ts +53 -0
  51. package/dist/fetcher/fetch-workflows.d.ts.map +1 -0
  52. package/dist/fetcher/fetch-workflows.js +164 -0
  53. package/dist/generated/hooks/customer-detail.d.ts +74 -0
  54. package/dist/generated/hooks/customer-detail.d.ts.map +1 -0
  55. package/dist/generated/hooks/customer-detail.js +113 -0
  56. package/dist/generated/hooks/design-system.d.ts +74 -0
  57. package/dist/generated/hooks/design-system.d.ts.map +1 -0
  58. package/dist/generated/hooks/design-system.js +109 -0
  59. package/dist/generated/hooks/index.d.ts +16 -0
  60. package/dist/generated/hooks/index.d.ts.map +1 -0
  61. package/dist/generated/hooks/index.js +14 -0
  62. package/dist/generated/hooks/shopify-collection.d.ts +74 -0
  63. package/dist/generated/hooks/shopify-collection.d.ts.map +1 -0
  64. package/dist/generated/hooks/shopify-collection.js +113 -0
  65. package/dist/generated/hooks/shopify-market.d.ts +74 -0
  66. package/dist/generated/hooks/shopify-market.d.ts.map +1 -0
  67. package/dist/generated/hooks/shopify-market.js +109 -0
  68. package/dist/generated/hooks/shopify-product.d.ts +74 -0
  69. package/dist/generated/hooks/shopify-product.d.ts.map +1 -0
  70. package/dist/generated/hooks/shopify-product.js +113 -0
  71. package/dist/generated/hooks/shopify-variant.d.ts +74 -0
  72. package/dist/generated/hooks/shopify-variant.d.ts.map +1 -0
  73. package/dist/generated/hooks/shopify-variant.js +113 -0
  74. package/dist/generated/hooks/template.d.ts +74 -0
  75. package/dist/generated/hooks/template.d.ts.map +1 -0
  76. package/dist/generated/hooks/template.js +107 -0
  77. package/dist/generated/types/config.d.ts +88 -0
  78. package/dist/generated/types/config.d.ts.map +1 -0
  79. package/dist/generated/types/config.js +14 -0
  80. package/dist/generated/types/data-models/index.d.ts +7 -0
  81. package/dist/generated/types/data-models/index.d.ts.map +1 -0
  82. package/dist/generated/types/data-models/index.js +6 -0
  83. package/dist/generated/types/data-models/test.d.ts +29 -0
  84. package/dist/generated/types/data-models/test.d.ts.map +1 -0
  85. package/dist/generated/types/data-models/test.js +1 -0
  86. package/dist/generated/types/data-models/watch.d.ts +26 -0
  87. package/dist/generated/types/data-models/watch.d.ts.map +1 -0
  88. package/dist/generated/types/data-models/watch.js +1 -0
  89. package/dist/generated/types/field-types.d.ts +255 -0
  90. package/dist/generated/types/field-types.d.ts.map +1 -0
  91. package/dist/generated/types/field-types.js +35 -0
  92. package/dist/generated/types/hooks.d.ts +106 -0
  93. package/dist/generated/types/hooks.d.ts.map +1 -0
  94. package/dist/generated/types/hooks.js +9 -0
  95. package/dist/generated/types/index.d.ts +10 -0
  96. package/dist/generated/types/index.d.ts.map +1 -0
  97. package/dist/generated/types/index.js +9 -0
  98. package/dist/generated/types/models/button-variant.d.ts +16 -0
  99. package/dist/generated/types/models/button-variant.d.ts.map +1 -0
  100. package/dist/generated/types/models/button-variant.js +1 -0
  101. package/dist/generated/types/models/color-palette.d.ts +27 -0
  102. package/dist/generated/types/models/color-palette.d.ts.map +1 -0
  103. package/dist/generated/types/models/color-palette.js +1 -0
  104. package/dist/generated/types/models/color-with-scale.d.ts +15 -0
  105. package/dist/generated/types/models/color-with-scale.d.ts.map +1 -0
  106. package/dist/generated/types/models/color-with-scale.js +1 -0
  107. package/dist/generated/types/models/context.d.ts +53 -0
  108. package/dist/generated/types/models/context.d.ts.map +1 -0
  109. package/dist/generated/types/models/context.js +51 -0
  110. package/dist/generated/types/models/customer-detail.d.ts +32 -0
  111. package/dist/generated/types/models/customer-detail.d.ts.map +1 -0
  112. package/dist/generated/types/models/customer-detail.js +26 -0
  113. package/dist/generated/types/models/design-system-badges.d.ts +16 -0
  114. package/dist/generated/types/models/design-system-badges.d.ts.map +1 -0
  115. package/dist/generated/types/models/design-system-badges.js +1 -0
  116. package/dist/generated/types/models/design-system-buttons.d.ts +17 -0
  117. package/dist/generated/types/models/design-system-buttons.d.ts.map +1 -0
  118. package/dist/generated/types/models/design-system-buttons.js +1 -0
  119. package/dist/generated/types/models/design-system-cards.d.ts +16 -0
  120. package/dist/generated/types/models/design-system-cards.d.ts.map +1 -0
  121. package/dist/generated/types/models/design-system-cards.js +1 -0
  122. package/dist/generated/types/models/design-system-colors.d.ts +12 -0
  123. package/dist/generated/types/models/design-system-colors.d.ts.map +1 -0
  124. package/dist/generated/types/models/design-system-colors.js +1 -0
  125. package/dist/generated/types/models/design-system-dark-mode.d.ts +13 -0
  126. package/dist/generated/types/models/design-system-dark-mode.d.ts.map +1 -0
  127. package/dist/generated/types/models/design-system-dark-mode.js +1 -0
  128. package/dist/generated/types/models/design-system-focus-ring.d.ts +14 -0
  129. package/dist/generated/types/models/design-system-focus-ring.d.ts.map +1 -0
  130. package/dist/generated/types/models/design-system-focus-ring.js +1 -0
  131. package/dist/generated/types/models/design-system-grid.d.ts +18 -0
  132. package/dist/generated/types/models/design-system-grid.d.ts.map +1 -0
  133. package/dist/generated/types/models/design-system-grid.js +1 -0
  134. package/dist/generated/types/models/design-system-inputs.d.ts +26 -0
  135. package/dist/generated/types/models/design-system-inputs.d.ts.map +1 -0
  136. package/dist/generated/types/models/design-system-inputs.js +1 -0
  137. package/dist/generated/types/models/design-system-links.d.ts +16 -0
  138. package/dist/generated/types/models/design-system-links.d.ts.map +1 -0
  139. package/dist/generated/types/models/design-system-links.js +1 -0
  140. package/dist/generated/types/models/design-system-shadows.d.ts +20 -0
  141. package/dist/generated/types/models/design-system-shadows.d.ts.map +1 -0
  142. package/dist/generated/types/models/design-system-shadows.js +1 -0
  143. package/dist/generated/types/models/design-system-spacing.d.ts +13 -0
  144. package/dist/generated/types/models/design-system-spacing.d.ts.map +1 -0
  145. package/dist/generated/types/models/design-system-spacing.js +1 -0
  146. package/dist/generated/types/models/design-system-transitions.d.ts +15 -0
  147. package/dist/generated/types/models/design-system-transitions.d.ts.map +1 -0
  148. package/dist/generated/types/models/design-system-transitions.js +1 -0
  149. package/dist/generated/types/models/design-system-typography.d.ts +21 -0
  150. package/dist/generated/types/models/design-system-typography.d.ts.map +1 -0
  151. package/dist/generated/types/models/design-system-typography.js +1 -0
  152. package/dist/generated/types/models/design-system.d.ts +138 -0
  153. package/dist/generated/types/models/design-system.d.ts.map +1 -0
  154. package/dist/generated/types/models/design-system.js +64 -0
  155. package/dist/generated/types/models/experiment.d.ts +57 -0
  156. package/dist/generated/types/models/experiment.d.ts.map +1 -0
  157. package/dist/generated/types/models/experiment.js +55 -0
  158. package/dist/generated/types/models/font-file.d.ts +16 -0
  159. package/dist/generated/types/models/font-file.d.ts.map +1 -0
  160. package/dist/generated/types/models/font-file.js +1 -0
  161. package/dist/generated/types/models/index.d.ts +38 -0
  162. package/dist/generated/types/models/index.d.ts.map +1 -0
  163. package/dist/generated/types/models/index.js +12 -0
  164. package/dist/generated/types/models/integration.d.ts +32 -0
  165. package/dist/generated/types/models/integration.d.ts.map +1 -0
  166. package/dist/generated/types/models/integration.js +26 -0
  167. package/dist/generated/types/models/route-tree.d.ts +43 -0
  168. package/dist/generated/types/models/route-tree.d.ts.map +1 -0
  169. package/dist/generated/types/models/route-tree.js +39 -0
  170. package/dist/generated/types/models/segment.d.ts +57 -0
  171. package/dist/generated/types/models/segment.d.ts.map +1 -0
  172. package/dist/generated/types/models/segment.js +55 -0
  173. package/dist/generated/types/models/shopify-collection.d.ts +32 -0
  174. package/dist/generated/types/models/shopify-collection.d.ts.map +1 -0
  175. package/dist/generated/types/models/shopify-collection.js +26 -0
  176. package/dist/generated/types/models/shopify-market.d.ts +32 -0
  177. package/dist/generated/types/models/shopify-market.d.ts.map +1 -0
  178. package/dist/generated/types/models/shopify-market.js +26 -0
  179. package/dist/generated/types/models/shopify-product.d.ts +32 -0
  180. package/dist/generated/types/models/shopify-product.d.ts.map +1 -0
  181. package/dist/generated/types/models/shopify-product.js +26 -0
  182. package/dist/generated/types/models/shopify-variant.d.ts +32 -0
  183. package/dist/generated/types/models/shopify-variant.d.ts.map +1 -0
  184. package/dist/generated/types/models/shopify-variant.js +26 -0
  185. package/dist/generated/types/models/template.d.ts +53 -0
  186. package/dist/generated/types/models/template.d.ts.map +1 -0
  187. package/dist/generated/types/models/template.js +40 -0
  188. package/dist/generated/types/models/typography-variant.d.ts +15 -0
  189. package/dist/generated/types/models/typography-variant.d.ts.map +1 -0
  190. package/dist/generated/types/models/typography-variant.js +1 -0
  191. package/dist/generated/types/scalars.d.ts +56 -0
  192. package/dist/generated/types/scalars.d.ts.map +1 -0
  193. package/dist/generated/types/scalars.js +6 -0
  194. package/dist/generators/admin/index.d.ts +32 -0
  195. package/dist/generators/admin/index.d.ts.map +1 -0
  196. package/dist/generators/admin/index.js +219 -0
  197. package/dist/generators/admin/mutations.d.ts +23 -0
  198. package/dist/generators/admin/mutations.d.ts.map +1 -0
  199. package/dist/generators/admin/mutations.js +424 -0
  200. package/dist/generators/admin/queries.d.ts +20 -0
  201. package/dist/generators/admin/queries.d.ts.map +1 -0
  202. package/dist/generators/admin/queries.js +476 -0
  203. package/dist/generators/admin/types.d.ts +28 -0
  204. package/dist/generators/admin/types.d.ts.map +1 -0
  205. package/dist/generators/admin/types.js +254 -0
  206. package/dist/generators/cms/index.d.ts +29 -0
  207. package/dist/generators/cms/index.d.ts.map +1 -0
  208. package/dist/generators/cms/index.js +126 -0
  209. package/dist/generators/cms/route.d.ts +27 -0
  210. package/dist/generators/cms/route.d.ts.map +1 -0
  211. package/dist/generators/cms/route.js +409 -0
  212. package/dist/generators/cms/types.d.ts +15 -0
  213. package/dist/generators/cms/types.d.ts.map +1 -0
  214. package/dist/generators/cms/types.js +137 -0
  215. package/dist/generators/contexts/index.d.ts +25 -0
  216. package/dist/generators/contexts/index.d.ts.map +1 -0
  217. package/dist/generators/contexts/index.js +591 -0
  218. package/dist/generators/documents/data-models.d.ts +6 -0
  219. package/dist/generators/documents/data-models.d.ts.map +1 -0
  220. package/dist/generators/documents/data-models.js +61 -0
  221. package/dist/generators/documents/entity-models.d.ts +7 -0
  222. package/dist/generators/documents/entity-models.d.ts.map +1 -0
  223. package/dist/generators/documents/entity-models.js +87 -0
  224. package/dist/generators/documents/workflows.d.ts +11 -0
  225. package/dist/generators/documents/workflows.d.ts.map +1 -0
  226. package/dist/generators/documents/workflows.js +101 -0
  227. package/dist/generators/filters/index.d.ts +16 -0
  228. package/dist/generators/filters/index.d.ts.map +1 -0
  229. package/dist/generators/filters/index.js +384 -0
  230. package/dist/generators/hooks/agnostic.d.ts +16 -0
  231. package/dist/generators/hooks/agnostic.d.ts.map +1 -0
  232. package/dist/generators/hooks/agnostic.js +248 -0
  233. package/dist/generators/hooks/index.d.ts +9 -0
  234. package/dist/generators/hooks/index.d.ts.map +1 -0
  235. package/dist/generators/hooks/index.js +8 -0
  236. package/dist/generators/hooks/react.d.ts +16 -0
  237. package/dist/generators/hooks/react.d.ts.map +1 -0
  238. package/dist/generators/hooks/react.js +394 -0
  239. package/dist/generators/hooks/remix.d.ts +16 -0
  240. package/dist/generators/hooks/remix.d.ts.map +1 -0
  241. package/dist/generators/hooks/remix.js +349 -0
  242. package/dist/generators/hooks/workflows.d.ts +23 -0
  243. package/dist/generators/hooks/workflows.d.ts.map +1 -0
  244. package/dist/generators/hooks/workflows.js +312 -0
  245. package/dist/generators/resolve/index.d.ts +13 -0
  246. package/dist/generators/resolve/index.d.ts.map +1 -0
  247. package/dist/generators/resolve/index.js +13 -0
  248. package/dist/generators/resolve/platform.d.ts +29 -0
  249. package/dist/generators/resolve/platform.d.ts.map +1 -0
  250. package/dist/generators/resolve/platform.js +479 -0
  251. package/dist/generators/types/config.d.ts +7 -0
  252. package/dist/generators/types/config.d.ts.map +1 -0
  253. package/dist/generators/types/config.js +113 -0
  254. package/dist/generators/types/data-models.d.ts +10 -0
  255. package/dist/generators/types/data-models.d.ts.map +1 -0
  256. package/dist/generators/types/data-models.js +100 -0
  257. package/dist/generators/types/entity-models.d.ts +13 -0
  258. package/dist/generators/types/entity-models.d.ts.map +1 -0
  259. package/dist/generators/types/entity-models.js +241 -0
  260. package/dist/generators/types/field-types.d.ts +9 -0
  261. package/dist/generators/types/field-types.d.ts.map +1 -0
  262. package/dist/generators/types/field-types.js +651 -0
  263. package/dist/generators/types/hooks.d.ts +7 -0
  264. package/dist/generators/types/hooks.d.ts.map +1 -0
  265. package/dist/generators/types/hooks.js +132 -0
  266. package/dist/generators/types/scalars.d.ts +6 -0
  267. package/dist/generators/types/scalars.d.ts.map +1 -0
  268. package/dist/generators/types/scalars.js +68 -0
  269. package/dist/generators/types/user-details.d.ts +6 -0
  270. package/dist/generators/types/user-details.d.ts.map +1 -0
  271. package/dist/generators/types/user-details.js +60 -0
  272. package/dist/generators/types/workflows.d.ts +15 -0
  273. package/dist/generators/types/workflows.d.ts.map +1 -0
  274. package/dist/generators/types/workflows.js +163 -0
  275. package/dist/graphql/generated/gql.d.ts +47 -0
  276. package/dist/graphql/generated/gql.d.ts.map +1 -0
  277. package/dist/graphql/generated/gql.js +10 -0
  278. package/dist/graphql/generated/graphql.d.ts +8455 -0
  279. package/dist/graphql/generated/graphql.d.ts.map +1 -0
  280. package/dist/graphql/generated/graphql.js +573 -0
  281. package/dist/graphql/generated/index.d.ts +2 -0
  282. package/dist/graphql/generated/index.d.ts.map +1 -0
  283. package/dist/graphql/generated/index.js +1 -0
  284. package/dist/index.d.ts +13 -0
  285. package/dist/index.d.ts.map +1 -0
  286. package/dist/index.js +9 -0
  287. package/dist/schema/define-entity-model.d.ts +122 -0
  288. package/dist/schema/define-entity-model.d.ts.map +1 -0
  289. package/dist/schema/define-entity-model.js +59 -0
  290. package/dist/schema/schema-loader.d.ts +10 -0
  291. package/dist/schema/schema-loader.d.ts.map +1 -0
  292. package/dist/schema/schema-loader.js +91 -0
  293. package/dist/utils/field-mapping.d.ts +83 -0
  294. package/dist/utils/field-mapping.d.ts.map +1 -0
  295. package/dist/utils/field-mapping.js +334 -0
  296. package/dist/writer/write-files.d.ts +12 -0
  297. package/dist/writer/write-files.d.ts.map +1 -0
  298. package/dist/writer/write-files.js +35 -0
  299. package/package.json +70 -0
@@ -0,0 +1,51 @@
1
+ import inquirer from 'inquirer';
2
+ import chalk from 'chalk';
3
+ import { getSettings, updateSettings } from '../config/settings.js';
4
+ const FRAMEWORK_CHOICES = [
5
+ {
6
+ name: 'React (Apollo Client)',
7
+ value: 'react',
8
+ description: 'Generate useQuery/useMutation hooks with Apollo Client',
9
+ },
10
+ {
11
+ name: 'Remix (Hydrogen/Storefront)',
12
+ value: 'remix',
13
+ description: 'Generate loader/action helpers for Remix and Hydrogen',
14
+ },
15
+ {
16
+ name: 'Agnostic (typed helpers only)',
17
+ value: 'agnostic',
18
+ description: 'Generate framework-agnostic typed parser functions',
19
+ },
20
+ ];
21
+ /**
22
+ * Setup command - configure UniformGen preferences
23
+ */
24
+ export async function setup() {
25
+ const currentSettings = await getSettings();
26
+ console.log(chalk.bold('\nUniformGen Setup\n'));
27
+ console.log('Configure your code generation preferences.\n');
28
+ // Framework selection
29
+ const { framework } = await inquirer.prompt([
30
+ {
31
+ type: 'list',
32
+ name: 'framework',
33
+ message: 'Select your target framework:',
34
+ default: currentSettings.framework,
35
+ choices: FRAMEWORK_CHOICES.map((choice) => ({
36
+ name: `${choice.name}\n ${chalk.gray(choice.description)}`,
37
+ value: choice.value,
38
+ short: choice.name,
39
+ })),
40
+ },
41
+ ]);
42
+ // Save settings
43
+ await updateSettings({ framework });
44
+ console.log('');
45
+ console.log(chalk.green('✓ Settings saved!'));
46
+ console.log('');
47
+ console.log(chalk.gray('Your preferences:'));
48
+ console.log(chalk.gray(` Framework: ${framework}`));
49
+ console.log('');
50
+ console.log(chalk.cyan('Run `uniformgen pull` to generate typed hooks for your models.'));
51
+ }
@@ -0,0 +1,13 @@
1
+ interface SyncOptions {
2
+ apiUrl: string;
3
+ schemasDir: string;
4
+ pattern?: string;
5
+ publish?: boolean;
6
+ config?: string;
7
+ }
8
+ /**
9
+ * Sync command - push local schemas then pull generated types
10
+ */
11
+ export declare function sync(options: SyncOptions): Promise<void>;
12
+ export {};
13
+ //# sourceMappingURL=sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAgEA,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAyX9D"}
@@ -0,0 +1,318 @@
1
+ import chalk from 'chalk';
2
+ import { push } from './push.js';
3
+ import { loadConfig } from '../config/load-config.js';
4
+ import { getSettings } from '../config/settings.js';
5
+ import { fetchEntityModels } from '../fetcher/fetch-schemas.js';
6
+ import { fetchWorkflows } from '../fetcher/fetch-workflows.js';
7
+ import { generateEntityModelTypes, generateEntityModelsIndex, } from '../generators/types/entity-models.js';
8
+ import { generateFieldTypesFile } from '../generators/types/field-types.js';
9
+ import { generateHooksFile } from '../generators/types/hooks.js';
10
+ import { generateConfigFile } from '../generators/types/config.js';
11
+ import { generateEntityModelDocuments } from '../generators/documents/entity-models.js';
12
+ import { generateAgnosticHooks, generateAgnosticHooksIndex, generateReactHooks, generateReactHooksIndex, generateRemixHooks, generateRemixHooksIndex, } from '../generators/hooks/index.js';
13
+ // Phase 13: Admin layer generators
14
+ import { generateAdminHooksReact, generateAdminHooksRemix, generateAdminHooksIndexReact, generateAdminHooksIndexRemix, } from '../generators/admin/index.js';
15
+ // Phase 13: Platform resolve generators
16
+ import { generatePlatformResolveReact, generatePlatformResolveRemix, generatePlatformResolveIndexReact, generatePlatformResolveIndexRemix, } from '../generators/resolve/index.js';
17
+ // Phase 13: CMS layer generators
18
+ import { getRoutableModels, generateCmsTypes, generateResolveRouteReact as generateCmsRouteReact, generateResolveRouteRemix as generateCmsRouteRemix, generateCmsIndexReact, generateCmsIndexRemix, } from '../generators/cms/index.js';
19
+ import { generateModelFilters, generateFiltersIndex, } from '../generators/filters/index.js';
20
+ // Workflow generators
21
+ import { generateWorkflowTypes, generateWorkflowTypesIndex, } from '../generators/types/workflows.js';
22
+ import { generateWorkflowReactHooks, generateWorkflowRemixHooks, generateWorkflowReactHooksIndex, generateWorkflowRemixHooksIndex, } from '../generators/hooks/workflows.js';
23
+ import { generateWorkflowDocuments } from '../generators/documents/workflows.js';
24
+ import { writeFiles } from '../writer/write-files.js';
25
+ import { join } from 'path';
26
+ /**
27
+ * Sync command - push local schemas then pull generated types
28
+ */
29
+ export async function sync(options) {
30
+ console.log(chalk.bold('Phase 1: Push local schemas\n'));
31
+ console.log('─'.repeat(40));
32
+ // Push schemas
33
+ await push({
34
+ apiUrl: options.apiUrl,
35
+ schemasDir: options.schemasDir,
36
+ pattern: options.pattern,
37
+ dryRun: false,
38
+ publish: options.publish,
39
+ });
40
+ console.log('\n' + chalk.bold('Phase 2: Pull generated types\n'));
41
+ console.log('─'.repeat(40));
42
+ // Load config for pull
43
+ const config = await loadConfig(options.config, process.cwd());
44
+ if (options.apiUrl)
45
+ config.apiUrl = options.apiUrl;
46
+ // Fetch updated entity models
47
+ console.log('Fetching updated entity models...');
48
+ const entityModels = await fetchEntityModels(config.apiUrl, config.accessToken, config.tenantId, config.projectId, { includeInline: true });
49
+ const recordModels = entityModels.filter((m) => m.modes.records);
50
+ const inlineOnlyModels = entityModels.filter((m) => m.modes.inline && !m.modes.records);
51
+ console.log(`Fetched ${entityModels.length} entity models (${recordModels.length} with records, ${inlineOnlyModels.length} inline-only)\n`);
52
+ // Generate files
53
+ const files = [];
54
+ // Generate base type files
55
+ console.log('Generating type definitions...');
56
+ files.push({
57
+ path: join(config.output.types, 'field-types.ts'),
58
+ content: generateFieldTypesFile(),
59
+ });
60
+ files.push({
61
+ path: join(config.output.types, 'hooks.ts'),
62
+ content: generateHooksFile(),
63
+ });
64
+ files.push({
65
+ path: join(config.output.types, 'config.ts'),
66
+ content: generateConfigFile(),
67
+ });
68
+ // Generate entity model types
69
+ if (entityModels.length > 0) {
70
+ const modelsDir = join(config.output.types, 'models');
71
+ for (const model of entityModels) {
72
+ files.push({
73
+ path: join(modelsDir, `${model.key}.ts`),
74
+ content: generateEntityModelTypes(model, entityModels),
75
+ });
76
+ }
77
+ files.push({
78
+ path: join(modelsDir, 'index.ts'),
79
+ content: generateEntityModelsIndex(entityModels),
80
+ });
81
+ }
82
+ // Generate GraphQL documents for public API models
83
+ const publicApiModels = recordModels.filter((m) => m.modes.publicApi);
84
+ if (publicApiModels.length > 0) {
85
+ console.log(`Generating GraphQL documents for ${publicApiModels.length} public API models...`);
86
+ for (const model of publicApiModels) {
87
+ files.push({
88
+ path: join(config.output.documents, `${model.key}.graphql`),
89
+ content: generateEntityModelDocuments(model),
90
+ });
91
+ }
92
+ }
93
+ // Generate typed hooks based on framework setting
94
+ const settings = await getSettings();
95
+ const framework = config.framework || settings.framework || 'agnostic';
96
+ const hooksDir = config.output.hooks;
97
+ if (publicApiModels.length > 0) {
98
+ console.log(`Generating ${framework} hooks for ${publicApiModels.length} models...`);
99
+ let generateHook;
100
+ let generateIndex;
101
+ switch (framework) {
102
+ case 'react':
103
+ generateHook = generateReactHooks;
104
+ generateIndex = generateReactHooksIndex;
105
+ break;
106
+ case 'remix':
107
+ generateHook = generateRemixHooks;
108
+ generateIndex = generateRemixHooksIndex;
109
+ break;
110
+ default:
111
+ generateHook = generateAgnosticHooks;
112
+ generateIndex = generateAgnosticHooksIndex;
113
+ }
114
+ for (const model of publicApiModels) {
115
+ const hookContent = generateHook(model, entityModels);
116
+ if (hookContent) {
117
+ files.push({
118
+ path: join(hooksDir, `${model.key}.ts`),
119
+ content: hookContent,
120
+ });
121
+ }
122
+ }
123
+ files.push({
124
+ path: join(hooksDir, 'index.ts'),
125
+ content: generateIndex(publicApiModels),
126
+ });
127
+ }
128
+ // ========================================================================
129
+ // Phase 13: Generate layered API structure
130
+ // ========================================================================
131
+ // Phase 13: Generate admin hooks (CRUD, versioning)
132
+ if (publicApiModels.length > 0 && framework !== 'agnostic') {
133
+ console.log(`Generating ${framework} admin hooks for ${publicApiModels.length} models...`);
134
+ const adminDir = join(hooksDir, 'admin');
135
+ const generateAdmin = framework === 'react' ? generateAdminHooksReact : generateAdminHooksRemix;
136
+ const generateAdminIndex = framework === 'react' ? generateAdminHooksIndexReact : generateAdminHooksIndexRemix;
137
+ for (const model of publicApiModels) {
138
+ const adminContent = generateAdmin(model, entityModels);
139
+ if (adminContent) {
140
+ files.push({
141
+ path: join(adminDir, `${model.key}.ts`),
142
+ content: adminContent,
143
+ });
144
+ }
145
+ }
146
+ files.push({
147
+ path: join(adminDir, 'index.ts'),
148
+ content: generateAdminIndex(publicApiModels),
149
+ });
150
+ }
151
+ // Phase 13: Generate platform resolve hooks (clean, no CMS features)
152
+ if (publicApiModels.length > 0 && framework !== 'agnostic') {
153
+ console.log(`Generating ${framework} platform resolve hooks for ${publicApiModels.length} models...`);
154
+ const platformResolveDir = join(hooksDir, 'resolve');
155
+ const generatePlatformResolve = framework === 'react' ? generatePlatformResolveReact : generatePlatformResolveRemix;
156
+ const generatePlatformIndex = framework === 'react' ? generatePlatformResolveIndexReact : generatePlatformResolveIndexRemix;
157
+ for (const model of publicApiModels) {
158
+ const resolveContent = generatePlatformResolve(model, entityModels);
159
+ if (resolveContent) {
160
+ files.push({
161
+ path: join(platformResolveDir, `${model.key}.ts`),
162
+ content: resolveContent,
163
+ });
164
+ }
165
+ }
166
+ files.push({
167
+ path: join(platformResolveDir, 'index.ts'),
168
+ content: generatePlatformIndex(publicApiModels),
169
+ });
170
+ }
171
+ // Phase 13: Generate CMS hooks (only if cms.enabled models exist)
172
+ const routableModels = getRoutableModels(entityModels);
173
+ if (routableModels.length > 0 && framework !== 'agnostic') {
174
+ console.log(`Generating ${framework} CMS hooks for ${routableModels.length} routable models...`);
175
+ const cmsDir = join(hooksDir, 'cms');
176
+ const generateCmsRoute = framework === 'react' ? generateCmsRouteReact : generateCmsRouteRemix;
177
+ const generateCmsIndex = framework === 'react' ? generateCmsIndexReact : generateCmsIndexRemix;
178
+ // Generate CMS types
179
+ files.push({
180
+ path: join(cmsDir, 'types.ts'),
181
+ content: generateCmsTypes(),
182
+ });
183
+ // Generate resolveRoute hook/function
184
+ files.push({
185
+ path: join(cmsDir, 'route.ts'),
186
+ content: generateCmsRoute(routableModels),
187
+ });
188
+ // Generate CMS index
189
+ files.push({
190
+ path: join(cmsDir, 'index.ts'),
191
+ content: generateCmsIndex(entityModels),
192
+ });
193
+ }
194
+ // Generate typed filters
195
+ if (publicApiModels.length > 0) {
196
+ console.log(`Generating typed filters for ${publicApiModels.length} models...`);
197
+ const filtersDir = join(config.output.types, '..', 'filters');
198
+ for (const model of publicApiModels) {
199
+ const filterContent = generateModelFilters(model, entityModels);
200
+ if (filterContent) {
201
+ files.push({
202
+ path: join(filtersDir, `${model.key}.ts`),
203
+ content: filterContent,
204
+ });
205
+ }
206
+ }
207
+ files.push({
208
+ path: join(filtersDir, 'index.ts'),
209
+ content: generateFiltersIndex(publicApiModels),
210
+ });
211
+ }
212
+ // ========================================================================
213
+ // Workflow Codegen: Generate typed workflow code
214
+ // ========================================================================
215
+ // Fetch workflows with API touchpoint
216
+ console.log('Fetching API workflows...');
217
+ let workflows = [];
218
+ try {
219
+ workflows = await fetchWorkflows(config.apiUrl, config.accessToken, config.tenantId, config.projectId);
220
+ console.log(`Fetched ${workflows.length} workflows with API touchpoint\n`);
221
+ }
222
+ catch (error) {
223
+ // Workflows may not exist yet - continue without them
224
+ console.log(chalk.yellow('Could not fetch workflows (this is OK if no workflows exist)\n'));
225
+ }
226
+ if (workflows.length > 0) {
227
+ // Generate workflow types
228
+ console.log(`Generating workflow types for ${workflows.length} workflows...`);
229
+ const workflowTypesDir = join(config.output.types, 'workflows');
230
+ for (const workflow of workflows) {
231
+ files.push({
232
+ path: join(workflowTypesDir, `${workflow.key}.ts`),
233
+ content: generateWorkflowTypes(workflow),
234
+ });
235
+ }
236
+ files.push({
237
+ path: join(workflowTypesDir, 'index.ts'),
238
+ content: generateWorkflowTypesIndex(workflows),
239
+ });
240
+ // Generate workflow GraphQL documents
241
+ console.log('Generating workflow GraphQL documents...');
242
+ files.push({
243
+ path: join(config.output.documents, 'workflows.ts'),
244
+ content: generateWorkflowDocuments(),
245
+ });
246
+ // Generate workflow hooks based on framework
247
+ if (framework !== 'agnostic') {
248
+ console.log(`Generating ${framework} workflow hooks for ${workflows.length} workflows...`);
249
+ const workflowHooksDir = join(hooksDir, 'workflows');
250
+ const generateWorkflowHook = framework === 'react'
251
+ ? generateWorkflowReactHooks
252
+ : generateWorkflowRemixHooks;
253
+ const generateWorkflowIndex = framework === 'react'
254
+ ? generateWorkflowReactHooksIndex
255
+ : generateWorkflowRemixHooksIndex;
256
+ for (const workflow of workflows) {
257
+ files.push({
258
+ path: join(workflowHooksDir, `${workflow.key}.ts`),
259
+ content: generateWorkflowHook(workflow),
260
+ });
261
+ }
262
+ files.push({
263
+ path: join(workflowHooksDir, 'index.ts'),
264
+ content: generateWorkflowIndex(workflows),
265
+ });
266
+ }
267
+ }
268
+ // Generate main index
269
+ files.push({
270
+ path: join(config.output.types, 'index.ts'),
271
+ content: `/**
272
+ * Generated types for EIDE project
273
+ *
274
+ * @generated by UniformGen - DO NOT EDIT MANUALLY
275
+ */
276
+
277
+ export * from './field-types.js';
278
+ export * from './hooks.js';
279
+ export * from './config.js';
280
+ ${entityModels.length > 0 ? "export * from './models/index.js';" : ''}
281
+ ${workflows.length > 0 ? "export * from './workflows/index.js';" : ''}
282
+ `,
283
+ });
284
+ // Write files
285
+ console.log(`Writing ${files.length} files...`);
286
+ await writeFiles(files, config.prettier);
287
+ console.log(chalk.green(`\n✓ Sync complete!`));
288
+ console.log(chalk.gray(` Types: ${config.output.types}`));
289
+ console.log(chalk.gray(` Documents: ${config.output.documents}`));
290
+ console.log(chalk.gray(` Hooks: ${config.output.hooks}`));
291
+ console.log('');
292
+ console.log(chalk.cyan('Generated:'));
293
+ console.log(chalk.gray(` • field-types.ts - Field type definitions and value types`));
294
+ console.log(chalk.gray(` • hooks.ts - Lifecycle hook type definitions`));
295
+ console.log(chalk.gray(` • config.ts - EntityModelConfig base type`));
296
+ console.log(chalk.gray(` • ${entityModels.length} model files (${recordModels.length} configs + ${inlineOnlyModels.length} inline types)`));
297
+ if (publicApiModels.length > 0) {
298
+ console.log(chalk.gray(` • ${publicApiModels.length} GraphQL document files`));
299
+ console.log(chalk.gray(` • ${publicApiModels.length} ${framework} hook files`));
300
+ console.log(chalk.gray(` • ${publicApiModels.length} typed filter files`));
301
+ }
302
+ // Phase 13 output
303
+ if (publicApiModels.length > 0 && framework !== 'agnostic') {
304
+ console.log(chalk.gray(` • hooks/admin/ - ${publicApiModels.length} admin CRUD hooks`));
305
+ console.log(chalk.gray(` • hooks/resolve/ - ${publicApiModels.length} platform resolve hooks`));
306
+ }
307
+ if (routableModels.length > 0 && framework !== 'agnostic') {
308
+ console.log(chalk.gray(` • hooks/cms/ - CMS route resolution (${routableModels.length} routable models)`));
309
+ }
310
+ // Workflow output
311
+ if (workflows.length > 0) {
312
+ console.log(chalk.gray(` • types/workflows/ - ${workflows.length} workflow type definitions`));
313
+ console.log(chalk.gray(` • documents/workflows.ts - Workflow GraphQL documents`));
314
+ if (framework !== 'agnostic') {
315
+ console.log(chalk.gray(` • hooks/workflows/ - ${workflows.length} ${framework} workflow hooks`));
316
+ }
317
+ }
318
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Whoami command - show current authentication status
3
+ */
4
+ export declare function whoami(): Promise<void>;
5
+ //# sourceMappingURL=whoami.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.d.ts","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,wBAAsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CA6B5C"}
@@ -0,0 +1,31 @@
1
+ import { getCredentials, isTokenExpired } from '../auth/credentials.js';
2
+ /**
3
+ * Whoami command - show current authentication status
4
+ */
5
+ export async function whoami() {
6
+ const credentials = await getCredentials();
7
+ if (!credentials) {
8
+ console.log('Not logged in.');
9
+ console.log('\nRun `uniformgen login` to authenticate.');
10
+ process.exit(1);
11
+ }
12
+ const expired = isTokenExpired(credentials);
13
+ console.log('Authentication Status');
14
+ console.log('─'.repeat(40));
15
+ console.log(`User: ${credentials.user.name} <${credentials.user.email}>`);
16
+ console.log(`User ID: ${credentials.user.id}`);
17
+ console.log(`Token: ${expired ? '⚠ Expired' : '✓ Valid'}`);
18
+ if (credentials.selectedProject) {
19
+ console.log('');
20
+ console.log('Selected Project');
21
+ console.log('─'.repeat(40));
22
+ console.log(`Name: ${credentials.selectedProject.name}`);
23
+ console.log(`ID: ${credentials.selectedProject.id}`);
24
+ console.log(`Tenant ID: ${credentials.selectedProject.tenantId}`);
25
+ }
26
+ else {
27
+ console.log('');
28
+ console.log('No project selected.');
29
+ console.log('Run `uniformgen select-project` to choose a project.');
30
+ }
31
+ }
@@ -0,0 +1,6 @@
1
+ import { type UniformGenConfig } from './types.js';
2
+ /**
3
+ * Load configuration from file or use defaults
4
+ */
5
+ export declare function loadConfig(configPath?: string, cwd?: string): Promise<UniformGenConfig>;
6
+ //# sourceMappingURL=load-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-config.d.ts","sourceRoot":"","sources":["../../src/config/load-config.ts"],"names":[],"mappings":"AAGA,OAAO,EAA+B,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAehF;;GAEG;AACH,wBAAsB,UAAU,CAC9B,UAAU,CAAC,EAAE,MAAM,EACnB,GAAG,GAAE,MAAsB,GAC1B,OAAO,CAAC,gBAAgB,CAAC,CAuG3B"}
@@ -0,0 +1,103 @@
1
+ import { pathToFileURL } from 'url';
2
+ import { existsSync } from 'fs';
3
+ import { resolve, join } from 'path';
4
+ import { ConfigSchema, defaultConfig } from './types.js';
5
+ import { getCredentials } from '../auth/credentials.js';
6
+ /**
7
+ * Possible config file names
8
+ */
9
+ const CONFIG_FILES = [
10
+ '.uniformrc.ts',
11
+ '.uniformrc.js',
12
+ '.uniformrc.mjs',
13
+ 'uniformgen.config.ts',
14
+ 'uniformgen.config.js',
15
+ 'uniformgen.config.mjs',
16
+ ];
17
+ /**
18
+ * Load configuration from file or use defaults
19
+ */
20
+ export async function loadConfig(configPath, cwd = process.cwd()) {
21
+ let configFile = null;
22
+ // If explicit config path provided, use it
23
+ if (configPath) {
24
+ const absolutePath = resolve(cwd, configPath);
25
+ if (!existsSync(absolutePath)) {
26
+ throw new Error(`Config file not found: ${absolutePath}`);
27
+ }
28
+ configFile = absolutePath;
29
+ }
30
+ else {
31
+ // Search for config file in current directory
32
+ for (const fileName of CONFIG_FILES) {
33
+ const filePath = join(cwd, fileName);
34
+ if (existsSync(filePath)) {
35
+ configFile = filePath;
36
+ break;
37
+ }
38
+ }
39
+ }
40
+ let userConfig = {};
41
+ // Load config file if found
42
+ if (configFile) {
43
+ try {
44
+ const configUrl = pathToFileURL(configFile).href;
45
+ const configModule = await import(configUrl);
46
+ userConfig = configModule.default || configModule;
47
+ }
48
+ catch (error) {
49
+ throw new Error(`Failed to load config file: ${configFile}\n${error instanceof Error ? error.message : String(error)}`);
50
+ }
51
+ }
52
+ // Get API URL from environment variable if not in config
53
+ const apiUrl = userConfig.apiUrl ||
54
+ process.env.UNIFORMGEN_API_URL ||
55
+ process.env.FOIR_API_URL ||
56
+ defaultConfig.apiUrl;
57
+ // Get credentials from CLI login
58
+ const credentials = await getCredentials();
59
+ // Try to get access token from multiple sources in order of preference:
60
+ // 1. Explicit access token in config/env
61
+ // 2. CLI credentials from login
62
+ const accessToken = userConfig.accessToken ||
63
+ process.env.UNIFORMGEN_ACCESS_TOKEN ||
64
+ process.env.FOIR_ACCESS_TOKEN ||
65
+ credentials?.accessToken;
66
+ // Require an access token
67
+ if (!accessToken) {
68
+ throw new Error('Authentication required. Run `uniformgen login` and `uniformgen select-project` to authenticate via CLI.');
69
+ }
70
+ // Require a selected project
71
+ if (!credentials?.selectedProject) {
72
+ throw new Error('No project selected. Run `uniformgen select-project` to choose a project.');
73
+ }
74
+ // Get tenant and project IDs from selected project
75
+ const tenantId = credentials.selectedProject.tenantId;
76
+ const projectId = credentials.selectedProject.id;
77
+ // Project key is optional (kept for backwards compatibility)
78
+ const projectKey = userConfig.projectKey ||
79
+ process.env.UNIFORMGEN_PROJECT_KEY ||
80
+ process.env.EIDE_PROJECT_KEY ||
81
+ credentials?.selectedProject?.apiKey;
82
+ // Merge with defaults
83
+ const mergedConfig = {
84
+ ...defaultConfig,
85
+ ...userConfig,
86
+ accessToken,
87
+ tenantId,
88
+ projectId,
89
+ projectKey,
90
+ apiUrl,
91
+ output: {
92
+ ...defaultConfig.output,
93
+ ...userConfig.output,
94
+ },
95
+ };
96
+ // Validate config
97
+ try {
98
+ return ConfigSchema.parse(mergedConfig);
99
+ }
100
+ catch (error) {
101
+ throw new Error(`Invalid configuration:\n${error instanceof Error ? error.message : String(error)}`);
102
+ }
103
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Local settings structure (stored per-machine, not per-project)
3
+ */
4
+ export interface LocalSettings {
5
+ /** Target framework for generated hooks */
6
+ framework: 'agnostic' | 'react' | 'remix';
7
+ }
8
+ /**
9
+ * Read local settings
10
+ */
11
+ export declare function getSettings(): Promise<LocalSettings>;
12
+ /**
13
+ * Write settings to file
14
+ */
15
+ export declare function writeSettings(settings: LocalSettings): Promise<void>;
16
+ /**
17
+ * Update settings with new values
18
+ */
19
+ export declare function updateSettings(updates: Partial<LocalSettings>): Promise<void>;
20
+ //# sourceMappingURL=settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/config/settings.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,2CAA2C;IAC3C,SAAS,EAAE,UAAU,GAAG,OAAO,GAAG,OAAO,CAAC;CAC3C;AAkCD;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,aAAa,CAAC,CAU1D;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAM1E;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,GAC9B,OAAO,CAAC,IAAI,CAAC,CAGf"}
@@ -0,0 +1,64 @@
1
+ import { promises as fs } from 'fs';
2
+ import { join } from 'path';
3
+ import { homedir } from 'os';
4
+ const DEFAULT_SETTINGS = {
5
+ framework: 'agnostic',
6
+ };
7
+ /**
8
+ * Get the settings directory path
9
+ */
10
+ function getSettingsDir() {
11
+ return join(homedir(), '.uniformgen');
12
+ }
13
+ /**
14
+ * Get the settings file path
15
+ */
16
+ function getSettingsPath() {
17
+ return join(getSettingsDir(), 'settings.json');
18
+ }
19
+ /**
20
+ * Ensure the settings directory exists
21
+ */
22
+ async function ensureSettingsDir() {
23
+ const dir = getSettingsDir();
24
+ try {
25
+ await fs.mkdir(dir, { recursive: true, mode: 0o700 });
26
+ }
27
+ catch (error) {
28
+ if (error.code !== 'EEXIST') {
29
+ throw error;
30
+ }
31
+ }
32
+ }
33
+ /**
34
+ * Read local settings
35
+ */
36
+ export async function getSettings() {
37
+ try {
38
+ const content = await fs.readFile(getSettingsPath(), 'utf-8');
39
+ return { ...DEFAULT_SETTINGS, ...JSON.parse(content) };
40
+ }
41
+ catch (error) {
42
+ if (error.code === 'ENOENT') {
43
+ return DEFAULT_SETTINGS;
44
+ }
45
+ throw error;
46
+ }
47
+ }
48
+ /**
49
+ * Write settings to file
50
+ */
51
+ export async function writeSettings(settings) {
52
+ await ensureSettingsDir();
53
+ const path = getSettingsPath();
54
+ await fs.writeFile(path, JSON.stringify(settings, null, 2), {
55
+ mode: 0o600,
56
+ });
57
+ }
58
+ /**
59
+ * Update settings with new values
60
+ */
61
+ export async function updateSettings(updates) {
62
+ const existing = await getSettings();
63
+ await writeSettings({ ...existing, ...updates });
64
+ }