faf-cli 3.2.4 → 3.2.6
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.
- package/README.md +62 -0
- package/dist/big-orange/bigo-push.js +1 -1
- package/dist/big-orange/bigo-push.js.map +1 -1
- package/dist/big-orange/compare.js +21 -14
- package/dist/big-orange/compare.js.map +1 -1
- package/dist/big-orange/faf-generator.d.ts +2 -2
- package/dist/big-orange/faf-generator.d.ts.map +1 -1
- package/dist/big-orange/faf-generator.js +2 -2
- package/dist/big-orange/faf-generator.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +21 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/ai-analyze.js +8 -10
- package/dist/commands/ai-analyze.js.map +1 -1
- package/dist/commands/ai-enhance.d.ts +1 -1
- package/dist/commands/ai-enhance.d.ts.map +1 -1
- package/dist/commands/ai-enhance.js +4 -4
- package/dist/commands/ai-enhance.js.map +1 -1
- package/dist/commands/audit.js.map +1 -1
- package/dist/commands/auto.d.ts.map +1 -1
- package/dist/commands/auto.js +51 -4
- package/dist/commands/auto.js.map +1 -1
- package/dist/commands/bi-sync.d.ts.map +1 -1
- package/dist/commands/bi-sync.js +0 -1
- package/dist/commands/bi-sync.js.map +1 -1
- package/dist/commands/chat.d.ts.map +1 -1
- package/dist/commands/chat.js +1 -1
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/check.js +1 -1
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/convert.js +2 -2
- package/dist/commands/convert.js.map +1 -1
- package/dist/commands/doctor.js +9 -5
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/drift.js +28 -21
- package/dist/commands/drift.js.map +1 -1
- package/dist/commands/edit-helper.d.ts +1 -1
- package/dist/commands/edit-helper.d.ts.map +1 -1
- package/dist/commands/edit-helper.js.map +1 -1
- package/dist/commands/edit.d.ts.map +1 -1
- package/dist/commands/edit.js +1 -1
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/enhance-real.d.ts.map +1 -1
- package/dist/commands/enhance-real.js +234 -129
- package/dist/commands/enhance-real.js.map +1 -1
- package/dist/commands/faf-auth.js.map +1 -1
- package/dist/commands/faf-dna.js.map +1 -1
- package/dist/commands/faf-log.js.map +1 -1
- package/dist/commands/faf-recover.js +27 -26
- package/dist/commands/faf-recover.js.map +1 -1
- package/dist/commands/fam.js +15 -12
- package/dist/commands/fam.js.map +1 -1
- package/dist/commands/formats.d.ts.map +1 -1
- package/dist/commands/formats.js +2 -0
- package/dist/commands/formats.js.map +1 -1
- package/dist/commands/git.d.ts.map +1 -1
- package/dist/commands/git.js +16 -8
- package/dist/commands/git.js.map +1 -1
- package/dist/commands/human.d.ts.map +1 -1
- package/dist/commands/human.js +2 -3
- package/dist/commands/human.js.map +1 -1
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +8 -6
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +18 -41
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/migrate.js +2 -2
- package/dist/commands/migrate.js.map +1 -1
- package/dist/commands/quick.js +31 -16
- package/dist/commands/quick.js.map +1 -1
- package/dist/commands/readme.js +27 -14
- package/dist/commands/readme.js.map +1 -1
- package/dist/commands/rename.d.ts.map +1 -1
- package/dist/commands/rename.js +4 -3
- package/dist/commands/rename.js.map +1 -1
- package/dist/commands/score-v3.js +32 -21
- package/dist/commands/score-v3.js.map +1 -1
- package/dist/commands/search.js +4 -4
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/share.js +2 -1
- package/dist/commands/share.js.map +1 -1
- package/dist/commands/show.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +2 -2
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +21 -12
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/todo.js +1 -1
- package/dist/commands/todo.js.map +1 -1
- package/dist/commands/trust.d.ts.map +1 -1
- package/dist/commands/trust.js +2 -5
- package/dist/commands/trust.js.map +1 -1
- package/dist/commands/tsa.js.map +1 -1
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/verify.js +2 -2
- package/dist/commands/verify.js.map +1 -1
- package/dist/commands/version.js.map +1 -1
- package/dist/commands/vibe.d.ts +1 -1
- package/dist/commands/vibe.d.ts.map +1 -1
- package/dist/commands/vibe.js +2 -2
- package/dist/commands/vibe.js.map +1 -1
- package/dist/commands/yolo.d.ts +12 -0
- package/dist/commands/yolo.d.ts.map +1 -0
- package/dist/commands/yolo.js +206 -0
- package/dist/commands/yolo.js.map +1 -0
- package/dist/compiler/faf-compiler.d.ts.map +1 -1
- package/dist/compiler/faf-compiler.js +720 -123
- package/dist/compiler/faf-compiler.js.map +1 -1
- package/dist/converters/faf-converters.d.ts.map +1 -1
- package/dist/converters/faf-converters.js +22 -11
- package/dist/converters/faf-converters.js.map +1 -1
- package/dist/engines/art-ansi-renderer.js +3 -7
- package/dist/engines/art-ansi-renderer.js.map +1 -1
- package/dist/engines/dependency-tsa.d.ts.map +1 -1
- package/dist/engines/dependency-tsa.js +8 -4
- package/dist/engines/dependency-tsa.js.map +1 -1
- package/dist/engines/fab-formats-processor.d.ts.map +1 -1
- package/dist/engines/fab-formats-processor.js +87 -49
- package/dist/engines/fab-formats-processor.js.map +1 -1
- package/dist/engines/faf-dna.d.ts +1 -1
- package/dist/engines/faf-dna.d.ts.map +1 -1
- package/dist/engines/faf-dna.js +20 -27
- package/dist/engines/faf-dna.js.map +1 -1
- package/dist/engines/relentless-context-extractor.d.ts.map +1 -1
- package/dist/engines/relentless-context-extractor.js +42 -31
- package/dist/engines/relentless-context-extractor.js.map +1 -1
- package/dist/family/registry.d.ts.map +1 -1
- package/dist/family/registry.js +8 -6
- package/dist/family/registry.js.map +1 -1
- package/dist/fix-once/colors.d.ts.map +1 -1
- package/dist/fix-once/colors.js +23 -11
- package/dist/fix-once/colors.js.map +1 -1
- package/dist/fix-once/commander.js +1 -1
- package/dist/fix-once/commander.js.map +1 -1
- package/dist/generators/faf-generator-championship.d.ts.map +1 -1
- package/dist/generators/faf-generator-championship.js +145 -59
- package/dist/generators/faf-generator-championship.js.map +1 -1
- package/dist/github/github-extractor.d.ts.map +1 -1
- package/dist/github/github-extractor.js +55 -28
- package/dist/github/github-extractor.js.map +1 -1
- package/dist/github/repo-selector.js +24 -14
- package/dist/github/repo-selector.js.map +1 -1
- package/dist/output/experience-manager.js +6 -3
- package/dist/output/experience-manager.js.map +1 -1
- package/dist/taf/stats.js +21 -13
- package/dist/taf/stats.js.map +1 -1
- package/dist/telemetry/analytics.js +1 -1
- package/dist/telemetry/analytics.js.map +1 -1
- package/dist/utils/balance-visualizer.d.ts.map +1 -1
- package/dist/utils/balance-visualizer.js +3 -10
- package/dist/utils/balance-visualizer.js.map +1 -1
- package/dist/utils/championship-core.js +14 -7
- package/dist/utils/championship-core.js.map +1 -1
- package/dist/utils/color-utils.d.ts.map +1 -1
- package/dist/utils/color-utils.js +1 -0
- package/dist/utils/color-utils.js.map +1 -1
- package/dist/utils/email-opt-in.js +5 -3
- package/dist/utils/email-opt-in.js.map +1 -1
- package/dist/utils/fab-formats-engine.d.ts.map +1 -1
- package/dist/utils/fab-formats-engine.js +105 -52
- package/dist/utils/fab-formats-engine.js.map +1 -1
- package/dist/utils/file-utils.js +1 -1
- package/dist/utils/file-utils.js.map +1 -1
- package/dist/utils/markdown-to-context.js +24 -13
- package/dist/utils/markdown-to-context.js.map +1 -1
- package/dist/utils/native-cli-parser.d.ts +2 -2
- package/dist/utils/native-cli-parser.d.ts.map +1 -1
- package/dist/utils/native-cli-parser.js +14 -10
- package/dist/utils/native-cli-parser.js.map +1 -1
- package/dist/utils/native-file-finder.js +1 -1
- package/dist/utils/native-file-finder.js.map +1 -1
- package/dist/utils/platform-detector.d.ts.map +1 -1
- package/dist/utils/platform-detector.js +3 -1
- package/dist/utils/platform-detector.js.map +1 -1
- package/dist/utils/technical-credit.js +2 -2
- package/dist/utils/technical-credit.js.map +1 -1
- package/dist/utils/trust-cache.d.ts.map +1 -1
- package/dist/utils/trust-cache.js +1 -2
- package/dist/utils/trust-cache.js.map +1 -1
- package/dist/utils/turbo-cat-knowledge.d.ts +17 -4
- package/dist/utils/turbo-cat-knowledge.d.ts.map +1 -1
- package/dist/utils/turbo-cat-knowledge.js +560 -4
- package/dist/utils/turbo-cat-knowledge.js.map +1 -1
- package/dist/utils/turbo-cat-pyramid.d.ts +14 -4
- package/dist/utils/turbo-cat-pyramid.d.ts.map +1 -1
- package/dist/utils/turbo-cat-pyramid.js +113 -21
- package/dist/utils/turbo-cat-pyramid.js.map +1 -1
- package/dist/utils/turbo-cat.d.ts.map +1 -1
- package/dist/utils/turbo-cat.js +50 -25
- package/dist/utils/turbo-cat.js.map +1 -1
- package/dist/utils/universal-fuzzy-detector.js +10 -5
- package/dist/utils/universal-fuzzy-detector.js.map +1 -1
- package/dist/utils/update-checker.d.ts.map +1 -1
- package/dist/utils/update-checker.js +15 -9
- package/dist/utils/update-checker.js.map +1 -1
- package/dist/utils/vibe-sync.d.ts.map +1 -1
- package/dist/utils/vibe-sync.js +12 -7
- package/dist/utils/vibe-sync.js.map +1 -1
- package/dist/utils/yaml-generator.d.ts +12 -12
- package/dist/utils/yaml-generator.d.ts.map +1 -1
- package/dist/utils/yaml-generator.js +58 -31
- package/dist/utils/yaml-generator.js.map +1 -1
- package/package.json +1 -1
|
@@ -50,6 +50,594 @@ const chrome_extension_detector_1 = require("../utils/chrome-extension-detector"
|
|
|
50
50
|
const fab_formats_processor_1 = require("../engines/fab-formats-processor");
|
|
51
51
|
const path = __importStar(require("path"));
|
|
52
52
|
// ============================================================================
|
|
53
|
+
// TYPE_DEFINITIONS - Single Source of Truth for Project Types
|
|
54
|
+
// ============================================================================
|
|
55
|
+
// Design: 21 slots always exist. Types define which slots COUNT toward scoring.
|
|
56
|
+
// slot_ignore in .faf file overrides type defaults for edge cases.
|
|
57
|
+
/**
|
|
58
|
+
* All 21 slots in the FAF system
|
|
59
|
+
*/
|
|
60
|
+
const ALL_SLOTS = {
|
|
61
|
+
// Project slots (3)
|
|
62
|
+
project: ['project.name', 'project.goal', 'project.main_language'],
|
|
63
|
+
// Frontend slots (4)
|
|
64
|
+
frontend: ['stack.frontend', 'stack.css_framework', 'stack.ui_library', 'stack.state_management'],
|
|
65
|
+
// Backend slots (5)
|
|
66
|
+
backend: ['stack.backend', 'stack.api_type', 'stack.runtime', 'stack.database', 'stack.connection'],
|
|
67
|
+
// Universal slots (3)
|
|
68
|
+
universal: ['stack.hosting', 'stack.build', 'stack.cicd'],
|
|
69
|
+
// Human context slots (6)
|
|
70
|
+
human: ['human.who', 'human.what', 'human.why', 'human.where', 'human.when', 'human.how']
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* TYPE_DEFINITIONS - Maps project types to their applicable slots
|
|
74
|
+
*
|
|
75
|
+
* Each type specifies which slot categories count toward scoring.
|
|
76
|
+
* slot_ignore in .faf can override these for edge cases.
|
|
77
|
+
*/
|
|
78
|
+
const TYPE_DEFINITIONS = {
|
|
79
|
+
// ============================================================================
|
|
80
|
+
// CLI/Tool Types (9 slots: project + human)
|
|
81
|
+
// ============================================================================
|
|
82
|
+
'cli': {
|
|
83
|
+
description: 'Command-line interface tool',
|
|
84
|
+
categories: ['project', 'human'],
|
|
85
|
+
aliases: ['cli-tool', 'command-line']
|
|
86
|
+
},
|
|
87
|
+
'cli-tool': {
|
|
88
|
+
description: 'Command-line interface tool',
|
|
89
|
+
categories: ['project', 'human']
|
|
90
|
+
},
|
|
91
|
+
// ============================================================================
|
|
92
|
+
// Library/Package Types (9 slots: project + human)
|
|
93
|
+
// ============================================================================
|
|
94
|
+
'library': {
|
|
95
|
+
description: 'Reusable code library/package',
|
|
96
|
+
categories: ['project', 'human'],
|
|
97
|
+
aliases: ['lib', 'package']
|
|
98
|
+
},
|
|
99
|
+
'npm-package': {
|
|
100
|
+
description: 'NPM package',
|
|
101
|
+
categories: ['project', 'human']
|
|
102
|
+
},
|
|
103
|
+
'pip-package': {
|
|
104
|
+
description: 'Python pip package',
|
|
105
|
+
categories: ['project', 'human'],
|
|
106
|
+
aliases: ['pypi']
|
|
107
|
+
},
|
|
108
|
+
'crate': {
|
|
109
|
+
description: 'Rust crate',
|
|
110
|
+
categories: ['project', 'human'],
|
|
111
|
+
aliases: ['rust-crate']
|
|
112
|
+
},
|
|
113
|
+
'gem': {
|
|
114
|
+
description: 'Ruby gem',
|
|
115
|
+
categories: ['project', 'human'],
|
|
116
|
+
aliases: ['ruby-gem']
|
|
117
|
+
},
|
|
118
|
+
// ============================================================================
|
|
119
|
+
// AI/ML Types
|
|
120
|
+
// ============================================================================
|
|
121
|
+
'mcp-server': {
|
|
122
|
+
description: 'Model Context Protocol server',
|
|
123
|
+
categories: ['project', 'backend', 'human']
|
|
124
|
+
},
|
|
125
|
+
'data-science': {
|
|
126
|
+
description: 'Data science/analysis project',
|
|
127
|
+
categories: ['project', 'backend', 'human'],
|
|
128
|
+
aliases: ['data-analysis', 'analytics']
|
|
129
|
+
},
|
|
130
|
+
'ml-model': {
|
|
131
|
+
description: 'Machine learning model',
|
|
132
|
+
categories: ['project', 'backend', 'human'],
|
|
133
|
+
aliases: ['ai-model', 'ml', 'machine-learning']
|
|
134
|
+
},
|
|
135
|
+
'jupyter': {
|
|
136
|
+
description: 'Jupyter notebook project',
|
|
137
|
+
categories: ['project', 'human'],
|
|
138
|
+
aliases: ['notebook', 'ipynb']
|
|
139
|
+
},
|
|
140
|
+
'data-pipeline': {
|
|
141
|
+
description: 'Data pipeline/ETL',
|
|
142
|
+
categories: ['project', 'backend', 'human'],
|
|
143
|
+
aliases: ['etl', 'pipeline']
|
|
144
|
+
},
|
|
145
|
+
// ============================================================================
|
|
146
|
+
// API/Backend Types
|
|
147
|
+
// ============================================================================
|
|
148
|
+
'backend-api': {
|
|
149
|
+
description: 'Backend API service',
|
|
150
|
+
categories: ['project', 'backend', 'universal', 'human'],
|
|
151
|
+
aliases: ['api', 'backend', 'rest-api']
|
|
152
|
+
},
|
|
153
|
+
'node-api': {
|
|
154
|
+
description: 'Node.js API service',
|
|
155
|
+
categories: ['project', 'backend', 'universal', 'human'],
|
|
156
|
+
aliases: ['express', 'fastify', 'nest']
|
|
157
|
+
},
|
|
158
|
+
'python-api': {
|
|
159
|
+
description: 'Python API service',
|
|
160
|
+
categories: ['project', 'backend', 'universal', 'human'],
|
|
161
|
+
aliases: ['flask', 'fastapi', 'django-api']
|
|
162
|
+
},
|
|
163
|
+
'python-app': {
|
|
164
|
+
description: 'Python application',
|
|
165
|
+
categories: ['project', 'backend', 'human']
|
|
166
|
+
},
|
|
167
|
+
'go-api': {
|
|
168
|
+
description: 'Go API service',
|
|
169
|
+
categories: ['project', 'backend', 'universal', 'human'],
|
|
170
|
+
aliases: ['golang', 'gin', 'fiber']
|
|
171
|
+
},
|
|
172
|
+
'rust-api': {
|
|
173
|
+
description: 'Rust API service',
|
|
174
|
+
categories: ['project', 'backend', 'universal', 'human'],
|
|
175
|
+
aliases: ['actix', 'axum', 'rocket']
|
|
176
|
+
},
|
|
177
|
+
'graphql': {
|
|
178
|
+
description: 'GraphQL API service',
|
|
179
|
+
categories: ['project', 'backend', 'universal', 'human'],
|
|
180
|
+
aliases: ['graphql-api']
|
|
181
|
+
},
|
|
182
|
+
'microservice': {
|
|
183
|
+
description: 'Microservice',
|
|
184
|
+
categories: ['project', 'backend', 'universal', 'human'],
|
|
185
|
+
aliases: ['service']
|
|
186
|
+
},
|
|
187
|
+
// ============================================================================
|
|
188
|
+
// Frontend Types
|
|
189
|
+
// ============================================================================
|
|
190
|
+
'frontend': {
|
|
191
|
+
description: 'Frontend-only web application',
|
|
192
|
+
categories: ['project', 'frontend', 'universal', 'human']
|
|
193
|
+
},
|
|
194
|
+
'svelte': {
|
|
195
|
+
description: 'Svelte web application',
|
|
196
|
+
categories: ['project', 'frontend', 'universal', 'human'],
|
|
197
|
+
aliases: ['sveltekit']
|
|
198
|
+
},
|
|
199
|
+
'react': {
|
|
200
|
+
description: 'React web application',
|
|
201
|
+
categories: ['project', 'frontend', 'universal', 'human'],
|
|
202
|
+
aliases: ['reactjs']
|
|
203
|
+
},
|
|
204
|
+
'vue': {
|
|
205
|
+
description: 'Vue.js web application',
|
|
206
|
+
categories: ['project', 'frontend', 'universal', 'human'],
|
|
207
|
+
aliases: ['vuejs', 'nuxt']
|
|
208
|
+
},
|
|
209
|
+
'angular': {
|
|
210
|
+
description: 'Angular web application',
|
|
211
|
+
categories: ['project', 'frontend', 'universal', 'human']
|
|
212
|
+
},
|
|
213
|
+
'nextjs': {
|
|
214
|
+
description: 'Next.js application',
|
|
215
|
+
categories: ['project', 'frontend', 'backend', 'universal', 'human'],
|
|
216
|
+
aliases: ['next']
|
|
217
|
+
},
|
|
218
|
+
'remix': {
|
|
219
|
+
description: 'Remix application',
|
|
220
|
+
categories: ['project', 'frontend', 'backend', 'universal', 'human']
|
|
221
|
+
},
|
|
222
|
+
'astro': {
|
|
223
|
+
description: 'Astro static site',
|
|
224
|
+
categories: ['project', 'frontend', 'universal', 'human']
|
|
225
|
+
},
|
|
226
|
+
'solid': {
|
|
227
|
+
description: 'SolidJS application',
|
|
228
|
+
categories: ['project', 'frontend', 'universal', 'human'],
|
|
229
|
+
aliases: ['solidjs']
|
|
230
|
+
},
|
|
231
|
+
'qwik': {
|
|
232
|
+
description: 'Qwik application',
|
|
233
|
+
categories: ['project', 'frontend', 'universal', 'human']
|
|
234
|
+
},
|
|
235
|
+
// ============================================================================
|
|
236
|
+
// Fullstack Types
|
|
237
|
+
// ============================================================================
|
|
238
|
+
'fullstack': {
|
|
239
|
+
description: 'Full-stack web application',
|
|
240
|
+
categories: ['project', 'frontend', 'backend', 'universal', 'human']
|
|
241
|
+
},
|
|
242
|
+
't3': {
|
|
243
|
+
description: 'T3 Stack (Next.js + tRPC + Prisma)',
|
|
244
|
+
categories: ['project', 'frontend', 'backend', 'universal', 'human'],
|
|
245
|
+
aliases: ['t3-stack', 'create-t3-app']
|
|
246
|
+
},
|
|
247
|
+
'mern': {
|
|
248
|
+
description: 'MERN Stack (MongoDB + Express + React + Node)',
|
|
249
|
+
categories: ['project', 'frontend', 'backend', 'universal', 'human']
|
|
250
|
+
},
|
|
251
|
+
'mean': {
|
|
252
|
+
description: 'MEAN Stack (MongoDB + Express + Angular + Node)',
|
|
253
|
+
categories: ['project', 'frontend', 'backend', 'universal', 'human']
|
|
254
|
+
},
|
|
255
|
+
'lamp': {
|
|
256
|
+
description: 'LAMP Stack (Linux + Apache + MySQL + PHP)',
|
|
257
|
+
categories: ['project', 'frontend', 'backend', 'universal', 'human']
|
|
258
|
+
},
|
|
259
|
+
'django': {
|
|
260
|
+
description: 'Django web application',
|
|
261
|
+
categories: ['project', 'frontend', 'backend', 'universal', 'human']
|
|
262
|
+
},
|
|
263
|
+
'rails': {
|
|
264
|
+
description: 'Ruby on Rails application',
|
|
265
|
+
categories: ['project', 'frontend', 'backend', 'universal', 'human'],
|
|
266
|
+
aliases: ['ruby-on-rails', 'ror']
|
|
267
|
+
},
|
|
268
|
+
'laravel': {
|
|
269
|
+
description: 'Laravel PHP application',
|
|
270
|
+
categories: ['project', 'frontend', 'backend', 'universal', 'human']
|
|
271
|
+
},
|
|
272
|
+
// ============================================================================
|
|
273
|
+
// Mobile Types
|
|
274
|
+
// ============================================================================
|
|
275
|
+
'mobile': {
|
|
276
|
+
description: 'Mobile application',
|
|
277
|
+
categories: ['project', 'frontend', 'human'],
|
|
278
|
+
aliases: ['mobile-app']
|
|
279
|
+
},
|
|
280
|
+
'react-native': {
|
|
281
|
+
description: 'React Native mobile app',
|
|
282
|
+
categories: ['project', 'frontend', 'human'],
|
|
283
|
+
aliases: ['rn', 'expo']
|
|
284
|
+
},
|
|
285
|
+
'flutter': {
|
|
286
|
+
description: 'Flutter mobile app',
|
|
287
|
+
categories: ['project', 'frontend', 'human'],
|
|
288
|
+
aliases: ['dart']
|
|
289
|
+
},
|
|
290
|
+
'ios': {
|
|
291
|
+
description: 'iOS native app',
|
|
292
|
+
categories: ['project', 'frontend', 'human'],
|
|
293
|
+
aliases: ['swift', 'swiftui']
|
|
294
|
+
},
|
|
295
|
+
'android': {
|
|
296
|
+
description: 'Android native app',
|
|
297
|
+
categories: ['project', 'frontend', 'human'],
|
|
298
|
+
aliases: ['kotlin', 'kotlin-android']
|
|
299
|
+
},
|
|
300
|
+
'ionic': {
|
|
301
|
+
description: 'Ionic mobile app',
|
|
302
|
+
categories: ['project', 'frontend', 'human'],
|
|
303
|
+
aliases: ['capacitor']
|
|
304
|
+
},
|
|
305
|
+
// ============================================================================
|
|
306
|
+
// Desktop Types
|
|
307
|
+
// ============================================================================
|
|
308
|
+
'desktop': {
|
|
309
|
+
description: 'Desktop application',
|
|
310
|
+
categories: ['project', 'frontend', 'human'],
|
|
311
|
+
aliases: ['desktop-app']
|
|
312
|
+
},
|
|
313
|
+
'electron': {
|
|
314
|
+
description: 'Electron desktop app',
|
|
315
|
+
categories: ['project', 'frontend', 'human']
|
|
316
|
+
},
|
|
317
|
+
'tauri': {
|
|
318
|
+
description: 'Tauri desktop app',
|
|
319
|
+
categories: ['project', 'frontend', 'human']
|
|
320
|
+
},
|
|
321
|
+
'qt': {
|
|
322
|
+
description: 'Qt desktop application',
|
|
323
|
+
categories: ['project', 'frontend', 'human'],
|
|
324
|
+
aliases: ['pyqt', 'pyside']
|
|
325
|
+
},
|
|
326
|
+
'gtk': {
|
|
327
|
+
description: 'GTK desktop application',
|
|
328
|
+
categories: ['project', 'frontend', 'human']
|
|
329
|
+
},
|
|
330
|
+
// ============================================================================
|
|
331
|
+
// Browser Extensions
|
|
332
|
+
// ============================================================================
|
|
333
|
+
'chrome-extension': {
|
|
334
|
+
description: 'Chrome browser extension',
|
|
335
|
+
categories: ['project', 'human'],
|
|
336
|
+
aliases: ['browser-extension', 'extension']
|
|
337
|
+
},
|
|
338
|
+
'firefox-extension': {
|
|
339
|
+
description: 'Firefox browser extension',
|
|
340
|
+
categories: ['project', 'human'],
|
|
341
|
+
aliases: ['firefox-addon']
|
|
342
|
+
},
|
|
343
|
+
'safari-extension': {
|
|
344
|
+
description: 'Safari browser extension',
|
|
345
|
+
categories: ['project', 'human']
|
|
346
|
+
},
|
|
347
|
+
// ============================================================================
|
|
348
|
+
// Automation/Workflow Types
|
|
349
|
+
// ============================================================================
|
|
350
|
+
'n8n-workflow': {
|
|
351
|
+
description: 'n8n automation workflow',
|
|
352
|
+
categories: ['project', 'backend', 'human'],
|
|
353
|
+
aliases: ['n8n']
|
|
354
|
+
},
|
|
355
|
+
'zapier': {
|
|
356
|
+
description: 'Zapier integration',
|
|
357
|
+
categories: ['project', 'human']
|
|
358
|
+
},
|
|
359
|
+
'github-action': {
|
|
360
|
+
description: 'GitHub Action',
|
|
361
|
+
categories: ['project', 'human'],
|
|
362
|
+
aliases: ['gha', 'action']
|
|
363
|
+
},
|
|
364
|
+
// ============================================================================
|
|
365
|
+
// DevOps/Infrastructure Types
|
|
366
|
+
// ============================================================================
|
|
367
|
+
'terraform': {
|
|
368
|
+
description: 'Terraform infrastructure',
|
|
369
|
+
categories: ['project', 'human'],
|
|
370
|
+
aliases: ['tf', 'iac']
|
|
371
|
+
},
|
|
372
|
+
'kubernetes': {
|
|
373
|
+
description: 'Kubernetes configuration',
|
|
374
|
+
categories: ['project', 'human'],
|
|
375
|
+
aliases: ['k8s', 'helm']
|
|
376
|
+
},
|
|
377
|
+
'docker': {
|
|
378
|
+
description: 'Docker/container configuration',
|
|
379
|
+
categories: ['project', 'human'],
|
|
380
|
+
aliases: ['dockerfile', 'container']
|
|
381
|
+
},
|
|
382
|
+
'ansible': {
|
|
383
|
+
description: 'Ansible playbooks',
|
|
384
|
+
categories: ['project', 'human']
|
|
385
|
+
},
|
|
386
|
+
'pulumi': {
|
|
387
|
+
description: 'Pulumi infrastructure',
|
|
388
|
+
categories: ['project', 'human']
|
|
389
|
+
},
|
|
390
|
+
'infrastructure': {
|
|
391
|
+
description: 'Infrastructure as code',
|
|
392
|
+
categories: ['project', 'human'],
|
|
393
|
+
aliases: ['infra', 'devops']
|
|
394
|
+
},
|
|
395
|
+
// ============================================================================
|
|
396
|
+
// Static Sites / Documentation
|
|
397
|
+
// ============================================================================
|
|
398
|
+
'static-html': {
|
|
399
|
+
description: 'Static HTML website',
|
|
400
|
+
categories: ['project', 'frontend', 'human'],
|
|
401
|
+
aliases: ['static-site', 'html']
|
|
402
|
+
},
|
|
403
|
+
'landing-page': {
|
|
404
|
+
description: 'Landing page website',
|
|
405
|
+
categories: ['project', 'frontend', 'human'],
|
|
406
|
+
aliases: ['landing']
|
|
407
|
+
},
|
|
408
|
+
'documentation': {
|
|
409
|
+
description: 'Documentation site',
|
|
410
|
+
categories: ['project', 'frontend', 'human'],
|
|
411
|
+
aliases: ['docs']
|
|
412
|
+
},
|
|
413
|
+
'docusaurus': {
|
|
414
|
+
description: 'Docusaurus documentation site',
|
|
415
|
+
categories: ['project', 'frontend', 'human']
|
|
416
|
+
},
|
|
417
|
+
'mkdocs': {
|
|
418
|
+
description: 'MkDocs documentation site',
|
|
419
|
+
categories: ['project', 'human']
|
|
420
|
+
},
|
|
421
|
+
'vitepress': {
|
|
422
|
+
description: 'VitePress documentation site',
|
|
423
|
+
categories: ['project', 'frontend', 'human']
|
|
424
|
+
},
|
|
425
|
+
'storybook': {
|
|
426
|
+
description: 'Storybook component library',
|
|
427
|
+
categories: ['project', 'frontend', 'human']
|
|
428
|
+
},
|
|
429
|
+
// ============================================================================
|
|
430
|
+
// CMS Types
|
|
431
|
+
// ============================================================================
|
|
432
|
+
'wordpress': {
|
|
433
|
+
description: 'WordPress site/plugin/theme',
|
|
434
|
+
categories: ['project', 'frontend', 'backend', 'universal', 'human'],
|
|
435
|
+
aliases: ['wp']
|
|
436
|
+
},
|
|
437
|
+
'cms': {
|
|
438
|
+
description: 'Content management system',
|
|
439
|
+
categories: ['project', 'frontend', 'backend', 'human']
|
|
440
|
+
},
|
|
441
|
+
'strapi': {
|
|
442
|
+
description: 'Strapi headless CMS',
|
|
443
|
+
categories: ['project', 'backend', 'universal', 'human']
|
|
444
|
+
},
|
|
445
|
+
'sanity': {
|
|
446
|
+
description: 'Sanity.io CMS',
|
|
447
|
+
categories: ['project', 'backend', 'human']
|
|
448
|
+
},
|
|
449
|
+
'contentful': {
|
|
450
|
+
description: 'Contentful CMS integration',
|
|
451
|
+
categories: ['project', 'human']
|
|
452
|
+
},
|
|
453
|
+
// ============================================================================
|
|
454
|
+
// Game Development Types
|
|
455
|
+
// ============================================================================
|
|
456
|
+
'game': {
|
|
457
|
+
description: 'Game project',
|
|
458
|
+
categories: ['project', 'frontend', 'human'],
|
|
459
|
+
aliases: ['gamedev']
|
|
460
|
+
},
|
|
461
|
+
'unity': {
|
|
462
|
+
description: 'Unity game',
|
|
463
|
+
categories: ['project', 'frontend', 'human'],
|
|
464
|
+
aliases: ['unity3d']
|
|
465
|
+
},
|
|
466
|
+
'godot': {
|
|
467
|
+
description: 'Godot game',
|
|
468
|
+
categories: ['project', 'frontend', 'human']
|
|
469
|
+
},
|
|
470
|
+
'unreal': {
|
|
471
|
+
description: 'Unreal Engine game',
|
|
472
|
+
categories: ['project', 'frontend', 'human'],
|
|
473
|
+
aliases: ['ue4', 'ue5']
|
|
474
|
+
},
|
|
475
|
+
'phaser': {
|
|
476
|
+
description: 'Phaser.js game',
|
|
477
|
+
categories: ['project', 'frontend', 'human']
|
|
478
|
+
},
|
|
479
|
+
'threejs': {
|
|
480
|
+
description: 'Three.js 3D project',
|
|
481
|
+
categories: ['project', 'frontend', 'human'],
|
|
482
|
+
aliases: ['three', '3d', 'webgl']
|
|
483
|
+
},
|
|
484
|
+
// ============================================================================
|
|
485
|
+
// Blockchain/Web3 Types
|
|
486
|
+
// ============================================================================
|
|
487
|
+
'smart-contract': {
|
|
488
|
+
description: 'Smart contract',
|
|
489
|
+
categories: ['project', 'human'],
|
|
490
|
+
aliases: ['solidity', 'contract']
|
|
491
|
+
},
|
|
492
|
+
'dapp': {
|
|
493
|
+
description: 'Decentralized application',
|
|
494
|
+
categories: ['project', 'frontend', 'human'],
|
|
495
|
+
aliases: ['web3', 'blockchain']
|
|
496
|
+
},
|
|
497
|
+
'hardhat': {
|
|
498
|
+
description: 'Hardhat Ethereum project',
|
|
499
|
+
categories: ['project', 'human']
|
|
500
|
+
},
|
|
501
|
+
'foundry': {
|
|
502
|
+
description: 'Foundry Ethereum project',
|
|
503
|
+
categories: ['project', 'human'],
|
|
504
|
+
aliases: ['forge']
|
|
505
|
+
},
|
|
506
|
+
// ============================================================================
|
|
507
|
+
// Monorepo Types
|
|
508
|
+
// Monorepos are CONTAINERS - they need ALL slots because they can contain
|
|
509
|
+
// any combination of frontend, backend, libraries, etc.
|
|
510
|
+
// The monorepo root .faf describes the overall architecture.
|
|
511
|
+
// Individual packages can have their own .faf files with specific types.
|
|
512
|
+
// ============================================================================
|
|
513
|
+
'monorepo': {
|
|
514
|
+
description: 'Monorepo - multi-package repository',
|
|
515
|
+
categories: ['project', 'frontend', 'backend', 'universal', 'human'],
|
|
516
|
+
aliases: ['mono', 'workspace']
|
|
517
|
+
},
|
|
518
|
+
'turborepo': {
|
|
519
|
+
description: 'Turborepo monorepo',
|
|
520
|
+
categories: ['project', 'frontend', 'backend', 'universal', 'human'],
|
|
521
|
+
aliases: ['turbo']
|
|
522
|
+
},
|
|
523
|
+
'nx': {
|
|
524
|
+
description: 'Nx monorepo',
|
|
525
|
+
categories: ['project', 'frontend', 'backend', 'universal', 'human']
|
|
526
|
+
},
|
|
527
|
+
'lerna': {
|
|
528
|
+
description: 'Lerna monorepo',
|
|
529
|
+
categories: ['project', 'frontend', 'backend', 'universal', 'human']
|
|
530
|
+
},
|
|
531
|
+
'pnpm-workspace': {
|
|
532
|
+
description: 'pnpm workspace monorepo',
|
|
533
|
+
categories: ['project', 'frontend', 'backend', 'universal', 'human'],
|
|
534
|
+
aliases: ['pnpm-mono']
|
|
535
|
+
},
|
|
536
|
+
'yarn-workspace': {
|
|
537
|
+
description: 'Yarn workspace monorepo',
|
|
538
|
+
categories: ['project', 'frontend', 'backend', 'universal', 'human'],
|
|
539
|
+
aliases: ['yarn-mono']
|
|
540
|
+
},
|
|
541
|
+
// ============================================================================
|
|
542
|
+
// Embedded/Systems Types
|
|
543
|
+
// ============================================================================
|
|
544
|
+
'embedded': {
|
|
545
|
+
description: 'Embedded systems',
|
|
546
|
+
categories: ['project', 'human'],
|
|
547
|
+
aliases: ['firmware', 'iot']
|
|
548
|
+
},
|
|
549
|
+
'arduino': {
|
|
550
|
+
description: 'Arduino project',
|
|
551
|
+
categories: ['project', 'human']
|
|
552
|
+
},
|
|
553
|
+
'raspberry-pi': {
|
|
554
|
+
description: 'Raspberry Pi project',
|
|
555
|
+
categories: ['project', 'human'],
|
|
556
|
+
aliases: ['rpi']
|
|
557
|
+
},
|
|
558
|
+
'wasm': {
|
|
559
|
+
description: 'WebAssembly module',
|
|
560
|
+
categories: ['project', 'human'],
|
|
561
|
+
aliases: ['webassembly']
|
|
562
|
+
},
|
|
563
|
+
// ============================================================================
|
|
564
|
+
// Testing Types
|
|
565
|
+
// ============================================================================
|
|
566
|
+
'test-suite': {
|
|
567
|
+
description: 'Test suite/framework',
|
|
568
|
+
categories: ['project', 'human'],
|
|
569
|
+
aliases: ['testing', 'tests']
|
|
570
|
+
},
|
|
571
|
+
'e2e-tests': {
|
|
572
|
+
description: 'End-to-end test suite',
|
|
573
|
+
categories: ['project', 'human'],
|
|
574
|
+
aliases: ['e2e', 'playwright', 'cypress']
|
|
575
|
+
},
|
|
576
|
+
// ============================================================================
|
|
577
|
+
// Default
|
|
578
|
+
// ============================================================================
|
|
579
|
+
'generic': {
|
|
580
|
+
description: 'Generic project (fallback)',
|
|
581
|
+
categories: ['project', 'universal', 'human']
|
|
582
|
+
}
|
|
583
|
+
};
|
|
584
|
+
/**
|
|
585
|
+
* Get applicable slots for a project type
|
|
586
|
+
*/
|
|
587
|
+
function getSlotsForType(projectType) {
|
|
588
|
+
// Check for aliases first
|
|
589
|
+
for (const [type, def] of Object.entries(TYPE_DEFINITIONS)) {
|
|
590
|
+
if (def.aliases?.includes(projectType)) {
|
|
591
|
+
projectType = type;
|
|
592
|
+
break;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
const typeDef = TYPE_DEFINITIONS[projectType] || TYPE_DEFINITIONS['generic'];
|
|
596
|
+
const slots = [];
|
|
597
|
+
for (const category of typeDef.categories) {
|
|
598
|
+
slots.push(...ALL_SLOTS[category]);
|
|
599
|
+
}
|
|
600
|
+
return slots;
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Parse slot_ignore from .faf content
|
|
604
|
+
* Accepts: slot_ignore: [hosting, cicd] or slot_ignore: hosting, cicd
|
|
605
|
+
*/
|
|
606
|
+
function parseSlotIgnore(ast) {
|
|
607
|
+
const slotIgnore = ast.slot_ignore || ast.slotIgnore || ast.ignore_slots;
|
|
608
|
+
if (!slotIgnore) {
|
|
609
|
+
return [];
|
|
610
|
+
}
|
|
611
|
+
// Handle array format
|
|
612
|
+
if (Array.isArray(slotIgnore)) {
|
|
613
|
+
return slotIgnore.map((s) => normalizeSlotName(s));
|
|
614
|
+
}
|
|
615
|
+
// Handle string format (comma-separated)
|
|
616
|
+
if (typeof slotIgnore === 'string') {
|
|
617
|
+
return slotIgnore.split(',').map((s) => normalizeSlotName(s.trim()));
|
|
618
|
+
}
|
|
619
|
+
return [];
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* Normalize slot names to full path
|
|
623
|
+
* Examples: "hosting" -> "stack.hosting", "who" -> "human.who"
|
|
624
|
+
*/
|
|
625
|
+
function normalizeSlotName(slot) {
|
|
626
|
+
// Already has prefix
|
|
627
|
+
if (slot.includes('.')) {
|
|
628
|
+
return slot;
|
|
629
|
+
}
|
|
630
|
+
// Check each category for the slot
|
|
631
|
+
for (const [_category, slots] of Object.entries(ALL_SLOTS)) {
|
|
632
|
+
const fullSlot = slots.find(s => s.endsWith(`.${slot}`));
|
|
633
|
+
if (fullSlot) {
|
|
634
|
+
return fullSlot;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
// Return as-is if not found (will be ignored)
|
|
638
|
+
return slot;
|
|
639
|
+
}
|
|
640
|
+
// ============================================================================
|
|
53
641
|
// Main Compiler Class
|
|
54
642
|
// ============================================================================
|
|
55
643
|
class FafCompiler {
|
|
@@ -233,20 +821,27 @@ class FafCompiler {
|
|
|
233
821
|
if (analysis.context) {
|
|
234
822
|
const ctx = analysis.context;
|
|
235
823
|
// Map discovered items (WITHOUT modifying original)
|
|
236
|
-
if (ctx.projectName)
|
|
824
|
+
if (ctx.projectName) {
|
|
237
825
|
discovered.projectName = ctx.projectName;
|
|
238
|
-
|
|
826
|
+
}
|
|
827
|
+
if (ctx.mainLanguage) {
|
|
239
828
|
discovered.mainLanguage = ctx.mainLanguage;
|
|
240
|
-
|
|
829
|
+
}
|
|
830
|
+
if (ctx.framework) {
|
|
241
831
|
discovered.framework = ctx.framework;
|
|
242
|
-
|
|
832
|
+
}
|
|
833
|
+
if (ctx.database) {
|
|
243
834
|
discovered.database = ctx.database;
|
|
244
|
-
|
|
835
|
+
}
|
|
836
|
+
if (ctx.backend) {
|
|
245
837
|
discovered.backend = ctx.backend;
|
|
246
|
-
|
|
838
|
+
}
|
|
839
|
+
if (ctx.hosting) {
|
|
247
840
|
discovered.hosting = ctx.hosting;
|
|
248
|
-
|
|
841
|
+
}
|
|
842
|
+
if (ctx.buildTool) {
|
|
249
843
|
discovered.buildTool = ctx.buildTool;
|
|
844
|
+
}
|
|
250
845
|
}
|
|
251
846
|
return discovered;
|
|
252
847
|
}
|
|
@@ -295,150 +890,123 @@ class FafCompiler {
|
|
|
295
890
|
}
|
|
296
891
|
buildIR(ast) {
|
|
297
892
|
const slots = [];
|
|
298
|
-
// Detect project type to determine applicable
|
|
893
|
+
// Detect project type to determine applicable slots
|
|
299
894
|
const projectType = this.detectProjectTypeFromContext(ast);
|
|
300
895
|
if (process.env.FAF_DEBUG) {
|
|
301
896
|
console.log(`\n[DEBUG] Project type detected: ${projectType}`);
|
|
302
897
|
}
|
|
303
|
-
|
|
304
|
-
const
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
898
|
+
// Parse slot_ignore from the .faf file
|
|
899
|
+
const ignoredSlots = parseSlotIgnore(ast);
|
|
900
|
+
if (process.env.FAF_DEBUG && ignoredSlots.length > 0) {
|
|
901
|
+
console.log(`[DEBUG] slot_ignore: ${ignoredSlots.join(', ')}`);
|
|
902
|
+
}
|
|
903
|
+
// Get applicable slots for this project type
|
|
904
|
+
const applicableSlots = getSlotsForType(projectType);
|
|
905
|
+
if (process.env.FAF_DEBUG) {
|
|
906
|
+
console.log(`[DEBUG] Applicable slots (${applicableSlots.length}): ${applicableSlots.join(', ')}`);
|
|
907
|
+
}
|
|
908
|
+
// Filter out ignored slots
|
|
909
|
+
const activeSlots = applicableSlots.filter(slot => !ignoredSlots.includes(slot));
|
|
910
|
+
if (process.env.FAF_DEBUG && ignoredSlots.length > 0) {
|
|
911
|
+
console.log(`[DEBUG] Active slots after ignore (${activeSlots.length}): ${activeSlots.join(', ')}`);
|
|
912
|
+
}
|
|
913
|
+
// Helper to get value from ast based on slot path
|
|
914
|
+
const getSlotValue = (slotPath) => {
|
|
915
|
+
const parts = slotPath.split('.');
|
|
916
|
+
if (parts[0] === 'project') {
|
|
917
|
+
return ast.project?.[parts[1]];
|
|
918
|
+
}
|
|
919
|
+
else if (parts[0] === 'stack') {
|
|
920
|
+
return ast.stack?.[parts[1]];
|
|
311
921
|
}
|
|
922
|
+
else if (parts[0] === 'human') {
|
|
923
|
+
return ast.human_context?.[parts[1]];
|
|
924
|
+
}
|
|
925
|
+
return undefined;
|
|
926
|
+
};
|
|
927
|
+
// Add all active slots to the IR
|
|
928
|
+
for (const slotPath of activeSlots) {
|
|
929
|
+
const value = getSlotValue(slotPath);
|
|
930
|
+
this.addSlot(slots, slotPath, value, 'string', 'original', 1);
|
|
312
931
|
}
|
|
313
|
-
//
|
|
314
|
-
|
|
315
|
-
this.addSlot(slots, 'project.goal', ast.project?.goal, 'string', 'original', 1);
|
|
316
|
-
this.addSlot(slots, 'project.main_language', ast.project?.main_language, 'string', 'original', 1);
|
|
317
|
-
// Chrome Extension auto-fill: If it's a Chrome Extension, intelligently fill slots
|
|
932
|
+
// Special handling for certain project types (auto-fill missing values)
|
|
933
|
+
// Chrome Extension: auto-fill technical context
|
|
318
934
|
if (projectType === 'chrome-extension') {
|
|
319
|
-
|
|
320
|
-
if (!ast.stack)
|
|
935
|
+
if (!ast.stack) {
|
|
321
936
|
ast.stack = {};
|
|
322
|
-
|
|
937
|
+
}
|
|
938
|
+
if (!ast.stack.runtime) {
|
|
323
939
|
ast.stack.runtime = 'Chrome/Browser';
|
|
324
|
-
|
|
940
|
+
}
|
|
941
|
+
if (!ast.stack.hosting) {
|
|
325
942
|
ast.stack.hosting = 'Chrome Web Store';
|
|
326
|
-
|
|
943
|
+
}
|
|
944
|
+
if (!ast.stack.api_type) {
|
|
327
945
|
ast.stack.api_type = 'Chrome Extension APIs';
|
|
328
|
-
|
|
946
|
+
}
|
|
947
|
+
if (!ast.stack.backend) {
|
|
329
948
|
ast.stack.backend = 'Service Worker';
|
|
330
|
-
|
|
949
|
+
}
|
|
950
|
+
if (!ast.stack.database) {
|
|
331
951
|
ast.stack.database = 'chrome.storage API';
|
|
332
|
-
if (!ast.deployment)
|
|
333
|
-
ast.deployment = 'Web Store Upload';
|
|
334
|
-
// Add Chrome Extension specific slots
|
|
335
|
-
this.addSlot(slots, 'stack.runtime', ast.stack.runtime, 'string', 'discovered', 1);
|
|
336
|
-
this.addSlot(slots, 'stack.hosting', ast.stack.hosting, 'string', 'discovered', 1);
|
|
337
|
-
this.addSlot(slots, 'stack.api_type', ast.stack.api_type, 'string', 'discovered', 1);
|
|
338
|
-
this.addSlot(slots, 'stack.backend', ast.stack.backend, 'string', 'discovered', 1);
|
|
339
|
-
this.addSlot(slots, 'stack.database', ast.stack.database, 'string', 'discovered', 1);
|
|
340
|
-
this.addSlot(slots, 'stack.deployment', ast.deployment, 'string', 'discovered', 1);
|
|
341
|
-
// Also include frontend framework if specified (e.g., Svelte Chrome Extension)
|
|
342
|
-
if (ast.stack?.frontend) {
|
|
343
|
-
this.addSlot(slots, 'stack.frontend', ast.stack.frontend, 'string', 'original', 1);
|
|
344
952
|
}
|
|
345
|
-
if
|
|
346
|
-
|
|
953
|
+
// Add auto-filled slots (only if they're in the active slots list)
|
|
954
|
+
const chromeSlots = ['stack.runtime', 'stack.hosting', 'stack.api_type', 'stack.backend', 'stack.database'];
|
|
955
|
+
for (const slot of chromeSlots) {
|
|
956
|
+
if (activeSlots.includes(slot) && !slots.find(s => s.path === slot)) {
|
|
957
|
+
this.addSlot(slots, slot, getSlotValue(slot), 'string', 'discovered', 1);
|
|
958
|
+
}
|
|
347
959
|
}
|
|
348
960
|
}
|
|
349
|
-
// Static HTML auto-fill
|
|
961
|
+
// Static HTML: auto-fill technical context
|
|
350
962
|
if (projectType === 'static-html' || projectType === 'landing-page') {
|
|
351
|
-
if (!ast.stack)
|
|
963
|
+
if (!ast.stack) {
|
|
352
964
|
ast.stack = {};
|
|
353
|
-
|
|
965
|
+
}
|
|
966
|
+
if (!ast.stack.frontend) {
|
|
354
967
|
ast.stack.frontend = 'HTML/CSS/JavaScript';
|
|
355
|
-
|
|
968
|
+
}
|
|
969
|
+
if (!ast.stack.runtime) {
|
|
356
970
|
ast.stack.runtime = 'Browser';
|
|
357
|
-
|
|
971
|
+
}
|
|
972
|
+
if (!ast.stack.hosting) {
|
|
358
973
|
ast.stack.hosting = 'Static Hosting';
|
|
359
|
-
|
|
974
|
+
}
|
|
975
|
+
if (!ast.stack.build) {
|
|
360
976
|
ast.stack.build = 'Direct HTML (no build step)';
|
|
361
|
-
|
|
362
|
-
this.addSlot(slots, 'stack.runtime', ast.stack.runtime, 'string', 'discovered', 1);
|
|
363
|
-
this.addSlot(slots, 'stack.hosting', ast.stack.hosting, 'string', 'discovered', 1);
|
|
364
|
-
this.addSlot(slots, 'stack.build', ast.stack.build, 'string', 'discovered', 1);
|
|
365
|
-
// Leave backend, database, cicd as "None" - legitimate for static sites
|
|
977
|
+
}
|
|
366
978
|
}
|
|
367
|
-
// n8n Workflow auto-fill
|
|
979
|
+
// n8n Workflow: auto-fill technical context
|
|
368
980
|
if (projectType === 'n8n-workflow') {
|
|
369
|
-
|
|
370
|
-
|
|
981
|
+
if (!ast.project) {
|
|
982
|
+
ast.project = {};
|
|
983
|
+
}
|
|
984
|
+
if (!ast.project.main_language) {
|
|
985
|
+
ast.project.main_language = ast.tech_stack?.primary_language || 'JSON (workflow definition)';
|
|
986
|
+
}
|
|
987
|
+
if (!ast.stack) {
|
|
371
988
|
ast.stack = {};
|
|
372
|
-
|
|
989
|
+
}
|
|
373
990
|
if (!ast.stack.runtime) {
|
|
374
991
|
ast.stack.runtime = ast.tech_stack?.workflow_engine || 'n8n';
|
|
375
992
|
}
|
|
376
|
-
// Backend = n8n server runtime
|
|
377
993
|
if (!ast.stack.backend) {
|
|
378
994
|
ast.stack.backend = 'Node.js (n8n server)';
|
|
379
995
|
}
|
|
380
|
-
// API type = n8n trigger types
|
|
381
996
|
if (!ast.stack.api_type) {
|
|
382
997
|
ast.stack.api_type = 'Webhooks + HTTP';
|
|
383
998
|
}
|
|
384
|
-
// Database = vector DB or workflow state
|
|
385
999
|
if (!ast.stack.database) {
|
|
386
1000
|
ast.stack.database = ast.tech_stack?.infrastructure?.vector_db || 'Workflow State';
|
|
387
1001
|
}
|
|
388
|
-
// Hosting = deployment location
|
|
389
1002
|
if (!ast.stack.hosting) {
|
|
390
1003
|
ast.stack.hosting = 'n8n Cloud';
|
|
391
1004
|
}
|
|
392
|
-
// Build tool = how workflows are created
|
|
393
1005
|
if (!ast.stack.build) {
|
|
394
1006
|
ast.stack.build = 'n8n Visual Editor';
|
|
395
1007
|
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
ast.stack.connection = Array.isArray(ast.tech_stack.integrations)
|
|
399
|
-
? ast.tech_stack.integrations.join(', ')
|
|
400
|
-
: String(ast.tech_stack.integrations);
|
|
401
|
-
}
|
|
402
|
-
// Add n8n-specific slots (maps to standard 21-slot system)
|
|
403
|
-
// Backend slots (5)
|
|
404
|
-
this.addSlot(slots, 'stack.runtime', ast.stack.runtime, 'string', 'discovered', 1);
|
|
405
|
-
this.addSlot(slots, 'stack.backend', ast.stack.backend, 'string', 'discovered', 1);
|
|
406
|
-
this.addSlot(slots, 'stack.api_type', ast.stack.api_type, 'string', 'discovered', 1);
|
|
407
|
-
this.addSlot(slots, 'stack.database', ast.stack.database, 'string', 'discovered', 1);
|
|
408
|
-
this.addSlot(slots, 'stack.connection', ast.stack.connection, 'string', 'original', 1);
|
|
409
|
-
// Frontend slots (4) - n8n workflows don't have frontend, but we still count them
|
|
410
|
-
this.addSlot(slots, 'stack.frontend', ast.stack?.frontend, 'string', 'original', 1);
|
|
411
|
-
this.addSlot(slots, 'stack.css_framework', ast.stack?.css_framework, 'string', 'original', 1);
|
|
412
|
-
this.addSlot(slots, 'stack.ui_library', ast.stack?.ui_library, 'string', 'original', 1);
|
|
413
|
-
this.addSlot(slots, 'stack.state_management', ast.stack?.state_management, 'string', 'original', 1);
|
|
414
|
-
// Universal slots (3) will be added below (hosting, build, cicd)
|
|
415
|
-
}
|
|
416
|
-
// Stack slots - only add relevant ones based on project type
|
|
417
|
-
if (isFrontendProject) {
|
|
418
|
-
this.addSlot(slots, 'stack.frontend', ast.stack?.frontend, 'string', 'original', 1);
|
|
419
|
-
this.addSlot(slots, 'stack.css_framework', ast.stack?.css_framework, 'string', 'original', 1);
|
|
420
|
-
this.addSlot(slots, 'stack.ui_library', ast.stack?.ui_library, 'string', 'original', 1);
|
|
421
|
-
this.addSlot(slots, 'stack.state_management', ast.stack?.state_management, 'string', 'original', 1);
|
|
422
|
-
}
|
|
423
|
-
if (isBackendProject) {
|
|
424
|
-
this.addSlot(slots, 'stack.backend', ast.stack?.backend, 'string', 'original', 1);
|
|
425
|
-
this.addSlot(slots, 'stack.api_type', ast.stack?.api_type, 'string', 'original', 1);
|
|
426
|
-
this.addSlot(slots, 'stack.runtime', ast.stack?.runtime, 'string', 'original', 1);
|
|
427
|
-
this.addSlot(slots, 'stack.database', ast.stack?.database, 'string', 'original', 1);
|
|
428
|
-
this.addSlot(slots, 'stack.connection', ast.stack?.connection, 'string', 'original', 1);
|
|
429
|
-
}
|
|
430
|
-
// Universal stack slots (apply to all project types)
|
|
431
|
-
this.addSlot(slots, 'stack.hosting', ast.stack?.hosting, 'string', 'original', 1);
|
|
432
|
-
this.addSlot(slots, 'stack.build', ast.stack?.build, 'string', 'original', 1);
|
|
433
|
-
this.addSlot(slots, 'stack.cicd', ast.stack?.cicd, 'string', 'original', 1);
|
|
434
|
-
// Human context slots (6) - always applicable
|
|
435
|
-
this.addSlot(slots, 'human.who', ast.human_context?.who, 'string', 'original', 1);
|
|
436
|
-
this.addSlot(slots, 'human.what', ast.human_context?.what, 'string', 'original', 1);
|
|
437
|
-
this.addSlot(slots, 'human.why', ast.human_context?.why, 'string', 'original', 1);
|
|
438
|
-
this.addSlot(slots, 'human.where', ast.human_context?.where, 'string', 'original', 1);
|
|
439
|
-
this.addSlot(slots, 'human.when', ast.human_context?.when, 'string', 'original', 1);
|
|
440
|
-
this.addSlot(slots, 'human.how', ast.human_context?.how, 'string', 'original', 1);
|
|
441
|
-
// Discovered slots (if any)
|
|
1008
|
+
}
|
|
1009
|
+
// Discovered slots (if any) - only add if slot is active and not already filled
|
|
442
1010
|
if (ast._discovered) {
|
|
443
1011
|
const discovered = ast._discovered;
|
|
444
1012
|
const mapping = {
|
|
@@ -450,9 +1018,12 @@ class FafCompiler {
|
|
|
450
1018
|
'hosting': 'stack.hosting',
|
|
451
1019
|
'buildTool': 'stack.build'
|
|
452
1020
|
};
|
|
453
|
-
for (const [key,
|
|
454
|
-
if (discovered[key] && !this.hasValue(ast,
|
|
455
|
-
|
|
1021
|
+
for (const [key, slotPath] of Object.entries(mapping)) {
|
|
1022
|
+
if (discovered[key] && activeSlots.includes(slotPath) && !this.hasValue(ast, slotPath)) {
|
|
1023
|
+
// Only add to discovery if not already in slots
|
|
1024
|
+
if (!slots.find(s => s.path === slotPath)) {
|
|
1025
|
+
this.addSlot(slots, `discovery.${slotPath}`, discovered[key], 'string', 'discovered', 1);
|
|
1026
|
+
}
|
|
456
1027
|
}
|
|
457
1028
|
}
|
|
458
1029
|
}
|
|
@@ -484,8 +1055,9 @@ class FafCompiler {
|
|
|
484
1055
|
}
|
|
485
1056
|
isSlotFilled(value) {
|
|
486
1057
|
// Handle null, undefined, false explicitly
|
|
487
|
-
if (value === null || value === undefined || value === false)
|
|
1058
|
+
if (value === null || value === undefined || value === false) {
|
|
488
1059
|
return false;
|
|
1060
|
+
}
|
|
489
1061
|
if (typeof value === 'string') {
|
|
490
1062
|
// Also treat string representations of null/undefined as empty
|
|
491
1063
|
const empty = ['', 'None', 'Unknown', 'Not specified', 'N/A', 'null', 'undefined', '~'];
|
|
@@ -509,8 +1081,9 @@ class FafCompiler {
|
|
|
509
1081
|
}
|
|
510
1082
|
if (typeof value === 'object') {
|
|
511
1083
|
// Arrays and objects need content
|
|
512
|
-
if (Array.isArray(value))
|
|
1084
|
+
if (Array.isArray(value)) {
|
|
513
1085
|
return value.length > 0;
|
|
1086
|
+
}
|
|
514
1087
|
return Object.keys(value).length > 0;
|
|
515
1088
|
}
|
|
516
1089
|
return true;
|
|
@@ -519,16 +1092,30 @@ class FafCompiler {
|
|
|
519
1092
|
const parts = path.split('.');
|
|
520
1093
|
let current = ast;
|
|
521
1094
|
for (const part of parts) {
|
|
522
|
-
if (!current || !current[part])
|
|
1095
|
+
if (!current || !current[part]) {
|
|
523
1096
|
return false;
|
|
1097
|
+
}
|
|
524
1098
|
current = current[part];
|
|
525
1099
|
}
|
|
526
1100
|
return this.isSlotFilled(current);
|
|
527
1101
|
}
|
|
528
1102
|
detectProjectTypeFromContext(ast) {
|
|
529
|
-
// Check for explicit project type
|
|
530
|
-
if (ast.project?.type)
|
|
531
|
-
|
|
1103
|
+
// Check for explicit project type first
|
|
1104
|
+
if (ast.project?.type) {
|
|
1105
|
+
const explicitType = ast.project.type.toLowerCase();
|
|
1106
|
+
// Resolve aliases to canonical type
|
|
1107
|
+
for (const [type, def] of Object.entries(TYPE_DEFINITIONS)) {
|
|
1108
|
+
if (type === explicitType || def.aliases?.includes(explicitType)) {
|
|
1109
|
+
return type;
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
// If the explicit type is in TYPE_DEFINITIONS, use it directly
|
|
1113
|
+
if (TYPE_DEFINITIONS[explicitType]) {
|
|
1114
|
+
return explicitType;
|
|
1115
|
+
}
|
|
1116
|
+
// Unknown explicit type - use as-is (will fall to generic in getSlotsForType)
|
|
1117
|
+
return explicitType;
|
|
1118
|
+
}
|
|
532
1119
|
// Infer from goal and context
|
|
533
1120
|
const goal = (ast.project?.goal || '').toLowerCase();
|
|
534
1121
|
const what = (ast.human_context?.what || '').toLowerCase();
|
|
@@ -536,7 +1123,12 @@ class FafCompiler {
|
|
|
536
1123
|
// CLI tool indicators (check BEFORE Chrome Extension to avoid false positives)
|
|
537
1124
|
if (goal.includes('cli') || what.includes('cli') ||
|
|
538
1125
|
goal.includes('command line') || what.includes('command line')) {
|
|
539
|
-
return 'cli
|
|
1126
|
+
return 'cli';
|
|
1127
|
+
}
|
|
1128
|
+
// MCP Server indicators
|
|
1129
|
+
if (goal.includes('mcp') || what.includes('mcp server') ||
|
|
1130
|
+
goal.includes('model context protocol')) {
|
|
1131
|
+
return 'mcp-server';
|
|
540
1132
|
}
|
|
541
1133
|
// Chrome Extension detection with fuzzy matching (only if not CLI)
|
|
542
1134
|
const goalDetection = chrome_extension_detector_1.ChromeExtensionDetector.detect(goal);
|
|
@@ -562,8 +1154,9 @@ class FafCompiler {
|
|
|
562
1154
|
}
|
|
563
1155
|
// Language-based defaults
|
|
564
1156
|
if (mainLanguage === 'python') {
|
|
565
|
-
if (ast.stack?.frontend)
|
|
1157
|
+
if (ast.stack?.frontend) {
|
|
566
1158
|
return 'fullstack';
|
|
1159
|
+
}
|
|
567
1160
|
return 'python-app'; // Could be CLI, API, or data science
|
|
568
1161
|
}
|
|
569
1162
|
return 'generic';
|
|
@@ -592,8 +1185,9 @@ class FafCompiler {
|
|
|
592
1185
|
section === 'project' ? 'project' : 'stack';
|
|
593
1186
|
const sec = sections[sectionKey];
|
|
594
1187
|
sec.total++;
|
|
595
|
-
if (slot.filled)
|
|
1188
|
+
if (slot.filled) {
|
|
596
1189
|
sec.filled++;
|
|
1190
|
+
}
|
|
597
1191
|
sec.slots.push({
|
|
598
1192
|
id: slot.id,
|
|
599
1193
|
value: slot.value,
|
|
@@ -634,8 +1228,9 @@ class FafCompiler {
|
|
|
634
1228
|
return { filled, total, breakdown };
|
|
635
1229
|
}
|
|
636
1230
|
calculateScore(slots) {
|
|
637
|
-
if (slots.total === 0)
|
|
1231
|
+
if (slots.total === 0) {
|
|
638
1232
|
return 0;
|
|
1233
|
+
}
|
|
639
1234
|
return (slots.filled / slots.total) * 100;
|
|
640
1235
|
}
|
|
641
1236
|
// ============================================================================
|
|
@@ -712,16 +1307,18 @@ class FafCompiler {
|
|
|
712
1307
|
console.log(`\n❌ ${byType.error.length} Errors:`);
|
|
713
1308
|
byType.error.forEach(d => {
|
|
714
1309
|
console.log(` ${d.message}`);
|
|
715
|
-
if (d.suggestion)
|
|
1310
|
+
if (d.suggestion) {
|
|
716
1311
|
console.log(` → ${d.suggestion}`);
|
|
1312
|
+
}
|
|
717
1313
|
});
|
|
718
1314
|
}
|
|
719
1315
|
if (byType.warning.length > 0) {
|
|
720
1316
|
console.log(`\n⚠️ ${byType.warning.length} Warnings:`);
|
|
721
1317
|
byType.warning.forEach(d => {
|
|
722
1318
|
console.log(` ${d.message}`);
|
|
723
|
-
if (d.suggestion)
|
|
1319
|
+
if (d.suggestion) {
|
|
724
1320
|
console.log(` → ${d.suggestion}`);
|
|
1321
|
+
}
|
|
725
1322
|
});
|
|
726
1323
|
}
|
|
727
1324
|
if (byType.info.length > 0) {
|