kubit-forge 0.0.1-canary.85d379a

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 (201) hide show
  1. package/CHANGELOG.md +229 -0
  2. package/LICENSE +201 -0
  3. package/README.md +841 -0
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.js +14294 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/index.d.ts +772 -0
  8. package/dist/index.js +1979 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/templates/README.md +243 -0
  11. package/dist/templates/config/README.md +94 -0
  12. package/dist/templates/config/config-templates.ts +138 -0
  13. package/dist/templates/config/defaults.ts +105 -0
  14. package/dist/templates/config/index.ts +6 -0
  15. package/dist/templates/features/.prettierignore.template +28 -0
  16. package/dist/templates/features/.prettierrc.template +10 -0
  17. package/dist/templates/features/README.md +111 -0
  18. package/dist/templates/features/bernova-foundations.ts.template +50 -0
  19. package/dist/templates/features/bernova-globalStyles.ts.template +33 -0
  20. package/dist/templates/features/bernova-mediaQueries.ts.template +6 -0
  21. package/dist/templates/features/bernova-theme.ts.template +1 -0
  22. package/dist/templates/features/bernova.config.json.template +58 -0
  23. package/dist/templates/features/changesets-config.json.template +11 -0
  24. package/dist/templates/features/changesets-readme.md.template +31 -0
  25. package/dist/templates/features/commitlint.config.js.template +23 -0
  26. package/dist/templates/features/cypress-support-commands.ts.template +22 -0
  27. package/dist/templates/features/cypress-support-e2e.ts.template +20 -0
  28. package/dist/templates/features/cypress.config.ts.template +23 -0
  29. package/dist/templates/features/eslint.config.js.template +13 -0
  30. package/dist/templates/features/husky-commit-msg.template +4 -0
  31. package/dist/templates/features/husky-pre-commit.template +4 -0
  32. package/dist/templates/features/index.ts +5 -0
  33. package/dist/templates/features/jest-setup.ts.template +1 -0
  34. package/dist/templates/features/jest.config.ts.template +23 -0
  35. package/dist/templates/features/lint-staged.config.js.template +5 -0
  36. package/dist/templates/features/playwright-example.spec.ts.template +14 -0
  37. package/dist/templates/features/playwright.config.ts.template +42 -0
  38. package/dist/templates/features/template-loader.ts +31 -0
  39. package/dist/templates/features/vitest-setup.ts.template +1 -0
  40. package/dist/templates/features/vitest.config.ts.template +11 -0
  41. package/dist/templates/generators/README.md +181 -0
  42. package/dist/templates/generators/index.ts +9 -0
  43. package/dist/templates/generators/plugin.ts +245 -0
  44. package/dist/templates/generators/react-app-bernova.ts +356 -0
  45. package/dist/templates/generators/react-component.ts +103 -0
  46. package/dist/templates/generators/react-hook.ts +56 -0
  47. package/dist/templates/generators/react-kubit-ui.ts +794 -0
  48. package/dist/templates/generators/react-page.ts +65 -0
  49. package/dist/templates-physical/kubit-full/.prettierrc +0 -0
  50. package/dist/templates-physical/kubit-full/README.md +223 -0
  51. package/dist/templates-physical/kubit-full/bernova.config.json +0 -0
  52. package/dist/templates-physical/kubit-full/eslint.config.js +0 -0
  53. package/dist/templates-physical/kubit-full/index.html +17 -0
  54. package/dist/templates-physical/kubit-full/package.json +53 -0
  55. package/dist/templates-physical/kubit-full/src/App.css +118 -0
  56. package/dist/templates-physical/kubit-full/src/App.tsx +75 -0
  57. package/dist/templates-physical/kubit-full/src/charts/ChartsShowcase.css +0 -0
  58. package/dist/templates-physical/kubit-full/src/charts/ChartsShowcase.tsx +0 -0
  59. package/dist/templates-physical/kubit-full/src/components/ComponentsShowcase.css +147 -0
  60. package/dist/templates-physical/kubit-full/src/components/ComponentsShowcase.tsx +0 -0
  61. package/dist/templates-physical/kubit-full/src/main.tsx +0 -0
  62. package/dist/templates-physical/kubit-full/src/styles/index.css +6 -0
  63. package/dist/templates-physical/kubit-full/src/styles/theme/components/button.ts +0 -0
  64. package/dist/templates-physical/kubit-full/src/styles/theme/components/card.ts +0 -0
  65. package/dist/templates-physical/kubit-full/src/styles/theme/components/input.ts +0 -0
  66. package/dist/templates-physical/kubit-full/src/styles/theme/foundations.ts +0 -0
  67. package/dist/templates-physical/kubit-full/src/styles/theme/globalStyles.ts +0 -0
  68. package/dist/templates-physical/kubit-full/src/styles/theme/mediaQueries.ts +0 -0
  69. package/dist/templates-physical/kubit-full/src/styles/theme/theme.ts +0 -0
  70. package/dist/templates-physical/kubit-full/src/test/setup.ts +0 -0
  71. package/dist/templates-physical/kubit-full/tsconfig.json +29 -0
  72. package/dist/templates-physical/kubit-full/tsconfig.node.json +11 -0
  73. package/dist/templates-physical/kubit-full/vite.config.ts +24 -0
  74. package/dist/templates-physical/kubit-full/vitest.config.ts +26 -0
  75. package/dist/templates-physical/react/.env.example +6 -0
  76. package/dist/templates-physical/react/.prettierrc +8 -0
  77. package/dist/templates-physical/react/README.md +81 -0
  78. package/dist/templates-physical/react/eslint.config.js +7 -0
  79. package/dist/templates-physical/react/index.html +13 -0
  80. package/dist/templates-physical/react/package.json +39 -0
  81. package/dist/templates-physical/react/src/app/App.module.css +39 -0
  82. package/dist/templates-physical/react/src/app/App.test.tsx +14 -0
  83. package/dist/templates-physical/react/src/app/App.tsx +17 -0
  84. package/dist/templates-physical/react/src/main.tsx +10 -0
  85. package/dist/templates-physical/react/src/styles/index.css +39 -0
  86. package/dist/templates-physical/react/src/test/setup.ts +57 -0
  87. package/dist/templates-physical/react/tsconfig.json +25 -0
  88. package/dist/templates-physical/react/tsconfig.node.json +10 -0
  89. package/dist/templates-physical/react/vite.config.ts +16 -0
  90. package/dist/templates-physical/react/vitest.config.ts +22 -0
  91. package/dist/templates-physical/react-bernova/.eslintrc.cjs +15 -0
  92. package/dist/templates-physical/react-bernova/.prettierrc +10 -0
  93. package/dist/templates-physical/react-bernova/README.md +150 -0
  94. package/dist/templates-physical/react-bernova/bernova.config.json +58 -0
  95. package/dist/templates-physical/react-bernova/eslint.config.js +7 -0
  96. package/dist/templates-physical/react-bernova/index.html +21 -0
  97. package/dist/templates-physical/react-bernova/package.json +43 -0
  98. package/dist/templates-physical/react-bernova/src/App.css +89 -0
  99. package/dist/templates-physical/react-bernova/src/App.tsx +51 -0
  100. package/dist/templates-physical/react-bernova/src/index.css +54 -0
  101. package/dist/templates-physical/react-bernova/src/main.tsx +10 -0
  102. package/dist/templates-physical/react-bernova/src/styles/foundations.ts +91 -0
  103. package/dist/templates-physical/react-bernova/src/styles/globalStyles.ts +118 -0
  104. package/dist/templates-physical/react-bernova/src/styles/mediaQueries.ts +18 -0
  105. package/dist/templates-physical/react-bernova/src/styles/theme.ts +94 -0
  106. package/dist/templates-physical/react-bernova/src/test/setup.ts +9 -0
  107. package/dist/templates-physical/react-bernova/tsconfig.json +31 -0
  108. package/dist/templates-physical/react-bernova/tsconfig.node.json +10 -0
  109. package/dist/templates-physical/react-bernova/vite.config.ts +20 -0
  110. package/dist/templates-physical/react-bernova/vitest.config.ts +18 -0
  111. package/dist/templates-physical/vanilla/.env.example +6 -0
  112. package/dist/templates-physical/vanilla/.prettierrc +8 -0
  113. package/dist/templates-physical/vanilla/README.md +76 -0
  114. package/dist/templates-physical/vanilla/eslint.config.js +7 -0
  115. package/dist/templates-physical/vanilla/index.html +13 -0
  116. package/dist/templates-physical/vanilla/package.json +28 -0
  117. package/dist/templates-physical/vanilla/src/app.module.css +39 -0
  118. package/dist/templates-physical/vanilla/src/app.test.ts +20 -0
  119. package/dist/templates-physical/vanilla/src/app.ts +31 -0
  120. package/dist/templates-physical/vanilla/src/main.ts +9 -0
  121. package/dist/templates-physical/vanilla/src/styles/main.css +39 -0
  122. package/dist/templates-physical/vanilla/tsconfig.json +23 -0
  123. package/dist/templates-physical/vanilla/vite.config.ts +14 -0
  124. package/dist/templates-physical/vanilla/vitest.config.ts +14 -0
  125. package/package.json +131 -0
  126. package/templates/kubit-full/.prettierrc +0 -0
  127. package/templates/kubit-full/README.md +223 -0
  128. package/templates/kubit-full/bernova.config.json +0 -0
  129. package/templates/kubit-full/eslint.config.js +0 -0
  130. package/templates/kubit-full/index.html +17 -0
  131. package/templates/kubit-full/package.json +53 -0
  132. package/templates/kubit-full/src/App.css +118 -0
  133. package/templates/kubit-full/src/App.tsx +75 -0
  134. package/templates/kubit-full/src/charts/ChartsShowcase.css +0 -0
  135. package/templates/kubit-full/src/charts/ChartsShowcase.tsx +0 -0
  136. package/templates/kubit-full/src/components/ComponentsShowcase.css +147 -0
  137. package/templates/kubit-full/src/components/ComponentsShowcase.tsx +0 -0
  138. package/templates/kubit-full/src/main.tsx +0 -0
  139. package/templates/kubit-full/src/styles/index.css +6 -0
  140. package/templates/kubit-full/src/styles/theme/components/button.ts +0 -0
  141. package/templates/kubit-full/src/styles/theme/components/card.ts +0 -0
  142. package/templates/kubit-full/src/styles/theme/components/input.ts +0 -0
  143. package/templates/kubit-full/src/styles/theme/foundations.ts +0 -0
  144. package/templates/kubit-full/src/styles/theme/globalStyles.ts +0 -0
  145. package/templates/kubit-full/src/styles/theme/mediaQueries.ts +0 -0
  146. package/templates/kubit-full/src/styles/theme/theme.ts +0 -0
  147. package/templates/kubit-full/src/test/setup.ts +0 -0
  148. package/templates/kubit-full/tsconfig.json +29 -0
  149. package/templates/kubit-full/tsconfig.node.json +11 -0
  150. package/templates/kubit-full/vite.config.ts +24 -0
  151. package/templates/kubit-full/vitest.config.ts +26 -0
  152. package/templates/react/.env.example +6 -0
  153. package/templates/react/.prettierrc +8 -0
  154. package/templates/react/README.md +81 -0
  155. package/templates/react/eslint.config.js +7 -0
  156. package/templates/react/index.html +13 -0
  157. package/templates/react/package.json +39 -0
  158. package/templates/react/src/app/App.module.css +39 -0
  159. package/templates/react/src/app/App.test.tsx +14 -0
  160. package/templates/react/src/app/App.tsx +17 -0
  161. package/templates/react/src/main.tsx +10 -0
  162. package/templates/react/src/styles/index.css +39 -0
  163. package/templates/react/src/test/setup.ts +57 -0
  164. package/templates/react/tsconfig.json +25 -0
  165. package/templates/react/tsconfig.node.json +10 -0
  166. package/templates/react/vite.config.ts +16 -0
  167. package/templates/react/vitest.config.ts +22 -0
  168. package/templates/react-bernova/.eslintrc.cjs +15 -0
  169. package/templates/react-bernova/.prettierrc +10 -0
  170. package/templates/react-bernova/README.md +150 -0
  171. package/templates/react-bernova/bernova.config.json +58 -0
  172. package/templates/react-bernova/eslint.config.js +7 -0
  173. package/templates/react-bernova/index.html +21 -0
  174. package/templates/react-bernova/package.json +43 -0
  175. package/templates/react-bernova/src/App.css +89 -0
  176. package/templates/react-bernova/src/App.tsx +51 -0
  177. package/templates/react-bernova/src/index.css +54 -0
  178. package/templates/react-bernova/src/main.tsx +10 -0
  179. package/templates/react-bernova/src/styles/foundations.ts +91 -0
  180. package/templates/react-bernova/src/styles/globalStyles.ts +118 -0
  181. package/templates/react-bernova/src/styles/mediaQueries.ts +18 -0
  182. package/templates/react-bernova/src/styles/theme.ts +94 -0
  183. package/templates/react-bernova/src/test/setup.ts +9 -0
  184. package/templates/react-bernova/tsconfig.json +31 -0
  185. package/templates/react-bernova/tsconfig.node.json +10 -0
  186. package/templates/react-bernova/vite.config.ts +20 -0
  187. package/templates/react-bernova/vitest.config.ts +18 -0
  188. package/templates/vanilla/.env.example +6 -0
  189. package/templates/vanilla/.prettierrc +8 -0
  190. package/templates/vanilla/README.md +76 -0
  191. package/templates/vanilla/eslint.config.js +7 -0
  192. package/templates/vanilla/index.html +13 -0
  193. package/templates/vanilla/package.json +28 -0
  194. package/templates/vanilla/src/app.module.css +39 -0
  195. package/templates/vanilla/src/app.test.ts +20 -0
  196. package/templates/vanilla/src/app.ts +31 -0
  197. package/templates/vanilla/src/main.ts +9 -0
  198. package/templates/vanilla/src/styles/main.css +39 -0
  199. package/templates/vanilla/tsconfig.json +23 -0
  200. package/templates/vanilla/vite.config.ts +14 -0
  201. package/templates/vanilla/vitest.config.ts +14 -0
package/dist/index.js ADDED
@@ -0,0 +1,1979 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/core/plugin-manager.ts
4
+ import { existsSync as existsSync2 } from "fs";
5
+ import { join as join2 } from "path";
6
+
7
+ // src/core/plugin-dependency-resolver.ts
8
+ var PluginDependencyResolver = class {
9
+ logger;
10
+ plugins = /* @__PURE__ */ new Map();
11
+ constructor(logger) {
12
+ this.logger = logger;
13
+ }
14
+ /**
15
+ * Register plugin metadata
16
+ */
17
+ register(metadata) {
18
+ this.plugins.set(metadata.name, metadata);
19
+ this.logger.debug(`Registered plugin metadata: ${metadata.name}@${metadata.version}`);
20
+ }
21
+ /**
22
+ * Resolve dependencies and determine load order
23
+ */
24
+ resolve(pluginNames) {
25
+ const errors = [];
26
+ const warnings = [];
27
+ const missing = [];
28
+ const conflicts = [];
29
+ const graph = this.buildDependencyGraph(pluginNames);
30
+ for (const pluginName of pluginNames) {
31
+ const metadata = this.plugins.get(pluginName);
32
+ if (!metadata) {
33
+ warnings.push(`Plugin '${pluginName}' not found (not installed or not registered)`);
34
+ continue;
35
+ }
36
+ if (metadata.dependencies) {
37
+ for (const dep of metadata.dependencies) {
38
+ if (!this.plugins.has(dep.name)) {
39
+ if (dep.optional) {
40
+ warnings.push(
41
+ `Optional dependency '${dep.name}' for '${pluginName}' is not installed`
42
+ );
43
+ } else {
44
+ errors.push(`Required dependency '${dep.name}' for '${pluginName}' is not installed`);
45
+ missing.push(dep);
46
+ }
47
+ }
48
+ }
49
+ }
50
+ if (metadata.peerDependencies) {
51
+ for (const peer of metadata.peerDependencies) {
52
+ if (!this.plugins.has(peer.name)) {
53
+ warnings.push(`Peer dependency '${peer.name}' for '${pluginName}' is not installed`);
54
+ if (!peer.optional) {
55
+ missing.push(peer);
56
+ }
57
+ }
58
+ }
59
+ }
60
+ if (metadata.conflicts) {
61
+ for (const conflict of metadata.conflicts) {
62
+ if (this.plugins.has(conflict)) {
63
+ errors.push(`Plugin '${pluginName}' conflicts with '${conflict}'`);
64
+ conflicts.push({ conflictsWith: conflict, plugin: pluginName });
65
+ }
66
+ }
67
+ }
68
+ }
69
+ const circular = this.detectCircularDependencies(graph);
70
+ if (circular.length > 0) {
71
+ errors.push(`Circular dependencies detected: ${circular.join(" -> ")}`);
72
+ }
73
+ let loadOrder = [];
74
+ if (errors.length === 0) {
75
+ try {
76
+ loadOrder = this.topologicalSort(graph);
77
+ } catch (error) {
78
+ errors.push(
79
+ `Failed to resolve load order: ${error instanceof Error ? error.message : "Unknown error"}`
80
+ );
81
+ }
82
+ }
83
+ return {
84
+ conflicts,
85
+ errors,
86
+ loadOrder,
87
+ missing,
88
+ warnings
89
+ };
90
+ }
91
+ /**
92
+ * Build dependency graph
93
+ */
94
+ buildDependencyGraph(pluginNames) {
95
+ const nodes = /* @__PURE__ */ new Map();
96
+ const edges = /* @__PURE__ */ new Map();
97
+ const visited = /* @__PURE__ */ new Set();
98
+ const queue = [...pluginNames];
99
+ while (queue.length > 0) {
100
+ const current = queue.shift();
101
+ if (visited.has(current)) {
102
+ continue;
103
+ }
104
+ visited.add(current);
105
+ const metadata = this.plugins.get(current);
106
+ if (!metadata) {
107
+ continue;
108
+ }
109
+ nodes.set(current, metadata);
110
+ if (metadata.dependencies) {
111
+ for (const dep of metadata.dependencies) {
112
+ if (!edges.has(current)) {
113
+ edges.set(current, /* @__PURE__ */ new Set());
114
+ }
115
+ edges.get(current).add(dep.name);
116
+ if (!visited.has(dep.name)) {
117
+ queue.push(dep.name);
118
+ }
119
+ }
120
+ }
121
+ if (metadata.peerDependencies) {
122
+ for (const peer of metadata.peerDependencies) {
123
+ if (!edges.has(current)) {
124
+ edges.set(current, /* @__PURE__ */ new Set());
125
+ }
126
+ edges.get(current).add(peer.name);
127
+ if (!visited.has(peer.name)) {
128
+ queue.push(peer.name);
129
+ }
130
+ }
131
+ }
132
+ }
133
+ return { edges, nodes };
134
+ }
135
+ /**
136
+ * Detect circular dependencies
137
+ */
138
+ detectCircularDependencies(graph) {
139
+ const visited = /* @__PURE__ */ new Set();
140
+ const recursionStack = /* @__PURE__ */ new Set();
141
+ const path = [];
142
+ const dfs = (node) => {
143
+ visited.add(node);
144
+ recursionStack.add(node);
145
+ path.push(node);
146
+ const dependencies = graph.edges.get(node) || /* @__PURE__ */ new Set();
147
+ for (const dep of dependencies) {
148
+ if (!visited.has(dep)) {
149
+ if (dfs(dep)) {
150
+ return true;
151
+ }
152
+ } else if (recursionStack.has(dep)) {
153
+ return true;
154
+ }
155
+ }
156
+ recursionStack.delete(node);
157
+ path.pop();
158
+ return false;
159
+ };
160
+ for (const node of graph.nodes.keys()) {
161
+ if (!visited.has(node)) {
162
+ if (dfs(node)) {
163
+ return path;
164
+ }
165
+ }
166
+ }
167
+ return [];
168
+ }
169
+ /**
170
+ * Topological sort to determine load order
171
+ */
172
+ topologicalSort(graph) {
173
+ const inDegree = /* @__PURE__ */ new Map();
174
+ const result = [];
175
+ for (const node of graph.nodes.keys()) {
176
+ inDegree.set(node, 0);
177
+ }
178
+ for (const dependencies of graph.edges.values()) {
179
+ for (const dep of dependencies) {
180
+ if (graph.nodes.has(dep)) {
181
+ inDegree.set(dep, (inDegree.get(dep) || 0) + 1);
182
+ }
183
+ }
184
+ }
185
+ const queue = [];
186
+ for (const [node, degree] of inDegree.entries()) {
187
+ if (degree === 0) {
188
+ queue.push(node);
189
+ }
190
+ }
191
+ while (queue.length > 0) {
192
+ const current = queue.shift();
193
+ result.push(current);
194
+ const dependencies = graph.edges.get(current) || /* @__PURE__ */ new Set();
195
+ for (const dep of dependencies) {
196
+ if (!graph.nodes.has(dep)) {
197
+ continue;
198
+ }
199
+ const newDegree = (inDegree.get(dep) || 0) - 1;
200
+ inDegree.set(dep, newDegree);
201
+ if (newDegree === 0) {
202
+ queue.push(dep);
203
+ }
204
+ }
205
+ }
206
+ if (result.length !== graph.nodes.size) {
207
+ throw new Error("Circular dependency detected");
208
+ }
209
+ return result.reverse();
210
+ }
211
+ /**
212
+ * Get dependency tree for a plugin
213
+ */
214
+ getDependencyTree(pluginName) {
215
+ const metadata = this.plugins.get(pluginName);
216
+ if (!metadata) {
217
+ return { dependencies: [], name: pluginName, version: "unknown" };
218
+ }
219
+ const tree = {
220
+ dependencies: [],
221
+ name: metadata.name,
222
+ version: metadata.version
223
+ };
224
+ if (metadata.dependencies) {
225
+ for (const dep of metadata.dependencies) {
226
+ const depTree = this.getDependencyTree(dep.name);
227
+ tree.dependencies.push(depTree);
228
+ }
229
+ }
230
+ return tree;
231
+ }
232
+ /**
233
+ * Get all dependencies (flat list)
234
+ */
235
+ getAllDependencies(pluginName) {
236
+ const dependencies = /* @__PURE__ */ new Set();
237
+ const visited = /* @__PURE__ */ new Set();
238
+ const traverse = (name) => {
239
+ if (visited.has(name)) {
240
+ return;
241
+ }
242
+ visited.add(name);
243
+ const metadata = this.plugins.get(name);
244
+ if (!metadata) {
245
+ return;
246
+ }
247
+ if (metadata.dependencies) {
248
+ for (const dep of metadata.dependencies) {
249
+ dependencies.add(dep.name);
250
+ traverse(dep.name);
251
+ }
252
+ }
253
+ if (metadata.peerDependencies) {
254
+ for (const peer of metadata.peerDependencies) {
255
+ dependencies.add(peer.name);
256
+ traverse(peer.name);
257
+ }
258
+ }
259
+ };
260
+ traverse(pluginName);
261
+ return dependencies;
262
+ }
263
+ /**
264
+ * Check if plugin can be safely unloaded
265
+ */
266
+ canUnload(pluginName) {
267
+ const blockedBy = [];
268
+ for (const [name] of this.plugins.entries()) {
269
+ if (name === pluginName) {
270
+ continue;
271
+ }
272
+ const deps = this.getAllDependencies(name);
273
+ if (deps.has(pluginName)) {
274
+ blockedBy.push(name);
275
+ }
276
+ }
277
+ return {
278
+ blockedBy,
279
+ canUnload: blockedBy.length === 0
280
+ };
281
+ }
282
+ /**
283
+ * Get plugins that depend on a specific plugin
284
+ */
285
+ getDependents(pluginName) {
286
+ const dependents = [];
287
+ for (const [name] of this.plugins.entries()) {
288
+ if (name === pluginName) {
289
+ continue;
290
+ }
291
+ const metadata = this.plugins.get(name);
292
+ if (!metadata) {
293
+ continue;
294
+ }
295
+ if (metadata.dependencies) {
296
+ const hasDep = metadata.dependencies.some((dep) => dep.name === pluginName);
297
+ if (hasDep) {
298
+ dependents.push(name);
299
+ }
300
+ }
301
+ if (metadata.peerDependencies) {
302
+ const hasPeer = metadata.peerDependencies.some((peer) => peer.name === pluginName);
303
+ if (hasPeer) {
304
+ dependents.push(name);
305
+ }
306
+ }
307
+ }
308
+ return dependents;
309
+ }
310
+ /**
311
+ * Clear all registered plugins
312
+ */
313
+ clear() {
314
+ this.plugins.clear();
315
+ }
316
+ /**
317
+ * Get statistics
318
+ */
319
+ getStats() {
320
+ let totalDeps = 0;
321
+ let totalPeerDeps = 0;
322
+ let totalConflicts = 0;
323
+ for (const metadata of this.plugins.values()) {
324
+ totalDeps += metadata.dependencies?.length || 0;
325
+ totalPeerDeps += metadata.peerDependencies?.length || 0;
326
+ totalConflicts += metadata.conflicts?.length || 0;
327
+ }
328
+ return {
329
+ totalConflicts,
330
+ totalDependencies: totalDeps,
331
+ totalPeerDependencies: totalPeerDeps,
332
+ totalPlugins: this.plugins.size
333
+ };
334
+ }
335
+ };
336
+
337
+ // src/core/plugin-registry.ts
338
+ var PluginRegistry = class {
339
+ logger;
340
+ constructor(logger, _registryUrl = "https://registry.npmjs.org") {
341
+ this.logger = logger;
342
+ }
343
+ /**
344
+ * Search for plugins matching query
345
+ *
346
+ * @param query - Search query
347
+ * @param options - Search options
348
+ * @returns Array of matching plugins
349
+ */
350
+ async search(query, options = {}) {
351
+ this.logger.debug(`Searching plugins: ${query}`);
352
+ const mockPlugins = [
353
+ {
354
+ author: "Kubit Team",
355
+ capabilities: ["fs:write", "shell:run"],
356
+ category: "tooling",
357
+ description: "Bernova Design System integration for Kubit projects",
358
+ downloads: 15e3,
359
+ kubitVersion: "^2.0.0",
360
+ name: "@kubit/plugin-bernova",
361
+ tags: ["css", "bernova", "design-system", "styling"],
362
+ verified: true,
363
+ version: "1.2.0"
364
+ },
365
+ {
366
+ author: "Kubit Team",
367
+ capabilities: ["fs:write", "shell:run", "net:localhost"],
368
+ category: "tooling",
369
+ description: "Storybook integration with hot reload",
370
+ downloads: 12e3,
371
+ kubitVersion: "^2.0.0",
372
+ name: "@kubit/plugin-storybook",
373
+ tags: ["storybook", "components", "ui"],
374
+ verified: true,
375
+ version: "2.0.1"
376
+ },
377
+ {
378
+ author: "Kubit Team",
379
+ capabilities: ["fs:read", "fs:write"],
380
+ category: "utility",
381
+ description: "Internationalization support with i18next",
382
+ downloads: 8e3,
383
+ kubitVersion: "^2.0.0",
384
+ name: "@kubit/plugin-i18n",
385
+ tags: ["i18n", "translation", "localization"],
386
+ verified: true,
387
+ version: "1.5.0"
388
+ }
389
+ ];
390
+ let results = mockPlugins.filter(
391
+ (p) => p.name.toLowerCase().includes(query.toLowerCase()) || p.description.toLowerCase().includes(query.toLowerCase()) || p.tags?.some((t) => t.toLowerCase().includes(query.toLowerCase()))
392
+ );
393
+ if (options.verified !== void 0) {
394
+ results = results.filter((p) => p.verified === options.verified);
395
+ }
396
+ if (options.category) {
397
+ results = results.filter((p) => p.category === options.category);
398
+ }
399
+ return results;
400
+ }
401
+ /**
402
+ * Get detailed information about a plugin
403
+ *
404
+ * @param name - Plugin name
405
+ * @returns Plugin information or null if not found
406
+ */
407
+ async getInfo(name) {
408
+ this.logger.debug(`Fetching plugin info: ${name}`);
409
+ const mockPlugin = {
410
+ author: "Plugin Author",
411
+ capabilities: ["fs:read"],
412
+ category: "utility",
413
+ description: "Plugin description",
414
+ downloads: 1e3,
415
+ homepage: `https://github.com/kubit-ui/${name}`,
416
+ kubitVersion: "^2.0.0",
417
+ name,
418
+ repository: `https://github.com/kubit-ui/${name}`,
419
+ tags: ["utility"],
420
+ updated: (/* @__PURE__ */ new Date()).toISOString(),
421
+ verified: false,
422
+ version: "1.0.0"
423
+ };
424
+ return mockPlugin;
425
+ }
426
+ /**
427
+ * Check if a plugin is verified
428
+ *
429
+ * @param name - Plugin name
430
+ * @returns True if verified
431
+ */
432
+ async isVerified(name) {
433
+ const info = await this.getInfo(name);
434
+ return info?.verified || false;
435
+ }
436
+ /**
437
+ * Get compatible plugins for current kubit-forge version
438
+ *
439
+ * @param kubitVersion - Current kubit-forge version
440
+ * @returns Array of compatible plugins
441
+ */
442
+ async getCompatible(_kubitVersion) {
443
+ return this.search("", {});
444
+ }
445
+ /**
446
+ * Get featured/recommended plugins
447
+ *
448
+ * @returns Array of featured plugins
449
+ */
450
+ async getFeatured() {
451
+ return this.search("", { verified: true });
452
+ }
453
+ };
454
+
455
+ // src/core/plugin-sandbox.ts
456
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
457
+ import { join } from "path";
458
+ var PluginSandbox = class {
459
+ logger;
460
+ options;
461
+ worker;
462
+ isRunning = false;
463
+ constructor(logger, options = {}) {
464
+ this.logger = logger;
465
+ this.options = {
466
+ allowedCapabilities: options.allowedCapabilities || [],
467
+ allowFileSystem: options.allowFileSystem ?? true,
468
+ allowNetwork: options.allowNetwork ?? false,
469
+ allowProcessEnv: options.allowProcessEnv ?? true,
470
+ memoryLimit: options.memoryLimit || 512 * 1024 * 1024,
471
+ // 512MB
472
+ timeout: options.timeout || 3e4
473
+ // 30 seconds
474
+ };
475
+ }
476
+ /**
477
+ * Execute plugin in sandboxed environment
478
+ */
479
+ async execute(pluginPath, method, args) {
480
+ if (this.isRunning) {
481
+ throw new Error("Sandbox is already running");
482
+ }
483
+ this.isRunning = true;
484
+ try {
485
+ if (!existsSync(pluginPath)) {
486
+ throw new Error(`Plugin not found: ${pluginPath}`);
487
+ }
488
+ const sandboxContext = this.createSandboxContext();
489
+ const result = await this.executeInWorker(pluginPath, method, args, sandboxContext);
490
+ return result;
491
+ } finally {
492
+ this.isRunning = false;
493
+ this.cleanup();
494
+ }
495
+ }
496
+ /**
497
+ * Create restricted context for plugin
498
+ */
499
+ createSandboxContext() {
500
+ const context = {
501
+ console: {
502
+ error: (...args) => this.logger.error(args.join(" ")),
503
+ log: (...args) => this.logger.info(args.join(" ")),
504
+ warn: (...args) => this.logger.warn(args.join(" "))
505
+ }
506
+ };
507
+ if (this.options.allowProcessEnv) {
508
+ context.process = {
509
+ arch: process.arch,
510
+ cwd: process.cwd,
511
+ env: { ...process.env },
512
+ platform: process.platform
513
+ };
514
+ }
515
+ if (this.options.allowFileSystem) {
516
+ context.fs = this.createRestrictedFS();
517
+ }
518
+ if (this.options.allowNetwork) {
519
+ context.fetch = fetch;
520
+ }
521
+ return context;
522
+ }
523
+ /**
524
+ * Create restricted filesystem API
525
+ */
526
+ createRestrictedFS() {
527
+ const cwd = process.cwd();
528
+ return {
529
+ exists: (path) => {
530
+ const fullPath = join(cwd, path);
531
+ if (!fullPath.startsWith(cwd)) {
532
+ throw new Error("Access denied: Path outside project directory");
533
+ }
534
+ return existsSync(fullPath);
535
+ },
536
+ mkdir: (path) => {
537
+ const fullPath = join(cwd, path);
538
+ if (!fullPath.startsWith(cwd)) {
539
+ throw new Error("Access denied: Path outside project directory");
540
+ }
541
+ return mkdirSync(fullPath, { recursive: true });
542
+ },
543
+ readFile: (path) => {
544
+ const fullPath = join(cwd, path);
545
+ if (!fullPath.startsWith(cwd)) {
546
+ throw new Error("Access denied: Path outside project directory");
547
+ }
548
+ return readFileSync(fullPath, "utf-8");
549
+ },
550
+ writeFile: (path, content) => {
551
+ const fullPath = join(cwd, path);
552
+ if (!fullPath.startsWith(cwd)) {
553
+ throw new Error("Access denied: Path outside project directory");
554
+ }
555
+ return writeFileSync(fullPath, content, "utf-8");
556
+ }
557
+ };
558
+ }
559
+ /**
560
+ * Execute plugin method in worker thread
561
+ */
562
+ async executeInWorker(pluginPath, method, args, _context) {
563
+ const timeout = setTimeout(() => {
564
+ if (this.worker) {
565
+ this.worker.terminate();
566
+ }
567
+ }, this.options.timeout);
568
+ try {
569
+ const pluginModule = await import(pluginPath);
570
+ const plugin = pluginModule.default || pluginModule;
571
+ const pluginInstance = plugin.default || plugin;
572
+ if (!pluginInstance[method]) {
573
+ clearTimeout(timeout);
574
+ throw new Error(`Method '${method}' not found in plugin`);
575
+ }
576
+ const result = pluginInstance[method](...args);
577
+ if (result instanceof Promise) {
578
+ return result.then((res) => {
579
+ clearTimeout(timeout);
580
+ return res;
581
+ }).catch((err) => {
582
+ clearTimeout(timeout);
583
+ throw err;
584
+ });
585
+ }
586
+ clearTimeout(timeout);
587
+ return result;
588
+ } catch (error) {
589
+ clearTimeout(timeout);
590
+ throw error;
591
+ }
592
+ }
593
+ /**
594
+ * Check if capability is allowed
595
+ */
596
+ hasCapability(capability) {
597
+ return this.options.allowedCapabilities.includes(capability);
598
+ }
599
+ /**
600
+ * Get sandbox statistics
601
+ */
602
+ getStats() {
603
+ return {
604
+ allowedCapabilities: this.options.allowedCapabilities,
605
+ allowFileSystem: this.options.allowFileSystem,
606
+ allowNetwork: this.options.allowNetwork,
607
+ isRunning: this.isRunning,
608
+ memoryLimit: this.options.memoryLimit,
609
+ timeout: this.options.timeout
610
+ };
611
+ }
612
+ /**
613
+ * Cleanup resources
614
+ */
615
+ cleanup() {
616
+ if (this.worker) {
617
+ this.worker.terminate();
618
+ this.worker = void 0;
619
+ }
620
+ }
621
+ /**
622
+ * Terminate sandbox
623
+ */
624
+ terminate() {
625
+ this.cleanup();
626
+ this.isRunning = false;
627
+ }
628
+ };
629
+ var SandboxManager = class {
630
+ sandboxes = /* @__PURE__ */ new Map();
631
+ logger;
632
+ constructor(logger) {
633
+ this.logger = logger;
634
+ }
635
+ /**
636
+ * Create sandbox for plugin
637
+ */
638
+ createSandbox(pluginName, options = {}) {
639
+ if (this.sandboxes.has(pluginName)) {
640
+ throw new Error(`Sandbox already exists for plugin '${pluginName}'`);
641
+ }
642
+ const sandbox = new PluginSandbox(this.logger, options);
643
+ this.sandboxes.set(pluginName, sandbox);
644
+ this.logger.debug(`Created sandbox for plugin '${pluginName}'`);
645
+ return sandbox;
646
+ }
647
+ /**
648
+ * Get sandbox for plugin
649
+ */
650
+ getSandbox(pluginName) {
651
+ return this.sandboxes.get(pluginName);
652
+ }
653
+ /**
654
+ * Remove sandbox
655
+ */
656
+ removeSandbox(pluginName) {
657
+ const sandbox = this.sandboxes.get(pluginName);
658
+ if (sandbox) {
659
+ sandbox.terminate();
660
+ this.sandboxes.delete(pluginName);
661
+ this.logger.debug(`Removed sandbox for plugin '${pluginName}'`);
662
+ }
663
+ }
664
+ /**
665
+ * Terminate all sandboxes
666
+ */
667
+ terminateAll() {
668
+ for (const [pluginName, sandbox] of this.sandboxes.entries()) {
669
+ sandbox.terminate();
670
+ this.logger.debug(`Terminated sandbox for plugin '${pluginName}'`);
671
+ }
672
+ this.sandboxes.clear();
673
+ }
674
+ /**
675
+ * Get statistics for all sandboxes
676
+ */
677
+ getStats() {
678
+ const stats = {};
679
+ for (const [pluginName, sandbox] of this.sandboxes.entries()) {
680
+ stats[pluginName] = sandbox.getStats();
681
+ }
682
+ return {
683
+ sandboxes: stats,
684
+ totalSandboxes: this.sandboxes.size
685
+ };
686
+ }
687
+ };
688
+
689
+ // src/core/plugin-validator.ts
690
+ var PluginValidator = class {
691
+ /**
692
+ * Validate a plugin
693
+ */
694
+ validate(plugin) {
695
+ const errors = [];
696
+ const warnings = [];
697
+ const securityIssues = [];
698
+ if (!plugin.name) {
699
+ errors.push("Plugin must have a name");
700
+ } else {
701
+ if (!/^[@a-z0-9-]+\/[a-z0-9-]+$|^[a-z0-9-]+$/.test(plugin.name)) {
702
+ errors.push(
703
+ 'Plugin name must be in format "name" or "@scope/name" with lowercase letters, numbers, and hyphens'
704
+ );
705
+ }
706
+ }
707
+ if (!plugin.version) {
708
+ errors.push("Plugin must have a version");
709
+ } else {
710
+ if (!/^\d+\.\d+\.\d+(-[a-z0-9.-]+)?(\+[a-z0-9.-]+)?$/i.test(plugin.version)) {
711
+ errors.push("Plugin version must follow semver format (e.g., 1.0.0)");
712
+ }
713
+ }
714
+ if (plugin.capabilities) {
715
+ const validCapabilities = [
716
+ "fs:read",
717
+ "fs:write",
718
+ "shell:run",
719
+ "net:localhost",
720
+ "process:env"
721
+ ];
722
+ for (const cap of plugin.capabilities) {
723
+ if (!validCapabilities.includes(cap)) {
724
+ errors.push(`Invalid capability: ${cap}`);
725
+ }
726
+ if (cap === "fs:write") {
727
+ securityIssues.push("Plugin requests file system write access");
728
+ }
729
+ if (cap === "shell:run") {
730
+ securityIssues.push("Plugin requests shell command execution");
731
+ }
732
+ if (cap === "process:env") {
733
+ warnings.push("Plugin requests access to environment variables");
734
+ }
735
+ }
736
+ }
737
+ const validHooks = [
738
+ "onLoad",
739
+ "onConfigLoaded",
740
+ "onProjectDetected",
741
+ "beforeCommand",
742
+ "afterCommand",
743
+ "beforeTask",
744
+ "afterTask"
745
+ ];
746
+ for (const hook of validHooks) {
747
+ if (hook in plugin && typeof plugin[hook] !== "function") {
748
+ errors.push(`Hook '${hook}' must be a function`);
749
+ }
750
+ }
751
+ const validRegistrations = [
752
+ "registerCommands",
753
+ "registerTasks",
754
+ "registerGenerators",
755
+ "registerProviders"
756
+ ];
757
+ for (const method of validRegistrations) {
758
+ if (method in plugin && typeof plugin[method] !== "function") {
759
+ errors.push(`Registration method '${method}' must be a function`);
760
+ }
761
+ }
762
+ if (!plugin.capabilities || plugin.capabilities.length === 0) {
763
+ warnings.push("Plugin does not declare any capabilities");
764
+ }
765
+ return {
766
+ errors,
767
+ securityIssues,
768
+ valid: errors.length === 0,
769
+ warnings
770
+ };
771
+ }
772
+ /**
773
+ * Check if plugin requires user approval based on capabilities
774
+ */
775
+ requiresApproval(plugin) {
776
+ if (!plugin.capabilities) {
777
+ return false;
778
+ }
779
+ const dangerousCapabilities = ["fs:write", "shell:run"];
780
+ return plugin.capabilities.some((cap) => dangerousCapabilities.includes(cap));
781
+ }
782
+ /**
783
+ * Get security level of plugin
784
+ */
785
+ getSecurityLevel(plugin) {
786
+ if (!plugin.capabilities || plugin.capabilities.length === 0) {
787
+ return "safe";
788
+ }
789
+ const dangerousCapabilities = ["fs:write", "shell:run"];
790
+ const hasDangerous = plugin.capabilities.some((cap) => dangerousCapabilities.includes(cap));
791
+ if (hasDangerous) {
792
+ return "dangerous";
793
+ }
794
+ const moderateCapabilities = ["process:env", "net:localhost"];
795
+ const hasModerate = plugin.capabilities.some((cap) => moderateCapabilities.includes(cap));
796
+ if (hasModerate) {
797
+ return "moderate";
798
+ }
799
+ return "safe";
800
+ }
801
+ /**
802
+ * Validate command registration
803
+ */
804
+ validateCommand(command) {
805
+ const errors = [];
806
+ if (!command.name || typeof command.name !== "string") {
807
+ errors.push("Command must have a name (string)");
808
+ }
809
+ if (!command.description || typeof command.description !== "string") {
810
+ errors.push("Command must have a description (string)");
811
+ }
812
+ if (!command.action || typeof command.action !== "function") {
813
+ errors.push("Command must have an action (function)");
814
+ }
815
+ if (command.options && !Array.isArray(command.options)) {
816
+ errors.push("Command options must be an array");
817
+ }
818
+ return {
819
+ errors,
820
+ valid: errors.length === 0
821
+ };
822
+ }
823
+ /**
824
+ * Validate task registration
825
+ */
826
+ validateTask(task) {
827
+ const errors = [];
828
+ if (!task.name || typeof task.name !== "string") {
829
+ errors.push("Task must have a name (string)");
830
+ }
831
+ if (!task.description || typeof task.description !== "string") {
832
+ errors.push("Task must have a description (string)");
833
+ }
834
+ if (!task.run || typeof task.run !== "function") {
835
+ errors.push("Task must have a run function");
836
+ }
837
+ return {
838
+ errors,
839
+ valid: errors.length === 0
840
+ };
841
+ }
842
+ /**
843
+ * Validate generator registration
844
+ */
845
+ validateGenerator(generator) {
846
+ const errors = [];
847
+ if (!generator.kind || typeof generator.kind !== "string") {
848
+ errors.push("Generator must have a kind (string)");
849
+ }
850
+ if (!generator.description || typeof generator.description !== "string") {
851
+ errors.push("Generator must have a description (string)");
852
+ }
853
+ if (!generator.generate || typeof generator.generate !== "function") {
854
+ errors.push("Generator must have a generate function");
855
+ }
856
+ return {
857
+ errors,
858
+ valid: errors.length === 0
859
+ };
860
+ }
861
+ /**
862
+ * Validate provider registration
863
+ */
864
+ validateProvider(provider) {
865
+ const errors = [];
866
+ if (!provider.command || typeof provider.command !== "string") {
867
+ errors.push("Provider must have a command (string)");
868
+ }
869
+ if (typeof provider.priority !== "number") {
870
+ errors.push("Provider must have a priority (number)");
871
+ }
872
+ if (!provider.canHandle || typeof provider.canHandle !== "function") {
873
+ errors.push("Provider must have a canHandle function");
874
+ }
875
+ if (!provider.handler || typeof provider.handler !== "function") {
876
+ errors.push("Provider must have a handler function");
877
+ }
878
+ return {
879
+ errors,
880
+ valid: errors.length === 0
881
+ };
882
+ }
883
+ };
884
+
885
+ // src/core/plugin-version-manager.ts
886
+ import { satisfies, valid, coerce, gt, lt, eq } from "semver";
887
+ var PluginVersionManager = class {
888
+ logger;
889
+ installedVersions = /* @__PURE__ */ new Map();
890
+ requiredVersions = /* @__PURE__ */ new Map();
891
+ latestVersions = /* @__PURE__ */ new Map();
892
+ constructor(logger) {
893
+ this.logger = logger;
894
+ }
895
+ /**
896
+ * Register installed plugin version
897
+ */
898
+ registerInstalled(pluginName, version) {
899
+ const normalized = this.normalizeVersion(version);
900
+ if (!normalized) {
901
+ this.logger.warn(`Invalid version for plugin '${pluginName}': ${version}`);
902
+ return;
903
+ }
904
+ this.installedVersions.set(pluginName, normalized);
905
+ this.logger.debug(`Registered plugin '${pluginName}' version ${normalized}`);
906
+ }
907
+ /**
908
+ * Set required version for plugin
909
+ */
910
+ setRequired(pluginName, versionRange) {
911
+ this.requiredVersions.set(pluginName, versionRange);
912
+ this.logger.debug(`Set required version for '${pluginName}': ${versionRange}`);
913
+ }
914
+ /**
915
+ * Set latest available version
916
+ */
917
+ setLatest(pluginName, version) {
918
+ const normalized = this.normalizeVersion(version);
919
+ if (normalized) {
920
+ this.latestVersions.set(pluginName, normalized);
921
+ }
922
+ }
923
+ /**
924
+ * Check if plugin version satisfies requirement
925
+ */
926
+ satisfies(pluginName, versionRange) {
927
+ const installed = this.installedVersions.get(pluginName);
928
+ if (!installed) {
929
+ return false;
930
+ }
931
+ try {
932
+ return satisfies(installed, versionRange);
933
+ } catch {
934
+ this.logger.warn(`Invalid version range for '${pluginName}': ${versionRange}`);
935
+ return false;
936
+ }
937
+ }
938
+ /**
939
+ * Check compatibility of plugin
940
+ */
941
+ checkCompatibility(pluginName) {
942
+ const issues = [];
943
+ const warnings = [];
944
+ const recommendations = [];
945
+ const installed = this.installedVersions.get(pluginName);
946
+ const required = this.requiredVersions.get(pluginName);
947
+ const latest = this.latestVersions.get(pluginName);
948
+ if (!installed) {
949
+ issues.push(`Plugin '${pluginName}' is not installed`);
950
+ return { compatible: false, issues, recommendations, warnings };
951
+ }
952
+ if (required && !this.satisfies(pluginName, required)) {
953
+ issues.push(
954
+ `Plugin '${pluginName}' version ${installed} does not satisfy requirement ${required}`
955
+ );
956
+ }
957
+ if (latest && gt(latest, installed)) {
958
+ warnings.push(`Plugin '${pluginName}' has an update available: ${installed} \u2192 ${latest}`);
959
+ recommendations.push(`Run: kubit-forge plugin:update ${pluginName}`);
960
+ }
961
+ if (latest) {
962
+ const installedMajor = parseInt(installed.split(".")[0], 10);
963
+ const latestMajor = parseInt(latest.split(".")[0], 10);
964
+ if (latestMajor > installedMajor + 1) {
965
+ warnings.push(
966
+ `Plugin '${pluginName}' is ${latestMajor - installedMajor} major versions behind`
967
+ );
968
+ recommendations.push(`Consider upgrading to version ${latest}`);
969
+ }
970
+ }
971
+ return {
972
+ compatible: issues.length === 0,
973
+ issues,
974
+ recommendations,
975
+ warnings
976
+ };
977
+ }
978
+ /**
979
+ * Get plugin version info
980
+ */
981
+ getVersionInfo(pluginName) {
982
+ const installed = this.installedVersions.get(pluginName);
983
+ const required = this.requiredVersions.get(pluginName);
984
+ const latest = this.latestVersions.get(pluginName);
985
+ const compatible = required ? this.satisfies(pluginName, required) : true;
986
+ const updateAvailable = installed && latest ? gt(latest, installed) : false;
987
+ return {
988
+ compatible,
989
+ installedVersion: installed,
990
+ latestVersion: latest,
991
+ name: pluginName,
992
+ requiredVersion: required,
993
+ updateAvailable,
994
+ version: installed || "not-installed"
995
+ };
996
+ }
997
+ /**
998
+ * Get all plugin versions
999
+ */
1000
+ getAllVersions() {
1001
+ const allPlugins = /* @__PURE__ */ new Set([
1002
+ ...this.installedVersions.keys(),
1003
+ ...this.requiredVersions.keys(),
1004
+ ...this.latestVersions.keys()
1005
+ ]);
1006
+ return Array.from(allPlugins).map((plugin) => this.getVersionInfo(plugin));
1007
+ }
1008
+ /**
1009
+ * Check if update is available
1010
+ */
1011
+ hasUpdate(pluginName) {
1012
+ const installed = this.installedVersions.get(pluginName);
1013
+ const latest = this.latestVersions.get(pluginName);
1014
+ if (!installed || !latest) {
1015
+ return false;
1016
+ }
1017
+ return gt(latest, installed);
1018
+ }
1019
+ /**
1020
+ * Get plugins with updates available
1021
+ */
1022
+ getUpdatablePlugins() {
1023
+ return this.getAllVersions().filter((p) => p.updateAvailable);
1024
+ }
1025
+ /**
1026
+ * Get incompatible plugins
1027
+ */
1028
+ getIncompatiblePlugins() {
1029
+ return this.getAllVersions().filter((p) => !p.compatible);
1030
+ }
1031
+ /**
1032
+ * Resolve version conflicts
1033
+ */
1034
+ resolveConflicts(constraints) {
1035
+ const resolved = /* @__PURE__ */ new Map();
1036
+ const conflicts = [];
1037
+ const byPlugin = /* @__PURE__ */ new Map();
1038
+ for (const constraint of constraints) {
1039
+ if (!byPlugin.has(constraint.plugin)) {
1040
+ byPlugin.set(constraint.plugin, []);
1041
+ }
1042
+ byPlugin.get(constraint.plugin).push(constraint);
1043
+ }
1044
+ for (const [plugin, pluginConstraints] of byPlugin.entries()) {
1045
+ if (pluginConstraints.length === 1) {
1046
+ resolved.set(plugin, pluginConstraints[0].version);
1047
+ continue;
1048
+ }
1049
+ const versions = pluginConstraints.map((c) => c.version);
1050
+ const compatible = this.findCompatibleVersion(versions);
1051
+ if (compatible) {
1052
+ resolved.set(plugin, compatible);
1053
+ } else {
1054
+ conflicts.push(
1055
+ `Cannot resolve version for '${plugin}': ${versions.join(", ")} are incompatible`
1056
+ );
1057
+ }
1058
+ }
1059
+ return { conflicts, resolved };
1060
+ }
1061
+ /**
1062
+ * Find compatible version from multiple constraints
1063
+ */
1064
+ findCompatibleVersion(versionRanges) {
1065
+ const candidates = [];
1066
+ for (const range of versionRanges) {
1067
+ const normalized = this.normalizeVersion(range);
1068
+ if (normalized && candidates.length === 0) {
1069
+ candidates.push(normalized);
1070
+ }
1071
+ }
1072
+ for (const candidate of candidates) {
1073
+ const satisfiesAll = versionRanges.every((range) => {
1074
+ try {
1075
+ return satisfies(candidate, range);
1076
+ } catch {
1077
+ return false;
1078
+ }
1079
+ });
1080
+ if (satisfiesAll) {
1081
+ return candidate;
1082
+ }
1083
+ }
1084
+ return null;
1085
+ }
1086
+ /**
1087
+ * Normalize version string
1088
+ */
1089
+ normalizeVersion(version) {
1090
+ if (valid(version)) {
1091
+ return version;
1092
+ }
1093
+ const coerced = coerce(version);
1094
+ if (coerced) {
1095
+ return coerced.version;
1096
+ }
1097
+ return null;
1098
+ }
1099
+ /**
1100
+ * Compare two versions
1101
+ */
1102
+ compare(version1, version2) {
1103
+ const v1 = this.normalizeVersion(version1);
1104
+ const v2 = this.normalizeVersion(version2);
1105
+ if (!v1 || !v2) {
1106
+ return 0;
1107
+ }
1108
+ if (gt(v1, v2)) {
1109
+ return 1;
1110
+ }
1111
+ if (lt(v1, v2)) {
1112
+ return -1;
1113
+ }
1114
+ return 0;
1115
+ }
1116
+ /**
1117
+ * Check if version is equal
1118
+ */
1119
+ isEqual(version1, version2) {
1120
+ const v1 = this.normalizeVersion(version1);
1121
+ const v2 = this.normalizeVersion(version2);
1122
+ if (!v1 || !v2) {
1123
+ return false;
1124
+ }
1125
+ return eq(v1, v2);
1126
+ }
1127
+ /**
1128
+ * Get version statistics
1129
+ */
1130
+ getStats() {
1131
+ const all = this.getAllVersions();
1132
+ return {
1133
+ compatible: all.filter((p) => p.compatible).length,
1134
+ incompatible: all.filter((p) => !p.compatible).length,
1135
+ installed: all.filter((p) => p.installedVersion).length,
1136
+ totalPlugins: all.length,
1137
+ updatable: all.filter((p) => p.updateAvailable).length
1138
+ };
1139
+ }
1140
+ /**
1141
+ * Clear all version data
1142
+ */
1143
+ clear() {
1144
+ this.installedVersions.clear();
1145
+ this.requiredVersions.clear();
1146
+ this.latestVersions.clear();
1147
+ }
1148
+ };
1149
+
1150
+ // src/core/plugin-manager.ts
1151
+ var PluginManager = class {
1152
+ plugins = /* @__PURE__ */ new Map();
1153
+ commands = /* @__PURE__ */ new Map();
1154
+ tasks = /* @__PURE__ */ new Map();
1155
+ generators = /* @__PURE__ */ new Map();
1156
+ providers = /* @__PURE__ */ new Map();
1157
+ logger;
1158
+ cwd;
1159
+ validator;
1160
+ registry;
1161
+ sandboxManager;
1162
+ versionManager;
1163
+ dependencyResolver;
1164
+ constructor(logger, cwd) {
1165
+ this.logger = logger;
1166
+ this.cwd = cwd;
1167
+ this.validator = new PluginValidator();
1168
+ this.registry = new PluginRegistry(logger);
1169
+ this.sandboxManager = new SandboxManager(logger);
1170
+ this.versionManager = new PluginVersionManager(logger);
1171
+ this.dependencyResolver = new PluginDependencyResolver(logger);
1172
+ }
1173
+ /**
1174
+ * Load plugins from config or auto-detect
1175
+ */
1176
+ async loadPlugins(pluginNames, ctx, options = {}) {
1177
+ if (options.checkDependencies !== false) {
1178
+ const resolution = this.dependencyResolver.resolve(pluginNames);
1179
+ if (resolution.errors.length > 0) {
1180
+ this.logger.error("Plugin dependency resolution failed:");
1181
+ resolution.errors.forEach((err) => this.logger.error(` - ${err}`));
1182
+ throw new Error("Cannot load plugins due to dependency errors");
1183
+ }
1184
+ if (resolution.warnings.length > 0) {
1185
+ resolution.warnings.forEach((warn) => this.logger.warn(warn));
1186
+ }
1187
+ pluginNames = resolution.loadOrder;
1188
+ this.logger.debug(`Plugin load order: ${pluginNames.join(" -> ")}`);
1189
+ }
1190
+ for (const pluginName of pluginNames) {
1191
+ try {
1192
+ await this.loadPlugin(pluginName, ctx, options);
1193
+ } catch (error) {
1194
+ this.logger.warn(
1195
+ `Failed to load plugin '${pluginName}': ${error instanceof Error ? error.message : "Unknown error"}`
1196
+ );
1197
+ }
1198
+ }
1199
+ }
1200
+ /**
1201
+ * Load a single plugin
1202
+ */
1203
+ async loadPlugin(pluginName, ctx, options = {}) {
1204
+ let pluginModule;
1205
+ try {
1206
+ const pluginPath = join2(this.cwd, "node_modules", pluginName);
1207
+ if (existsSync2(pluginPath)) {
1208
+ pluginModule = await import(pluginPath);
1209
+ } else {
1210
+ pluginModule = await import(pluginName);
1211
+ }
1212
+ } catch {
1213
+ throw new Error(`Cannot resolve plugin '${pluginName}'`);
1214
+ }
1215
+ const plugin = pluginModule.default || pluginModule;
1216
+ if (!plugin.name || !plugin.version) {
1217
+ throw new Error(`Invalid plugin '${pluginName}': missing name or version`);
1218
+ }
1219
+ this.versionManager.registerInstalled(plugin.name, plugin.version);
1220
+ const versionCheck = this.versionManager.checkCompatibility(plugin.name);
1221
+ if (!versionCheck.compatible) {
1222
+ this.logger.error(`Plugin '${plugin.name}' version compatibility check failed:`);
1223
+ versionCheck.issues.forEach((issue) => this.logger.error(` - ${issue}`));
1224
+ throw new Error(`Plugin '${plugin.name}' is not compatible`);
1225
+ }
1226
+ if (versionCheck.warnings.length > 0) {
1227
+ versionCheck.warnings.forEach((warn) => this.logger.warn(warn));
1228
+ }
1229
+ if (options.validate !== false) {
1230
+ const validation = this.validator.validate(plugin);
1231
+ if (!validation.valid) {
1232
+ throw new Error(
1233
+ `Plugin '${plugin.name}' validation failed:
1234
+ ${validation.errors.join("\n")}`
1235
+ );
1236
+ }
1237
+ if (validation.warnings.length > 0) {
1238
+ for (const warning of validation.warnings) {
1239
+ this.logger.warn(`Plugin '${plugin.name}': ${warning}`);
1240
+ }
1241
+ }
1242
+ if (!options.skipSecurityCheck && validation.securityIssues.length > 0) {
1243
+ this.logger.warn(`
1244
+ Security notice for plugin '${plugin.name}':`);
1245
+ for (const issue of validation.securityIssues) {
1246
+ this.logger.warn(` - ${issue}`);
1247
+ }
1248
+ const securityLevel = this.validator.getSecurityLevel(plugin);
1249
+ if (securityLevel === "dangerous") {
1250
+ this.logger.warn(
1251
+ "\nThis plugin requires dangerous permissions. Only install if you trust the source."
1252
+ );
1253
+ }
1254
+ }
1255
+ }
1256
+ this.plugins.set(plugin.name, plugin);
1257
+ if (plugin.onLoad) {
1258
+ await plugin.onLoad(ctx);
1259
+ }
1260
+ if (plugin.registerCommands) {
1261
+ const commands = plugin.registerCommands();
1262
+ for (const cmd of commands) {
1263
+ this.commands.set(cmd.name, cmd);
1264
+ this.logger.debug(`Registered command '${cmd.name}' from plugin '${plugin.name}'`);
1265
+ }
1266
+ }
1267
+ if (plugin.registerTasks) {
1268
+ const tasks = plugin.registerTasks();
1269
+ for (const task of tasks) {
1270
+ this.tasks.set(task.name, task);
1271
+ this.logger.debug(`Registered task '${task.name}' from plugin '${plugin.name}'`);
1272
+ }
1273
+ }
1274
+ if (plugin.registerGenerators) {
1275
+ const generators = plugin.registerGenerators();
1276
+ for (const gen of generators) {
1277
+ this.generators.set(gen.kind, gen);
1278
+ this.logger.debug(`Registered generator '${gen.kind}' from plugin '${plugin.name}'`);
1279
+ }
1280
+ }
1281
+ if (plugin.registerProviders) {
1282
+ const providers = plugin.registerProviders();
1283
+ for (const provider of providers) {
1284
+ if (!this.providers.has(provider.command)) {
1285
+ this.providers.set(provider.command, []);
1286
+ }
1287
+ this.providers.get(provider.command).push(provider);
1288
+ this.logger.debug(
1289
+ `Registered provider for '${provider.command}' from plugin '${plugin.name}'`
1290
+ );
1291
+ }
1292
+ }
1293
+ this.logger.debug(`Loaded plugin '${plugin.name}' v${plugin.version}`);
1294
+ }
1295
+ /**
1296
+ * Get all loaded plugins
1297
+ */
1298
+ getPlugins() {
1299
+ return Array.from(this.plugins.values());
1300
+ }
1301
+ /**
1302
+ * Get command by name
1303
+ */
1304
+ getCommand(name) {
1305
+ return this.commands.get(name);
1306
+ }
1307
+ /**
1308
+ * Get all commands
1309
+ */
1310
+ getCommands() {
1311
+ return Array.from(this.commands.values());
1312
+ }
1313
+ /**
1314
+ * Get task by name
1315
+ */
1316
+ getTask(name) {
1317
+ return this.tasks.get(name);
1318
+ }
1319
+ /**
1320
+ * Get all tasks
1321
+ */
1322
+ getTasks() {
1323
+ return Array.from(this.tasks.values());
1324
+ }
1325
+ /**
1326
+ * Get generator by kind
1327
+ */
1328
+ getGenerator(kind) {
1329
+ return this.generators.get(kind);
1330
+ }
1331
+ /**
1332
+ * Get all generators
1333
+ */
1334
+ getGenerators() {
1335
+ return Array.from(this.generators.values());
1336
+ }
1337
+ /**
1338
+ * Get best provider for a command
1339
+ */
1340
+ getProvider(command, ctx) {
1341
+ const providers = this.providers.get(command) || [];
1342
+ const capable = providers.filter((p) => p.canHandle(ctx));
1343
+ if (capable.length === 0) {
1344
+ return void 0;
1345
+ }
1346
+ capable.sort((a, b) => b.priority - a.priority);
1347
+ return capable[0];
1348
+ }
1349
+ /**
1350
+ * Call beforeCommand hooks
1351
+ */
1352
+ async callBeforeCommand(command, ctx) {
1353
+ for (const plugin of this.plugins.values()) {
1354
+ if (plugin.beforeCommand) {
1355
+ await plugin.beforeCommand(command, ctx);
1356
+ }
1357
+ }
1358
+ }
1359
+ /**
1360
+ * Call afterCommand hooks
1361
+ */
1362
+ async callAfterCommand(command, ctx, result) {
1363
+ for (const plugin of this.plugins.values()) {
1364
+ if (plugin.afterCommand) {
1365
+ await plugin.afterCommand(command, ctx, result);
1366
+ }
1367
+ }
1368
+ }
1369
+ /**
1370
+ * Call beforeTask hooks
1371
+ */
1372
+ async callBeforeTask(task, ctx) {
1373
+ for (const plugin of this.plugins.values()) {
1374
+ if (plugin.beforeTask) {
1375
+ await plugin.beforeTask(task, ctx);
1376
+ }
1377
+ }
1378
+ }
1379
+ /**
1380
+ * Call afterTask hooks
1381
+ */
1382
+ async callAfterTask(task, ctx, result) {
1383
+ for (const plugin of this.plugins.values()) {
1384
+ if (plugin.afterTask) {
1385
+ await plugin.afterTask(task, ctx, result);
1386
+ }
1387
+ }
1388
+ }
1389
+ /**
1390
+ * Search for plugins in registry
1391
+ */
1392
+ async searchPlugins(query, options) {
1393
+ return this.registry.search(query, options);
1394
+ }
1395
+ /**
1396
+ * Get plugin info from registry
1397
+ */
1398
+ async getPluginInfo(name) {
1399
+ return this.registry.getInfo(name);
1400
+ }
1401
+ /**
1402
+ * Get featured plugins
1403
+ */
1404
+ async getFeaturedPlugins() {
1405
+ return this.registry.getFeatured();
1406
+ }
1407
+ /**
1408
+ * Check if plugin is loaded
1409
+ */
1410
+ isLoaded(pluginName) {
1411
+ return this.plugins.has(pluginName);
1412
+ }
1413
+ /**
1414
+ * Get loaded plugin by name
1415
+ */
1416
+ getPlugin(pluginName) {
1417
+ return this.plugins.get(pluginName);
1418
+ }
1419
+ /**
1420
+ * Unload a plugin
1421
+ */
1422
+ async unloadPlugin(pluginName) {
1423
+ const plugin = this.plugins.get(pluginName);
1424
+ if (!plugin) {
1425
+ return;
1426
+ }
1427
+ if (plugin.registerCommands) {
1428
+ const commands = plugin.registerCommands();
1429
+ for (const cmd of commands) {
1430
+ this.commands.delete(cmd.name);
1431
+ }
1432
+ }
1433
+ if (plugin.registerTasks) {
1434
+ const tasks = plugin.registerTasks();
1435
+ for (const task of tasks) {
1436
+ this.tasks.delete(task.name);
1437
+ }
1438
+ }
1439
+ if (plugin.registerGenerators) {
1440
+ const generators = plugin.registerGenerators();
1441
+ for (const gen of generators) {
1442
+ this.generators.delete(gen.kind);
1443
+ }
1444
+ }
1445
+ if (plugin.registerProviders) {
1446
+ const providers = plugin.registerProviders();
1447
+ for (const provider of providers) {
1448
+ const list = this.providers.get(provider.command);
1449
+ if (list) {
1450
+ const index = list.indexOf(provider);
1451
+ if (index !== -1) {
1452
+ list.splice(index, 1);
1453
+ }
1454
+ }
1455
+ }
1456
+ }
1457
+ this.plugins.delete(pluginName);
1458
+ this.logger.debug(`Unloaded plugin '${pluginName}'`);
1459
+ }
1460
+ /**
1461
+ * Get plugin statistics
1462
+ */
1463
+ getStats() {
1464
+ return {
1465
+ commands: this.commands.size,
1466
+ dependencies: this.dependencyResolver.getStats(),
1467
+ generators: this.generators.size,
1468
+ plugins: this.plugins.size,
1469
+ providers: Array.from(this.providers.values()).reduce((sum, list) => sum + list.length, 0),
1470
+ tasks: this.tasks.size,
1471
+ versions: this.versionManager.getStats()
1472
+ };
1473
+ }
1474
+ /**
1475
+ * Get version manager
1476
+ */
1477
+ getVersionManager() {
1478
+ return this.versionManager;
1479
+ }
1480
+ /**
1481
+ * Get dependency resolver
1482
+ */
1483
+ getDependencyResolver() {
1484
+ return this.dependencyResolver;
1485
+ }
1486
+ /**
1487
+ * Get sandbox manager
1488
+ */
1489
+ getSandboxManager() {
1490
+ return this.sandboxManager;
1491
+ }
1492
+ /**
1493
+ * Register plugin metadata for dependency resolution
1494
+ */
1495
+ registerPluginMetadata(metadata) {
1496
+ this.dependencyResolver.register(metadata);
1497
+ }
1498
+ /**
1499
+ * Check plugin updates
1500
+ */
1501
+ async checkUpdates() {
1502
+ const updates = [];
1503
+ for (const plugin of this.plugins.values()) {
1504
+ try {
1505
+ const info = await this.registry.getInfo(plugin.name);
1506
+ if (info && info.version) {
1507
+ this.versionManager.setLatest(plugin.name, info.version);
1508
+ if (this.versionManager.hasUpdate(plugin.name)) {
1509
+ updates.push({
1510
+ current: plugin.version,
1511
+ latest: info.version,
1512
+ name: plugin.name
1513
+ });
1514
+ }
1515
+ }
1516
+ } catch {
1517
+ }
1518
+ }
1519
+ return updates;
1520
+ }
1521
+ };
1522
+
1523
+ // src/types/index.ts
1524
+ import { z } from "zod";
1525
+ var KubitConfigSchema = z.object({
1526
+ commands: z.object({
1527
+ buildProvider: z.string().optional(),
1528
+ devProvider: z.string().optional()
1529
+ }).optional(),
1530
+ env: z.object({
1531
+ required: z.array(z.string()).optional(),
1532
+ schema: z.string().optional()
1533
+ }).optional(),
1534
+ kubit: z.object({
1535
+ cliVersion: z.string().optional()
1536
+ }).optional(),
1537
+ paths: z.object({
1538
+ dist: z.string().default("dist"),
1539
+ envExample: z.string().default(".env.example"),
1540
+ envLocal: z.string().default(".env.local"),
1541
+ src: z.string().default("src")
1542
+ }).optional(),
1543
+ plugins: z.object({
1544
+ enabled: z.array(z.string()).optional()
1545
+ }).optional(),
1546
+ project: z.object({
1547
+ devPort: z.number().default(5173),
1548
+ language: z.enum(["ts", "js"]).default("ts"),
1549
+ name: z.string(),
1550
+ nodeVersion: z.string().default("20"),
1551
+ packageManager: z.enum(["pnpm", "npm", "yarn"]).default("pnpm"),
1552
+ stack: z.enum(["react", "vanilla"]),
1553
+ type: z.enum(["web", "library"]).default("web")
1554
+ }),
1555
+ quality: z.object({
1556
+ format: z.boolean().default(true),
1557
+ lint: z.boolean().default(true),
1558
+ typecheck: z.boolean().default(true),
1559
+ unitTest: z.boolean().default(true)
1560
+ }).optional()
1561
+ });
1562
+
1563
+ // src/utils/config-loader.ts
1564
+ import { readFileSync as readFileSync2, existsSync as existsSync3 } from "fs";
1565
+ import { join as join3 } from "path";
1566
+ import { parse as parseToml } from "smol-toml";
1567
+
1568
+ // src/templates/config/defaults.ts
1569
+ var PROJECT_DEFAULTS = {
1570
+ nodeVersion: "20",
1571
+ devPort: 5173,
1572
+ packageManager: "pnpm"
1573
+ };
1574
+ var PATHS_DEFAULTS = {
1575
+ src: "src",
1576
+ dist: "dist",
1577
+ envExample: ".env.example",
1578
+ envLocal: ".env.local"
1579
+ };
1580
+ var QUALITY_DEFAULTS = {
1581
+ lint: true,
1582
+ format: true,
1583
+ typecheck: true,
1584
+ unitTest: true
1585
+ };
1586
+ var QUALITY_MINIMAL = {
1587
+ lint: false,
1588
+ format: false,
1589
+ typecheck: false,
1590
+ unitTest: false
1591
+ };
1592
+ var PLUGIN_DEFAULTS = {
1593
+ enabled: []
1594
+ };
1595
+
1596
+ // src/templates/config/config-templates.ts
1597
+ var ConfigTemplateLoader = class {
1598
+ /**
1599
+ * Build a complete default configuration
1600
+ */
1601
+ static buildDefault(options = {}) {
1602
+ return {
1603
+ kubit: {
1604
+ cliVersion: "^4.0.0"
1605
+ },
1606
+ project: this.buildProjectConfig(options),
1607
+ paths: this.buildPathsConfig(),
1608
+ quality: this.buildQualityConfig(options),
1609
+ plugins: this.buildPluginsConfig()
1610
+ };
1611
+ }
1612
+ /**
1613
+ * Build project configuration with defaults
1614
+ */
1615
+ static buildProjectConfig(options = {}) {
1616
+ return {
1617
+ name: options.name || "my-project",
1618
+ type: options.type || "web",
1619
+ stack: options.stack || "vanilla",
1620
+ language: options.language || "js",
1621
+ packageManager: options.packageManager || PROJECT_DEFAULTS.packageManager,
1622
+ nodeVersion: options.nodeVersion || PROJECT_DEFAULTS.nodeVersion,
1623
+ devPort: options.devPort || PROJECT_DEFAULTS.devPort
1624
+ };
1625
+ }
1626
+ /**
1627
+ * Build paths configuration with defaults
1628
+ */
1629
+ static buildPathsConfig(overrides) {
1630
+ return {
1631
+ ...PATHS_DEFAULTS,
1632
+ ...overrides
1633
+ };
1634
+ }
1635
+ /**
1636
+ * Build quality configuration with defaults
1637
+ */
1638
+ static buildQualityConfig(options = {}) {
1639
+ const baseDefaults = options.minimal ? QUALITY_MINIMAL : QUALITY_DEFAULTS;
1640
+ return {
1641
+ ...baseDefaults,
1642
+ // Auto-adjust typecheck based on language
1643
+ typecheck: options.language === "ts" ? baseDefaults.typecheck : false
1644
+ };
1645
+ }
1646
+ /**
1647
+ * Build plugins configuration with defaults
1648
+ */
1649
+ static buildPluginsConfig(plugins) {
1650
+ return {
1651
+ enabled: plugins || PLUGIN_DEFAULTS.enabled
1652
+ };
1653
+ }
1654
+ /**
1655
+ * Get project defaults
1656
+ */
1657
+ static getProjectDefaults() {
1658
+ return { ...PROJECT_DEFAULTS };
1659
+ }
1660
+ /**
1661
+ * Get paths defaults
1662
+ */
1663
+ static getPathsDefaults() {
1664
+ return { ...PATHS_DEFAULTS };
1665
+ }
1666
+ /**
1667
+ * Get quality defaults
1668
+ */
1669
+ static getQualityDefaults(minimal = false) {
1670
+ return minimal ? { ...QUALITY_MINIMAL } : { ...QUALITY_DEFAULTS };
1671
+ }
1672
+ /**
1673
+ * Get plugin defaults
1674
+ */
1675
+ static getPluginDefaults() {
1676
+ return { ...PLUGIN_DEFAULTS };
1677
+ }
1678
+ /**
1679
+ * Merge partial config with defaults
1680
+ */
1681
+ static mergeWithDefaults(partial, options = {}) {
1682
+ const defaults = this.buildDefault(options);
1683
+ return {
1684
+ kubit: partial.kubit || defaults.kubit,
1685
+ project: { ...defaults.project, ...partial.project || {} },
1686
+ paths: { ...defaults.paths, ...partial.paths || {} },
1687
+ quality: { ...defaults.quality, ...partial.quality || {} },
1688
+ plugins: { ...defaults.plugins, ...partial.plugins || {} }
1689
+ };
1690
+ }
1691
+ };
1692
+
1693
+ // src/utils/config-loader.ts
1694
+ var ConfigLoader = class {
1695
+ cwd;
1696
+ constructor(cwd = process.cwd()) {
1697
+ this.cwd = cwd;
1698
+ }
1699
+ /**
1700
+ * Load kubit config from project
1701
+ * Supports: kubit.config.toml, kubit.config.json
1702
+ */
1703
+ async load(configPath) {
1704
+ const configFile = configPath ? join3(this.cwd, configPath) : this.findConfigFile();
1705
+ if (!configFile) {
1706
+ return null;
1707
+ }
1708
+ try {
1709
+ const content = readFileSync2(configFile, "utf-8");
1710
+ let rawConfig;
1711
+ if (configFile.endsWith(".toml")) {
1712
+ rawConfig = parseToml(content);
1713
+ } else if (configFile.endsWith(".json")) {
1714
+ rawConfig = JSON.parse(content);
1715
+ } else {
1716
+ throw new Error(`Unsupported config format: ${configFile}`);
1717
+ }
1718
+ const config = KubitConfigSchema.parse(rawConfig);
1719
+ return config;
1720
+ } catch (error) {
1721
+ throw new Error(
1722
+ `Failed to load config from ${configFile}: ${error instanceof Error ? error.message : "Unknown error"}`
1723
+ );
1724
+ }
1725
+ }
1726
+ /**
1727
+ * Auto-detect project configuration when no config file exists
1728
+ */
1729
+ async autoDetect() {
1730
+ const packageJsonPath = join3(this.cwd, "package.json");
1731
+ if (!existsSync3(packageJsonPath)) {
1732
+ const projectName = this.cwd.split("/").pop() || "my-project";
1733
+ return ConfigTemplateLoader.buildDefault({
1734
+ minimal: true,
1735
+ name: projectName
1736
+ });
1737
+ }
1738
+ const packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf-8"));
1739
+ const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
1740
+ let stack = "vanilla";
1741
+ if (deps.react) {
1742
+ stack = "react";
1743
+ }
1744
+ const language = existsSync3(join3(this.cwd, "tsconfig.json")) ? "ts" : "js";
1745
+ let packageManager = "npm";
1746
+ if (existsSync3(join3(this.cwd, "pnpm-lock.yaml"))) {
1747
+ packageManager = "pnpm";
1748
+ } else if (existsSync3(join3(this.cwd, "yarn.lock"))) {
1749
+ packageManager = "yarn";
1750
+ } else if (existsSync3(join3(this.cwd, "package-lock.json"))) {
1751
+ packageManager = "npm";
1752
+ }
1753
+ const config = ConfigTemplateLoader.buildDefault({
1754
+ language,
1755
+ name: packageJson.name || "my-app",
1756
+ packageManager,
1757
+ stack,
1758
+ type: "web"
1759
+ });
1760
+ config.quality = {
1761
+ ...config.quality,
1762
+ format: true,
1763
+ lint: true,
1764
+ typecheck: language === "ts",
1765
+ unitTest: !!deps.vitest || !!deps.jest
1766
+ };
1767
+ return config;
1768
+ }
1769
+ findConfigFile() {
1770
+ const candidates = ["kubit.config.toml", "kubit.config.json"];
1771
+ for (const candidate of candidates) {
1772
+ const path = join3(this.cwd, candidate);
1773
+ if (existsSync3(path)) {
1774
+ return path;
1775
+ }
1776
+ }
1777
+ return null;
1778
+ }
1779
+ };
1780
+
1781
+ // src/utils/logger.ts
1782
+ import chalk2 from "chalk";
1783
+
1784
+ // src/utils/theme.ts
1785
+ import chalk from "chalk";
1786
+ var colors = {
1787
+ bold: chalk.bold,
1788
+ boolean: chalk.hex("#06b6d4"),
1789
+ // Cyan
1790
+ code: chalk.hex("#e879f9"),
1791
+ dim: chalk.dim,
1792
+ error: chalk.hex("#ef4444"),
1793
+ // Red
1794
+ info: chalk.hex("#3b82f6"),
1795
+ // Blue
1796
+ keyword: chalk.hex("#a855f7"),
1797
+ // Purple
1798
+ // Special
1799
+ link: chalk.hex("#3b82f6").underline,
1800
+ // UI colors
1801
+ muted: chalk.hex("#6b7280"),
1802
+ // Gray
1803
+ number: chalk.hex("#f97316"),
1804
+ // Orange
1805
+ // Primary brand colors
1806
+ primary: chalk.hex("#6366f1"),
1807
+ // Indigo - main brand color
1808
+ secondary: chalk.hex("#8b5cf6"),
1809
+ // Purple - accent color
1810
+ // Syntax highlighting
1811
+ string: chalk.hex("#22c55e"),
1812
+ // Green
1813
+ // Semantic colors
1814
+ success: chalk.hex("#10b981"),
1815
+ // Green
1816
+ warning: chalk.hex("#f59e0b")
1817
+ // Amber
1818
+ };
1819
+ var symbols = {
1820
+ bullet: "\u2022",
1821
+ ellipsis: "...",
1822
+ error: "\u2717",
1823
+ info: "i",
1824
+ line: "\u2500",
1825
+ pointer: "\u203A",
1826
+ step: "\u2192",
1827
+ success: "\u2713",
1828
+ warning: "!"
1829
+ };
1830
+
1831
+ // src/utils/logger.ts
1832
+ var ConsoleLogger = class {
1833
+ useColor;
1834
+ isVerbose;
1835
+ isQuiet;
1836
+ useJson;
1837
+ constructor(options = {}) {
1838
+ this.useColor = !options.noColor;
1839
+ this.isVerbose = options.verbose || false;
1840
+ this.isQuiet = options.quiet || false;
1841
+ this.useJson = options.json || false;
1842
+ }
1843
+ info(message) {
1844
+ if (this.isQuiet) {
1845
+ return;
1846
+ }
1847
+ if (this.useJson) {
1848
+ console.log(JSON.stringify({ level: "info", message }));
1849
+ return;
1850
+ }
1851
+ console.log(this.useColor ? colors.info(symbols.info) : "i", message);
1852
+ }
1853
+ success(message) {
1854
+ if (this.isQuiet) {
1855
+ return;
1856
+ }
1857
+ if (this.useJson) {
1858
+ console.log(JSON.stringify({ level: "success", message }));
1859
+ return;
1860
+ }
1861
+ console.log(this.useColor ? colors.success(symbols.success) : symbols.success, message);
1862
+ }
1863
+ warn(message) {
1864
+ if (this.useJson) {
1865
+ console.log(JSON.stringify({ level: "warning", message }));
1866
+ return;
1867
+ }
1868
+ console.warn(this.useColor ? colors.warning(symbols.warning) : symbols.warning, message);
1869
+ }
1870
+ error(message, error) {
1871
+ if (this.useJson) {
1872
+ console.log(
1873
+ JSON.stringify({
1874
+ error: error?.message,
1875
+ level: "error",
1876
+ message,
1877
+ stack: error?.stack
1878
+ })
1879
+ );
1880
+ return;
1881
+ }
1882
+ console.error(this.useColor ? colors.error(symbols.error) : symbols.error, message);
1883
+ if (error && this.isVerbose) {
1884
+ console.error(chalk2.gray(error.stack || error.message));
1885
+ }
1886
+ }
1887
+ debug(message) {
1888
+ if (!this.isVerbose) {
1889
+ return;
1890
+ }
1891
+ if (this.useJson) {
1892
+ console.log(JSON.stringify({ level: "debug", message }));
1893
+ return;
1894
+ }
1895
+ console.log(this.useColor ? colors.muted(symbols.pointer) : symbols.pointer, message);
1896
+ }
1897
+ step(message) {
1898
+ if (this.isQuiet) {
1899
+ return;
1900
+ }
1901
+ if (this.useJson) {
1902
+ console.log(JSON.stringify({ level: "step", message }));
1903
+ return;
1904
+ }
1905
+ console.log(this.useColor ? colors.primary(symbols.step) : symbols.step, message);
1906
+ }
1907
+ json(data) {
1908
+ console.log(JSON.stringify(data, null, 2));
1909
+ }
1910
+ };
1911
+
1912
+ // src/utils/task-runner.ts
1913
+ import { execa } from "execa";
1914
+ var DefaultTaskRunner = class {
1915
+ tasks = /* @__PURE__ */ new Map();
1916
+ logger;
1917
+ constructor(logger) {
1918
+ this.logger = logger;
1919
+ }
1920
+ registerTask(name, task) {
1921
+ this.tasks.set(name, task);
1922
+ }
1923
+ async run(command, args = [], options = {}) {
1924
+ const startTime = Date.now();
1925
+ const cwd = options.cwd || process.cwd();
1926
+ try {
1927
+ if (!options.silent) {
1928
+ this.logger.debug(`Running: ${command} ${args.join(" ")}`);
1929
+ }
1930
+ const result = await execa(command, args, {
1931
+ all: true,
1932
+ cwd,
1933
+ env: { ...process.env, ...options.env },
1934
+ reject: false
1935
+ });
1936
+ const duration = Date.now() - startTime;
1937
+ if (result.exitCode === 0) {
1938
+ return {
1939
+ duration,
1940
+ exitCode: result.exitCode,
1941
+ output: options.captureOutput ? result.all : void 0,
1942
+ status: "ok"
1943
+ };
1944
+ }
1945
+ return {
1946
+ duration,
1947
+ exitCode: result.exitCode,
1948
+ message: `Command failed with exit code ${result.exitCode}`,
1949
+ output: result.all,
1950
+ status: "error"
1951
+ };
1952
+ } catch (error) {
1953
+ const duration = Date.now() - startTime;
1954
+ return {
1955
+ duration,
1956
+ message: error instanceof Error ? error.message : "Unknown error",
1957
+ status: "error"
1958
+ };
1959
+ }
1960
+ }
1961
+ async runTask(taskName) {
1962
+ const task = this.tasks.get(taskName);
1963
+ if (!task) {
1964
+ return {
1965
+ message: `Task '${taskName}' not found`,
1966
+ status: "error"
1967
+ };
1968
+ }
1969
+ return await task();
1970
+ }
1971
+ };
1972
+ export {
1973
+ ConfigLoader,
1974
+ ConsoleLogger,
1975
+ DefaultTaskRunner,
1976
+ KubitConfigSchema,
1977
+ PluginManager
1978
+ };
1979
+ //# sourceMappingURL=index.js.map