@l4yercak3/cli 1.3.1 → 2.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (357) hide show
  1. package/README.md +10 -220
  2. package/dist/api/client.d.ts +12 -0
  3. package/dist/api/client.d.ts.map +1 -0
  4. package/dist/api/client.js +37 -0
  5. package/dist/api/client.js.map +1 -0
  6. package/dist/api/platform.d.ts +161 -0
  7. package/dist/api/platform.d.ts.map +1 -0
  8. package/dist/api/platform.js +70 -0
  9. package/dist/api/platform.js.map +1 -0
  10. package/dist/bin/sevenlayers.d.ts +3 -0
  11. package/dist/bin/sevenlayers.d.ts.map +1 -0
  12. package/dist/bin/sevenlayers.js +198 -0
  13. package/dist/bin/sevenlayers.js.map +1 -0
  14. package/dist/commands/agent/catalog.d.ts +5 -0
  15. package/dist/commands/agent/catalog.d.ts.map +1 -0
  16. package/dist/commands/agent/catalog.js +142 -0
  17. package/dist/commands/agent/catalog.js.map +1 -0
  18. package/dist/commands/agent/drift.d.ts +5 -0
  19. package/dist/commands/agent/drift.d.ts.map +1 -0
  20. package/dist/commands/agent/drift.js +113 -0
  21. package/dist/commands/agent/drift.js.map +1 -0
  22. package/dist/commands/agent/init.d.ts +5 -0
  23. package/dist/commands/agent/init.d.ts.map +1 -0
  24. package/dist/commands/agent/init.js +75 -0
  25. package/dist/commands/agent/init.js.map +1 -0
  26. package/dist/commands/agent/permissions.d.ts +5 -0
  27. package/dist/commands/agent/permissions.d.ts.map +1 -0
  28. package/dist/commands/agent/permissions.js +88 -0
  29. package/dist/commands/agent/permissions.js.map +1 -0
  30. package/dist/commands/agent/runner.d.ts +14 -0
  31. package/dist/commands/agent/runner.d.ts.map +1 -0
  32. package/dist/commands/agent/runner.js +59 -0
  33. package/dist/commands/agent/runner.js.map +1 -0
  34. package/dist/commands/agent/shared.d.ts +13 -0
  35. package/dist/commands/agent/shared.d.ts.map +1 -0
  36. package/dist/commands/agent/shared.js +31 -0
  37. package/dist/commands/agent/shared.js.map +1 -0
  38. package/dist/commands/agent/template.d.ts +5 -0
  39. package/dist/commands/agent/template.d.ts.map +1 -0
  40. package/dist/commands/agent/template.js +104 -0
  41. package/dist/commands/agent/template.js.map +1 -0
  42. package/dist/commands/app/connect.d.ts +7 -0
  43. package/dist/commands/app/connect.d.ts.map +1 -0
  44. package/dist/commands/app/connect.js +12 -0
  45. package/dist/commands/app/connect.js.map +1 -0
  46. package/dist/commands/app/init.d.ts +7 -0
  47. package/dist/commands/app/init.d.ts.map +1 -0
  48. package/dist/commands/app/init.js +12 -0
  49. package/dist/commands/app/init.js.map +1 -0
  50. package/dist/commands/app/link.d.ts +3 -0
  51. package/dist/commands/app/link.d.ts.map +1 -0
  52. package/dist/commands/app/link.js +92 -0
  53. package/dist/commands/app/link.js.map +1 -0
  54. package/dist/commands/app/pages.d.ts +15 -0
  55. package/dist/commands/app/pages.d.ts.map +1 -0
  56. package/dist/commands/app/pages.js +180 -0
  57. package/dist/commands/app/pages.js.map +1 -0
  58. package/dist/commands/app/register.d.ts +3 -0
  59. package/dist/commands/app/register.d.ts.map +1 -0
  60. package/dist/commands/app/register.js +120 -0
  61. package/dist/commands/app/register.js.map +1 -0
  62. package/dist/commands/app/remote.d.ts +14 -0
  63. package/dist/commands/app/remote.d.ts.map +1 -0
  64. package/dist/commands/app/remote.js +44 -0
  65. package/dist/commands/app/remote.js.map +1 -0
  66. package/dist/commands/app/setup.d.ts +3 -0
  67. package/dist/commands/app/setup.d.ts.map +1 -0
  68. package/dist/commands/app/setup.js +299 -0
  69. package/dist/commands/app/setup.js.map +1 -0
  70. package/dist/commands/app/shared.d.ts +9 -0
  71. package/dist/commands/app/shared.d.ts.map +1 -0
  72. package/dist/commands/app/shared.js +122 -0
  73. package/dist/commands/app/shared.js.map +1 -0
  74. package/dist/commands/app/sync.d.ts +7 -0
  75. package/dist/commands/app/sync.d.ts.map +1 -0
  76. package/dist/commands/app/sync.js +107 -0
  77. package/dist/commands/app/sync.js.map +1 -0
  78. package/dist/commands/booking/check.d.ts +3 -0
  79. package/dist/commands/booking/check.d.ts.map +1 -0
  80. package/dist/commands/booking/check.js +68 -0
  81. package/dist/commands/booking/check.js.map +1 -0
  82. package/dist/commands/booking/setup.d.ts +3 -0
  83. package/dist/commands/booking/setup.d.ts.map +1 -0
  84. package/dist/commands/booking/setup.js +95 -0
  85. package/dist/commands/booking/setup.js.map +1 -0
  86. package/dist/commands/booking/shared.d.ts +31 -0
  87. package/dist/commands/booking/shared.d.ts.map +1 -0
  88. package/dist/commands/booking/shared.js +112 -0
  89. package/dist/commands/booking/shared.js.map +1 -0
  90. package/dist/commands/booking/smoke.d.ts +3 -0
  91. package/dist/commands/booking/smoke.d.ts.map +1 -0
  92. package/dist/commands/booking/smoke.js +101 -0
  93. package/dist/commands/booking/smoke.js.map +1 -0
  94. package/dist/commands/cms/bind.d.ts +3 -0
  95. package/dist/commands/cms/bind.d.ts.map +1 -0
  96. package/dist/commands/cms/bind.js +212 -0
  97. package/dist/commands/cms/bind.js.map +1 -0
  98. package/dist/commands/cms/content.d.ts +40 -0
  99. package/dist/commands/cms/content.d.ts.map +1 -0
  100. package/dist/commands/cms/content.js +169 -0
  101. package/dist/commands/cms/content.js.map +1 -0
  102. package/dist/commands/cms/doctor.d.ts +3 -0
  103. package/dist/commands/cms/doctor.d.ts.map +1 -0
  104. package/dist/commands/cms/doctor.js +69 -0
  105. package/dist/commands/cms/doctor.js.map +1 -0
  106. package/dist/commands/cms/migrate.d.ts +3 -0
  107. package/dist/commands/cms/migrate.d.ts.map +1 -0
  108. package/dist/commands/cms/migrate.js +78 -0
  109. package/dist/commands/cms/migrate.js.map +1 -0
  110. package/dist/commands/cms/registry.d.ts +3 -0
  111. package/dist/commands/cms/registry.d.ts.map +1 -0
  112. package/dist/commands/cms/registry.js +161 -0
  113. package/dist/commands/cms/registry.js.map +1 -0
  114. package/dist/commands/cms/seed.d.ts +3 -0
  115. package/dist/commands/cms/seed.d.ts.map +1 -0
  116. package/dist/commands/cms/seed.js +102 -0
  117. package/dist/commands/cms/seed.js.map +1 -0
  118. package/dist/commands/cms/shared.d.ts +22 -0
  119. package/dist/commands/cms/shared.d.ts.map +1 -0
  120. package/dist/commands/cms/shared.js +82 -0
  121. package/dist/commands/cms/shared.js.map +1 -0
  122. package/dist/commands/doctor/target.d.ts +3 -0
  123. package/dist/commands/doctor/target.d.ts.map +1 -0
  124. package/dist/commands/doctor/target.js +46 -0
  125. package/dist/commands/doctor/target.js.map +1 -0
  126. package/dist/commands/env/list.d.ts +3 -0
  127. package/dist/commands/env/list.d.ts.map +1 -0
  128. package/dist/commands/env/list.js +28 -0
  129. package/dist/commands/env/list.js.map +1 -0
  130. package/dist/commands/env/set.d.ts +3 -0
  131. package/dist/commands/env/set.d.ts.map +1 -0
  132. package/dist/commands/env/set.js +36 -0
  133. package/dist/commands/env/set.js.map +1 -0
  134. package/dist/commands/env/use.d.ts +3 -0
  135. package/dist/commands/env/use.d.ts.map +1 -0
  136. package/dist/commands/env/use.js +15 -0
  137. package/dist/commands/env/use.js.map +1 -0
  138. package/dist/commands/legacy/connect.d.ts +3 -0
  139. package/dist/commands/legacy/connect.d.ts.map +1 -0
  140. package/dist/commands/legacy/connect.js +8 -0
  141. package/dist/commands/legacy/connect.js.map +1 -0
  142. package/dist/commands/legacy/pages.d.ts +3 -0
  143. package/dist/commands/legacy/pages.d.ts.map +1 -0
  144. package/dist/commands/legacy/pages.js +16 -0
  145. package/dist/commands/legacy/pages.js.map +1 -0
  146. package/dist/commands/legacy/spread.d.ts +3 -0
  147. package/dist/commands/legacy/spread.d.ts.map +1 -0
  148. package/dist/commands/legacy/spread.js +8 -0
  149. package/dist/commands/legacy/spread.js.map +1 -0
  150. package/dist/commands/legacy/sync.d.ts +3 -0
  151. package/dist/commands/legacy/sync.d.ts.map +1 -0
  152. package/dist/commands/legacy/sync.js +8 -0
  153. package/dist/commands/legacy/sync.js.map +1 -0
  154. package/dist/config/env-diff.d.ts +10 -0
  155. package/dist/config/env-diff.d.ts.map +1 -0
  156. package/dist/config/env-diff.js +24 -0
  157. package/dist/config/env-diff.js.map +1 -0
  158. package/dist/config/env-parser.d.ts +20 -0
  159. package/dist/config/env-parser.d.ts.map +1 -0
  160. package/dist/config/env-parser.js +70 -0
  161. package/dist/config/env-parser.js.map +1 -0
  162. package/dist/config/env-writer.d.ts +22 -0
  163. package/dist/config/env-writer.d.ts.map +1 -0
  164. package/dist/config/env-writer.js +172 -0
  165. package/dist/config/env-writer.js.map +1 -0
  166. package/dist/config/profile-store.d.ts +29 -0
  167. package/dist/config/profile-store.d.ts.map +1 -0
  168. package/dist/config/profile-store.js +257 -0
  169. package/dist/config/profile-store.js.map +1 -0
  170. package/dist/core/args.d.ts +11 -0
  171. package/dist/core/args.d.ts.map +1 -0
  172. package/dist/core/args.js +106 -0
  173. package/dist/core/args.js.map +1 -0
  174. package/dist/core/colors.d.ts +6 -0
  175. package/dist/core/colors.d.ts.map +1 -0
  176. package/dist/core/colors.js +29 -0
  177. package/dist/core/colors.js.map +1 -0
  178. package/dist/safety/target-guard.d.ts +16 -0
  179. package/dist/safety/target-guard.d.ts.map +1 -0
  180. package/dist/safety/target-guard.js +55 -0
  181. package/dist/safety/target-guard.js.map +1 -0
  182. package/dist/testing/booking-smoke.d.ts +17 -0
  183. package/dist/testing/booking-smoke.d.ts.map +1 -0
  184. package/dist/testing/booking-smoke.js +43 -0
  185. package/dist/testing/booking-smoke.js.map +1 -0
  186. package/dist/tests/agent-commands.test.d.ts +2 -0
  187. package/dist/tests/agent-commands.test.d.ts.map +1 -0
  188. package/dist/tests/agent-commands.test.js +180 -0
  189. package/dist/tests/agent-commands.test.js.map +1 -0
  190. package/dist/tests/agent-governance.test.d.ts +2 -0
  191. package/dist/tests/agent-governance.test.d.ts.map +1 -0
  192. package/dist/tests/agent-governance.test.js +233 -0
  193. package/dist/tests/agent-governance.test.js.map +1 -0
  194. package/dist/tests/app-commands.test.d.ts +2 -0
  195. package/dist/tests/app-commands.test.d.ts.map +1 -0
  196. package/dist/tests/app-commands.test.js +462 -0
  197. package/dist/tests/app-commands.test.js.map +1 -0
  198. package/dist/tests/booking-commands.test.d.ts +2 -0
  199. package/dist/tests/booking-commands.test.d.ts.map +1 -0
  200. package/dist/tests/booking-commands.test.js +204 -0
  201. package/dist/tests/booking-commands.test.js.map +1 -0
  202. package/dist/tests/booking-smoke.test.d.ts +2 -0
  203. package/dist/tests/booking-smoke.test.d.ts.map +1 -0
  204. package/dist/tests/booking-smoke.test.js +183 -0
  205. package/dist/tests/booking-smoke.test.js.map +1 -0
  206. package/dist/tests/cms-commands.test.d.ts +2 -0
  207. package/dist/tests/cms-commands.test.d.ts.map +1 -0
  208. package/dist/tests/cms-commands.test.js +254 -0
  209. package/dist/tests/cms-commands.test.js.map +1 -0
  210. package/dist/tests/cms-ops.test.d.ts +2 -0
  211. package/dist/tests/cms-ops.test.d.ts.map +1 -0
  212. package/dist/tests/cms-ops.test.js +125 -0
  213. package/dist/tests/cms-ops.test.js.map +1 -0
  214. package/dist/tests/env-writer.test.d.ts +2 -0
  215. package/dist/tests/env-writer.test.d.ts.map +1 -0
  216. package/dist/tests/env-writer.test.js +90 -0
  217. package/dist/tests/env-writer.test.js.map +1 -0
  218. package/dist/tests/profile-store.test.d.ts +2 -0
  219. package/dist/tests/profile-store.test.d.ts.map +1 -0
  220. package/dist/tests/profile-store.test.js +88 -0
  221. package/dist/tests/profile-store.test.js.map +1 -0
  222. package/dist/tests/target-guard.test.d.ts +2 -0
  223. package/dist/tests/target-guard.test.d.ts.map +1 -0
  224. package/dist/tests/target-guard.test.js +132 -0
  225. package/dist/tests/target-guard.test.js.map +1 -0
  226. package/dist/ui/logo.d.ts +2 -0
  227. package/dist/ui/logo.d.ts.map +1 -0
  228. package/dist/ui/logo.js +22 -0
  229. package/dist/ui/logo.js.map +1 -0
  230. package/package.json +17 -53
  231. package/.claude/settings.local.json +0 -36
  232. package/.cursor/rules.md +0 -203
  233. package/.eslintrc.js +0 -31
  234. package/CLAUDE.md +0 -100
  235. package/bin/cli.js +0 -116
  236. package/docs/ADDING_FRAMEWORK_DETECTORS.md +0 -391
  237. package/docs/ADDING_NEW_PROJECT_TYPE.md +0 -156
  238. package/docs/ARCHITECTURE_RELATIONSHIPS.md +0 -411
  239. package/docs/CLI_AUTHENTICATION.md +0 -214
  240. package/docs/CLI_PAGE_DETECTION_REQUIREMENTS.md +0 -519
  241. package/docs/CRM-PIPELINES-SEQUENCES-SPEC.md +0 -429
  242. package/docs/DETECTOR_ARCHITECTURE.md +0 -326
  243. package/docs/DEVELOPMENT.md +0 -194
  244. package/docs/IMPLEMENTATION_PHASES.md +0 -468
  245. package/docs/INTEGRATION_PATHS_ARCHITECTURE.md +0 -1543
  246. package/docs/OAUTH_CLARIFICATION.md +0 -258
  247. package/docs/OAUTH_SETUP_GUIDE_TEMPLATE.md +0 -211
  248. package/docs/PHASE_0_PROGRESS.md +0 -120
  249. package/docs/PHASE_1_COMPLETE.md +0 -366
  250. package/docs/PHASE_SUMMARY.md +0 -149
  251. package/docs/PLAN.md +0 -511
  252. package/docs/README.md +0 -56
  253. package/docs/STRIPE_INTEGRATION.md +0 -447
  254. package/docs/SUMMARY.md +0 -230
  255. package/docs/UPDATED_PLAN.md +0 -447
  256. package/docs/mcp_server/MCP_EXTENSION_GUIDE.md +0 -1313
  257. package/docs/mcp_server/MCP_SERVER_ARCHITECTURE.md +0 -1481
  258. package/docs/mcp_server/applicationOntology.ts +0 -817
  259. package/docs/mcp_server/cliApplications.ts +0 -639
  260. package/docs/mcp_server/crmOntology.ts +0 -1063
  261. package/docs/mcp_server/eventOntology.ts +0 -1183
  262. package/docs/mcp_server/formsOntology.ts +0 -1401
  263. package/docs/mcp_server/ontologySchemas.ts +0 -185
  264. package/docs/mcp_server/schema.ts +0 -250
  265. package/docs/microsass_production_machine/CLI_API_REFERENCE.md +0 -1197
  266. package/docs/microsass_production_machine/CLI_PRODUCT_VISION.md +0 -676
  267. package/docs/microsass_production_machine/CLI_REQUIREMENTS.md +0 -606
  268. package/docs/microsass_production_machine/CONNECTED_APPLICATIONS_SPEC.md +0 -390
  269. package/docs/microsass_production_machine/IMPLEMENTATION_ROADMAP.md +0 -725
  270. package/docs/microsass_production_machine/OBJECT_MAPPINGS.md +0 -808
  271. package/docs/microsass_production_machine/REFERENCE_IMPLEMENTATION.md +0 -532
  272. package/src/api/backend-client.js +0 -449
  273. package/src/commands/api-keys.js +0 -119
  274. package/src/commands/connect.js +0 -243
  275. package/src/commands/login.js +0 -332
  276. package/src/commands/logout.js +0 -30
  277. package/src/commands/mcp-server.js +0 -85
  278. package/src/commands/mcp-setup.js +0 -686
  279. package/src/commands/pages.js +0 -317
  280. package/src/commands/scaffold.js +0 -409
  281. package/src/commands/spread.js +0 -861
  282. package/src/commands/status.js +0 -62
  283. package/src/commands/sync.js +0 -169
  284. package/src/commands/upgrade.js +0 -48
  285. package/src/config/config-manager.js +0 -206
  286. package/src/detectors/api-client-detector.js +0 -85
  287. package/src/detectors/base-detector.js +0 -77
  288. package/src/detectors/database-detector.js +0 -245
  289. package/src/detectors/expo-detector.js +0 -166
  290. package/src/detectors/github-detector.js +0 -74
  291. package/src/detectors/index.js +0 -106
  292. package/src/detectors/mapping-suggestor.js +0 -119
  293. package/src/detectors/model-detector.js +0 -318
  294. package/src/detectors/nextjs-detector.js +0 -139
  295. package/src/detectors/oauth-detector.js +0 -122
  296. package/src/detectors/page-detector.js +0 -480
  297. package/src/detectors/registry.js +0 -121
  298. package/src/generators/api-client-generator.js +0 -223
  299. package/src/generators/api-only/client.js +0 -683
  300. package/src/generators/api-only/index.js +0 -96
  301. package/src/generators/api-only/types.js +0 -618
  302. package/src/generators/api-only/webhooks.js +0 -377
  303. package/src/generators/env-generator.js +0 -191
  304. package/src/generators/expo-auth-generator.js +0 -1009
  305. package/src/generators/gitignore-generator.js +0 -92
  306. package/src/generators/index.js +0 -166
  307. package/src/generators/manifest-generator.js +0 -154
  308. package/src/generators/mcp-guide-generator.js +0 -256
  309. package/src/generators/nextauth-generator.js +0 -247
  310. package/src/generators/oauth-guide-generator.js +0 -277
  311. package/src/generators/quickstart/components/index.js +0 -1699
  312. package/src/generators/quickstart/components-mobile/index.js +0 -1440
  313. package/src/generators/quickstart/database/convex.js +0 -1257
  314. package/src/generators/quickstart/database/index.js +0 -34
  315. package/src/generators/quickstart/database/supabase.js +0 -1132
  316. package/src/generators/quickstart/hooks/index.js +0 -1065
  317. package/src/generators/quickstart/index.js +0 -191
  318. package/src/generators/quickstart/pages/index.js +0 -1466
  319. package/src/generators/quickstart/screens/index.js +0 -1498
  320. package/src/logo.js +0 -116
  321. package/src/mcp/auth.js +0 -127
  322. package/src/mcp/registry/domains/applications.js +0 -516
  323. package/src/mcp/registry/domains/benefits.js +0 -798
  324. package/src/mcp/registry/domains/codegen.js +0 -894
  325. package/src/mcp/registry/domains/core.js +0 -324
  326. package/src/mcp/registry/domains/crm.js +0 -591
  327. package/src/mcp/registry/domains/events.js +0 -649
  328. package/src/mcp/registry/domains/forms.js +0 -696
  329. package/src/mcp/registry/index.js +0 -164
  330. package/src/mcp/server.js +0 -116
  331. package/src/utils/file-utils.js +0 -117
  332. package/src/utils/init-helpers.js +0 -243
  333. package/src/utils/prompt-utils.js +0 -195
  334. package/templates/CLAUDE.md +0 -86
  335. package/tests/api-client-detector.test.js +0 -214
  336. package/tests/api-client-generator.test.js +0 -176
  337. package/tests/backend-client.test.js +0 -640
  338. package/tests/base-detector.test.js +0 -101
  339. package/tests/commands/login.test.js +0 -143
  340. package/tests/commands/logout.test.js +0 -84
  341. package/tests/commands/status.test.js +0 -167
  342. package/tests/config-manager.test.js +0 -321
  343. package/tests/database-detector.test.js +0 -221
  344. package/tests/detector-index.test.js +0 -209
  345. package/tests/detector-registry.test.js +0 -93
  346. package/tests/env-generator.test.js +0 -278
  347. package/tests/expo-detector.test.js +0 -263
  348. package/tests/file-utils.test.js +0 -194
  349. package/tests/generators-index.test.js +0 -454
  350. package/tests/github-detector.test.js +0 -145
  351. package/tests/gitignore-generator.test.js +0 -109
  352. package/tests/logo.test.js +0 -96
  353. package/tests/nextauth-generator.test.js +0 -255
  354. package/tests/nextjs-detector.test.js +0 -235
  355. package/tests/oauth-detector.test.js +0 -264
  356. package/tests/oauth-guide-generator.test.js +0 -273
  357. package/tests/page-detector.test.js +0 -371
@@ -1,861 +0,0 @@
1
- /**
2
- * Spread Command
3
- * Main command for setting up boilerplate integration
4
- */
5
-
6
- const fs = require('fs');
7
- const path = require('path');
8
- const configManager = require('../config/config-manager');
9
- const backendClient = require('../api/backend-client');
10
- const projectDetector = require('../detectors');
11
- const fileGenerator = require('../generators');
12
- const manifestGenerator = require('../generators/manifest-generator');
13
- const pageDetector = require('../detectors/page-detector');
14
- const { suggestMappings } = require('../detectors/mapping-suggestor');
15
- const { generateProjectPathHash } = require('../utils/file-utils');
16
- const {
17
- createOrganization,
18
- generateNewApiKey,
19
- checkGitStatusBeforeGeneration,
20
- requireAuth,
21
- } = require('../utils/init-helpers');
22
- const inquirer = require('inquirer');
23
- const chalk = require('chalk');
24
- const pkg = require('../../package.json');
25
- const { showMainMenu, executeMenuAction } = require('../utils/prompt-utils');
26
-
27
- async function handleSpread() {
28
- requireAuth(configManager);
29
-
30
- console.log(chalk.cyan(' 🍰 Setting up your Layer Cake integration...\n'));
31
-
32
- try {
33
- // Step 1: Detect project
34
- console.log(chalk.gray(' 🔍 Detecting project...\n'));
35
- const detection = projectDetector.detect();
36
-
37
- // Display framework detection results
38
- if (detection.framework.type) {
39
- const frameworkNames = {
40
- 'nextjs': 'Next.js',
41
- 'expo': 'Expo',
42
- 'react-native': 'React Native',
43
- };
44
- const frameworkName = frameworkNames[detection.framework.type] || detection.framework.type;
45
- console.log(chalk.green(` ✅ Detected ${frameworkName} project`));
46
-
47
- const meta = detection.framework.metadata || {};
48
-
49
- if (detection.framework.type === 'nextjs') {
50
- if (meta.version) {
51
- console.log(chalk.gray(` Version: ${meta.version}`));
52
- }
53
- if (meta.routerType) {
54
- console.log(chalk.gray(` Router: ${meta.routerType === 'app' ? 'App Router' : 'Pages Router'}`));
55
- }
56
- if (meta.hasTypeScript) {
57
- console.log(chalk.gray(' TypeScript: Yes'));
58
- }
59
- } else if (detection.framework.type === 'expo' || detection.framework.type === 'react-native') {
60
- if (meta.expoVersion) {
61
- console.log(chalk.gray(` Expo SDK: ${meta.expoVersion}`));
62
- }
63
- if (meta.reactNativeVersion) {
64
- console.log(chalk.gray(` React Native: ${meta.reactNativeVersion}`));
65
- }
66
- if (meta.routerType) {
67
- const routerName = meta.routerType === 'expo-router' ? 'Expo Router' :
68
- meta.routerType === 'react-navigation' ? 'React Navigation' : 'Native';
69
- console.log(chalk.gray(` Navigation: ${routerName}`));
70
- }
71
- if (meta.hasTypeScript) {
72
- console.log(chalk.gray(' TypeScript: Yes'));
73
- }
74
- }
75
-
76
- // Show supported features
77
- const features = detection.framework.supportedFeatures;
78
- const supportedFeatures = Object.entries(features)
79
- .filter(([_, supported]) => supported === true || supported === 'manual')
80
- .map(([name]) => name);
81
-
82
- if (supportedFeatures.length > 0) {
83
- console.log(chalk.gray(` Supported features: ${supportedFeatures.join(', ')}`));
84
- }
85
- } else {
86
- console.log(chalk.yellow(' ⚠️ Could not detect project type'));
87
- const { continueAnyway } = await inquirer.prompt([
88
- {
89
- type: 'confirm',
90
- name: 'continueAnyway',
91
- message: 'Continue with basic setup anyway?',
92
- default: false,
93
- },
94
- ]);
95
-
96
- if (!continueAnyway) {
97
- console.log(chalk.gray('\n Setup cancelled.\n'));
98
- const action = await showMainMenu({ isLoggedIn: true, isInProject: true });
99
- await executeMenuAction(action);
100
- return;
101
- }
102
- }
103
-
104
- // Display GitHub detection
105
- if (detection.github.isGitHub) {
106
- console.log(chalk.green(` ✅ Detected GitHub repository: ${detection.github.owner}/${detection.github.repo}`));
107
- }
108
-
109
- // Display API client detection
110
- if (detection.apiClient.hasApiClient) {
111
- console.log(chalk.yellow(` ⚠️ Existing API client found: ${detection.apiClient.clientPath}`));
112
- }
113
-
114
- // Display OAuth detection
115
- if (detection.oauth.hasOAuth) {
116
- console.log(chalk.yellow(` ⚠️ Existing OAuth setup detected: ${detection.oauth.oauthType}`));
117
- if (detection.oauth.providers.length > 0) {
118
- console.log(chalk.gray(` Providers: ${detection.oauth.providers.join(', ')}`));
119
- }
120
- if (detection.oauth.configPath) {
121
- console.log(chalk.gray(` Config: ${detection.oauth.configPath}`));
122
- }
123
- }
124
-
125
- // Display model detection
126
- if (detection.models && detection.models.hasModels) {
127
- console.log(chalk.green(` ✅ Detected ${detection.models.models.length} model(s)`));
128
- for (const model of detection.models.models.slice(0, 5)) {
129
- console.log(chalk.gray(` • ${model.name} (${model.source}) [${model.fields.length} fields]`));
130
- }
131
- if (detection.models.models.length > 5) {
132
- console.log(chalk.gray(` ... and ${detection.models.models.length - 5} more`));
133
- }
134
- }
135
-
136
- // Scan routes with HTTP methods
137
- const detectedRoutes = pageDetector.detect(
138
- detection.projectPath,
139
- detection.framework.type,
140
- detection.framework.metadata || {}
141
- );
142
- const apiRoutes = detectedRoutes.filter(r => r.pageType === 'api_route');
143
- if (apiRoutes.length > 0) {
144
- console.log(chalk.green(` ✅ Detected ${apiRoutes.length} API route(s)`));
145
- for (const route of apiRoutes.slice(0, 5)) {
146
- const methods = route.methods ? route.methods.join(', ') : 'GET, POST';
147
- console.log(chalk.gray(` • ${route.path} [${methods}]`));
148
- }
149
- if (apiRoutes.length > 5) {
150
- console.log(chalk.gray(` ... and ${apiRoutes.length - 5} more`));
151
- }
152
- }
153
-
154
- // Compute suggested mappings
155
- const models = detection.models ? detection.models.models : [];
156
- const mappings = suggestMappings(models);
157
- if (mappings.length > 0) {
158
- console.log(chalk.green(` ✅ ${mappings.length} suggested mapping(s)`));
159
- for (const mapping of mappings) {
160
- console.log(chalk.gray(` • ${mapping.localModel} → ${mapping.platformType} (${mapping.confidence}% confidence)`));
161
- }
162
- }
163
-
164
- console.log('');
165
-
166
- // Step 1.5: Project name
167
- const folderName = path.basename(detection.projectPath);
168
- const defaultProjectName = detection.github.repo || folderName;
169
-
170
- const { projectName } = await inquirer.prompt([
171
- {
172
- type: 'input',
173
- name: 'projectName',
174
- message: 'Project name:',
175
- default: defaultProjectName,
176
- validate: (input) => input.trim().length > 0 || 'Project name is required',
177
- },
178
- ]);
179
- console.log(chalk.green(` ✅ Project: ${projectName}\n`));
180
-
181
- // Step 2: Organization selection
182
- console.log(chalk.cyan(' 📦 Organization Setup\n'));
183
- let organizationId;
184
- let organizationName;
185
-
186
- try {
187
- const orgsResponse = await backendClient.getOrganizations();
188
- // Handle different response formats
189
- const organizations = Array.isArray(orgsResponse)
190
- ? orgsResponse
191
- : orgsResponse.organizations || orgsResponse.data || [];
192
-
193
- if (organizations.length === 0) {
194
- // No organizations, create one
195
- const { orgName } = await inquirer.prompt([
196
- {
197
- type: 'input',
198
- name: 'orgName',
199
- message: 'Organization name:',
200
- default: detection.github.repo || 'My Organization',
201
- validate: (input) => input.trim().length > 0 || 'Organization name is required',
202
- },
203
- ]);
204
-
205
- const result = await createOrganization(orgName);
206
- organizationId = result.organizationId;
207
- organizationName = result.organizationName;
208
- } else {
209
- // Select or create organization
210
- const { orgChoice } = await inquirer.prompt([
211
- {
212
- type: 'list',
213
- name: 'orgChoice',
214
- message: 'Select organization:',
215
- choices: [
216
- ...organizations.map(org => ({
217
- name: `${org.name} (${org.id})`,
218
- value: org.id,
219
- })),
220
- { name: '➕ Create new organization', value: '__create__' },
221
- ],
222
- },
223
- ]);
224
-
225
- if (orgChoice === '__create__') {
226
- const { orgName } = await inquirer.prompt([
227
- {
228
- type: 'input',
229
- name: 'orgName',
230
- message: 'Organization name:',
231
- default: detection.github.repo || 'My Organization',
232
- validate: (input) => input.trim().length > 0 || 'Organization name is required',
233
- },
234
- ]);
235
-
236
- const result = await createOrganization(orgName);
237
- organizationId = result.organizationId;
238
- organizationName = result.organizationName;
239
- } else {
240
- const selectedOrg = organizations.find(org => org.id === orgChoice);
241
- organizationId = orgChoice;
242
- organizationName = selectedOrg.name;
243
- console.log(chalk.green(` ✅ Selected organization: ${organizationName}\n`));
244
- }
245
- }
246
- } catch (error) {
247
- console.error(chalk.red(` ❌ Error managing organizations: ${error.message}\n`));
248
- process.exit(1);
249
- }
250
-
251
- // Step 3: API Key Setup
252
- console.log(chalk.cyan(' 🔑 API Key Setup\n'));
253
- let apiKey;
254
-
255
- try {
256
- // First, check if .env.local already has an API key configured
257
- const envPath = path.join(detection.projectPath, '.env.local');
258
- let existingEnvKey = null;
259
- if (fs.existsSync(envPath)) {
260
- try {
261
- const envContent = fs.readFileSync(envPath, 'utf8');
262
- const match = envContent.match(/^L4YERCAK3_API_KEY=(.+)$/m);
263
- if (match && match[1] && match[1].startsWith('sk_')) {
264
- existingEnvKey = match[1].trim();
265
- }
266
- } catch {
267
- // Ignore read errors
268
- }
269
- }
270
-
271
- if (existingEnvKey) {
272
- // Found existing API key in .env.local
273
- const keyPreview = `${existingEnvKey.substring(0, 12)}...`;
274
- console.log(chalk.green(` ✅ Found existing API key in .env.local (${keyPreview})\n`));
275
-
276
- const { useExisting } = await inquirer.prompt([
277
- {
278
- type: 'list',
279
- name: 'useExisting',
280
- message: 'What would you like to do?',
281
- choices: [
282
- { name: 'Keep existing API key (recommended)', value: 'keep' },
283
- { name: 'Generate a new API key', value: 'generate' },
284
- ],
285
- },
286
- ]);
287
-
288
- if (useExisting === 'keep') {
289
- apiKey = null; // Will preserve existing key in .env.local
290
- console.log(chalk.green(` ✅ Keeping existing API key\n`));
291
- } else {
292
- apiKey = await generateNewApiKey(organizationId);
293
- }
294
- } else {
295
- // No existing key in .env.local - check backend for keys
296
- console.log(chalk.gray(' Checking existing API keys...'));
297
- let existingKeys = null;
298
-
299
- try {
300
- existingKeys = await backendClient.listApiKeys(organizationId);
301
- } catch (listError) {
302
- // If listing fails, continue to try generating
303
- console.log(chalk.gray(' Could not check existing keys, attempting to generate...'));
304
- }
305
-
306
- if (existingKeys && existingKeys.canCreateMore === false) {
307
- // At API key limit - inform user and exit (only if explicitly false, not undefined)
308
- console.log(chalk.yellow(` ⚠️ You've reached your API key limit (${existingKeys.keys?.length || 0} key(s))`));
309
- if (existingKeys.limitDescription) {
310
- console.log(chalk.gray(` ${existingKeys.limitDescription}`));
311
- }
312
- console.log(chalk.cyan('\n To continue, either:'));
313
- console.log(chalk.gray(' • Delete an existing key at https://app.l4yercak3.com?openWindow=integrations&panel=api-keys'));
314
- console.log(chalk.gray(' • Upgrade your plan at https://app.l4yercak3.com?openWindow=store\n'));
315
- const action = await showMainMenu({ isLoggedIn: true, isInProject: true });
316
- await executeMenuAction(action);
317
- return;
318
- } else if (existingKeys && existingKeys.keys && existingKeys.keys.length > 0) {
319
- // Has existing keys on backend - offer to reuse or generate new
320
- const activeKeys = existingKeys.keys.filter(k => k.status === 'active');
321
-
322
- if (activeKeys.length > 0) {
323
- console.log(chalk.gray(` Found ${activeKeys.length} active API key(s)\n`));
324
-
325
- const keyChoices = activeKeys.map(key => ({
326
- name: `Use ${key.name} (${key.keyPreview})`,
327
- value: key.id,
328
- }));
329
- keyChoices.push({ name: '➕ Generate a new API key', value: '__generate__' });
330
-
331
- const { keyChoice } = await inquirer.prompt([
332
- {
333
- type: 'list',
334
- name: 'keyChoice',
335
- message: 'Which API key would you like to use?',
336
- choices: keyChoices,
337
- },
338
- ]);
339
-
340
- if (keyChoice === '__generate__') {
341
- apiKey = await generateNewApiKey(organizationId);
342
- } else {
343
- // User selected existing key - prompt for the full key
344
- const selectedKey = activeKeys.find(k => k.id === keyChoice);
345
- console.log(chalk.yellow(`\n ⚠️ For security, we can't retrieve the full API key.`));
346
- console.log(chalk.gray(` You selected: ${selectedKey.name} (${selectedKey.keyPreview})`));
347
- console.log(chalk.gray(` Enter the key if you have it, or press Enter to generate a new one.\n`));
348
-
349
- const { existingKey } = await inquirer.prompt([
350
- {
351
- type: 'input',
352
- name: 'existingKey',
353
- message: 'Enter your API key (or press Enter to generate new):',
354
- },
355
- ]);
356
-
357
- if (existingKey.trim()) {
358
- apiKey = existingKey.trim();
359
- console.log(chalk.green(` ✅ Using existing API key\n`));
360
- } else {
361
- apiKey = await generateNewApiKey(organizationId);
362
- }
363
- }
364
- } else {
365
- // Only revoked keys exist - generate new
366
- apiKey = await generateNewApiKey(organizationId);
367
- }
368
- } else {
369
- // No existing keys - generate one
370
- apiKey = await generateNewApiKey(organizationId);
371
- }
372
- }
373
- } catch (error) {
374
- // Handle specific error codes
375
- if (error.code === 'API_KEY_LIMIT_REACHED') {
376
- console.log(chalk.yellow(`\n ⚠️ ${error.message}`));
377
- if (error.suggestion) {
378
- console.log(chalk.gray(` ${error.suggestion}`));
379
- }
380
- console.log(chalk.cyan('\n To continue, either:'));
381
- console.log(chalk.gray(' • Delete an existing key at https://app.l4yercak3.com?openWindow=integrations&panel=api-keys'));
382
- console.log(chalk.gray(' • Upgrade your plan at https://app.l4yercak3.com?openWindow=store\n'));
383
- const action = await showMainMenu({ isLoggedIn: true, isInProject: true });
384
- await executeMenuAction(action);
385
- return;
386
- } else if (error.code === 'API_KEY_ALREADY_LINKED') {
387
- console.log(chalk.yellow(`\n ⚠️ ${error.message}`));
388
- if (error.suggestion) {
389
- console.log(chalk.gray(` ${error.suggestion}`));
390
- }
391
- console.log(chalk.cyan('\n Each API key can only be connected to one application.'));
392
- console.log(chalk.gray(' Generate a new API key for this project.\n'));
393
-
394
- // Offer to generate a new key
395
- const { generateNew } = await inquirer.prompt([
396
- {
397
- type: 'confirm',
398
- name: 'generateNew',
399
- message: 'Generate a new API key for this project?',
400
- default: true,
401
- },
402
- ]);
403
-
404
- if (generateNew) {
405
- apiKey = await generateNewApiKey(organizationId);
406
- } else {
407
- const action = await showMainMenu({ isLoggedIn: true, isInProject: true });
408
- await executeMenuAction(action);
409
- return;
410
- }
411
- } else if (error.code === 'SESSION_EXPIRED' || error.code === 'INVALID_SESSION') {
412
- console.log(chalk.red(`\n ❌ Session expired. Please run "l4yercak3 login" again.\n`));
413
- process.exit(1);
414
- } else if (error.code === 'NOT_AUTHORIZED' || error.code === 'UNAUTHORIZED') {
415
- console.log(chalk.red(`\n ❌ You don't have permission to manage API keys for this organization.\n`));
416
- process.exit(1);
417
- } else {
418
- console.error(chalk.red(` ❌ Error setting up API key: ${error.message}\n`));
419
- process.exit(1);
420
- }
421
- }
422
-
423
- // Step 4: Feature selection
424
- // Auto-check features based on detected model mappings
425
- const platformTypeToFeature = {
426
- contact: 'crm',
427
- booking: 'events',
428
- event: 'events',
429
- product: 'products',
430
- invoice: 'invoicing',
431
- project: 'projects',
432
- form: 'forms',
433
- certificate: 'certificates',
434
- benefit: 'benefits',
435
- };
436
- const autoCheckedFeatures = new Set(['crm']); // CRM always default
437
- for (const mapping of mappings) {
438
- const feature = platformTypeToFeature[mapping.platformType];
439
- if (feature) autoCheckedFeatures.add(feature);
440
- }
441
-
442
- console.log(chalk.cyan(' ⚙️ Feature Selection\n'));
443
- if (mappings.length > 0) {
444
- console.log(chalk.gray(' Features pre-selected based on detected models:\n'));
445
- }
446
- const { features } = await inquirer.prompt([
447
- {
448
- type: 'checkbox',
449
- name: 'features',
450
- message: 'Select features to enable:',
451
- choices: [
452
- { name: 'CRM (contacts, organizations)', value: 'crm', checked: autoCheckedFeatures.has('crm') },
453
- { name: 'Events (event management, registrations)', value: 'events', checked: autoCheckedFeatures.has('events') },
454
- { name: 'Forms (form builder, submissions)', value: 'forms', checked: autoCheckedFeatures.has('forms') },
455
- { name: 'Products (product catalog, inventory)', value: 'products', checked: autoCheckedFeatures.has('products') },
456
- { name: 'Checkout (cart, payments)', value: 'checkout', checked: autoCheckedFeatures.has('checkout') },
457
- { name: 'Invoicing (B2B/B2C invoices)', value: 'invoicing', checked: autoCheckedFeatures.has('invoicing') },
458
- { name: 'Benefits (claims, commissions)', value: 'benefits', checked: autoCheckedFeatures.has('benefits') },
459
- { name: 'Certificates (CME, attendance)', value: 'certificates', checked: autoCheckedFeatures.has('certificates') },
460
- { name: 'Projects (task management)', value: 'projects', checked: autoCheckedFeatures.has('projects') },
461
- { name: 'OAuth Authentication', value: 'oauth', checked: false },
462
- ],
463
- },
464
- ]);
465
-
466
- // Step 4.5: Integration path selection
467
- console.log(chalk.cyan('\n 🛤️ Integration Path\n'));
468
- const { integrationPath } = await inquirer.prompt([
469
- {
470
- type: 'list',
471
- name: 'integrationPath',
472
- message: 'Choose your integration approach:',
473
- choices: [
474
- {
475
- name: 'Quick Start (Recommended) - Full-stack with UI components & database',
476
- value: 'quickstart',
477
- },
478
- {
479
- name: 'API Only - Just the typed API client, you build the UI',
480
- value: 'api-only',
481
- },
482
- {
483
- name: 'MCP-Assisted - AI-powered custom generation with Claude Code',
484
- value: 'mcp-assisted',
485
- },
486
- ],
487
- },
488
- ]);
489
- console.log(chalk.green(` ✅ Path: ${integrationPath === 'quickstart' ? 'Quick Start' : integrationPath === 'api-only' ? 'API Only' : 'MCP-Assisted'}\n`));
490
-
491
- // Step 4.6: Database selection (for Quick Start path when no DB detected)
492
- let selectedDatabase = null;
493
- if (integrationPath === 'quickstart') {
494
- const dbDetection = detection.database || { hasDatabase: false };
495
-
496
- if (!dbDetection.hasDatabase) {
497
- console.log(chalk.yellow(' ℹ️ No database detected in your project.\n'));
498
-
499
- const { database } = await inquirer.prompt([
500
- {
501
- type: 'list',
502
- name: 'database',
503
- message: 'Which database would you like to use?',
504
- choices: [
505
- {
506
- name: 'Convex (Recommended) - Real-time, serverless, TypeScript-first',
507
- value: 'convex',
508
- },
509
- {
510
- name: 'Supabase - PostgreSQL with Auth, Storage, and Edge Functions',
511
- value: 'supabase',
512
- },
513
- {
514
- name: 'None - I\'ll set up my own database later',
515
- value: 'none',
516
- },
517
- ],
518
- },
519
- ]);
520
-
521
- selectedDatabase = database !== 'none' ? database : null;
522
- if (selectedDatabase) {
523
- console.log(chalk.green(` ✅ Database: ${selectedDatabase}\n`));
524
- }
525
- } else {
526
- console.log(chalk.green(` ✅ Detected ${dbDetection.primary?.type || 'existing'} database\n`));
527
- selectedDatabase = dbDetection.primary?.type || 'existing';
528
- }
529
- }
530
-
531
- // Step 5: OAuth provider selection (if OAuth enabled)
532
- let oauthProviders = [];
533
- if (features.includes('oauth')) {
534
- const { providers } = await inquirer.prompt([
535
- {
536
- type: 'checkbox',
537
- name: 'providers',
538
- message: 'Select OAuth providers:',
539
- choices: [
540
- { name: 'Google', value: 'google', checked: true },
541
- { name: 'Microsoft', value: 'microsoft', checked: true },
542
- { name: 'GitHub', value: 'github', checked: false },
543
- ],
544
- },
545
- ]);
546
- oauthProviders = providers;
547
- }
548
-
549
- // Step 6: Backend URL (fixed to Convex HTTP endpoint)
550
- const backendUrl = 'https://agreeable-lion-828.convex.site';
551
-
552
- // Step 7: Production domain (for OAuth redirect URIs)
553
- let productionDomain = null;
554
- if (features.includes('oauth')) {
555
- console.log(chalk.gray('\n ℹ️ The following settings are written to .env.local for local development.'));
556
- console.log(chalk.gray(' For production, set NEXTAUTH_URL in your hosting platform (e.g., Vercel).\n'));
557
-
558
- const { configureNow } = await inquirer.prompt([
559
- {
560
- type: 'confirm',
561
- name: 'configureNow',
562
- message: 'Configure production domain now? (You can skip and do this later)',
563
- default: true,
564
- },
565
- ]);
566
-
567
- if (configureNow) {
568
- const { domain } = await inquirer.prompt([
569
- {
570
- type: 'input',
571
- name: 'domain',
572
- message: 'Production domain (for OAuth redirect URIs):',
573
- default: detection.github.repo ? `${detection.github.repo}.vercel.app` : 'your-domain.com',
574
- },
575
- ]);
576
- productionDomain = domain;
577
- } else {
578
- console.log(chalk.gray(' Skipping production domain configuration.'));
579
- console.log(chalk.gray(' Set NEXTAUTH_URL in your hosting platform when deploying.\n'));
580
- }
581
- }
582
-
583
- // Step 8: Check for uncommitted changes before generating files
584
- const shouldProceed = await checkGitStatusBeforeGeneration(detection.projectPath);
585
- if (!shouldProceed) {
586
- return;
587
- }
588
-
589
- // Step 9: Generate files
590
- console.log(chalk.cyan('\n 📝 Generating files...\n'));
591
-
592
- // Extract framework metadata for generation
593
- const frameworkMeta = detection.framework.metadata || {};
594
- const isTypeScript = frameworkMeta.hasTypeScript || false;
595
- const routerType = frameworkMeta.routerType || 'pages';
596
-
597
- const generationOptions = {
598
- projectPath: detection.projectPath,
599
- apiKey,
600
- backendUrl,
601
- organizationId,
602
- organizationName,
603
- features,
604
- oauthProviders,
605
- productionDomain,
606
- appName: projectName,
607
- isTypeScript,
608
- routerType,
609
- frameworkType: detection.framework.type || 'unknown',
610
- integrationPath,
611
- selectedDatabase,
612
- };
613
-
614
- // Debug: Log generation options
615
- if (process.env.L4YERCAK3_DEBUG) {
616
- console.log('\n[DEBUG] Spread: Generation options:');
617
- console.log(` frameworkType: "${generationOptions.frameworkType}"`);
618
- console.log(` integrationPath: "${generationOptions.integrationPath}"`);
619
- console.log(` isTypeScript: ${generationOptions.isTypeScript}`);
620
- console.log(` features: [${generationOptions.features.join(', ')}]`);
621
- }
622
-
623
- const generatedFiles = await fileGenerator.generate(generationOptions);
624
-
625
- // Display results
626
- console.log(chalk.green(' ✅ Files generated:\n'));
627
-
628
- // API client files (api-only and quickstart paths)
629
- if (generatedFiles.apiClient) {
630
- console.log(chalk.gray(` • ${path.relative(process.cwd(), generatedFiles.apiClient)}`));
631
- }
632
- if (generatedFiles.types) {
633
- console.log(chalk.gray(` • ${path.relative(process.cwd(), generatedFiles.types)}`));
634
- }
635
- if (generatedFiles.webhooks) {
636
- console.log(chalk.gray(` • ${path.relative(process.cwd(), generatedFiles.webhooks)}`));
637
- }
638
- if (generatedFiles.index) {
639
- console.log(chalk.gray(` • ${path.relative(process.cwd(), generatedFiles.index)}`));
640
- }
641
-
642
- // MCP files (mcp-assisted path)
643
- if (generatedFiles.mcpConfig) {
644
- console.log(chalk.gray(` • ${path.relative(process.cwd(), generatedFiles.mcpConfig)}`));
645
- }
646
- if (generatedFiles.mcpGuide) {
647
- console.log(chalk.gray(` • ${path.relative(process.cwd(), generatedFiles.mcpGuide)}`));
648
- }
649
-
650
- // Common files
651
- if (generatedFiles.envFile) {
652
- console.log(chalk.gray(` • ${path.relative(process.cwd(), generatedFiles.envFile)}`));
653
- }
654
- if (generatedFiles.nextauth) {
655
- console.log(chalk.gray(` • ${path.relative(process.cwd(), generatedFiles.nextauth)}`));
656
- }
657
- if (generatedFiles.oauthGuide) {
658
- console.log(chalk.gray(` • ${path.relative(process.cwd(), generatedFiles.oauthGuide)}`));
659
- }
660
- if (generatedFiles.gitignore) {
661
- console.log(chalk.gray(` • ${path.relative(process.cwd(), generatedFiles.gitignore)} (updated)`));
662
- }
663
-
664
- // Generate .l4yercak3.json manifest
665
- const manifestPath = manifestGenerator.generate({
666
- projectPath: detection.projectPath,
667
- detection,
668
- models,
669
- routes: detectedRoutes,
670
- mappings,
671
- });
672
- console.log(chalk.gray(` • ${path.relative(process.cwd(), manifestPath)}`));
673
-
674
- // Step 9: Register application with backend
675
- console.log(chalk.cyan('\n 🔗 Registering with L4YERCAK3...\n'));
676
-
677
- const projectPathHash = generateProjectPathHash(detection.projectPath);
678
- let applicationId = null;
679
- let isUpdate = false;
680
-
681
- try {
682
- // Check if application already exists for this project
683
- const existingApp = await backendClient.checkExistingApplication(organizationId, projectPathHash);
684
-
685
- // Helper to register a new application
686
- const registerNewApplication = async () => {
687
- // Build source object, only including routerType if it has a value
688
- const sourceData = {
689
- type: 'cli',
690
- projectPathHash,
691
- cliVersion: pkg.version,
692
- framework: detection.framework.type || 'unknown',
693
- frameworkVersion: detection.framework.metadata?.version,
694
- hasTypeScript: detection.framework.metadata?.hasTypeScript || false,
695
- };
696
-
697
- // Only add routerType if it exists
698
- if (detection.framework.metadata?.routerType) {
699
- sourceData.routerType = detection.framework.metadata.routerType;
700
- }
701
-
702
- const registrationData = {
703
- organizationId,
704
- name: projectName,
705
- description: `Connected via CLI from ${detection.framework.type || 'unknown'} project`,
706
- source: sourceData,
707
- connection: {
708
- features,
709
- hasFrontendDatabase: !!detection.framework.metadata?.hasPrisma,
710
- frontendDatabaseType: detection.framework.metadata?.hasPrisma ? 'prisma' : undefined,
711
- },
712
- deployment: {
713
- productionUrl: productionDomain ? `https://${productionDomain}` : undefined,
714
- githubRepo: detection.github.isGitHub ? `${detection.github.owner}/${detection.github.repo}` : undefined,
715
- githubBranch: detection.github.branch || 'main',
716
- },
717
- // Don't generate a new API key if user already has one configured
718
- skipApiKeyGeneration: apiKey === null,
719
- };
720
-
721
- const registrationResult = await backendClient.registerApplication(registrationData);
722
- return registrationResult;
723
- };
724
-
725
- if (existingApp.found && existingApp.application) {
726
- // Application already registered
727
- console.log(chalk.yellow(` ⚠️ This project is already registered as "${existingApp.application.name}"`));
728
-
729
- const { updateAction } = await inquirer.prompt([
730
- {
731
- type: 'list',
732
- name: 'updateAction',
733
- message: 'What would you like to do?',
734
- choices: [
735
- { name: 'Update existing registration', value: 'update' },
736
- { name: 'Register as new application', value: 'new' },
737
- { name: 'Skip registration (keep existing)', value: 'skip' },
738
- ],
739
- },
740
- ]);
741
-
742
- if (updateAction === 'update') {
743
- // Update existing application
744
- const updateData = {
745
- name: projectName, // Update name too
746
- connection: {
747
- features,
748
- hasFrontendDatabase: !!detection.framework.metadata?.hasPrisma,
749
- frontendDatabaseType: detection.framework.metadata?.hasPrisma ? 'prisma' : undefined,
750
- },
751
- deployment: {
752
- productionUrl: productionDomain ? `https://${productionDomain}` : undefined,
753
- githubRepo: detection.github.isGitHub ? `${detection.github.owner}/${detection.github.repo}` : undefined,
754
- },
755
- };
756
-
757
- await backendClient.updateApplication(existingApp.application.id, updateData);
758
- applicationId = existingApp.application.id;
759
- isUpdate = true;
760
- console.log(chalk.green(` ✅ Application registration updated\n`));
761
- } else if (updateAction === 'new') {
762
- // Register as new application
763
- const registrationResult = await registerNewApplication();
764
- applicationId = registrationResult.applicationId;
765
- console.log(chalk.green(` ✅ New application registered with L4YERCAK3\n`));
766
-
767
- if (registrationResult.apiKey && registrationResult.apiKey.key) {
768
- console.log(chalk.gray(` API key generated: ${registrationResult.apiKey.prefix}`));
769
- }
770
- } else {
771
- applicationId = existingApp.application.id;
772
- console.log(chalk.gray(` Skipped registration update\n`));
773
- }
774
- } else {
775
- // Register new application
776
- const registrationResult = await registerNewApplication();
777
- applicationId = registrationResult.applicationId;
778
- console.log(chalk.green(` ✅ Application registered with L4YERCAK3\n`));
779
-
780
- // Show API key if backend generated one
781
- if (registrationResult.apiKey && registrationResult.apiKey.key) {
782
- console.log(chalk.gray(` API key: ${registrationResult.apiKey.prefix}`));
783
- }
784
- }
785
- } catch (regError) {
786
- // Registration failed but files were generated - warn but don't fail
787
- console.log(chalk.yellow(` ⚠️ Could not register with backend: ${regError.message}`));
788
- console.log(chalk.gray(' Your files were generated successfully.'));
789
- console.log(chalk.gray(' Backend registration will be available in a future update.\n'));
790
- }
791
-
792
- // Save project configuration
793
- const projectConfig = {
794
- organizationId,
795
- organizationName,
796
- applicationId,
797
- projectPathHash,
798
- apiKey: apiKey ? `${apiKey.substring(0, 10)}...` : '(using existing)', // Store partial key for reference only
799
- backendUrl,
800
- features,
801
- oauthProviders,
802
- productionDomain,
803
- frameworkType: detection.framework.type,
804
- integrationPath,
805
- selectedDatabase,
806
- createdAt: Date.now(),
807
- updatedAt: isUpdate ? Date.now() : undefined,
808
- };
809
-
810
- configManager.saveProjectConfig(detection.projectPath, projectConfig);
811
- console.log(chalk.gray(` 📝 Configuration saved to ~/.l4yercak3/config.json\n`));
812
-
813
- // Show appropriate completion message based on registration status
814
- if (applicationId) {
815
- console.log(chalk.cyan('\n 🎉 Setup complete!\n'));
816
- } else {
817
- console.log(chalk.cyan('\n 🎉 Local setup complete!\n'));
818
- console.log(chalk.yellow(' ⚠️ Note: Backend registration pending - your app works locally but'));
819
- console.log(chalk.yellow(' won\'t appear in the L4YERCAK3 dashboard until endpoints are available.\n'));
820
- }
821
-
822
- if (features.includes('oauth')) {
823
- console.log(chalk.yellow(' 📋 Next steps:\n'));
824
- console.log(chalk.gray(' 1. Follow the OAuth setup guide (OAUTH_SETUP_GUIDE.md)'));
825
- console.log(chalk.gray(' 2. Add OAuth credentials to .env.local'));
826
-
827
- // Framework-specific OAuth instructions
828
- const frameworkType = detection.framework.type;
829
- if (frameworkType === 'expo' || frameworkType === 'react-native') {
830
- console.log(chalk.gray(' 3. Install expo-auth-session: npx expo install expo-auth-session expo-crypto'));
831
- console.log(chalk.gray(' 4. Configure app.json with your OAuth scheme'));
832
- } else {
833
- console.log(chalk.gray(' 3. Install NextAuth.js: npm install next-auth'));
834
- if (oauthProviders.includes('microsoft')) {
835
- console.log(chalk.gray(' 4. Install Azure AD provider: npm install next-auth/providers/azure-ad'));
836
- }
837
- }
838
- console.log('');
839
- }
840
-
841
- console.log(chalk.gray(' Your project is now connected to L4YERCAK3! 🍰\n'));
842
-
843
- // Show menu for next actions
844
- const action = await showMainMenu({ isLoggedIn: true, isInProject: true, hasExistingConfig: true });
845
- await executeMenuAction(action);
846
-
847
- } catch (error) {
848
- console.error(chalk.red(`\n ❌ Error: ${error.message}\n`));
849
- if (error.stack) {
850
- console.error(chalk.gray(error.stack));
851
- }
852
- process.exit(1);
853
- }
854
- }
855
-
856
- module.exports = {
857
- command: 'spread',
858
- description: 'Initialize a new project integration',
859
- handler: handleSpread,
860
- };
861
-