@launch77/cli 1.4.3 → 1.5.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 (152) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/cli.js +1 -4
  3. package/dist/cli.js.map +1 -1
  4. package/dist/infrastructure/npm-package.d.ts +42 -0
  5. package/dist/infrastructure/npm-package.d.ts.map +1 -0
  6. package/dist/infrastructure/npm-package.js +46 -0
  7. package/dist/infrastructure/npm-package.js.map +1 -0
  8. package/dist/infrastructure/package-resolver.d.ts +117 -0
  9. package/dist/infrastructure/package-resolver.d.ts.map +1 -0
  10. package/dist/infrastructure/package-resolver.js +170 -0
  11. package/dist/infrastructure/package-resolver.js.map +1 -0
  12. package/dist/infrastructure/package-resolver.test.d.ts +2 -0
  13. package/dist/infrastructure/package-resolver.test.d.ts.map +1 -0
  14. package/dist/infrastructure/package-resolver.test.js +251 -0
  15. package/dist/infrastructure/package-resolver.test.js.map +1 -0
  16. package/dist/infrastructure/template.d.ts +0 -1
  17. package/dist/infrastructure/template.d.ts.map +1 -1
  18. package/dist/infrastructure/template.js.map +1 -1
  19. package/dist/modules/app/commands/create-app.d.ts.map +1 -1
  20. package/dist/modules/app/commands/create-app.js +14 -15
  21. package/dist/modules/app/commands/create-app.js.map +1 -1
  22. package/dist/modules/app/commands/delete-app.js +1 -1
  23. package/dist/modules/app/commands/delete-app.js.map +1 -1
  24. package/dist/modules/app/commands/validate-manifest.d.ts.map +1 -1
  25. package/dist/modules/app/commands/validate-manifest.js +0 -1
  26. package/dist/modules/app/commands/validate-manifest.js.map +1 -1
  27. package/dist/modules/app/index.d.ts +1 -2
  28. package/dist/modules/app/index.d.ts.map +1 -1
  29. package/dist/modules/app/index.js +0 -1
  30. package/dist/modules/app/index.js.map +1 -1
  31. package/dist/modules/app/lib/app-template-resolver.d.ts +14 -0
  32. package/dist/modules/app/lib/app-template-resolver.d.ts.map +1 -0
  33. package/dist/modules/app/lib/app-template-resolver.js +51 -0
  34. package/dist/modules/app/lib/app-template-resolver.js.map +1 -0
  35. package/dist/modules/app/lib/manifest-schema.d.ts +0 -7
  36. package/dist/modules/app/lib/manifest-schema.d.ts.map +1 -1
  37. package/dist/modules/app/lib/manifest-schema.js +0 -2
  38. package/dist/modules/app/lib/manifest-schema.js.map +1 -1
  39. package/dist/modules/app/services/app-svc.d.ts +2 -1
  40. package/dist/modules/app/services/app-svc.d.ts.map +1 -1
  41. package/dist/modules/app/services/app-svc.js +77 -12
  42. package/dist/modules/app/services/app-svc.js.map +1 -1
  43. package/dist/modules/app/services/manifest-svc.d.ts +2 -2
  44. package/dist/modules/app/services/manifest-svc.d.ts.map +1 -1
  45. package/dist/modules/app/services/manifest-svc.js +9 -50
  46. package/dist/modules/app/services/manifest-svc.js.map +1 -1
  47. package/dist/modules/app/types/app-types.d.ts +2 -5
  48. package/dist/modules/app/types/app-types.d.ts.map +1 -1
  49. package/dist/modules/app/types/app-types.js +1 -4
  50. package/dist/modules/app/types/app-types.js.map +1 -1
  51. package/dist/modules/catalog/commands/scan.js +3 -3
  52. package/dist/modules/catalog/commands/scan.js.map +1 -1
  53. package/dist/modules/catalog/services/catalog-svc.d.ts +2 -2
  54. package/dist/modules/catalog/services/catalog-svc.d.ts.map +1 -1
  55. package/dist/modules/catalog/services/catalog-svc.js +2 -2
  56. package/dist/modules/catalog/services/catalog-svc.js.map +1 -1
  57. package/dist/modules/deploy/commands/deploy-init-action.d.ts.map +1 -1
  58. package/dist/modules/deploy/commands/deploy-init-action.js +21 -20
  59. package/dist/modules/deploy/commands/deploy-init-action.js.map +1 -1
  60. package/dist/modules/deploy/commands/deploy-logs-action.d.ts.map +1 -1
  61. package/dist/modules/deploy/commands/deploy-logs-action.js +16 -13
  62. package/dist/modules/deploy/commands/deploy-logs-action.js.map +1 -1
  63. package/dist/modules/deploy/commands/deploy-status-action.d.ts.map +1 -1
  64. package/dist/modules/deploy/commands/deploy-status-action.js +16 -13
  65. package/dist/modules/deploy/commands/deploy-status-action.js.map +1 -1
  66. package/dist/modules/plugin/lib/plugin-resolver.d.ts +10 -72
  67. package/dist/modules/plugin/lib/plugin-resolver.d.ts.map +1 -1
  68. package/dist/modules/plugin/lib/plugin-resolver.js +23 -115
  69. package/dist/modules/plugin/lib/plugin-resolver.js.map +1 -1
  70. package/dist/modules/plugin/lib/plugin-resolver.test.js +45 -39
  71. package/dist/modules/plugin/lib/plugin-resolver.test.js.map +1 -1
  72. package/dist/modules/plugin/services/plugin-svc.d.ts +2 -0
  73. package/dist/modules/plugin/services/plugin-svc.d.ts.map +1 -1
  74. package/dist/modules/plugin/services/plugin-svc.js +24 -19
  75. package/dist/modules/plugin/services/plugin-svc.js.map +1 -1
  76. package/dist/modules/plugin/services/plugin-svc.test.js +12 -6
  77. package/dist/modules/plugin/services/plugin-svc.test.js.map +1 -1
  78. package/dist/templates/plugin/package.json.hbs +1 -1
  79. package/dist/templates/plugin/plugin.json.hbs +1 -3
  80. package/dist/utils/validation.d.ts +3 -7
  81. package/dist/utils/validation.d.ts.map +1 -1
  82. package/dist/utils/validation.js +7 -31
  83. package/dist/utils/validation.js.map +1 -1
  84. package/package.json +1 -1
  85. package/src/cli.ts +1 -4
  86. package/src/infrastructure/npm-package.ts +73 -0
  87. package/src/infrastructure/package-resolver.test.ts +313 -0
  88. package/src/infrastructure/package-resolver.ts +223 -0
  89. package/src/infrastructure/template.ts +0 -1
  90. package/src/modules/app/commands/create-app.ts +14 -18
  91. package/src/modules/app/commands/delete-app.ts +1 -1
  92. package/src/modules/app/commands/validate-manifest.ts +0 -1
  93. package/src/modules/app/index.ts +1 -2
  94. package/src/modules/app/lib/app-template-resolver.ts +56 -0
  95. package/src/modules/app/lib/manifest-schema.ts +0 -5
  96. package/src/modules/app/services/app-svc.ts +89 -13
  97. package/src/modules/app/services/manifest-svc.ts +8 -57
  98. package/src/modules/app/types/app-types.ts +2 -9
  99. package/src/modules/catalog/commands/scan.ts +3 -3
  100. package/src/modules/catalog/services/catalog-svc.ts +4 -4
  101. package/src/modules/deploy/commands/deploy-init-action.ts +23 -20
  102. package/src/modules/deploy/commands/deploy-logs-action.ts +19 -13
  103. package/src/modules/deploy/commands/deploy-status-action.ts +19 -13
  104. package/src/modules/plugin/lib/plugin-resolver.test.ts +48 -39
  105. package/src/modules/plugin/lib/plugin-resolver.ts +22 -141
  106. package/src/modules/plugin/services/plugin-svc.test.ts +12 -6
  107. package/src/modules/plugin/services/plugin-svc.ts +27 -18
  108. package/src/utils/validation.ts +10 -38
  109. package/templates/plugin/package.json.hbs +1 -1
  110. package/templates/plugin/plugin.json.hbs +1 -3
  111. package/dist/modules/app/commands/generate-manifest.d.ts +0 -3
  112. package/dist/modules/app/commands/generate-manifest.d.ts.map +0 -1
  113. package/dist/modules/app/commands/generate-manifest.js +0 -62
  114. package/dist/modules/app/commands/generate-manifest.js.map +0 -1
  115. package/dist/modules/startup/commands/create-startup.d.ts +0 -3
  116. package/dist/modules/startup/commands/create-startup.d.ts.map +0 -1
  117. package/dist/modules/startup/commands/create-startup.js +0 -43
  118. package/dist/modules/startup/commands/create-startup.js.map +0 -1
  119. package/dist/modules/startup/errors/startup-errors.d.ts +0 -13
  120. package/dist/modules/startup/errors/startup-errors.d.ts.map +0 -1
  121. package/dist/modules/startup/errors/startup-errors.js +0 -25
  122. package/dist/modules/startup/errors/startup-errors.js.map +0 -1
  123. package/dist/modules/startup/index.d.ts +0 -5
  124. package/dist/modules/startup/index.d.ts.map +0 -1
  125. package/dist/modules/startup/index.js +0 -7
  126. package/dist/modules/startup/index.js.map +0 -1
  127. package/dist/modules/startup/services/startup-service.d.ts +0 -7
  128. package/dist/modules/startup/services/startup-service.d.ts.map +0 -1
  129. package/dist/modules/startup/services/startup-service.js +0 -43
  130. package/dist/modules/startup/services/startup-service.js.map +0 -1
  131. package/dist/modules/startup/types/startup-types.d.ts +0 -8
  132. package/dist/modules/startup/types/startup-types.d.ts.map +0 -1
  133. package/dist/modules/startup/types/startup-types.js +0 -2
  134. package/dist/modules/startup/types/startup-types.js.map +0 -1
  135. package/dist/modules/startup/utils/startup-validators.d.ts +0 -8
  136. package/dist/modules/startup/utils/startup-validators.d.ts.map +0 -1
  137. package/dist/modules/startup/utils/startup-validators.js +0 -17
  138. package/dist/modules/startup/utils/startup-validators.js.map +0 -1
  139. package/dist/templates/startup/apps/.gitkeep +0 -8
  140. package/dist/utils/monorepo.d.ts +0 -19
  141. package/dist/utils/monorepo.d.ts.map +0 -1
  142. package/dist/utils/monorepo.js +0 -100
  143. package/dist/utils/monorepo.js.map +0 -1
  144. package/src/modules/app/commands/generate-manifest.ts +0 -75
  145. package/src/modules/startup/commands/create-startup.ts +0 -53
  146. package/src/modules/startup/errors/startup-errors.ts +0 -23
  147. package/src/modules/startup/index.ts +0 -11
  148. package/src/modules/startup/services/startup-service.ts +0 -57
  149. package/src/modules/startup/types/startup-types.ts +0 -8
  150. package/src/modules/startup/utils/startup-validators.ts +0 -19
  151. package/src/utils/monorepo.ts +0 -137
  152. package/templates/startup/apps/.gitkeep +0 -8
@@ -0,0 +1,56 @@
1
+ import * as path from 'path'
2
+
3
+ import fs from 'fs-extra'
4
+
5
+ import { PackageResolver } from '../../../infrastructure/package-resolver.js'
6
+
7
+ /**
8
+ * App template resolver implementation
9
+ *
10
+ * Resolves app templates from:
11
+ * - Local workspace app-templates/ directory
12
+ * - npm packages with @launch77-shared/app-template- prefix
13
+ */
14
+ export class AppTemplateResolver extends PackageResolver {
15
+ protected getFolderName(): string {
16
+ return 'app-templates'
17
+ }
18
+
19
+ protected getPackagePrefix(): string {
20
+ return '@launch77-shared/app-template-'
21
+ }
22
+
23
+ protected async verify(localPath: string): Promise<boolean> {
24
+ // All Launch77 packages must have package.json with version
25
+ const hasPackageJson = await fs.pathExists(path.join(localPath, 'package.json'))
26
+ if (!hasPackageJson) {
27
+ return false
28
+ }
29
+
30
+ // Verify package.json has a version field
31
+ try {
32
+ const packageJson = await fs.readJson(path.join(localPath, 'package.json'))
33
+ if (!packageJson.version) {
34
+ return false
35
+ }
36
+ } catch {
37
+ return false
38
+ }
39
+
40
+ // Check for either:
41
+ // 1. A 'template' subdirectory (preferred structure for npm packages)
42
+ // 2. Any files at the root (simple local templates)
43
+ const hasTemplateDir = await fs.pathExists(path.join(localPath, 'template'))
44
+ if (hasTemplateDir) {
45
+ return true
46
+ }
47
+
48
+ // Check if directory has any files (not just an empty directory)
49
+ try {
50
+ const files = await fs.readdir(localPath)
51
+ return files.length > 0
52
+ } catch {
53
+ return false
54
+ }
55
+ }
56
+ }
@@ -1,7 +1,5 @@
1
1
  import { z } from 'zod'
2
2
 
3
- import type { AppType } from '../types/app-types.js'
4
-
5
3
  // Deployment configuration
6
4
  export type DeploymentConfig = {
7
5
  platform: 'vercel'
@@ -14,7 +12,6 @@ export type DeploymentConfig = {
14
12
  export type AppManifest = {
15
13
  schemaVersion: 1
16
14
  name: string
17
- type: AppType | 'marketing' // Support both 'marketing' and 'marketing-site'
18
15
  package: string
19
16
  deployment?: DeploymentConfig
20
17
  }
@@ -28,12 +25,10 @@ const deploymentConfigZ = z.object({
28
25
  })
29
26
 
30
27
  // Main manifest schema - strict mode to reject extra fields
31
- // Note: Manifests store 'marketing' but we accept 'marketing-site' in commands
32
28
  export const manifestZ = z
33
29
  .object({
34
30
  schemaVersion: z.literal(1),
35
31
  name: z.string().min(1),
36
- type: z.enum(['marketing', 'webapp', 'api']),
37
32
  package: z.string().min(1),
38
33
  deployment: deploymentConfigZ.optional(),
39
34
  })
@@ -1,23 +1,27 @@
1
1
  import * as path from 'path'
2
2
 
3
3
  import fs from 'fs-extra'
4
+ import { readTemplateMetadata } from '@launch77/plugin-runtime'
4
5
 
5
6
  import { ManifestService } from './manifest-svc.js'
6
7
  import * as filesystem from '../../../infrastructure/filesystem.js'
7
8
  import * as npm from '../../../infrastructure/npm.js'
8
- import { generateFromTemplate } from '../../../infrastructure/template-generator.js'
9
- import { templateExists } from '../../../infrastructure/template.js'
9
+ import { downloadNpmPackage } from '../../../infrastructure/npm-package.js'
10
+ import { processTemplate } from '../../../infrastructure/template.js'
10
11
  import { validateWorkspaceContext } from '../../../utils/launch77-validation.js'
11
12
  import { validateAppName } from '../../../utils/validation.js'
13
+ import { AppTemplateResolver } from '../lib/app-template-resolver.js'
12
14
 
13
- import type { Launch77Context } from '@launch77/plugin-runtime'
14
15
  import type { CreateAppRequest, CreateAppResult, DeleteAppRequest, DeleteAppResult } from '../types/app-types.js'
16
+ import type { Launch77Context, TemplateReference, Launch77PackageManifest } from '@launch77/plugin-runtime'
15
17
 
16
18
  export class AppService {
17
19
  private manifestService: ManifestService
20
+ private appTemplateResolver: AppTemplateResolver
18
21
 
19
22
  constructor() {
20
23
  this.manifestService = new ManifestService()
24
+ this.appTemplateResolver = new AppTemplateResolver()
21
25
  }
22
26
 
23
27
  /**
@@ -38,30 +42,102 @@ export class AppService {
38
42
  throw new Error(contextValidation.errorMessage)
39
43
  }
40
44
 
41
- // 3. Determine app path
45
+ // 3. Validate template name
46
+ const templateValidation = this.appTemplateResolver.validateInput(type)
47
+ if (!templateValidation.isValid) {
48
+ throw new Error(templateValidation.error || `Invalid template name: ${type}`)
49
+ }
50
+
51
+ // 4. Resolve template location
52
+ const templateResolution = await this.appTemplateResolver.resolveLocation(type, context.workspaceRoot)
53
+
54
+ let templatePath: string
55
+ let templateVersion: string
56
+ let packageRootPath: string
57
+
58
+ if (templateResolution.source === 'local') {
59
+ // Use local template
60
+ packageRootPath = templateResolution.localPath!
61
+ templatePath = packageRootPath
62
+ templateVersion = templateResolution.version! // Local templates always have version after verification
63
+ } else {
64
+ // Download npm template
65
+ const downloadResult = await downloadNpmPackage({
66
+ packageName: templateResolution.npmPackage!,
67
+ workspaceRoot: context.workspaceRoot,
68
+ })
69
+
70
+ packageRootPath = downloadResult.packagePath
71
+
72
+ // Check if template has a 'template' subdirectory, otherwise use package root
73
+ const templateSubdir = path.join(packageRootPath, 'template')
74
+ if (await fs.pathExists(templateSubdir)) {
75
+ templatePath = templateSubdir
76
+ } else {
77
+ templatePath = packageRootPath
78
+ }
79
+
80
+ // Read version from downloaded package
81
+ const packageJsonPath = path.join(packageRootPath, 'package.json')
82
+ const packageJson = await fs.readJson(packageJsonPath)
83
+ templateVersion = packageJson.version
84
+ }
85
+
86
+ // 5. Determine app path
42
87
  const appPath = path.join(context.appsDir, appName)
43
88
 
44
- // 4. Check if app already exists
89
+ // 6. Check if app already exists
45
90
  if (await fs.pathExists(appPath)) {
46
91
  throw new Error(`App ${appName} already exists at ${appPath}`)
47
92
  }
48
93
 
49
- // 5. Validate template exists
50
- if (!(await templateExists(type))) {
51
- throw new Error(`Unknown app type: ${type}. Currently supported: api, webapp, marketing-site`)
94
+ // 7. Verify template path exists
95
+ if (!(await fs.pathExists(templatePath))) {
96
+ throw new Error(`Template not found at: ${templatePath}`)
97
+ }
98
+
99
+ // 8. Generate from template (context already has packageName computed)
100
+ await processTemplate(templatePath, appPath, {
101
+ appName,
102
+ workspaceName: context.workspaceName,
103
+ packageName: context.packageName,
104
+ port,
105
+ })
106
+
107
+ // 9. Read template metadata (currently empty, placeholder for future config)
108
+ //const templateMetadata = await readTemplateMetadata(templatePath)
109
+
110
+ // 10. Write template reference to app's package.json
111
+ const appPackageJsonPath = path.join(appPath, 'package.json')
112
+ const appPackageJson = await fs.readJson(appPackageJsonPath)
113
+
114
+ // Build template reference - version read from package.json
115
+ const templatePackage = templateResolution.source === 'npm' ? templateResolution.npmPackage! : templateResolution.resolvedName
116
+ const templateRef: TemplateReference = {
117
+ package: templatePackage,
118
+ version: templateVersion,
119
+ source: templateResolution.source,
120
+ createdAt: new Date().toISOString(),
121
+ }
122
+
123
+ // Initialize launch77 manifest structure
124
+ if (!appPackageJson.launch77) {
125
+ appPackageJson.launch77 = {}
52
126
  }
127
+ const launch77Manifest = appPackageJson.launch77 as Launch77PackageManifest
128
+ launch77Manifest.template = templateRef
53
129
 
54
- // 6. Generate from template (context already has packageName computed)
55
- await generateFromTemplate(type, appPath, appName, context, { port })
130
+ // Write updated package.json
131
+ await fs.writeJson(appPackageJsonPath, appPackageJson, { spaces: 2 })
56
132
 
57
- // 7. Generate and write app manifest
58
- const manifest = this.manifestService.generateManifest(type, appName, context, { port })
133
+ // 11. Generate and write app manifest
134
+ const manifest = this.manifestService.generateManifest(appName, context, { port })
59
135
  const launchDir = path.join(appPath, '.launch')
60
136
  await filesystem.ensureDir(launchDir)
61
137
  const manifestPath = path.join(launchDir, 'app.json')
62
138
  await filesystem.writeJSON(manifestPath, manifest)
63
139
 
64
- // 8. Install dependencies
140
+ // 12. Install dependencies
65
141
  await npm.install(context.workspaceRoot)
66
142
 
67
143
  return {
@@ -8,7 +8,7 @@ import type { AppManifest } from '../lib/manifest-schema.js'
8
8
 
9
9
  /**
10
10
  * Convert kebab-case to Title Case
11
- * e.g., "my-startup-name" -> "My Startup Name"
11
+ * e.g., "my-workspace-name" -> "My Workspace Name"
12
12
  */
13
13
  function toTitleCase(str: string): string {
14
14
  return str
@@ -17,66 +17,17 @@ function toTitleCase(str: string): string {
17
17
  .join(' ')
18
18
  }
19
19
 
20
- /**
21
- * Generate a manifest for a marketing app
22
- */
23
- function generateMarketingManifest(appName: string, context: Launch77Context): AppManifest {
24
- const workspaceName = context.workspaceName
25
-
26
- return {
27
- schemaVersion: 1,
28
- name: `${toTitleCase(workspaceName)} Marketing`,
29
- type: 'marketing',
30
- package: `@${workspaceName}/${appName}`,
31
- }
32
- }
33
-
34
- /**
35
- * Generate a manifest for a webapp
36
- */
37
- function generateWebappManifest(appName: string, context: Launch77Context): AppManifest {
38
- const workspaceName = context.workspaceName
39
-
40
- return {
41
- schemaVersion: 1,
42
- name: `${toTitleCase(workspaceName)} Web`,
43
- type: 'webapp',
44
- package: `@${workspaceName}/${appName}`,
45
- }
46
- }
47
-
48
- /**
49
- * Generate a manifest for an API app
50
- */
51
- function generateApiManifest(appName: string, context: Launch77Context): AppManifest {
52
- const workspaceName = context.workspaceName
53
-
54
- return {
55
- schemaVersion: 1,
56
- name: `${toTitleCase(workspaceName)} API`,
57
- type: 'api',
58
- package: `@${workspaceName}/${appName}`,
59
- }
60
- }
61
-
62
20
  export class ManifestService {
63
21
  /**
64
- * Generate an app manifest based on app type
22
+ * Generate an app manifest
65
23
  */
66
- generateManifest(type: string, appName: string, context: Launch77Context, _options: { port?: string }): AppManifest {
67
- switch (type) {
68
- case 'marketing-site':
69
- case 'marketing':
70
- return generateMarketingManifest(appName, context)
71
-
72
- case 'webapp':
73
- return generateWebappManifest(appName, context)
74
-
75
- case 'api':
76
- return generateApiManifest(appName, context)
24
+ generateManifest(appName: string, context: Launch77Context, _options: { port?: string }): AppManifest {
25
+ const workspaceName = context.workspaceName
77
26
 
78
- default:
79
- throw new Error(`Unsupported app type for manifest generation: ${type}. Supported types: api, webapp, marketing-site`)
27
+ return {
28
+ schemaVersion: 1,
29
+ name: toTitleCase(workspaceName),
30
+ package: `@${workspaceName}/${appName}`,
80
31
  }
81
32
  }
82
33
 
@@ -1,12 +1,5 @@
1
- // Supported app types
2
- export const APP_TYPES = ['api', 'webapp', 'marketing-site'] as const
3
- export type AppType = (typeof APP_TYPES)[number]
4
-
5
- // Display list for error messages
6
- export const APP_TYPES_LIST = APP_TYPES.join(', ')
7
-
8
1
  export interface CreateAppRequest {
9
- type: AppType
2
+ type: string
10
3
  appName: string
11
4
  port: string
12
5
  }
@@ -14,7 +7,7 @@ export interface CreateAppRequest {
14
7
  export interface CreateAppResult {
15
8
  appPath: string
16
9
  appName: string
17
- type: AppType
10
+ type: string
18
11
  }
19
12
 
20
13
  export interface DeleteAppRequest {
@@ -1,7 +1,7 @@
1
1
  import chalk from 'chalk'
2
2
  import { Command } from 'commander'
3
+ import { detectLaunch77Context } from '@launch77/plugin-runtime'
3
4
 
4
- import { detectMonorepoContext } from '../../../utils/monorepo.js'
5
5
  import { CatalogService } from '../services/catalog-svc.js'
6
6
 
7
7
  /**
@@ -17,10 +17,10 @@ export function scanCommand(): Command {
17
17
  .option('--quiet', 'Suppress quality report output')
18
18
  .action(async (options) => {
19
19
  try {
20
- const context = await detectMonorepoContext(process.cwd())
20
+ const context = await detectLaunch77Context(process.cwd())
21
21
 
22
22
  if (!context.isValid) {
23
- console.error(chalk.red('\n✖ Must be run from within a Launch77 monorepo\n'))
23
+ console.error(chalk.red('\n✖ Must be run from within a Launch77 workspace\n'))
24
24
  process.exit(1)
25
25
  }
26
26
 
@@ -9,7 +9,7 @@ import { scanUILibrary } from '../scanners/ui-component-scanner.js'
9
9
  import { generateExamplesFiles } from '../utils/examples-generator.js'
10
10
  import { generateQualityReport, printQualityReport } from '../utils/quality-reporter.js'
11
11
 
12
- import type { MonorepoContext } from '../../../utils/monorepo.js'
12
+ import type { Launch77Context } from '@launch77/plugin-runtime'
13
13
  import type { ValidationResult, UiComponent } from '../types/catalog-types.js'
14
14
 
15
15
  export interface ScanCatalogOptions {
@@ -32,13 +32,13 @@ export class CatalogService {
32
32
  /**
33
33
  * Scan Launch77 codebase and generate catalog.json
34
34
  */
35
- async scanCatalog(context: MonorepoContext, options: ScanCatalogOptions = {}): Promise<ScanCatalogResult> {
35
+ async scanCatalog(context: Launch77Context, options: ScanCatalogOptions = {}): Promise<ScanCatalogResult> {
36
36
  const strict = options.strict !== false // Default to true (strict mode)
37
37
  const quiet = options.quiet || false
38
38
 
39
39
  console.log(chalk.blue('\n🔍 Scanning Launch77 artifacts...\n'))
40
40
 
41
- const launch77Root = path.join(context.monorepoRoot, 'launch77')
41
+ const launch77Root = path.join(context.workspaceRoot, 'launch77')
42
42
 
43
43
  const spinner = ora('Scanning codebase...').start()
44
44
 
@@ -109,7 +109,7 @@ export class CatalogService {
109
109
  console.log(chalk.green(` ✓ Saved to ${path.relative(process.cwd(), catalogPath)}`))
110
110
 
111
111
  // Sync catalog to Launch77 marketing site
112
- const marketingSiteCatalogPath = path.join(context.monorepoRoot, 'startups/launch77/apps/marketing/src/catalog.json')
112
+ const marketingSiteCatalogPath = path.join(context.workspaceRoot, 'apps/marketing/src/catalog.json')
113
113
 
114
114
  if (await fs.pathExists(path.dirname(marketingSiteCatalogPath))) {
115
115
  await fs.writeFile(marketingSiteCatalogPath, formatted)
@@ -6,10 +6,10 @@
6
6
  import * as path from 'path'
7
7
 
8
8
  import chalk from 'chalk'
9
+ import { detectLaunch77Context } from '@launch77/plugin-runtime'
9
10
  import fs from 'fs-extra'
10
11
  import ora from 'ora'
11
12
 
12
- import { detectMonorepoContext } from '../../../utils/monorepo.js'
13
13
  import { DeployService } from '../services/deploy-svc.js'
14
14
  import { connectGitRepository, getPackageName, getVercelInstallInstructions, isVercelCliInstalled, loadVercelProject, runVercelCommand, updateProjectRootDirectory, verifyVercelProjectExists } from '../utils/vercel-extended.js'
15
15
 
@@ -23,16 +23,15 @@ interface DeployInitOptions {
23
23
  export async function deployInit(options: DeployInitOptions = {}) {
24
24
  const deployService = new DeployService()
25
25
 
26
- // Detect monorepo context
27
- const context = await detectMonorepoContext(process.cwd())
26
+ // Detect Launch77 context
27
+ const context = await detectLaunch77Context(process.cwd())
28
28
 
29
- if (context.location !== 'startup-app') {
30
- throw new Error('Must be run from within an app directory (e.g., startups/mycompany/apps/myapp)')
29
+ if (context.locationType !== 'workspace-app') {
30
+ throw new Error('Must be run from within an app directory (e.g., apps/myapp)')
31
31
  }
32
32
 
33
33
  const appPath = process.cwd()
34
34
  const appName = context.appName!
35
- const startupName = context.startupName!
36
35
 
37
36
  console.log(chalk.blue(`\n🚀 Initializing Vercel deployment for ${appName}...\n`))
38
37
 
@@ -116,23 +115,27 @@ export async function deployInit(options: DeployInitOptions = {}) {
116
115
  throw new Error('Could not read package name from package.json')
117
116
  }
118
117
 
118
+ // Check template type from app's package.json
119
+ const appPackageJsonPath = path.join(appPath, 'package.json')
120
+ const appPackageJson = await fs.readJson(appPackageJsonPath)
121
+ const templatePackage = appPackageJson.launch77?.template?.package
122
+
119
123
  console.log(chalk.gray(`App details:`))
120
124
  console.log(chalk.gray(` Name: ${manifest.name}`))
121
- console.log(chalk.gray(` Type: ${manifest.type}`))
122
125
  console.log(chalk.gray(` Package: ${packageName}`))
126
+ if (templatePackage) {
127
+ console.log(chalk.gray(` Template: ${templatePackage}`))
128
+ }
123
129
  console.log()
124
130
 
125
- // Check if this is an API app - Railway deployment coming soon
126
- if (manifest.type === 'api') {
127
- console.log(chalk.yellow('⚠️ Railway deployments for API apps are not yet supported'))
128
- console.log()
129
- console.log(chalk.cyan('Coming soon! For now, you can deploy manually to:'))
130
- console.log(chalk.white(' Railway.app'), chalk.gray('- Simple deployment with databases'))
131
- console.log(chalk.white(' • Fly.io'), chalk.gray('- Global edge deployment'))
132
- console.log(chalk.white(' • Render.com'), chalk.gray('- Managed cloud hosting'))
131
+ // Only allow webapp apps to deploy to Vercel
132
+ const isWebapp = templatePackage === 'webapp' || templatePackage === '@launch77-shared/app-template-webapp'
133
+
134
+ if (!isWebapp) {
135
+ console.log(chalk.yellow('⚠️ Vercel deployment only supports webapp apps'))
136
+ console.log(chalk.gray('Other app types coming soon'))
133
137
  console.log()
134
- console.log(chalk.gray('Stay tuned for automated Railway deployment support!'))
135
- process.exit(0)
138
+ process.exit(1)
136
139
  }
137
140
 
138
141
  // Check if vercel.json exists
@@ -160,7 +163,7 @@ export async function deployInit(options: DeployInitOptions = {}) {
160
163
  console.log()
161
164
 
162
165
  try {
163
- const suggestedProjectName = `${startupName}--${appName}`
166
+ const suggestedProjectName = appName
164
167
  await runVercelCommand(['link', '--project', suggestedProjectName, '--yes'], appPath)
165
168
 
166
169
  console.log()
@@ -172,7 +175,7 @@ export async function deployInit(options: DeployInitOptions = {}) {
172
175
 
173
176
  // Read the created .vercel/project.json to get project info
174
177
  const vercelProject = await loadVercelProject(appPath)
175
- const projectName = vercelProject?.projectName || `${startupName}--${appName}`
178
+ const projectName = vercelProject?.projectName || appName
176
179
 
177
180
  // Update manifest with deployment configuration
178
181
  manifest.deployment = {
@@ -187,7 +190,7 @@ export async function deployInit(options: DeployInitOptions = {}) {
187
190
 
188
191
  // Set Root Directory for monorepo deployments
189
192
  console.log()
190
- const rootDirectory = `startups/${startupName}/apps/${appName}`
193
+ const rootDirectory = `apps/${appName}`
191
194
  await updateProjectRootDirectory(projectName, rootDirectory)
192
195
 
193
196
  // Automatically connect to Git repository
@@ -3,9 +3,12 @@
3
3
  */
4
4
 
5
5
  /* eslint-disable no-console */
6
+ import * as path from 'path'
7
+
6
8
  import chalk from 'chalk'
9
+ import { detectLaunch77Context } from '@launch77/plugin-runtime'
10
+ import fs from 'fs-extra'
7
11
 
8
- import { detectMonorepoContext } from '../../../utils/monorepo.js'
9
12
  import { DeployService } from '../services/deploy-svc.js'
10
13
  import { getVercelInstallInstructions, isVercelCliInstalled, runVercelCommand } from '../utils/vercel-extended.js'
11
14
 
@@ -20,11 +23,11 @@ export interface DeployLogsOptions {
20
23
  export async function deployLogs(options: DeployLogsOptions) {
21
24
  const deployService = new DeployService()
22
25
 
23
- // Detect monorepo context
24
- const context = await detectMonorepoContext(process.cwd())
26
+ // Detect Launch77 context
27
+ const context = await detectLaunch77Context(process.cwd())
25
28
 
26
- if (context.location !== 'startup-app') {
27
- throw new Error('Must be run from within an app directory (e.g., startups/mycompany/apps/myapp)')
29
+ if (context.locationType !== 'workspace-app') {
30
+ throw new Error('Must be run from within an app directory (e.g., apps/myapp)')
28
31
  }
29
32
 
30
33
  const appPath = process.cwd()
@@ -34,14 +37,17 @@ export async function deployLogs(options: DeployLogsOptions) {
34
37
  // Load manifest
35
38
  const manifest = await deployService.loadManifest()
36
39
 
37
- // Check if this is an API app
38
- if (manifest.type === 'api') {
39
- console.log(chalk.yellow('⚠️ Railway deployments for API apps are not yet supported'))
40
- console.log()
41
- console.log(chalk.cyan('Coming soon! For now, you can view logs at:'))
42
- console.log(chalk.white(' Railway.app dashboard'))
43
- console.log(chalk.white(' Fly.io dashboard'))
44
- console.log(chalk.white(' • Render.com dashboard'))
40
+ // Check template type from app's package.json
41
+ const appPackageJsonPath = path.join(appPath, 'package.json')
42
+ const appPackageJson = await fs.readJson(appPackageJsonPath)
43
+ const templatePackage = appPackageJson.launch77?.template?.package
44
+
45
+ // Only allow webapp apps to deploy to Vercel
46
+ const isWebapp = templatePackage === 'webapp' || templatePackage === '@launch77-shared/app-template-webapp'
47
+
48
+ if (!isWebapp) {
49
+ console.log(chalk.yellow('⚠️ Vercel deployment only supports webapp apps'))
50
+ console.log(chalk.gray('Other app types coming soon'))
45
51
  console.log()
46
52
  return
47
53
  }
@@ -3,10 +3,13 @@
3
3
  */
4
4
 
5
5
  /* eslint-disable no-console */
6
+ import * as path from 'path'
7
+
6
8
  import chalk from 'chalk'
9
+ import { detectLaunch77Context } from '@launch77/plugin-runtime'
10
+ import fs from 'fs-extra'
7
11
  import ora from 'ora'
8
12
 
9
- import { detectMonorepoContext } from '../../../utils/monorepo.js'
10
13
  import { DeployService } from '../services/deploy-svc.js'
11
14
  import { getVercelInstallInstructions, isVercelCliInstalled, runVercelCommand, verifyVercelProjectExists } from '../utils/vercel-extended.js'
12
15
 
@@ -16,11 +19,11 @@ import { getVercelInstallInstructions, isVercelCliInstalled, runVercelCommand, v
16
19
  export async function deployStatus() {
17
20
  const deployService = new DeployService()
18
21
 
19
- // Detect monorepo context
20
- const context = await detectMonorepoContext(process.cwd())
22
+ // Detect Launch77 context
23
+ const context = await detectLaunch77Context(process.cwd())
21
24
 
22
- if (context.location !== 'startup-app') {
23
- throw new Error('Must be run from within an app directory (e.g., startups/mycompany/apps/myapp)')
25
+ if (context.locationType !== 'workspace-app') {
26
+ throw new Error('Must be run from within an app directory (e.g., apps/myapp)')
24
27
  }
25
28
 
26
29
  const appPath = process.cwd()
@@ -30,14 +33,17 @@ export async function deployStatus() {
30
33
  // Load manifest
31
34
  const manifest = await deployService.loadManifest()
32
35
 
33
- // Check if this is an API app
34
- if (manifest.type === 'api') {
35
- console.log(chalk.yellow('⚠️ Railway deployments for API apps are not yet supported'))
36
- console.log()
37
- console.log(chalk.cyan('Coming soon! For now, you can check your deployment status at:'))
38
- console.log(chalk.white(' Railway.app dashboard'))
39
- console.log(chalk.white(' Fly.io dashboard'))
40
- console.log(chalk.white(' • Render.com dashboard'))
36
+ // Check template type from app's package.json
37
+ const appPackageJsonPath = path.join(appPath, 'package.json')
38
+ const appPackageJson = await fs.readJson(appPackageJsonPath)
39
+ const templatePackage = appPackageJson.launch77?.template?.package
40
+
41
+ // Only allow webapp apps to deploy to Vercel
42
+ const isWebapp = templatePackage === 'webapp' || templatePackage === '@launch77-shared/app-template-webapp'
43
+
44
+ if (!isWebapp) {
45
+ console.log(chalk.yellow('⚠️ Vercel deployment only supports webapp apps'))
46
+ console.log(chalk.gray('Other app types coming soon'))
41
47
  console.log()
42
48
  return
43
49
  }