@friggframework/devtools 2.0.0--canary.400.bed3308.0 → 2.0.0--canary.404.e9d4980.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 (182) hide show
  1. package/frigg-cli/build-command/index.js +3 -18
  2. package/frigg-cli/deploy-command/index.js +3 -19
  3. package/frigg-cli/index.js +1 -73
  4. package/frigg-cli/install-command/index.js +2 -15
  5. package/frigg-cli/start-command/index.js +2 -17
  6. package/infrastructure/create-frigg-infrastructure.js +2 -2
  7. package/infrastructure/serverless-template.js +79 -529
  8. package/package.json +5 -9
  9. package/frigg-cli/.eslintrc.js +0 -141
  10. package/frigg-cli/__tests__/jest.config.js +0 -102
  11. package/frigg-cli/__tests__/unit/commands/build.test.js +0 -483
  12. package/frigg-cli/__tests__/unit/commands/install.test.js +0 -418
  13. package/frigg-cli/__tests__/unit/commands/ui.test.js +0 -592
  14. package/frigg-cli/__tests__/utils/command-tester.js +0 -170
  15. package/frigg-cli/__tests__/utils/mock-factory.js +0 -270
  16. package/frigg-cli/__tests__/utils/test-fixtures.js +0 -463
  17. package/frigg-cli/__tests__/utils/test-setup.js +0 -286
  18. package/frigg-cli/generate-command/__tests__/generate-command.test.js +0 -312
  19. package/frigg-cli/generate-command/azure-generator.js +0 -43
  20. package/frigg-cli/generate-command/gcp-generator.js +0 -47
  21. package/frigg-cli/generate-command/index.js +0 -350
  22. package/frigg-cli/generate-command/terraform-generator.js +0 -555
  23. package/frigg-cli/generate-iam-command.js +0 -115
  24. package/frigg-cli/package.json +0 -75
  25. package/frigg-cli/ui-command/index.js +0 -167
  26. package/frigg-cli/utils/app-resolver.js +0 -319
  27. package/frigg-cli/utils/backend-path.js +0 -38
  28. package/frigg-cli/utils/process-manager.js +0 -199
  29. package/frigg-cli/utils/repo-detection.js +0 -405
  30. package/infrastructure/AWS-DISCOVERY-TROUBLESHOOTING.md +0 -245
  31. package/infrastructure/AWS-IAM-CREDENTIAL-NEEDS.md +0 -620
  32. package/infrastructure/DEPLOYMENT-INSTRUCTIONS.md +0 -268
  33. package/infrastructure/GENERATE-IAM-DOCS.md +0 -253
  34. package/infrastructure/IAM-POLICY-TEMPLATES.md +0 -176
  35. package/infrastructure/README-TESTING.md +0 -332
  36. package/infrastructure/README.md +0 -421
  37. package/infrastructure/WEBSOCKET-CONFIGURATION.md +0 -105
  38. package/infrastructure/__tests__/fixtures/mock-aws-resources.js +0 -391
  39. package/infrastructure/__tests__/helpers/test-utils.js +0 -277
  40. package/infrastructure/aws-discovery.js +0 -568
  41. package/infrastructure/aws-discovery.test.js +0 -373
  42. package/infrastructure/build-time-discovery.js +0 -206
  43. package/infrastructure/build-time-discovery.test.js +0 -375
  44. package/infrastructure/frigg-deployment-iam-stack.yaml +0 -393
  45. package/infrastructure/iam-generator.js +0 -810
  46. package/infrastructure/iam-generator.test.js +0 -169
  47. package/infrastructure/iam-policy-basic.json +0 -236
  48. package/infrastructure/iam-policy-full.json +0 -305
  49. package/infrastructure/integration.test.js +0 -383
  50. package/infrastructure/run-discovery.js +0 -110
  51. package/infrastructure/serverless-template.test.js +0 -553
  52. package/management-ui/.eslintrc.js +0 -22
  53. package/management-ui/README.md +0 -203
  54. package/management-ui/components.json +0 -21
  55. package/management-ui/index.html +0 -13
  56. package/management-ui/merge-conflict-cleaner.py +0 -371
  57. package/management-ui/package-lock.json +0 -10997
  58. package/management-ui/package.json +0 -76
  59. package/management-ui/postcss.config.js +0 -6
  60. package/management-ui/server/api/backend.js +0 -256
  61. package/management-ui/server/api/cli.js +0 -315
  62. package/management-ui/server/api/codegen.js +0 -663
  63. package/management-ui/server/api/connections.js +0 -857
  64. package/management-ui/server/api/discovery.js +0 -185
  65. package/management-ui/server/api/environment/index.js +0 -1
  66. package/management-ui/server/api/environment/router.js +0 -378
  67. package/management-ui/server/api/environment.js +0 -328
  68. package/management-ui/server/api/integrations.js +0 -479
  69. package/management-ui/server/api/logs.js +0 -248
  70. package/management-ui/server/api/monitoring.js +0 -282
  71. package/management-ui/server/api/open-ide.js +0 -31
  72. package/management-ui/server/api/project.js +0 -553
  73. package/management-ui/server/api/users/sessions.js +0 -371
  74. package/management-ui/server/api/users/simulation.js +0 -254
  75. package/management-ui/server/api/users.js +0 -362
  76. package/management-ui/server/api-contract.md +0 -275
  77. package/management-ui/server/index.js +0 -428
  78. package/management-ui/server/middleware/errorHandler.js +0 -70
  79. package/management-ui/server/middleware/security.js +0 -32
  80. package/management-ui/server/processManager.js +0 -296
  81. package/management-ui/server/server.js +0 -188
  82. package/management-ui/server/services/aws-monitor.js +0 -413
  83. package/management-ui/server/services/npm-registry.js +0 -347
  84. package/management-ui/server/services/template-engine.js +0 -538
  85. package/management-ui/server/utils/cliIntegration.js +0 -220
  86. package/management-ui/server/utils/environment/auditLogger.js +0 -471
  87. package/management-ui/server/utils/environment/awsParameterStore.js +0 -264
  88. package/management-ui/server/utils/environment/encryption.js +0 -278
  89. package/management-ui/server/utils/environment/envFileManager.js +0 -286
  90. package/management-ui/server/utils/import-commonjs.js +0 -28
  91. package/management-ui/server/utils/response.js +0 -83
  92. package/management-ui/server/websocket/handler.js +0 -325
  93. package/management-ui/src/App.jsx +0 -51
  94. package/management-ui/src/assets/FriggLogo.svg +0 -1
  95. package/management-ui/src/components/AppRouter.jsx +0 -65
  96. package/management-ui/src/components/Button.jsx +0 -2
  97. package/management-ui/src/components/Card.jsx +0 -9
  98. package/management-ui/src/components/EnvironmentCompare.jsx +0 -400
  99. package/management-ui/src/components/EnvironmentEditor.jsx +0 -372
  100. package/management-ui/src/components/EnvironmentImportExport.jsx +0 -469
  101. package/management-ui/src/components/EnvironmentSchema.jsx +0 -491
  102. package/management-ui/src/components/EnvironmentSecurity.jsx +0 -463
  103. package/management-ui/src/components/ErrorBoundary.jsx +0 -73
  104. package/management-ui/src/components/IntegrationCard.jsx +0 -199
  105. package/management-ui/src/components/IntegrationCardEnhanced.jsx +0 -490
  106. package/management-ui/src/components/IntegrationExplorer.jsx +0 -379
  107. package/management-ui/src/components/IntegrationStatus.jsx +0 -235
  108. package/management-ui/src/components/Layout.jsx +0 -250
  109. package/management-ui/src/components/LoadingSpinner.jsx +0 -45
  110. package/management-ui/src/components/RepositoryPicker.jsx +0 -248
  111. package/management-ui/src/components/SessionMonitor.jsx +0 -255
  112. package/management-ui/src/components/StatusBadge.jsx +0 -70
  113. package/management-ui/src/components/UserContextSwitcher.jsx +0 -154
  114. package/management-ui/src/components/UserSimulation.jsx +0 -299
  115. package/management-ui/src/components/Welcome.jsx +0 -434
  116. package/management-ui/src/components/codegen/APIEndpointGenerator.jsx +0 -637
  117. package/management-ui/src/components/codegen/APIModuleSelector.jsx +0 -227
  118. package/management-ui/src/components/codegen/CodeGenerationWizard.jsx +0 -247
  119. package/management-ui/src/components/codegen/CodePreviewEditor.jsx +0 -316
  120. package/management-ui/src/components/codegen/DynamicModuleForm.jsx +0 -271
  121. package/management-ui/src/components/codegen/FormBuilder.jsx +0 -737
  122. package/management-ui/src/components/codegen/IntegrationGenerator.jsx +0 -855
  123. package/management-ui/src/components/codegen/ProjectScaffoldWizard.jsx +0 -797
  124. package/management-ui/src/components/codegen/SchemaBuilder.jsx +0 -303
  125. package/management-ui/src/components/codegen/TemplateSelector.jsx +0 -586
  126. package/management-ui/src/components/codegen/index.js +0 -10
  127. package/management-ui/src/components/connections/ConnectionConfigForm.jsx +0 -362
  128. package/management-ui/src/components/connections/ConnectionHealthMonitor.jsx +0 -182
  129. package/management-ui/src/components/connections/ConnectionTester.jsx +0 -200
  130. package/management-ui/src/components/connections/EntityRelationshipMapper.jsx +0 -292
  131. package/management-ui/src/components/connections/OAuthFlow.jsx +0 -204
  132. package/management-ui/src/components/connections/index.js +0 -5
  133. package/management-ui/src/components/index.js +0 -21
  134. package/management-ui/src/components/monitoring/APIGatewayMetrics.jsx +0 -222
  135. package/management-ui/src/components/monitoring/LambdaMetrics.jsx +0 -169
  136. package/management-ui/src/components/monitoring/MetricsChart.jsx +0 -197
  137. package/management-ui/src/components/monitoring/MonitoringDashboard.jsx +0 -393
  138. package/management-ui/src/components/monitoring/SQSMetrics.jsx +0 -246
  139. package/management-ui/src/components/monitoring/index.js +0 -6
  140. package/management-ui/src/components/monitoring/monitoring.css +0 -218
  141. package/management-ui/src/components/theme-provider.jsx +0 -52
  142. package/management-ui/src/components/theme-toggle.jsx +0 -39
  143. package/management-ui/src/components/ui/badge.tsx +0 -36
  144. package/management-ui/src/components/ui/button.test.jsx +0 -56
  145. package/management-ui/src/components/ui/button.tsx +0 -57
  146. package/management-ui/src/components/ui/card.tsx +0 -76
  147. package/management-ui/src/components/ui/dropdown-menu.tsx +0 -199
  148. package/management-ui/src/components/ui/select.tsx +0 -157
  149. package/management-ui/src/components/ui/skeleton.jsx +0 -15
  150. package/management-ui/src/hooks/useFrigg.jsx +0 -387
  151. package/management-ui/src/hooks/useSocket.jsx +0 -58
  152. package/management-ui/src/index.css +0 -194
  153. package/management-ui/src/lib/utils.ts +0 -6
  154. package/management-ui/src/main.jsx +0 -10
  155. package/management-ui/src/pages/CodeGeneration.jsx +0 -14
  156. package/management-ui/src/pages/Connections.jsx +0 -252
  157. package/management-ui/src/pages/ConnectionsEnhanced.jsx +0 -427
  158. package/management-ui/src/pages/Dashboard.jsx +0 -311
  159. package/management-ui/src/pages/Environment.jsx +0 -314
  160. package/management-ui/src/pages/IntegrationConfigure.jsx +0 -544
  161. package/management-ui/src/pages/IntegrationDiscovery.jsx +0 -479
  162. package/management-ui/src/pages/IntegrationTest.jsx +0 -494
  163. package/management-ui/src/pages/Integrations.jsx +0 -254
  164. package/management-ui/src/pages/Monitoring.jsx +0 -17
  165. package/management-ui/src/pages/Simulation.jsx +0 -155
  166. package/management-ui/src/pages/Users.jsx +0 -492
  167. package/management-ui/src/services/api.js +0 -41
  168. package/management-ui/src/services/apiModuleService.js +0 -193
  169. package/management-ui/src/services/websocket-handlers.js +0 -120
  170. package/management-ui/src/test/api/project.test.js +0 -273
  171. package/management-ui/src/test/components/Welcome.test.jsx +0 -378
  172. package/management-ui/src/test/mocks/server.js +0 -178
  173. package/management-ui/src/test/setup.js +0 -61
  174. package/management-ui/src/test/utils/test-utils.jsx +0 -134
  175. package/management-ui/src/utils/repository.js +0 -98
  176. package/management-ui/src/utils/repository.test.js +0 -118
  177. package/management-ui/src/workflows/phase2-integration-workflows.js +0 -884
  178. package/management-ui/tailwind.config.js +0 -63
  179. package/management-ui/tsconfig.json +0 -37
  180. package/management-ui/tsconfig.node.json +0 -10
  181. package/management-ui/vite.config.js +0 -26
  182. package/management-ui/vitest.config.js +0 -38
@@ -1,199 +0,0 @@
1
- const chalk = require('chalk');
2
- const { spawn } = require('child_process');
3
- const readline = require('readline');
4
-
5
- class ProcessManager {
6
- constructor() {
7
- this.processes = new Map();
8
- this.isShuttingDown = false;
9
- this.outputBuffer = new Map();
10
- this.setupShutdownHandlers();
11
- }
12
-
13
- setupShutdownHandlers() {
14
- const shutdown = async () => {
15
- if (this.isShuttingDown) return;
16
- this.isShuttingDown = true;
17
-
18
- console.log('\n' + chalk.yellow('⏹ Shutting down...'));
19
-
20
- const shutdownPromises = [];
21
- for (const [name, proc] of this.processes) {
22
- shutdownPromises.push(this.killProcess(name, proc));
23
- }
24
-
25
- await Promise.all(shutdownPromises);
26
-
27
- console.log(chalk.green('✓ All processes stopped cleanly'));
28
- process.exit(0);
29
- };
30
-
31
- process.on('SIGINT', shutdown);
32
- process.on('SIGTERM', shutdown);
33
- process.on('exit', () => {
34
- for (const [, proc] of this.processes) {
35
- try {
36
- proc.kill('SIGKILL');
37
- } catch (e) {
38
- // Process already dead
39
- }
40
- }
41
- });
42
- }
43
-
44
- async killProcess(name, proc) {
45
- return new Promise((resolve) => {
46
- if (!proc || proc.killed) {
47
- resolve();
48
- return;
49
- }
50
-
51
- const timeout = setTimeout(() => {
52
- try {
53
- proc.kill('SIGKILL');
54
- } catch (e) {
55
- // Process already dead
56
- }
57
- resolve();
58
- }, 5000);
59
-
60
- proc.once('exit', () => {
61
- clearTimeout(timeout);
62
- this.processes.delete(name);
63
- resolve();
64
- });
65
-
66
- try {
67
- proc.kill('SIGTERM');
68
- } catch (e) {
69
- clearTimeout(timeout);
70
- resolve();
71
- }
72
- });
73
- }
74
-
75
- spawnProcess(name, command, args, options = {}) {
76
- const proc = spawn(command, args, {
77
- ...options,
78
- stdio: ['inherit', 'pipe', 'pipe'],
79
- shell: true
80
- });
81
-
82
- this.processes.set(name, proc);
83
- this.outputBuffer.set(name, []);
84
-
85
- // Create readline interfaces for better line handling
86
- const stdoutReader = readline.createInterface({
87
- input: proc.stdout,
88
- crlfDelay: Infinity
89
- });
90
-
91
- const stderrReader = readline.createInterface({
92
- input: proc.stderr,
93
- crlfDelay: Infinity
94
- });
95
-
96
- stdoutReader.on('line', (line) => {
97
- if (!this.isShuttingDown) {
98
- this.handleOutput(name, line, 'stdout');
99
- }
100
- });
101
-
102
- stderrReader.on('line', (line) => {
103
- if (!this.isShuttingDown) {
104
- this.handleOutput(name, line, 'stderr');
105
- }
106
- });
107
-
108
- proc.on('error', (error) => {
109
- if (!this.isShuttingDown) {
110
- console.error(chalk.red(`[${name}] Process error:`), error.message);
111
- }
112
- });
113
-
114
- proc.on('exit', (code, signal) => {
115
- this.processes.delete(name);
116
- if (!this.isShuttingDown && code !== 0 && code !== null) {
117
- console.error(chalk.red(`[${name}] Process exited with code ${code}`));
118
- }
119
- });
120
-
121
- return proc;
122
- }
123
-
124
- handleOutput(processName, line, stream) {
125
- // Filter out noisy/redundant messages
126
- const filters = [
127
- /VITE v\d+\.\d+\.\d+/,
128
- /ready in \d+ ms/,
129
- /Local:/,
130
- /Network:/,
131
- /press h \+ enter to show help/,
132
- /\[nodemon\]/,
133
- /watching for file changes/,
134
- /restarting due to changes/,
135
- /starting/,
136
- /clean exit/,
137
- /waiting for changes before restart/,
138
- /^$/ // empty lines
139
- ];
140
-
141
- if (filters.some(filter => filter.test(line))) {
142
- return;
143
- }
144
-
145
- // Format output based on process
146
- const prefix = this.getProcessPrefix(processName);
147
- const coloredLine = this.colorizeOutput(line, stream);
148
-
149
- console.log(`${prefix} ${coloredLine}`);
150
- }
151
-
152
- getProcessPrefix(processName) {
153
- const prefixes = {
154
- 'frontend': chalk.blue('[Frontend]'),
155
- 'backend': chalk.green('[Backend]'),
156
- 'vite': chalk.blue('[Vite]'),
157
- 'server': chalk.green('[Server]')
158
- };
159
-
160
- return prefixes[processName.toLowerCase()] || chalk.gray(`[${processName}]`);
161
- }
162
-
163
- colorizeOutput(line, stream) {
164
- // Error detection
165
- if (stream === 'stderr' || /error|fail|exception/i.test(line)) {
166
- return chalk.red(line);
167
- }
168
-
169
- // Warning detection
170
- if (/warn|warning/i.test(line)) {
171
- return chalk.yellow(line);
172
- }
173
-
174
- // Success detection
175
- if (/success|ready|started|listening|compiled/i.test(line)) {
176
- return chalk.green(line);
177
- }
178
-
179
- // Info detection
180
- if (/info|starting/i.test(line)) {
181
- return chalk.blue(line);
182
- }
183
-
184
- return chalk.gray(line);
185
- }
186
-
187
- printStatus(frontendUrl, backendUrl, repoName) {
188
- console.log('\n' + chalk.bold.green('✨ Frigg Management UI is ready!'));
189
- console.log('');
190
- console.log(chalk.cyan(' Frontend: ') + chalk.white(frontendUrl));
191
- console.log(chalk.cyan(' Backend: ') + chalk.white(backendUrl));
192
- console.log(chalk.cyan(' Repository:') + chalk.white(` ${repoName}`));
193
- console.log('');
194
- console.log(chalk.gray(' Press ' + chalk.bold('Ctrl+C') + ' to stop all servers'));
195
- console.log('');
196
- }
197
- }
198
-
199
- module.exports = ProcessManager;
@@ -1,405 +0,0 @@
1
- /**
2
- * Copyright (c) 2024 Frigg Integration Framework
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- */
7
-
8
- 'use strict';
9
-
10
- const fs = require('fs-extra');
11
- const path = require('path');
12
- const os = require('os');
13
- const chalk = require('chalk');
14
-
15
- /**
16
- * Checks if a directory is a Frigg repository
17
- * @param {string} directory - Path to check
18
- * @returns {Promise<{isFriggRepo: boolean, repoInfo: object|null}>}
19
- */
20
- async function isFriggRepository(directory) {
21
- try {
22
- const packageJsonPath = path.join(directory, 'package.json');
23
-
24
- // Check if package.json exists
25
- if (!fs.existsSync(packageJsonPath)) {
26
- return { isFriggRepo: false, repoInfo: null };
27
- }
28
-
29
- const packageJson = await fs.readJson(packageJsonPath);
30
-
31
- // Primary indicators of a Frigg repository
32
- const indicators = {
33
- hasFriggDependencies: false,
34
- hasBackendWorkspace: false,
35
- hasFrontendWorkspace: false,
36
- hasServerlessConfig: false,
37
- friggDependencies: []
38
- };
39
-
40
- // Check for @friggframework dependencies
41
- const allDeps = {
42
- ...packageJson.dependencies,
43
- ...packageJson.devDependencies,
44
- ...packageJson.peerDependencies
45
- };
46
-
47
- for (const dep in allDeps) {
48
- if (dep.startsWith('@friggframework/')) {
49
- indicators.hasFriggDependencies = true;
50
- indicators.friggDependencies.push(dep);
51
- }
52
- }
53
-
54
- // Check for Frigg-specific files
55
- const friggConfigFiles = [
56
- 'frigg.config.js',
57
- 'frigg.config.json',
58
- '.friggrc',
59
- '.friggrc.json',
60
- '.friggrc.js'
61
- ];
62
-
63
- indicators.hasFriggConfig = friggConfigFiles.some(file =>
64
- fs.existsSync(path.join(directory, file))
65
- );
66
-
67
- // Check for Frigg-specific directories
68
- const friggDirs = [
69
- '.frigg',
70
- 'frigg-modules',
71
- 'api-modules'
72
- ];
73
-
74
- indicators.hasFriggDirectories = friggDirs.some(dir =>
75
- fs.existsSync(path.join(directory, dir))
76
- );
77
-
78
- // Check for Frigg-specific scripts in package.json
79
- indicators.hasFriggScripts = false;
80
- if (packageJson.scripts) {
81
- const friggScriptPatterns = ['frigg', 'frigg-dev', 'frigg-build', 'frigg-deploy'];
82
- indicators.hasFriggScripts = Object.keys(packageJson.scripts).some(script =>
83
- friggScriptPatterns.some(pattern => script.includes(pattern)) ||
84
- Object.values(packageJson.scripts).some(cmd =>
85
- typeof cmd === 'string' && cmd.includes('frigg ')
86
- )
87
- );
88
- }
89
-
90
- // Check for workspace structure
91
- if (packageJson.workspaces) {
92
- const workspaces = Array.isArray(packageJson.workspaces)
93
- ? packageJson.workspaces
94
- : packageJson.workspaces.packages || [];
95
-
96
- indicators.hasBackendWorkspace = workspaces.some(ws =>
97
- ws.includes('backend') || ws === 'backend'
98
- );
99
- indicators.hasFrontendWorkspace = workspaces.some(ws =>
100
- ws.includes('frontend') || ws === 'frontend'
101
- );
102
- }
103
-
104
- // Check for backend/serverless.yml
105
- const serverlessPath = path.join(directory, 'backend', 'serverless.yml');
106
- indicators.hasServerlessConfig = fs.existsSync(serverlessPath);
107
-
108
- // Check for individual frontend directories (React, Vue, etc.)
109
- const frontendDirs = ['frontend', 'react', 'vue', 'svelte', 'angular'];
110
- const existingFrontendDirs = frontendDirs.filter(dir =>
111
- fs.existsSync(path.join(directory, dir))
112
- );
113
-
114
- // Skip @friggframework packages (they're framework packages, not Frigg apps)
115
- if (packageJson.name && packageJson.name.startsWith('@friggframework/')) {
116
- return { isFriggRepo: false, repoInfo: null };
117
- }
118
-
119
- // Additional check for Zapier apps that shouldn't be detected as Frigg repos
120
- const isZapierApp = packageJson.name && (
121
- packageJson.name.includes('zapier-public') ||
122
- packageJson.name.includes('zapier-app') ||
123
- (packageJson.scripts && packageJson.scripts.zapier)
124
- );
125
-
126
- // Check for specific Frigg indicators in serverless.yml
127
- let hasFriggServerlessIndicators = false;
128
- if (indicators.hasServerlessConfig) {
129
- try {
130
- const serverlessContent = fs.readFileSync(serverlessPath, 'utf8');
131
- hasFriggServerlessIndicators = serverlessContent.includes('frigg') ||
132
- serverlessContent.includes('FriggHandler') ||
133
- serverlessContent.includes('@friggframework');
134
- } catch (error) {
135
- // Ignore read errors
136
- }
137
- }
138
-
139
- // A directory is considered a Frigg repo if it has:
140
- // 1. Frigg dependencies (MANDATORY - most reliable indicator) OR
141
- // 2. Frigg-specific configuration files OR
142
- // 3. Frigg-specific directories OR
143
- // 4. Frigg-specific scripts in package.json OR
144
- // 5. Serverless config with explicit Frigg references AND proper structure
145
- //
146
- // For Zapier apps, we require explicit Frigg indicators
147
- const hasFriggIndicators = indicators.hasFriggDependencies ||
148
- indicators.hasFriggConfig ||
149
- indicators.hasFriggDirectories ||
150
- indicators.hasFriggScripts ||
151
- hasFriggServerlessIndicators;
152
-
153
- // Determine if it's a Frigg repository
154
- let isFriggRepo = false;
155
-
156
- if (isZapierApp) {
157
- // For Zapier apps, require explicit Frigg dependencies or config
158
- isFriggRepo = indicators.hasFriggDependencies || indicators.hasFriggConfig;
159
- } else {
160
- // For non-Zapier apps, any Frigg indicator is sufficient
161
- isFriggRepo = hasFriggIndicators;
162
- }
163
-
164
- // Additional validation for edge cases
165
- if (isZapierApp && !indicators.hasFriggDependencies && !indicators.hasFriggConfig) {
166
- return { isFriggRepo: false, repoInfo: null };
167
- }
168
-
169
- if (isFriggRepo) {
170
- return {
171
- isFriggRepo: true,
172
- repoInfo: {
173
- name: packageJson.name || path.basename(directory),
174
- path: directory,
175
- version: packageJson.version,
176
- framework: detectFramework(directory, existingFrontendDirs),
177
- hasBackend: fs.existsSync(path.join(directory, 'backend')),
178
- friggDependencies: indicators.friggDependencies,
179
- workspaces: packageJson.workspaces,
180
- hasFriggConfig: indicators.hasFriggConfig,
181
- hasFriggDirectories: indicators.hasFriggDirectories,
182
- isZapierApp: isZapierApp,
183
- ...indicators
184
- }
185
- };
186
- }
187
-
188
- return { isFriggRepo: false, repoInfo: null };
189
-
190
- } catch (error) {
191
- return { isFriggRepo: false, repoInfo: null };
192
- }
193
- }
194
-
195
- /**
196
- * Detects the frontend framework used in the Frigg repository
197
- * @param {string} directory - Repository directory
198
- * @param {string[]} existingFrontendDirs - List of existing frontend directories
199
- * @returns {string} Framework name
200
- */
201
- function detectFramework(directory, existingFrontendDirs) {
202
- // Check for framework-specific directories
203
- const frameworkDirs = {
204
- 'react': 'React',
205
- 'vue': 'Vue',
206
- 'svelte': 'Svelte',
207
- 'angular': 'Angular'
208
- };
209
-
210
- for (const dir of existingFrontendDirs) {
211
- if (frameworkDirs[dir]) {
212
- return frameworkDirs[dir];
213
- }
214
- }
215
-
216
- // Check frontend directory for framework indicators
217
- const frontendPath = path.join(directory, 'frontend');
218
- if (fs.existsSync(frontendPath)) {
219
- try {
220
- const frontendPackageJson = path.join(frontendPath, 'package.json');
221
- if (fs.existsSync(frontendPackageJson)) {
222
- const frontendPkg = fs.readJsonSync(frontendPackageJson);
223
- const deps = { ...frontendPkg.dependencies, ...frontendPkg.devDependencies };
224
-
225
- if (deps.react) return 'React';
226
- if (deps.vue) return 'Vue';
227
- if (deps.svelte) return 'Svelte';
228
- if (deps['@angular/core']) return 'Angular';
229
- }
230
- } catch (error) {
231
- // Ignore errors
232
- }
233
- }
234
-
235
- return 'Unknown';
236
- }
237
-
238
- /**
239
- * Searches for Frigg repositories in common locations
240
- * @param {Object} options - Search options
241
- * @returns {Promise<Array>} Array of discovered repositories
242
- */
243
- async function discoverFriggRepositories(options = {}) {
244
- const {
245
- searchPaths = [
246
- process.cwd(),
247
- path.join(os.homedir(), 'Documents'),
248
- path.join(os.homedir(), 'Projects'),
249
- path.join(os.homedir(), 'Development'),
250
- path.join(os.homedir(), 'dev'),
251
- path.join(os.homedir(), 'Code')
252
- ],
253
- maxDepth = 3,
254
- excludePatterns = ['node_modules', '.git', 'dist', 'build', '.next', 'coverage']
255
- } = options;
256
-
257
- const discoveredRepos = [];
258
- const visited = new Set();
259
-
260
- for (const searchPath of searchPaths) {
261
- if (fs.existsSync(searchPath)) {
262
- await searchDirectory(searchPath, 0, maxDepth, excludePatterns, discoveredRepos, visited);
263
- }
264
- }
265
-
266
- // Remove duplicates and sort by name
267
- const uniqueRepos = Array.from(
268
- new Map(discoveredRepos.map(repo => [repo.path, repo])).values()
269
- );
270
-
271
- return uniqueRepos.sort((a, b) => a.name.localeCompare(b.name));
272
- }
273
-
274
- /**
275
- * Recursively searches a directory for Frigg repositories
276
- */
277
- async function searchDirectory(dirPath, currentDepth, maxDepth, excludePatterns, results, visited) {
278
- // Avoid infinite loops from symlinks
279
- const realPath = fs.realpathSync(dirPath);
280
- if (visited.has(realPath)) return;
281
- visited.add(realPath);
282
-
283
- if (currentDepth > maxDepth) return;
284
-
285
- try {
286
- // Check if current directory is a Frigg repo
287
- const { isFriggRepo, repoInfo } = await isFriggRepository(dirPath);
288
- if (isFriggRepo) {
289
- results.push(repoInfo);
290
- return; // Don't search inside Frigg repos
291
- }
292
-
293
- // Continue searching subdirectories
294
- const entries = await fs.readdir(dirPath, { withFileTypes: true });
295
-
296
- for (const entry of entries) {
297
- if (entry.isDirectory()) {
298
- const entryName = entry.name;
299
-
300
- // Skip excluded patterns
301
- if (excludePatterns.some(pattern => entryName.includes(pattern))) {
302
- continue;
303
- }
304
-
305
- // Skip hidden directories except .git for workspace detection
306
- if (entryName.startsWith('.') && entryName !== '.git') {
307
- continue;
308
- }
309
-
310
- const entryPath = path.join(dirPath, entryName);
311
- await searchDirectory(entryPath, currentDepth + 1, maxDepth, excludePatterns, results, visited);
312
- }
313
- }
314
- } catch (error) {
315
- // Silently skip directories we can't access
316
- }
317
- }
318
-
319
- /**
320
- * Gets the current directory's Frigg repository status
321
- * @returns {Promise<Object>} Current repository info
322
- */
323
- async function getCurrentRepositoryInfo() {
324
- const currentDir = process.cwd();
325
-
326
- // Check current directory
327
- let { isFriggRepo, repoInfo } = await isFriggRepository(currentDir);
328
-
329
- if (isFriggRepo) {
330
- return { ...repoInfo, isCurrent: true };
331
- }
332
-
333
- // Check parent directories up to 3 levels
334
- let checkDir = currentDir;
335
- for (let i = 0; i < 3; i++) {
336
- const parentDir = path.dirname(checkDir);
337
- if (parentDir === checkDir) break; // Reached root
338
-
339
- const result = await isFriggRepository(parentDir);
340
- if (result.isFriggRepo) {
341
- return { ...result.repoInfo, isCurrent: false, currentSubPath: path.relative(parentDir, currentDir) };
342
- }
343
- checkDir = parentDir;
344
- }
345
-
346
- return null;
347
- }
348
-
349
- /**
350
- * Prompts user to select a repository from discovered repos
351
- * @param {Array} repositories - List of discovered repositories
352
- * @returns {Promise<Object|null>} Selected repository or null
353
- */
354
- async function promptRepositorySelection(repositories) {
355
- if (repositories.length === 0) {
356
- console.log(chalk.yellow('No Frigg repositories found.'));
357
- console.log(chalk.gray('To create a new Frigg project, run: frigg init <project-name>'));
358
- return null;
359
- }
360
-
361
- if (repositories.length === 1) {
362
- console.log(chalk.green(`Found 1 Frigg repository: ${repositories[0].name}`));
363
- return repositories[0];
364
- }
365
-
366
- console.log(chalk.blue(`Found ${repositories.length} Frigg repositories:`));
367
- console.log();
368
-
369
- repositories.forEach((repo, index) => {
370
- const framework = repo.framework !== 'Unknown' ? chalk.gray(`(${repo.framework})`) : '';
371
- console.log(` ${chalk.cyan((index + 1).toString().padStart(2))}. ${chalk.white(repo.name)} ${framework}`);
372
- console.log(` ${chalk.gray(repo.path)}`);
373
- });
374
-
375
- console.log();
376
-
377
- // For now, return the first one. In a full implementation, you'd use a prompt library
378
- console.log(chalk.yellow('Auto-selecting first repository. Use interactive selection in future versions.'));
379
- return repositories[0];
380
- }
381
-
382
- /**
383
- * Formats repository information for display
384
- * @param {Object} repoInfo - Repository information
385
- * @returns {string} Formatted display string
386
- */
387
- function formatRepositoryInfo(repoInfo) {
388
- const parts = [
389
- chalk.white(repoInfo.name),
390
- repoInfo.version ? chalk.gray(`v${repoInfo.version}`) : '',
391
- repoInfo.framework !== 'Unknown' ? chalk.blue(`[${repoInfo.framework}]`) : '',
392
- repoInfo.hasBackend ? chalk.green('[Backend]') : ''
393
- ].filter(Boolean);
394
-
395
- return parts.join(' ');
396
- }
397
-
398
- module.exports = {
399
- isFriggRepository,
400
- discoverFriggRepositories,
401
- getCurrentRepositoryInfo,
402
- promptRepositorySelection,
403
- formatRepositoryInfo,
404
- detectFramework
405
- };