great-cto 1.0.122 → 1.0.124
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/dist/archetypes.js +17 -3
- package/dist/detect.js +223 -1
- package/package.json +1 -1
package/dist/archetypes.js
CHANGED
|
@@ -169,19 +169,33 @@ const RULES = [
|
|
|
169
169
|
},
|
|
170
170
|
},
|
|
171
171
|
// ── library (no app framework, just code) ────────
|
|
172
|
+
// Detection priority: explicit "library" or "cli" stack signal from detect.ts (high confidence)
|
|
173
|
+
// Fallback: plain runtime + no web/mobile/infra framework (low confidence)
|
|
172
174
|
{
|
|
173
175
|
archetype: "library",
|
|
174
176
|
score: (d) => {
|
|
175
|
-
|
|
177
|
+
// Strong signal: detect.ts found library indicators
|
|
178
|
+
if (d.stack.includes("library") || d.stack.includes("cli")) {
|
|
179
|
+
return 7;
|
|
180
|
+
}
|
|
181
|
+
// Weaker signal: no app framework detected
|
|
182
|
+
const hasApp = d.stack.some((t) => ["next.js", "django", "fastapi", "flask", "express", "fastify", "nestjs", "hono",
|
|
183
|
+
"react-native", "expo", "tauri", "capacitor", "flutter",
|
|
184
|
+
"terraform", "pulumi", "aws-cdk", "helm",
|
|
185
|
+
"embedded", "zephyr", "esp-idf"].includes(t));
|
|
176
186
|
if (hasApp)
|
|
177
187
|
return 0;
|
|
178
|
-
// Plain Node or Python or Go or Rust with no web/mobile/infra → likely a library
|
|
179
188
|
if (d.stack.includes("nodejs") || d.stack.includes("python") || d.stack.includes("go") || d.stack.includes("rust")) {
|
|
180
189
|
return 2;
|
|
181
190
|
}
|
|
182
191
|
return 0;
|
|
183
192
|
},
|
|
184
|
-
reason: (
|
|
193
|
+
reason: (d) => {
|
|
194
|
+
if (d.stack.includes("library") || d.stack.includes("cli")) {
|
|
195
|
+
return "package.json/pyproject/Cargo.toml indicates a publishable library or CLI";
|
|
196
|
+
}
|
|
197
|
+
return "no web/mobile/infra framework detected — looks like a library/SDK";
|
|
198
|
+
},
|
|
185
199
|
},
|
|
186
200
|
];
|
|
187
201
|
export function pickArchetype(d) {
|
package/dist/detect.js
CHANGED
|
@@ -60,6 +60,14 @@ export function detect(dir) {
|
|
|
60
60
|
}
|
|
61
61
|
if (has("expo"))
|
|
62
62
|
stack.add("expo");
|
|
63
|
+
if (has("@tauri-apps/api") || has("@tauri-apps/cli")) {
|
|
64
|
+
stack.add("tauri");
|
|
65
|
+
sig("desktop", "tauri");
|
|
66
|
+
}
|
|
67
|
+
if (has("@capacitor/core")) {
|
|
68
|
+
stack.add("capacitor");
|
|
69
|
+
sig("mobile", "capacitor");
|
|
70
|
+
}
|
|
63
71
|
// AI / agents
|
|
64
72
|
if (has("openai")) {
|
|
65
73
|
stack.add("openai-sdk");
|
|
@@ -73,6 +81,14 @@ export function detect(dir) {
|
|
|
73
81
|
stack.add("langchain");
|
|
74
82
|
sig("ai", "langchain");
|
|
75
83
|
}
|
|
84
|
+
if (has("@langchain/langgraph")) {
|
|
85
|
+
stack.add("langgraph");
|
|
86
|
+
sig("agent", "langgraph");
|
|
87
|
+
}
|
|
88
|
+
if (has("crewai")) {
|
|
89
|
+
stack.add("crewai");
|
|
90
|
+
sig("agent", "crewai");
|
|
91
|
+
}
|
|
76
92
|
if (has("llamaindex")) {
|
|
77
93
|
stack.add("llamaindex");
|
|
78
94
|
sig("ai", "llamaindex");
|
|
@@ -81,6 +97,18 @@ export function detect(dir) {
|
|
|
81
97
|
stack.add("mcp");
|
|
82
98
|
sig("ai", "mcp");
|
|
83
99
|
}
|
|
100
|
+
if (has("ollama")) {
|
|
101
|
+
stack.add("ollama");
|
|
102
|
+
sig("ai", "ollama");
|
|
103
|
+
}
|
|
104
|
+
if (has("@mastra/core")) {
|
|
105
|
+
stack.add("mastra");
|
|
106
|
+
sig("agent", "mastra");
|
|
107
|
+
}
|
|
108
|
+
if (has("ai")) {
|
|
109
|
+
stack.add("vercel-ai-sdk");
|
|
110
|
+
sig("ai", "vercel-ai-sdk");
|
|
111
|
+
}
|
|
84
112
|
// Payments / commerce
|
|
85
113
|
if (has("stripe") || has("@stripe/stripe-js")) {
|
|
86
114
|
stack.add("stripe");
|
|
@@ -94,6 +122,22 @@ export function detect(dir) {
|
|
|
94
122
|
stack.add("braintree");
|
|
95
123
|
sig("commerce", "braintree");
|
|
96
124
|
}
|
|
125
|
+
if (has("@adyen/api-library")) {
|
|
126
|
+
stack.add("adyen");
|
|
127
|
+
sig("commerce", "adyen");
|
|
128
|
+
}
|
|
129
|
+
if (has("@paddle/paddle-node-sdk")) {
|
|
130
|
+
stack.add("paddle");
|
|
131
|
+
sig("commerce", "paddle");
|
|
132
|
+
}
|
|
133
|
+
if (has("@lemonsqueezy/lemonsqueezy.js")) {
|
|
134
|
+
stack.add("lemonsqueezy");
|
|
135
|
+
sig("commerce", "lemonsqueezy");
|
|
136
|
+
}
|
|
137
|
+
if (has("polar-sh")) {
|
|
138
|
+
stack.add("polar");
|
|
139
|
+
sig("commerce", "polar");
|
|
140
|
+
}
|
|
97
141
|
// Auth
|
|
98
142
|
if (has("next-auth") || has("@auth/core"))
|
|
99
143
|
stack.add("auth");
|
|
@@ -101,25 +145,66 @@ export function detect(dir) {
|
|
|
101
145
|
stack.add("clerk");
|
|
102
146
|
if (has("@supabase/supabase-js"))
|
|
103
147
|
stack.add("supabase");
|
|
148
|
+
if (has("lucia")) {
|
|
149
|
+
stack.add("lucia");
|
|
150
|
+
}
|
|
151
|
+
if (has("@workos-inc/node")) {
|
|
152
|
+
stack.add("workos");
|
|
153
|
+
}
|
|
104
154
|
// Databases / ORMs
|
|
105
155
|
if (has("prisma") || has("@prisma/client"))
|
|
106
156
|
stack.add("prisma");
|
|
107
157
|
if (has("drizzle-orm"))
|
|
108
158
|
stack.add("drizzle");
|
|
159
|
+
if (has("kysely"))
|
|
160
|
+
stack.add("kysely");
|
|
109
161
|
if (has("typeorm"))
|
|
110
162
|
stack.add("typeorm");
|
|
111
163
|
if (has("mongodb") || has("mongoose"))
|
|
112
164
|
stack.add("mongodb");
|
|
113
165
|
if (has("pg") || has("postgres"))
|
|
114
166
|
stack.add("postgres");
|
|
167
|
+
if (has("@neondatabase/serverless")) {
|
|
168
|
+
stack.add("neon");
|
|
169
|
+
sig("edge", "neon");
|
|
170
|
+
}
|
|
171
|
+
if (has("@planetscale/database")) {
|
|
172
|
+
stack.add("planetscale");
|
|
173
|
+
sig("edge", "planetscale");
|
|
174
|
+
}
|
|
175
|
+
if (has("@libsql/client")) {
|
|
176
|
+
stack.add("turso");
|
|
177
|
+
sig("edge", "turso");
|
|
178
|
+
}
|
|
115
179
|
if (has("mysql") || has("mysql2"))
|
|
116
180
|
stack.add("mysql");
|
|
117
181
|
if (has("redis") || has("ioredis"))
|
|
118
182
|
stack.add("redis");
|
|
183
|
+
if (has("duckdb") || has("@duckdb/node-api")) {
|
|
184
|
+
stack.add("duckdb");
|
|
185
|
+
sig("data", "duckdb");
|
|
186
|
+
}
|
|
119
187
|
// Testing
|
|
120
188
|
if (has("jest") || has("vitest") || has("mocha") || has("@playwright/test") || has("playwright")) {
|
|
121
189
|
sig("tests", "package.json");
|
|
122
190
|
}
|
|
191
|
+
// Library detection (npm package intended for distribution)
|
|
192
|
+
// Signals: has "main" or "exports", NOT "private:true", NOT a typical app structure
|
|
193
|
+
const isPublishable = !pkg.private && (pkg.main || pkg.exports || pkg.module || pkg.type === "module");
|
|
194
|
+
const hasAppStructure = existsSync(join(dir, "pages")) ||
|
|
195
|
+
existsSync(join(dir, "app")) ||
|
|
196
|
+
existsSync(join(dir, "src/pages")) ||
|
|
197
|
+
existsSync(join(dir, "src/app")) ||
|
|
198
|
+
existsSync(join(dir, "public/index.html"));
|
|
199
|
+
const hasBin = !!pkg.bin;
|
|
200
|
+
if (isPublishable && !hasAppStructure) {
|
|
201
|
+
stack.add("library");
|
|
202
|
+
sig("library", "package.json");
|
|
203
|
+
}
|
|
204
|
+
if (hasBin) {
|
|
205
|
+
stack.add("cli");
|
|
206
|
+
sig("library", "bin");
|
|
207
|
+
}
|
|
123
208
|
}
|
|
124
209
|
catch { /* ignore malformed */ }
|
|
125
210
|
}
|
|
@@ -157,20 +242,96 @@ export function detect(dir) {
|
|
|
157
242
|
stack.add("langchain");
|
|
158
243
|
sig("ai", "langchain");
|
|
159
244
|
}
|
|
245
|
+
if (ihas("langgraph")) {
|
|
246
|
+
stack.add("langgraph");
|
|
247
|
+
sig("agent", "langgraph");
|
|
248
|
+
}
|
|
249
|
+
if (ihas("crewai")) {
|
|
250
|
+
stack.add("crewai");
|
|
251
|
+
sig("agent", "crewai");
|
|
252
|
+
}
|
|
253
|
+
if (ihas("autogen-agentchat") || ihas("pyautogen")) {
|
|
254
|
+
stack.add("autogen");
|
|
255
|
+
sig("agent", "autogen");
|
|
256
|
+
}
|
|
257
|
+
if (ihas("dspy-ai")) {
|
|
258
|
+
stack.add("dspy");
|
|
259
|
+
sig("ai", "dspy");
|
|
260
|
+
}
|
|
261
|
+
if (ihas("vllm")) {
|
|
262
|
+
stack.add("vllm");
|
|
263
|
+
sig("ai", "vllm");
|
|
264
|
+
}
|
|
265
|
+
if (ihas("ollama")) {
|
|
266
|
+
stack.add("ollama");
|
|
267
|
+
sig("ai", "ollama");
|
|
268
|
+
}
|
|
269
|
+
if (ihas("ragas") || ihas("deepeval")) {
|
|
270
|
+
stack.add("llm-eval");
|
|
271
|
+
sig("ai", "llm-eval");
|
|
272
|
+
}
|
|
160
273
|
if (ihas("llama-index") || ihas("llamaindex"))
|
|
161
274
|
stack.add("llamaindex");
|
|
162
275
|
if (ihas("torch") || ihas("tensorflow") || ihas("scikit-learn")) {
|
|
163
276
|
stack.add("ml");
|
|
164
277
|
sig("ml", "python");
|
|
165
278
|
}
|
|
166
|
-
if (ihas("
|
|
279
|
+
if (ihas("opencv") || ihas("ultralytics") || ihas("detectron2")) {
|
|
280
|
+
stack.add("computer-vision");
|
|
281
|
+
sig("ai", "computer-vision");
|
|
282
|
+
}
|
|
283
|
+
if (ihas("pandas") || ihas("dask") || ihas("airflow") || ihas("prefect") || ihas("dagster")) {
|
|
167
284
|
stack.add("data-pipeline");
|
|
168
285
|
sig("data", "python");
|
|
169
286
|
}
|
|
287
|
+
if (ihas("polars")) {
|
|
288
|
+
stack.add("polars");
|
|
289
|
+
sig("data", "polars");
|
|
290
|
+
}
|
|
291
|
+
if (ihas("duckdb")) {
|
|
292
|
+
stack.add("duckdb");
|
|
293
|
+
sig("data", "duckdb");
|
|
294
|
+
}
|
|
295
|
+
if (ihas("pyiceberg")) {
|
|
296
|
+
stack.add("iceberg");
|
|
297
|
+
sig("data", "iceberg");
|
|
298
|
+
}
|
|
299
|
+
if (ihas("dbt-core") || ihas("dbt-")) {
|
|
300
|
+
stack.add("dbt");
|
|
301
|
+
sig("data", "dbt");
|
|
302
|
+
}
|
|
170
303
|
if (ihas("stripe")) {
|
|
171
304
|
stack.add("stripe");
|
|
172
305
|
sig("commerce", "stripe");
|
|
173
306
|
}
|
|
307
|
+
// Library detection — Python package intended for distribution
|
|
308
|
+
// Signal: has setup.py / pyproject.toml [project] or [tool.poetry] without 'private = true'
|
|
309
|
+
const isPyLib = pyproject.includes("[project]") || pyproject.includes("[tool.poetry]") ||
|
|
310
|
+
existsSync(join(dir, "setup.py"));
|
|
311
|
+
const hasPyApp = existsSync(join(dir, "manage.py")) ||
|
|
312
|
+
existsSync(join(dir, "main.py")) ||
|
|
313
|
+
existsSync(join(dir, "app.py")) ||
|
|
314
|
+
existsSync(join(dir, "wsgi.py"));
|
|
315
|
+
if (isPyLib && !hasPyApp) {
|
|
316
|
+
stack.add("library");
|
|
317
|
+
sig("library", "python");
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
catch { /* ignore */ }
|
|
321
|
+
}
|
|
322
|
+
// ── Flutter / Dart ────────────────────────────────────────
|
|
323
|
+
if (existsSync(join(dir, "pubspec.yaml"))) {
|
|
324
|
+
sig("flutter", "pubspec.yaml");
|
|
325
|
+
stack.add("flutter");
|
|
326
|
+
languages.add("dart");
|
|
327
|
+
try {
|
|
328
|
+
const pubspec = readFileSync(join(dir, "pubspec.yaml"), "utf-8").toLowerCase();
|
|
329
|
+
if (pubspec.includes("flutter:"))
|
|
330
|
+
sig("mobile", "flutter");
|
|
331
|
+
if (pubspec.includes("flutter_bloc"))
|
|
332
|
+
stack.add("bloc");
|
|
333
|
+
if (pubspec.includes("riverpod"))
|
|
334
|
+
stack.add("riverpod");
|
|
174
335
|
}
|
|
175
336
|
catch { /* ignore */ }
|
|
176
337
|
}
|
|
@@ -185,6 +346,20 @@ export function detect(dir) {
|
|
|
185
346
|
stack.add("stripe");
|
|
186
347
|
if (gomod.includes("openai-go"))
|
|
187
348
|
stack.add("openai-sdk");
|
|
349
|
+
if (gomod.includes("anthropic-sdk-go"))
|
|
350
|
+
stack.add("anthropic-sdk");
|
|
351
|
+
if (gomod.includes("gin-gonic/gin"))
|
|
352
|
+
stack.add("gin");
|
|
353
|
+
if (gomod.includes("labstack/echo"))
|
|
354
|
+
stack.add("echo");
|
|
355
|
+
if (gomod.includes("go-chi/chi"))
|
|
356
|
+
stack.add("chi");
|
|
357
|
+
// Library detection: no main package + intended as module
|
|
358
|
+
const hasMainGo = existsSync(join(dir, "main.go")) || existsSync(join(dir, "cmd"));
|
|
359
|
+
if (!hasMainGo) {
|
|
360
|
+
stack.add("library");
|
|
361
|
+
sig("library", "go");
|
|
362
|
+
}
|
|
188
363
|
}
|
|
189
364
|
catch { /* ignore */ }
|
|
190
365
|
}
|
|
@@ -198,6 +373,17 @@ export function detect(dir) {
|
|
|
198
373
|
if (cargo.includes("actix-web") || cargo.includes("axum") || cargo.includes("rocket")) {
|
|
199
374
|
sig("web-rust", "Cargo.toml");
|
|
200
375
|
}
|
|
376
|
+
if (cargo.includes("embassy")) {
|
|
377
|
+
stack.add("embassy");
|
|
378
|
+
sig("embedded", "embassy");
|
|
379
|
+
}
|
|
380
|
+
// Library detection: [lib] section without [[bin]]
|
|
381
|
+
const hasLib = cargo.includes("[lib]") || (!cargo.includes("[[bin]]") && cargo.includes("[package]"));
|
|
382
|
+
const hasBin = cargo.includes("[[bin]]") || existsSync(join(dir, "src/main.rs"));
|
|
383
|
+
if (hasLib && !hasBin) {
|
|
384
|
+
stack.add("library");
|
|
385
|
+
sig("library", "rust");
|
|
386
|
+
}
|
|
201
387
|
}
|
|
202
388
|
catch { /* ignore */ }
|
|
203
389
|
}
|
|
@@ -230,18 +416,44 @@ export function detect(dir) {
|
|
|
230
416
|
sig("infra", "terraform");
|
|
231
417
|
stack.add("terraform");
|
|
232
418
|
}
|
|
419
|
+
if (existsSync(join(dir, "Pulumi.yaml")) || existsSync(join(dir, "Pulumi.yml"))) {
|
|
420
|
+
sig("infra", "pulumi");
|
|
421
|
+
stack.add("pulumi");
|
|
422
|
+
}
|
|
423
|
+
if (existsSync(join(dir, "cdk.json"))) {
|
|
424
|
+
sig("infra", "aws-cdk");
|
|
425
|
+
stack.add("aws-cdk");
|
|
426
|
+
}
|
|
233
427
|
if (existsSync(join(dir, "Chart.yaml")) || existsSync(join(dir, "values.yaml"))) {
|
|
234
428
|
sig("infra", "helm");
|
|
235
429
|
stack.add("helm");
|
|
236
430
|
}
|
|
431
|
+
if (existsSync(join(dir, "helmfile.yaml")) || existsSync(join(dir, "helmfile.yml"))) {
|
|
432
|
+
sig("infra", "helmfile");
|
|
433
|
+
stack.add("helmfile");
|
|
434
|
+
}
|
|
237
435
|
if (safeGlob(dir, /kustomization\.ya?ml$/)) {
|
|
238
436
|
sig("infra", "kustomize");
|
|
239
437
|
stack.add("kubernetes");
|
|
240
438
|
}
|
|
439
|
+
if (existsSync(join(dir, "argocd")) || safeGlob(dir, /argocd-application\.ya?ml$/)) {
|
|
440
|
+
sig("infra", "argocd");
|
|
441
|
+
stack.add("argocd");
|
|
442
|
+
}
|
|
241
443
|
if (existsSync(join(dir, "Dockerfile")) || existsSync(join(dir, "docker-compose.yml"))) {
|
|
242
444
|
sig("docker", "Dockerfile");
|
|
243
445
|
stack.add("docker");
|
|
244
446
|
}
|
|
447
|
+
if (existsSync(join(dir, "dbt_project.yml"))) {
|
|
448
|
+
sig("data", "dbt");
|
|
449
|
+
stack.add("dbt");
|
|
450
|
+
stack.add("data-pipeline");
|
|
451
|
+
}
|
|
452
|
+
if (existsSync(join(dir, "dagster.yaml")) || existsSync(join(dir, "workspace.yaml"))) {
|
|
453
|
+
sig("data", "dagster");
|
|
454
|
+
stack.add("dagster");
|
|
455
|
+
stack.add("data-pipeline");
|
|
456
|
+
}
|
|
245
457
|
// ── Smart contracts ──────────────────────────────────────
|
|
246
458
|
if (existsSync(join(dir, "hardhat.config.js")) ||
|
|
247
459
|
existsSync(join(dir, "hardhat.config.ts")) ||
|
|
@@ -262,6 +474,16 @@ export function detect(dir) {
|
|
|
262
474
|
sig("embedded", "platformio/sdk");
|
|
263
475
|
stack.add("embedded");
|
|
264
476
|
}
|
|
477
|
+
if (existsSync(join(dir, "west.yml")) || existsSync(join(dir, "zephyr"))) {
|
|
478
|
+
sig("embedded", "zephyr");
|
|
479
|
+
stack.add("embedded");
|
|
480
|
+
stack.add("zephyr");
|
|
481
|
+
}
|
|
482
|
+
if (existsSync(join(dir, "CMakePresets.json")) && existsSync(join(dir, "components"))) {
|
|
483
|
+
sig("embedded", "esp-idf");
|
|
484
|
+
stack.add("embedded");
|
|
485
|
+
stack.add("esp-idf");
|
|
486
|
+
}
|
|
265
487
|
// ── Package manager ──────────────────────────────────────
|
|
266
488
|
let packageManager = null;
|
|
267
489
|
if (existsSync(join(dir, "pnpm-lock.yaml")))
|
package/package.json
CHANGED