create-fullstack-scaffold 0.4.3 → 0.4.4

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 (147) hide show
  1. package/dist/cli/index.js +513 -122
  2. package/dist/cli/index.js.map +1 -1
  3. package/package.json +1 -1
  4. package/template/dist/cli/index.js +237 -94
  5. package/template/dist/cli/index.js.map +1 -1
  6. package/template/dist/client/admin.html +15 -10
  7. package/template/dist/client/assets/App-BpFUIC-5.js +114 -0
  8. package/template/dist/client/assets/{CartPage-DESSHkaG.js → CartPage-DgDZP-R5.js} +2 -2
  9. package/template/dist/client/assets/{CategoriesPage-DqLZ_Mom.js → CategoriesPage-fuYNiSmE.js} +2 -2
  10. package/template/dist/client/assets/ContentDetailPage-BvvFU1Mr.js +1 -0
  11. package/template/dist/client/assets/ContentListPage-ShPxo6WG.js +1 -0
  12. package/template/dist/client/assets/DashboardPage-C1rZzZo4.js +11 -0
  13. package/template/dist/client/assets/{DeveloperDashboardPage-Cum7zFwO.js → DeveloperDashboardPage-_WtmbVoA.js} +2 -2
  14. package/template/dist/client/assets/{EmptyState-BK7ttK8D.js → EmptyState-DEyOQjbY.js} +1 -1
  15. package/template/dist/client/assets/LoadingSpinner-BcHjaM1m.js +6 -0
  16. package/template/dist/client/assets/LoginPage-CjeQqDdO.js +1 -0
  17. package/template/dist/client/assets/LogoutOutlined-ColFAHdd.js +1 -0
  18. package/template/dist/client/assets/NotificationPage-DRkEv02s.js +1 -0
  19. package/template/dist/client/assets/OrdersPage-7I3vPWLP.js +11 -0
  20. package/template/dist/client/assets/{PluginDetailPage-Br24YS4P.js → PluginDetailPage-CWyxdVCg.js} +3 -13
  21. package/template/dist/client/assets/PluginsPage-DRgWLeJT.js +6 -0
  22. package/template/dist/client/assets/ProfilePage-2FFkaii8.js +16 -0
  23. package/template/dist/client/assets/PublishPage-DW7yvROx.js +1 -0
  24. package/template/dist/client/assets/{RegisterPage-rPFG4Sry.js → RegisterPage-Dvaf9b0e.js} +2 -2
  25. package/template/dist/client/assets/SaveOutlined-CLQ2tsSY.js +2 -0
  26. package/template/dist/client/assets/{SearchPage-DQl1U5Uy.js → SearchPage-DvnEyswS.js} +2 -2
  27. package/template/dist/client/assets/{SettingsPage-DaYE80wj.js → SettingsPage-IrU-L9Zr.js} +2 -2
  28. package/template/dist/client/assets/{StatusBadge-BJ3W2Zc7.js → StatusBadge-CG7wVqpu.js} +1 -1
  29. package/template/dist/client/assets/{TodoPage-zC5wWNBa.js → TodoPage-B7D-bl65.js} +3 -3
  30. package/template/dist/client/assets/TopicsPage-CYCNr-mn.js +6 -0
  31. package/template/dist/client/assets/{WebSocketPage-B4NLdz1w.js → WebSocketPage-CGEg6QJE.js} +2 -2
  32. package/template/dist/client/assets/{activity-B94BUAsD.js → activity-CgTz9Mrd.js} +1 -1
  33. package/template/dist/client/assets/admin-D2iHWNOg.js +1 -0
  34. package/template/dist/client/assets/api-request-DIJocPxr.js +356 -0
  35. package/template/dist/client/assets/{arrow-left-H5JH0iU1.js → arrow-left-DtLQ3tTk.js} +1 -1
  36. package/template/dist/client/assets/{chevron-down-DwRh_wjD.js → chevron-down-CpIAV_yr.js} +1 -1
  37. package/template/dist/client/assets/{chevron-right-CpIWaqAL.js → chevron-right-CnU7oPQs.js} +1 -1
  38. package/template/dist/client/assets/{circle-check-big-CSElLscG.js → circle-check-big-CrZdwS75.js} +1 -1
  39. package/template/dist/client/assets/{circle-x-CYxr4RAw.js → circle-x-CvN9r3fW.js} +1 -1
  40. package/template/dist/client/assets/{clock-BseUJ7ex.js → clock-CTeSZBiH.js} +1 -1
  41. package/template/dist/client/assets/{download-BsGC_Xhq.js → download-OSVfVuNV.js} +1 -1
  42. package/template/dist/client/assets/{external-link-UTDzdjq8.js → external-link-fBsuHMby.js} +1 -1
  43. package/template/dist/client/assets/{eye-nR10ui7i.js → eye-CwlZZEsj.js} +1 -1
  44. package/template/dist/client/assets/index-09IqiOaE.css +1 -0
  45. package/template/dist/client/assets/index-B3CRby6r.js +51 -0
  46. package/template/dist/client/assets/index-CC_zy73y.js +17 -0
  47. package/template/dist/client/assets/main-Cn4IDo2I.js +92 -0
  48. package/template/dist/client/assets/merchant-DDDN9bMu.js +40 -0
  49. package/template/dist/client/assets/{message-square-CwWGL-Bh.js → message-square-BRaZfgbJ.js} +1 -1
  50. package/template/dist/client/assets/pluginStore-DDsWJPe6.js +1 -0
  51. package/template/dist/client/assets/{plus-pZld_nUL.js → plus-DDZfPiDJ.js} +1 -1
  52. package/template/dist/client/assets/sse-client-DGQ072hl.js +64 -0
  53. package/template/dist/client/assets/star-C7tO6w4H.js +11 -0
  54. package/template/dist/client/assets/{tag-DsiUPF90.js → tag-DBfpQDuJ.js} +1 -1
  55. package/template/dist/client/assets/tenant-CizbLaLJ.js +1 -0
  56. package/template/dist/client/assets/{trash-2-DRblNbnA.js → trash-2-BP7fkd5b.js} +1 -1
  57. package/template/dist/client/assets/{triangle-alert-D1CLh-Vd.js → triangle-alert-CrOQEdJ2.js} +1 -1
  58. package/template/dist/client/assets/{wifi-BwXjnCqI.js → wifi-CwYSE0J4.js} +1 -1
  59. package/template/dist/client/assets/{x-BH2rJdFq.js → x-t615pnNR.js} +1 -1
  60. package/template/dist/client/content/index.html +5 -4
  61. package/template/dist/client/index.html +4 -3
  62. package/template/dist/client/merchant.html +18 -0
  63. package/template/dist/client/notifications/index.html +6 -5
  64. package/template/dist/client/tenant.html +18 -0
  65. package/template/dist/client/todos/index.html +6 -5
  66. package/template/dist/client/websocket/index.html +6 -5
  67. package/template/dist/cloudflare/chunk-HX7DVRDX.js +1 -0
  68. package/template/dist/cloudflare/{chunk-QBHAPWIA.js → chunk-IXJL2LE4.js} +1 -1
  69. package/template/dist/cloudflare/chunk-Q34AN3RF.js +14 -0
  70. package/template/dist/cloudflare/{chunk-BHPTQ4K2.js → chunk-ZAMVL4EG.js} +2 -2
  71. package/template/dist/cloudflare/cloudflare.js +35 -29
  72. package/template/dist/cloudflare/db-4AQOSFAX.js +1 -0
  73. package/template/dist/cloudflare/{migrator-2ZYYKNI5.js → migrator-TEPBVUFO.js} +1 -1
  74. package/template/dist/cloudflare/permission-service-impl-RE7NPW3Q.js +1 -0
  75. package/template/dist/cloudflare/schema-DVEMT3X2.js +1 -0
  76. package/template/dist/cloudflare/test-setup-Z2RYE5B4.js +265 -0
  77. package/template/dist/server/chunk-27SIJSPF.js +1 -0
  78. package/template/dist/server/chunk-37QNGBQU.js +1 -0
  79. package/template/dist/server/chunk-FIY4CGJJ.js +1 -0
  80. package/template/dist/server/chunk-HZUDBIT4.js +1 -0
  81. package/template/dist/server/chunk-I6OBDFDU.js +1 -0
  82. package/template/dist/server/chunk-JHNYLNG7.js +1 -0
  83. package/template/dist/server/chunk-MDOVVKKD.js +1 -0
  84. package/template/dist/server/chunk-NSOCT7E5.js +1 -0
  85. package/template/dist/server/chunk-OU5IGVVO.js +1 -0
  86. package/template/dist/server/chunk-OYCBNRMK.js +1 -0
  87. package/template/dist/server/chunk-P2RJNNGD.js +1 -0
  88. package/template/dist/server/chunk-UMAQLNPE.js +1 -0
  89. package/template/dist/server/chunk-XZZTSRSN.js +1 -0
  90. package/template/dist/server/content-service-5QVHDR5X.js +1 -0
  91. package/template/dist/server/db-FLI5L5DD.js +1 -0
  92. package/template/dist/server/dispute-service-E2FCYUEM.js +1 -0
  93. package/template/dist/server/init-72JXJV3I.js +46 -0
  94. package/template/dist/server/init-FWYXSKPX.js +46 -0
  95. package/template/dist/server/node.js +34 -28
  96. package/template/dist/server/order-service-TKGG5S5K.js +1 -0
  97. package/template/dist/server/permission-service-impl-M3AKEYNY.js +1 -0
  98. package/template/dist/server/schema-V4UG7HMU.js +1 -0
  99. package/template/dist/server/tenant-service-JG6UUWXQ.js +1 -0
  100. package/template/dist/server/tenant-service-XJWZSEDX.js +1 -0
  101. package/template/dist/{cloudflare/test-setup-NMZJZLRV.js → server/test-setup-VFOPBGYM.js} +83 -2
  102. package/template/dist/server/ticket-service-3RSW7V2Z.js +1 -0
  103. package/template/dist/server/todo-service-S6BGIO7D.js +1 -0
  104. package/template/src/merchant/pages/DisputesPage.tsx +11 -11
  105. package/template/src/merchant/pages/OrdersPage.tsx +4 -3
  106. package/template/src/merchant/pages/ProductsPage.tsx +2 -2
  107. package/template/src/merchant/stores/merchantStore.ts +11 -6
  108. package/template/src/server/db/init.ts +5 -642
  109. package/template/src/server/module-plugin/services/plugin-seed-service.ts +623 -0
  110. package/template/src/server/module-tenant/routes/tenant-routes.ts +2 -2
  111. package/template/src/server/module-tenant/services/tenant-service.ts +63 -17
  112. package/template/src/shared/modules/merchant/index.ts +9 -0
  113. package/template/src/shared/modules/merchant/schemas.ts +37 -0
  114. package/template/src/shared/modules/tenant/index.ts +2 -0
  115. package/template/src/shared/schemas/index.ts +27 -0
  116. package/template/src/tenant/layouts/Header.tsx +1 -1
  117. package/template/src/tenant/layouts/Sidebar.tsx +1 -1
  118. package/template/src/tenant/pages/SettingsPage.tsx +4 -8
  119. package/template/src/tenant/stores/tenantStore.ts +41 -302
  120. package/template/tsconfig.json +1 -0
  121. package/template/tsup.config.ts +11 -3
  122. package/template/dist/client/assets/ContentDetailPage-DdltMANL.js +0 -1
  123. package/template/dist/client/assets/ContentListPage-B63sUB6N.js +0 -1
  124. package/template/dist/client/assets/DashboardPage-tUMilc7Z.js +0 -11
  125. package/template/dist/client/assets/LoadingSpinner-DVYOLSRM.js +0 -6
  126. package/template/dist/client/assets/LoginPage-g9mSLIMC.js +0 -6
  127. package/template/dist/client/assets/NotificationPage-COTzp-HD.js +0 -1
  128. package/template/dist/client/assets/OrdersPage-BsPh4oEI.js +0 -11
  129. package/template/dist/client/assets/PluginsPage-BNtAe_yo.js +0 -6
  130. package/template/dist/client/assets/ProfilePage-dL_iSuZN.js +0 -16
  131. package/template/dist/client/assets/PublishPage-D96FnbLA.js +0 -1
  132. package/template/dist/client/assets/TopicsPage-DyLjZa4D.js +0 -6
  133. package/template/dist/client/assets/admin-Bh1vfz_L.js +0 -486
  134. package/template/dist/client/assets/index-1bA-ixFv.js +0 -114
  135. package/template/dist/client/assets/index-CWh3vXC_.css +0 -1
  136. package/template/dist/client/assets/main-DHnArIp_.js +0 -82
  137. package/template/dist/client/assets/pluginStore-XQfsm3iR.js +0 -1
  138. package/template/dist/client/content/content-1/index.html +0 -18
  139. package/template/dist/client/content/content-13/index.html +0 -18
  140. package/template/dist/client/content/content-14/index.html +0 -18
  141. package/template/dist/client/content/content-15/index.html +0 -18
  142. package/template/dist/client/content/content-19/index.html +0 -18
  143. package/template/dist/client/content/content-2/index.html +0 -18
  144. package/template/dist/client/content/content-20/index.html +0 -18
  145. package/template/dist/cloudflare/chunk-YY6FRMAQ.js +0 -14
  146. package/template/dist/cloudflare/db-7J42RQ3T.js +0 -1
  147. package/template/dist/cloudflare/permission-service-impl-TGXVSSSA.js +0 -1
package/dist/cli/index.js CHANGED
@@ -1,13 +1,433 @@
1
1
  #!/usr/bin/env node
2
- import { readFileSync, existsSync, readdirSync, statSync } from 'fs';
3
- import path, { join } from 'path';
2
+ import { program } from 'commander';
3
+ import { hc } from 'hono/client';
4
+ import { z } from '@hono/zod-openapi';
5
+ import fs, { readdirSync, statSync, existsSync, readFileSync } from 'fs';
6
+ import path2, { join } from 'path';
7
+ import os from 'os';
4
8
  import { fileURLToPath, pathToFileURL } from 'url';
5
- import { Command } from 'commander';
9
+ import fs2 from 'fs-extra';
6
10
  import chalk from 'chalk';
7
- import { select } from '@inquirer/prompts';
8
- import fs from 'fs-extra';
9
11
  import ora from 'ora';
10
12
 
13
+ function createRPCClient(baseUrl) {
14
+ return hc(baseUrl);
15
+ }
16
+
17
+ // src/cli/utils/api.ts
18
+ var DEFAULT_BASE_URL = "http://localhost:3010";
19
+ var globalBaseUrl = process.env.BIOMIMIC_API_URL || DEFAULT_BASE_URL;
20
+ function setBaseUrl(url) {
21
+ globalBaseUrl = url;
22
+ }
23
+ function getBaseUrl() {
24
+ return globalBaseUrl;
25
+ }
26
+ function getClient() {
27
+ return createRPCClient(globalBaseUrl);
28
+ }
29
+
30
+ // src/cli/utils/logger.ts
31
+ var Logger = class {
32
+ level = "info";
33
+ constructor(options = {}) {
34
+ if (options.debug || process.env.BIOMIMIC_DEBUG === "true") {
35
+ this.level = "debug";
36
+ } else if (options.verbose || process.env.BIOMIMIC_VERBOSE === "true") {
37
+ this.level = "info";
38
+ }
39
+ }
40
+ setLevel(level) {
41
+ this.level = level;
42
+ }
43
+ shouldLog(level) {
44
+ const levels = ["silent", "error", "warn", "info", "debug"];
45
+ return levels.indexOf(level) <= levels.indexOf(this.level);
46
+ }
47
+ info(message, ...args) {
48
+ if (this.shouldLog("info")) {
49
+ process.stdout.write(`${message}${args.length ? " " + args.join(" ") : ""}
50
+ `);
51
+ }
52
+ }
53
+ debug(message, ...args) {
54
+ if (this.shouldLog("debug")) {
55
+ process.stdout.write(`[debug] ${message}${args.length ? " " + args.join(" ") : ""}
56
+ `);
57
+ }
58
+ }
59
+ warn(message) {
60
+ if (this.shouldLog("warn")) {
61
+ process.stderr.write(`[warn] ${message}
62
+ `);
63
+ }
64
+ }
65
+ error(message) {
66
+ if (this.shouldLog("error")) {
67
+ process.stderr.write(`[error] ${message}
68
+ `);
69
+ }
70
+ }
71
+ success(message, ...args) {
72
+ if (this.shouldLog("info")) {
73
+ process.stdout.write(`\u2713 ${message}${args.length ? " " + args.join(" ") : ""}
74
+ `);
75
+ }
76
+ }
77
+ fail(message) {
78
+ if (this.shouldLog("error")) {
79
+ process.stderr.write(`\u2717 ${message}
80
+ `);
81
+ }
82
+ }
83
+ };
84
+ var logger = null;
85
+ function createLogger(options = {}) {
86
+ logger = new Logger(options);
87
+ return logger;
88
+ }
89
+ function getLogger() {
90
+ if (!logger) {
91
+ logger = new Logger();
92
+ }
93
+ return logger;
94
+ }
95
+
96
+ // src/cli/utils/auto-command.ts
97
+ function extractZodInfo(schema) {
98
+ const def = schema._def;
99
+ if (def.typeName === "ZodOptional") {
100
+ const inner = schema._def.innerType;
101
+ const info = extractZodInfo(inner);
102
+ return { ...info, required: false };
103
+ }
104
+ if (def.typeName === "ZodDefault") {
105
+ const innerDef = schema._def;
106
+ const defaultValue = innerDef.defaultValue();
107
+ const info = extractZodInfo(innerDef.innerType);
108
+ return { ...info, required: false, defaultValue };
109
+ }
110
+ if (def.typeName === "ZodEnum") {
111
+ const enumValues = [...schema._def.values];
112
+ return { type: "enum", required: true, enumValues };
113
+ }
114
+ if (def.typeName === "ZodString") return { type: "string", required: true };
115
+ if (def.typeName === "ZodNumber") return { type: "number", required: true };
116
+ if (def.typeName === "ZodBoolean") return { type: "boolean", required: true };
117
+ if (def.typeName === "ZodObject") return { type: "object", required: true };
118
+ return { type: "string", required: true };
119
+ }
120
+ function schemaToOptions(schema) {
121
+ const options = [];
122
+ const shape = schema.shape;
123
+ for (const [key, zodType] of Object.entries(shape)) {
124
+ const info = extractZodInfo(zodType);
125
+ const longFlag = key.replace(/([A-Z])/g, "-$1").toLowerCase();
126
+ let flags = `--${longFlag} <value>`;
127
+ if (info.type === "boolean") {
128
+ flags = `--${longFlag}`;
129
+ }
130
+ let description = String(info.type);
131
+ if (info.enumValues) {
132
+ description = `${info.type} (${info.enumValues.join("|")})`;
133
+ }
134
+ options.push({
135
+ flags,
136
+ description,
137
+ required: info.required,
138
+ defaultValue: info.defaultValue
139
+ });
140
+ }
141
+ return options;
142
+ }
143
+ function pathToApiCall(client, _method, path3) {
144
+ const pathParts = path3.split("/").filter(Boolean);
145
+ let current = client.api;
146
+ for (const part of pathParts) {
147
+ if (part.startsWith("{") && part.endsWith("}")) {
148
+ continue;
149
+ }
150
+ current = current[part] || current[`:${part}`];
151
+ }
152
+ return current;
153
+ }
154
+ function createCommandFromRoute(config) {
155
+ const options = [];
156
+ const arguments_ = [];
157
+ if (config.params) {
158
+ const shape = config.params.shape;
159
+ for (const [key] of Object.entries(shape)) {
160
+ arguments_.push({
161
+ name: key,
162
+ description: `${key} parameter`,
163
+ required: true
164
+ });
165
+ }
166
+ }
167
+ if (config.body) {
168
+ const bodySchema = config.body;
169
+ if (bodySchema.shape) {
170
+ options.push(...schemaToOptions(bodySchema) || []);
171
+ }
172
+ }
173
+ if (config.query) {
174
+ options.push(...schemaToOptions(config.query) || []);
175
+ }
176
+ return {
177
+ name: config.command,
178
+ description: config.description,
179
+ options,
180
+ arguments: arguments_,
181
+ action: async (opts, args) => {
182
+ const logger2 = getLogger();
183
+ const client = getClient();
184
+ const param = {};
185
+ if (config.params) {
186
+ const shape = config.params.shape;
187
+ const keys = Object.keys(shape);
188
+ keys.forEach((key, i) => {
189
+ param[key] = args[i] || String(opts[key]);
190
+ });
191
+ }
192
+ const json = {};
193
+ if (config.body && opts) {
194
+ const bodySchema = config.body;
195
+ if (bodySchema.shape) {
196
+ const shape = bodySchema.shape;
197
+ for (const key of Object.keys(shape)) {
198
+ if (opts[key] !== void 0) {
199
+ json[key] = opts[key];
200
+ }
201
+ }
202
+ }
203
+ }
204
+ const query = {};
205
+ if (config.query && opts) {
206
+ const shape = config.query.shape;
207
+ for (const key of Object.keys(shape)) {
208
+ if (opts[key] !== void 0) {
209
+ query[key] = String(opts[key]);
210
+ }
211
+ }
212
+ }
213
+ const apiCall = pathToApiCall(client, config.method, config.path);
214
+ const methodCall = apiCall[`$${config.method.charAt(0).toUpperCase() + config.method.slice(1)}`] || apiCall.$get;
215
+ const res = await methodCall.call(apiCall, {
216
+ param: Object.keys(param).length > 0 ? param : void 0,
217
+ query: Object.keys(query).length > 0 ? query : void 0,
218
+ json: Object.keys(json).length > 0 ? json : void 0
219
+ });
220
+ const data = await res.json();
221
+ logger2.info(JSON.stringify(data, null, 2));
222
+ }
223
+ };
224
+ }
225
+ function registerAutoCommand(program2, config) {
226
+ const cmd = createCommandFromRoute(config);
227
+ const command = program2.command(cmd.name).description(cmd.description).action(async (firstArg, opts) => {
228
+ const args = typeof firstArg === "string" ? [firstArg] : [];
229
+ const options = (typeof firstArg === "object" ? firstArg : opts) || {};
230
+ await cmd.action(options, args);
231
+ });
232
+ cmd.options?.forEach((opt) => {
233
+ if (opt.required) {
234
+ command.requiredOption(opt.flags, opt.description, opt.defaultValue);
235
+ } else {
236
+ command.option(opt.flags, opt.description, opt.defaultValue);
237
+ }
238
+ });
239
+ cmd.arguments?.forEach((arg) => {
240
+ command.argument(arg.required ? `<${arg.name}>` : `[${arg.name}]`, arg.description);
241
+ });
242
+ }
243
+ var TodoStatusSchema = z.enum(["pending", "in_progress", "completed"]);
244
+ var todoRoutes = [
245
+ {
246
+ method: "get",
247
+ path: "/todos",
248
+ command: "list",
249
+ description: "List all todos"
250
+ },
251
+ {
252
+ method: "get",
253
+ path: "/todos/{id}",
254
+ command: "get",
255
+ description: "Get a todo by ID",
256
+ params: z.object({ id: z.string() })
257
+ },
258
+ {
259
+ method: "post",
260
+ path: "/todos",
261
+ command: "create",
262
+ description: "Create a new todo",
263
+ body: z.object({
264
+ title: z.string().min(1),
265
+ description: z.string().optional()
266
+ })
267
+ },
268
+ {
269
+ method: "put",
270
+ path: "/todos/{id}",
271
+ command: "update",
272
+ description: "Update a todo",
273
+ params: z.object({ id: z.string() }),
274
+ body: z.object({
275
+ title: z.string().optional(),
276
+ description: z.string().optional(),
277
+ status: TodoStatusSchema.optional()
278
+ })
279
+ },
280
+ {
281
+ method: "delete",
282
+ path: "/todos/{id}",
283
+ command: "delete",
284
+ description: "Delete a todo",
285
+ params: z.object({ id: z.string() })
286
+ }
287
+ ];
288
+ function registerTodoCommands(program2) {
289
+ const todo = program2.command("todo").description("Todo management commands");
290
+ for (const route of todoRoutes) {
291
+ registerAutoCommand(todo, route);
292
+ }
293
+ }
294
+
295
+ // src/cli/modules/notification/index.ts
296
+ function registerNotificationCommands(program2) {
297
+ const notification = program2.command("notification").description("Notification management commands");
298
+ notification.command("list").description("List all notifications").option("--unread-only", "Show only unread notifications").option("--limit <number>", "Limit number of results", "20").action(async (options) => {
299
+ const logger2 = getLogger();
300
+ const client = getClient();
301
+ const unreadOnly = Boolean(options.unreadOnly);
302
+ const limit = parseInt(options.limit || "20");
303
+ const res = await client.api.notifications.$get({
304
+ query: { unreadOnly: String(unreadOnly), limit: String(limit) }
305
+ });
306
+ const data = await res.json();
307
+ logger2.info(JSON.stringify(data, null, 2));
308
+ });
309
+ notification.command("create").description("Create a new notification").requiredOption("-t, --title <title>", "Notification title").requiredOption("-m, --message <message>", "Notification message").option("--type <type>", "Notification type (info|warning|success|error)", "info").action(async (options) => {
310
+ const logger2 = getLogger();
311
+ const client = getClient();
312
+ const res = await client.api.notifications.$post({
313
+ json: {
314
+ type: options.type,
315
+ title: options.title,
316
+ message: options.message
317
+ }
318
+ });
319
+ const data = await res.json();
320
+ logger2.success("Notification created");
321
+ logger2.info(JSON.stringify(data, null, 2));
322
+ });
323
+ notification.command("unread-count").description("Get unread notification count").action(async () => {
324
+ const logger2 = getLogger();
325
+ const client = getClient();
326
+ const res = await client.api.notifications["unread-count"].$get();
327
+ const data = await res.json();
328
+ logger2.info(JSON.stringify(data, null, 2));
329
+ });
330
+ notification.command("mark-read").description("Mark a notification as read").argument("<id>", "Notification ID").action(async (id) => {
331
+ const logger2 = getLogger();
332
+ const client = getClient();
333
+ const res = await client.api.notifications[":id"].read.$patch({ param: { id } });
334
+ const data = await res.json();
335
+ logger2.success("Notification marked as read");
336
+ logger2.info(JSON.stringify(data, null, 2));
337
+ });
338
+ notification.command("delete").description("Delete a notification").argument("<id>", "Notification ID").action(async (id) => {
339
+ const logger2 = getLogger();
340
+ const client = getClient();
341
+ const res = await client.api.notifications[":id"].$delete({ param: { id } });
342
+ const data = await res.json();
343
+ logger2.success("Notification deleted");
344
+ logger2.info(JSON.stringify(data, null, 2));
345
+ });
346
+ }
347
+ var CONFIG_DIR = path2.join(os.homedir(), ".biomimic");
348
+ var CONFIG_FILE = path2.join(CONFIG_DIR, "config.json");
349
+ function loadConfig() {
350
+ try {
351
+ if (fs.existsSync(CONFIG_FILE)) {
352
+ const content = fs.readFileSync(CONFIG_FILE, "utf-8");
353
+ return JSON.parse(content);
354
+ }
355
+ } catch {
356
+ }
357
+ return { baseUrl: "http://localhost:3010" };
358
+ }
359
+ function saveConfig(config) {
360
+ if (!fs.existsSync(CONFIG_DIR)) {
361
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
362
+ }
363
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
364
+ }
365
+ function registerConfigCommands(program2) {
366
+ const config = program2.command("config").description("CLI configuration and service management");
367
+ config.command("get").description("Show current configuration").option("-k, --key <key>", "Get specific config key").action((options) => {
368
+ const logger2 = getLogger();
369
+ const cfg = loadConfig();
370
+ if (options.key) {
371
+ const value = cfg[options.key];
372
+ logger2.info(`${options.key}: ${value ?? "not set"}`);
373
+ } else {
374
+ logger2.info(JSON.stringify(cfg, null, 2));
375
+ }
376
+ });
377
+ config.command("set").description("Set configuration value").option("-u, --url <url>", "Set server URL").action((options) => {
378
+ const logger2 = getLogger();
379
+ const cfg = loadConfig();
380
+ if (options.url) {
381
+ cfg.baseUrl = options.url;
382
+ setBaseUrl(options.url);
383
+ logger2.success(`Server URL set to: ${options.url}`);
384
+ }
385
+ saveConfig(cfg);
386
+ });
387
+ config.command("url").description("Show or set server URL").argument("[url]", "New server URL").action((url) => {
388
+ const logger2 = getLogger();
389
+ if (url) {
390
+ const cfg = loadConfig();
391
+ cfg.baseUrl = url;
392
+ setBaseUrl(url);
393
+ saveConfig(cfg);
394
+ logger2.success(`Server URL set to: ${url}`);
395
+ } else {
396
+ logger2.info(`Current server URL: ${getBaseUrl()}`);
397
+ }
398
+ });
399
+ config.command("status").description("Check server connection status").action(async () => {
400
+ const logger2 = getLogger();
401
+ const client = getClient();
402
+ try {
403
+ const res = await client.health.$get();
404
+ const data = await res.json();
405
+ logger2.success("Server is reachable");
406
+ logger2.info(JSON.stringify(data, null, 2));
407
+ } catch (error) {
408
+ logger2.error(`Server not reachable: ${getBaseUrl()}`);
409
+ logger2.error(String(error));
410
+ }
411
+ });
412
+ config.command("reset").description("Reset configuration to defaults").action(() => {
413
+ const logger2 = getLogger();
414
+ const defaultConfig = { baseUrl: "http://localhost:3010" };
415
+ saveConfig(defaultConfig);
416
+ setBaseUrl(defaultConfig.baseUrl);
417
+ logger2.success("Configuration reset to defaults");
418
+ });
419
+ config.command("path").description("Show config file path").action(() => {
420
+ const logger2 = getLogger();
421
+ logger2.info(`Config file: ${CONFIG_FILE}`);
422
+ });
423
+ }
424
+
425
+ // src/cli/modules/index.ts
426
+ function registerModules(program2) {
427
+ registerTodoCommands(program2);
428
+ registerNotificationCommands(program2);
429
+ registerConfigCommands(program2);
430
+ }
11
431
  var tsImportFn;
12
432
  async function getTsImport() {
13
433
  if (tsImportFn) return tsImportFn;
@@ -3006,7 +3426,7 @@ if (typeof window !== 'undefined') {
3006
3426
 
3007
3427
  // src/commands/create.ts
3008
3428
  var __filename$1 = fileURLToPath(import.meta.url);
3009
- var __dirname$1 = path.dirname(__filename$1);
3429
+ var __dirname$1 = path2.dirname(__filename$1);
3010
3430
  var TEMPLATE_PROJECT_NAME = "biomimic-todo-app";
3011
3431
  var TEMPLATE_DB_NAME = "biomimic-todo-db";
3012
3432
  var ScaffoldError = class extends Error {
@@ -3048,11 +3468,11 @@ function generateDbName(projectName) {
3048
3468
  return `${sanitized}-db`;
3049
3469
  }
3050
3470
  async function updateWranglerToml(targetDir, projectName) {
3051
- const wranglerPath = path.join(targetDir, "wrangler.toml");
3052
- if (!await fs.pathExists(wranglerPath)) {
3471
+ const wranglerPath = path2.join(targetDir, "wrangler.toml");
3472
+ if (!await fs2.pathExists(wranglerPath)) {
3053
3473
  return;
3054
3474
  }
3055
- let content = await fs.readFile(wranglerPath, "utf-8");
3475
+ let content = await fs2.readFile(wranglerPath, "utf-8");
3056
3476
  const dbName = generateDbName(projectName);
3057
3477
  content = content.replace(
3058
3478
  new RegExp(`^name = "${TEMPLATE_PROJECT_NAME}"`, "m"),
@@ -3066,43 +3486,43 @@ async function updateWranglerToml(targetDir, projectName) {
3066
3486
  /database_id = "[^"]+"/,
3067
3487
  `database_id = "" # TODO: Run 'wrangler d1 create ${dbName}' and paste the ID here`
3068
3488
  );
3069
- await fs.writeFile(wranglerPath, content);
3489
+ await fs2.writeFile(wranglerPath, content);
3070
3490
  }
3071
3491
  async function updatePackageJson(targetDir, projectName, resolved) {
3072
- const pkgJsonPath = path.join(targetDir, "package.json");
3073
- if (!await fs.pathExists(pkgJsonPath)) {
3492
+ const pkgJsonPath = path2.join(targetDir, "package.json");
3493
+ if (!await fs2.pathExists(pkgJsonPath)) {
3074
3494
  return;
3075
3495
  }
3076
- let pkgJson = await fs.readJson(pkgJsonPath);
3496
+ let pkgJson = await fs2.readJson(pkgJsonPath);
3077
3497
  pkgJson = filterPackageJson(pkgJson, resolved);
3078
3498
  pkgJson.name = projectName;
3079
3499
  if (pkgJson.bin) {
3080
3500
  delete pkgJson.bin;
3081
3501
  }
3082
- await fs.writeJson(pkgJsonPath, pkgJson, { spaces: 2 });
3502
+ await fs2.writeJson(pkgJsonPath, pkgJson, { spaces: 2 });
3083
3503
  }
3084
3504
  async function updatePackageLockJson(targetDir, projectName) {
3085
- const lockFilePath = path.join(targetDir, "package-lock.json");
3086
- if (!await fs.pathExists(lockFilePath)) {
3505
+ const lockFilePath = path2.join(targetDir, "package-lock.json");
3506
+ if (!await fs2.pathExists(lockFilePath)) {
3087
3507
  return;
3088
3508
  }
3089
- const lockFile = await fs.readJson(lockFilePath);
3509
+ const lockFile = await fs2.readJson(lockFilePath);
3090
3510
  if (lockFile.name === TEMPLATE_PROJECT_NAME) {
3091
3511
  lockFile.name = projectName;
3092
3512
  }
3093
3513
  if (lockFile.packages?.[""]?.name === TEMPLATE_PROJECT_NAME) {
3094
3514
  lockFile.packages[""].name = projectName;
3095
3515
  }
3096
- await fs.writeJson(lockFilePath, lockFile, { spaces: 2 });
3516
+ await fs2.writeJson(lockFilePath, lockFile, { spaces: 2 });
3097
3517
  }
3098
3518
  async function updateReadme(targetDir, projectName) {
3099
- const readmePath = path.join(targetDir, "README.md");
3100
- if (!await fs.pathExists(readmePath)) {
3519
+ const readmePath = path2.join(targetDir, "README.md");
3520
+ if (!await fs2.pathExists(readmePath)) {
3101
3521
  return;
3102
3522
  }
3103
- let content = await fs.readFile(readmePath, "utf-8");
3523
+ let content = await fs2.readFile(readmePath, "utf-8");
3104
3524
  content = content.replace(/^# (.+)$/m, `# ${projectName}`);
3105
- await fs.writeFile(readmePath, content);
3525
+ await fs2.writeFile(readmePath, content);
3106
3526
  }
3107
3527
  async function createProject(projectNameOrOptions, useCurrentDir = false, preset) {
3108
3528
  let projectName;
@@ -3125,19 +3545,19 @@ async function createProject(projectNameOrOptions, useCurrentDir = false, preset
3125
3545
  if (!currentDir) {
3126
3546
  validateProjectName(projectName);
3127
3547
  }
3128
- const templateDir = path.join(__dirname$1, "../../template");
3548
+ const templateDir = path2.join(__dirname$1, "../../template");
3129
3549
  let targetDir;
3130
3550
  if (currentDir) {
3131
3551
  targetDir = process.cwd();
3132
- projectName = path.basename(targetDir);
3552
+ projectName = path2.basename(targetDir);
3133
3553
  } else if (outputDir) {
3134
- targetDir = path.resolve(outputDir);
3135
- if (await fs.pathExists(targetDir)) {
3554
+ targetDir = path2.resolve(outputDir);
3555
+ if (await fs2.pathExists(targetDir)) {
3136
3556
  throw new ScaffoldError(`Directory ${outputDir} already exists`);
3137
3557
  }
3138
3558
  } else {
3139
- targetDir = path.resolve(process.cwd(), projectName);
3140
- if (await fs.pathExists(targetDir)) {
3559
+ targetDir = path2.resolve(process.cwd(), projectName);
3560
+ if (await fs2.pathExists(targetDir)) {
3141
3561
  throw new ScaffoldError(`Directory ${projectName} already exists`);
3142
3562
  }
3143
3563
  }
@@ -3164,16 +3584,16 @@ async function createProject(projectNameOrOptions, useCurrentDir = false, preset
3164
3584
  for (const file of generatedFiles2) {
3165
3585
  console.log(` ${chalk.green("\u2713")} ${file}`);
3166
3586
  }
3167
- const gitignorePath2 = path.join(templateDir, ".gitignore");
3587
+ const gitignorePath2 = path2.join(templateDir, ".gitignore");
3168
3588
  let ignorePatterns2 = [];
3169
- if (await fs.pathExists(gitignorePath2)) {
3170
- const gitignoreContent = await fs.readFile(gitignorePath2, "utf-8");
3589
+ if (await fs2.pathExists(gitignorePath2)) {
3590
+ const gitignoreContent = await fs2.readFile(gitignorePath2, "utf-8");
3171
3591
  ignorePatterns2 = parseGitignore(gitignoreContent);
3172
3592
  }
3173
3593
  ignorePatterns2.push("node_modules", ".wrangler");
3174
3594
  const excludePatterns2 = getExcludePatterns(resolved, allManifests);
3175
3595
  let templateFileCount = 0;
3176
- const templateFiles = await fs.readdir(templateDir, { recursive: true });
3596
+ const templateFiles = await fs2.readdir(templateDir, { recursive: true });
3177
3597
  for (const file of templateFiles) {
3178
3598
  const relative = String(file);
3179
3599
  if (!relative) continue;
@@ -3208,21 +3628,21 @@ async function createProject(projectNameOrOptions, useCurrentDir = false, preset
3208
3628
  }
3209
3629
  if (!currentDir) {
3210
3630
  const dirSpinner = ora("Creating project directory...").start();
3211
- await fs.ensureDir(targetDir);
3631
+ await fs2.ensureDir(targetDir);
3212
3632
  dirSpinner.succeed(chalk.green("Project directory created"));
3213
3633
  }
3214
3634
  const copySpinner = ora("Copying template files...").start();
3215
- const gitignorePath = path.join(templateDir, ".gitignore");
3635
+ const gitignorePath = path2.join(templateDir, ".gitignore");
3216
3636
  let ignorePatterns = [];
3217
- if (await fs.pathExists(gitignorePath)) {
3218
- const gitignoreContent = await fs.readFile(gitignorePath, "utf-8");
3637
+ if (await fs2.pathExists(gitignorePath)) {
3638
+ const gitignoreContent = await fs2.readFile(gitignorePath, "utf-8");
3219
3639
  ignorePatterns = parseGitignore(gitignoreContent);
3220
3640
  }
3221
3641
  ignorePatterns.push("node_modules", ".wrangler");
3222
3642
  const excludePatterns = getExcludePatterns(resolved, allManifests);
3223
- await fs.copy(templateDir, targetDir, {
3643
+ await fs2.copy(templateDir, targetDir, {
3224
3644
  filter: (src) => {
3225
- const relative = path.relative(templateDir, src);
3645
+ const relative = path2.relative(templateDir, src);
3226
3646
  if (relative === "") return true;
3227
3647
  const negated = ignorePatterns.filter((p) => p.startsWith("!"));
3228
3648
  const gitIgnored = ignorePatterns.filter((p) => !p.startsWith("!") && relative.startsWith(p));
@@ -3244,80 +3664,80 @@ async function createProject(projectNameOrOptions, useCurrentDir = false, preset
3244
3664
  copySpinner.succeed(chalk.green("Template files copied"));
3245
3665
  const genSpinner = ora("Generating module-specific files...").start();
3246
3666
  const routeRegistryContent = generateRouteRegistry(resolved);
3247
- await fs.writeFile(path.join(targetDir, "src/server/route-registry.ts"), routeRegistryContent);
3667
+ await fs2.writeFile(path2.join(targetDir, "src/server/route-registry.ts"), routeRegistryContent);
3248
3668
  const dbSchemaContent = generateDbSchemaBarrel(resolved);
3249
- await fs.writeFile(path.join(targetDir, "src/server/db/schema/index.ts"), dbSchemaContent);
3669
+ await fs2.writeFile(path2.join(targetDir, "src/server/db/schema/index.ts"), dbSchemaContent);
3250
3670
  if (resolved.hasClient) {
3251
3671
  const clientNavContent = generateClientNavigation(resolved);
3252
- await fs.writeFile(
3253
- path.join(targetDir, "src/client/components/Navigation.tsx"),
3672
+ await fs2.writeFile(
3673
+ path2.join(targetDir, "src/client/components/Navigation.tsx"),
3254
3674
  clientNavContent
3255
3675
  );
3256
3676
  const clientAppTestContent = generateClientAppTest(resolved);
3257
- await fs.ensureDir(path.join(targetDir, "src/client/components/__tests__"));
3258
- await fs.writeFile(
3259
- path.join(targetDir, "src/client/components/__tests__/App.test.tsx"),
3677
+ await fs2.ensureDir(path2.join(targetDir, "src/client/components/__tests__"));
3678
+ await fs2.writeFile(
3679
+ path2.join(targetDir, "src/client/components/__tests__/App.test.tsx"),
3260
3680
  clientAppTestContent
3261
3681
  );
3262
3682
  const clientNavTestContent = generateClientNavigationTest(resolved);
3263
- await fs.writeFile(
3264
- path.join(targetDir, "src/client/components/__tests__/Navigation.test.tsx"),
3683
+ await fs2.writeFile(
3684
+ path2.join(targetDir, "src/client/components/__tests__/Navigation.test.tsx"),
3265
3685
  clientNavTestContent
3266
3686
  );
3267
3687
  const presetUIConfigContent = generatePresetUIConfig(resolved, selectedPreset.id);
3268
- await fs.writeFile(
3269
- path.join(targetDir, "src/client/preset-ui-config.ts"),
3688
+ await fs2.writeFile(
3689
+ path2.join(targetDir, "src/client/preset-ui-config.ts"),
3270
3690
  presetUIConfigContent
3271
3691
  );
3272
3692
  const clientMainContent = generateClientMain(resolved, selectedPreset.id);
3273
- await fs.writeFile(path.join(targetDir, "src/client/main.tsx"), clientMainContent);
3693
+ await fs2.writeFile(path2.join(targetDir, "src/client/main.tsx"), clientMainContent);
3274
3694
  }
3275
3695
  if (resolved.hasClient && resolved.modules.has("admin")) {
3276
3696
  const adminAppContent = generateAdminApp(resolved);
3277
3697
  if (adminAppContent) {
3278
- await fs.ensureDir(path.join(targetDir, "src/admin"));
3279
- await fs.writeFile(path.join(targetDir, "src/admin/App.tsx"), adminAppContent);
3698
+ await fs2.ensureDir(path2.join(targetDir, "src/admin"));
3699
+ await fs2.writeFile(path2.join(targetDir, "src/admin/App.tsx"), adminAppContent);
3280
3700
  }
3281
3701
  }
3282
3702
  const serverAppContent = generateServerApp(resolved);
3283
- await fs.writeFile(path.join(targetDir, "src/server/app.ts"), serverAppContent);
3703
+ await fs2.writeFile(path2.join(targetDir, "src/server/app.ts"), serverAppContent);
3284
3704
  const generatedFiles = getGeneratedFiles(resolved);
3285
3705
  if (generatedFiles.includes("src/server/db/init.ts")) {
3286
3706
  const dbInitContent = generateDbInit(resolved);
3287
- await fs.writeFile(path.join(targetDir, "src/server/db/init.ts"), dbInitContent);
3707
+ await fs2.writeFile(path2.join(targetDir, "src/server/db/init.ts"), dbInitContent);
3288
3708
  }
3289
3709
  const sharedModulesContent = generateSharedModulesIndex(resolved);
3290
- await fs.writeFile(path.join(targetDir, "src/shared/modules/index.ts"), sharedModulesContent);
3710
+ await fs2.writeFile(path2.join(targetDir, "src/shared/modules/index.ts"), sharedModulesContent);
3291
3711
  const sharedSchemasContent = generateSharedSchemasIndex(resolved);
3292
- await fs.writeFile(path.join(targetDir, "src/shared/schemas/index.ts"), sharedSchemasContent);
3712
+ await fs2.writeFile(path2.join(targetDir, "src/shared/schemas/index.ts"), sharedSchemasContent);
3293
3713
  const middlewareIndexContent = generateMiddlewareIndex(resolved);
3294
- await fs.writeFile(
3295
- path.join(targetDir, "src/server/middleware/index.ts"),
3714
+ await fs2.writeFile(
3715
+ path2.join(targetDir, "src/server/middleware/index.ts"),
3296
3716
  middlewareIndexContent
3297
3717
  );
3298
3718
  if (generatedFiles.includes("src/server/middleware/auth.ts")) {
3299
3719
  const authMiddlewareContent = generateAuthMiddleware(resolved);
3300
- await fs.writeFile(
3301
- path.join(targetDir, "src/server/middleware/auth.ts"),
3720
+ await fs2.writeFile(
3721
+ path2.join(targetDir, "src/server/middleware/auth.ts"),
3302
3722
  authMiddlewareContent
3303
3723
  );
3304
3724
  }
3305
3725
  if (generatedFiles.includes("src/server/utils/auth.ts")) {
3306
3726
  const authUtilsContent = generateAuthUtils(resolved);
3307
- await fs.writeFile(path.join(targetDir, "src/server/utils/auth.ts"), authUtilsContent);
3727
+ await fs2.writeFile(path2.join(targetDir, "src/server/utils/auth.ts"), authUtilsContent);
3308
3728
  }
3309
3729
  if (resolved.hasClient) {
3310
3730
  const clientComponentsContent = generateClientComponentsIndex(resolved);
3311
- await fs.writeFile(
3312
- path.join(targetDir, "src/client/components/index.ts"),
3731
+ await fs2.writeFile(
3732
+ path2.join(targetDir, "src/client/components/index.ts"),
3313
3733
  clientComponentsContent
3314
3734
  );
3315
3735
  }
3316
3736
  const cliModulesContent = generateCliModulesIndex(resolved);
3317
- await fs.writeFile(path.join(targetDir, "src/cli/modules/index.ts"), cliModulesContent);
3737
+ await fs2.writeFile(path2.join(targetDir, "src/cli/modules/index.ts"), cliModulesContent);
3318
3738
  if (resolved.hasClient && generatedFiles.includes("vite.config.ts")) {
3319
3739
  const viteConfigContent = generateViteConfig(resolved, templateDir);
3320
- await fs.writeFile(path.join(targetDir, "vite.config.ts"), viteConfigContent);
3740
+ await fs2.writeFile(path2.join(targetDir, "vite.config.ts"), viteConfigContent);
3321
3741
  }
3322
3742
  genSpinner.succeed(chalk.green("Module-specific files generated"));
3323
3743
  const pkgSpinner = ora("Configuring package.json...").start();
@@ -3369,66 +3789,37 @@ async function createProject(projectNameOrOptions, useCurrentDir = false, preset
3369
3789
  }
3370
3790
  }
3371
3791
 
3372
- // src/index.ts
3373
- var __filename2 = fileURLToPath(import.meta.url);
3374
- var __dirname2 = path.dirname(__filename2);
3375
- var rootDir = __dirname2.endsWith(path.join("src")) || __dirname2.endsWith(path.join("dist")) ? path.resolve(__dirname2, "..") : path.resolve(__dirname2, "..", "..");
3376
- var packageJson = JSON.parse(readFileSync(path.join(rootDir, "package.json"), "utf-8"));
3377
- var program = new Command();
3378
- program.name("create-fullstack-scaffold").description("Create a new full-stack scaffold app with Todo List example").version(packageJson.version).argument("[project-name]", "Name of your project").option("-c, --current-dir", "Create project in current directory").option(
3379
- "-p, --preset <preset>",
3380
- "Template preset to use (fullstack-admin, todo-app, cli-only, minimal)"
3381
- ).option("-o, --output-dir <path>", "Output directory (defaults to project name)").option("--dry-run", "Show what would be generated without creating files").action(
3382
- async (projectName = "my-fullstack-app", options) => {
3383
- console.log("");
3384
- console.log(chalk.cyan.bold(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
3385
- console.log(chalk.cyan.bold(" \u2551 Create Fullstack Scaffold App \u2551"));
3386
- console.log(chalk.cyan.bold(" \u2551 React + Hono + Vite + Zustand + TS \u2551"));
3387
- console.log(chalk.cyan.bold(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
3388
- console.log("");
3389
- let preset = options.preset;
3390
- if (!preset && process.stdin.isTTY) {
3391
- const templateDir = path.join(__dirname2, "../template");
3392
- const presets = await loadPresets(templateDir);
3393
- preset = await select({
3394
- message: "Choose a template preset:",
3395
- choices: presets.map((p) => ({
3396
- value: p.id,
3397
- name: `${p.name} \u2014 ${p.description}`
3398
- }))
3399
- });
3400
- }
3401
- if (!preset) {
3402
- preset = "fullstack-admin";
3403
- }
3404
- try {
3405
- await createProject({
3406
- projectName,
3407
- currentDir: options.currentDir ?? false,
3408
- preset,
3409
- outputDir: options.outputDir,
3410
- dryRun: options.dryRun ?? false
3411
- });
3412
- } catch (error) {
3413
- if (error instanceof ScaffoldError) {
3414
- console.error(chalk.red(` \u2716 ${error.message}`));
3415
- process.exit(1);
3416
- }
3417
- throw error;
3418
- }
3792
+ // src/cli/index.ts
3793
+ var MODULE_COMMANDS = ["todo", "notification", "config"];
3794
+ program.name("create-fullstack-scaffold").description("Create a new fullstack scaffolded project").version("0.1.1").argument("[project-name]", "Name of the project to create").option("-v, --verbose", "Enable verbose output").option("-u, --url <url>", "Server URL", "http://localhost:3010").option("-p, --preset <preset>", "Template preset to use", "fullstack-admin").option("-d, --dry-run", "Preview files without creating them").option("--current-dir", "Scaffold in the current directory").action(async (projectName, cmdOptions) => {
3795
+ if (projectName && !MODULE_COMMANDS.includes(projectName)) {
3796
+ const isCurrentDir = cmdOptions.currentDir === true || projectName === ".";
3797
+ createLogger({ verbose: cmdOptions.verbose });
3798
+ const options = {
3799
+ projectName: isCurrentDir ? "." : projectName,
3800
+ currentDir: isCurrentDir,
3801
+ preset: cmdOptions.preset,
3802
+ dryRun: cmdOptions.dryRun
3803
+ };
3804
+ await createProject(options).catch((err) => {
3805
+ console.error(`Error: ${err.message}`);
3806
+ process.exit(1);
3807
+ });
3808
+ return;
3809
+ }
3810
+ if (!projectName) {
3811
+ program.outputHelp();
3812
+ process.exit(1);
3419
3813
  }
3420
- );
3421
- program.command("presets").description("List available template presets").action(async () => {
3422
- const templateDir = path.join(__dirname2, "../template");
3423
- const presets = await loadPresets(templateDir);
3424
- console.log(chalk.cyan("\nAvailable presets:\n"));
3425
- for (const preset of presets) {
3426
- console.log(` ${chalk.green(preset.id.padEnd(20))} ${preset.name}`);
3427
- console.log(` ${" ".repeat(20)} ${preset.description}`);
3428
- console.log(` ${" ".repeat(20)} Modules: ${preset.modules.join(", ")}`);
3429
- console.log();
3814
+ });
3815
+ program.hook("preAction", (thisCommand) => {
3816
+ const options = thisCommand.opts();
3817
+ createLogger({ verbose: options.verbose });
3818
+ if (options.url) {
3819
+ setBaseUrl(options.url);
3430
3820
  }
3431
3821
  });
3822
+ registerModules(program);
3432
3823
  program.parse();
3433
3824
  //# sourceMappingURL=index.js.map
3434
3825
  //# sourceMappingURL=index.js.map