adelie-ai 0.3.6 → 0.3.7
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/adelie/__init__.py +1 -1
- package/adelie/agents/expert_ai.py +215 -164
- package/package.json +1 -1
package/adelie/__init__.py
CHANGED
|
@@ -267,178 +267,229 @@ def _get_scaffolding_need() -> str:
|
|
|
267
267
|
if not project_root.exists():
|
|
268
268
|
return ""
|
|
269
269
|
|
|
270
|
-
# Gather existing files for detection
|
|
271
|
-
existing = set()
|
|
272
|
-
for f in project_root.iterdir():
|
|
273
|
-
if f.is_file():
|
|
274
|
-
existing.add(f.name.lower())
|
|
275
|
-
src_dir = project_root / "src"
|
|
276
|
-
if src_dir.exists():
|
|
277
|
-
for f in src_dir.iterdir():
|
|
278
|
-
if f.is_file():
|
|
279
|
-
existing.add(f"src/{f.name}".lower())
|
|
280
|
-
|
|
281
|
-
# Define scaffolding checks per project type
|
|
282
270
|
checks: list[dict] = []
|
|
283
271
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
# ── Framework-aware scaffolding checks ────────────────────────────
|
|
289
|
-
framework = _detect_framework(project_root)
|
|
290
|
-
|
|
291
|
-
if framework == "nextjs":
|
|
292
|
-
# Next.js needs: package.json, next.config.*, src/app/layout.tsx or pages/
|
|
293
|
-
entry_files = {
|
|
294
|
-
"package.json": "Node.js dependencies and scripts (npm run dev, npm run build)",
|
|
295
|
-
}
|
|
296
|
-
# Check for app router or pages router
|
|
297
|
-
has_app_router = (
|
|
298
|
-
(src_dir / "app" / "layout.tsx").exists()
|
|
299
|
-
or (src_dir / "app" / "layout.ts").exists()
|
|
300
|
-
or (src_dir / "app" / "layout.jsx").exists()
|
|
301
|
-
or (project_root / "app" / "layout.tsx").exists()
|
|
302
|
-
)
|
|
303
|
-
has_pages_router = (
|
|
304
|
-
(src_dir / "pages").exists()
|
|
305
|
-
or (project_root / "pages").exists()
|
|
306
|
-
)
|
|
307
|
-
if not has_app_router and not has_pages_router:
|
|
308
|
-
entry_files["src/app/layout.tsx"] = "Next.js App Router root layout"
|
|
309
|
-
entry_files["src/app/page.tsx"] = "Next.js App Router home page"
|
|
310
|
-
|
|
311
|
-
for fname, desc in entry_files.items():
|
|
312
|
-
path = project_root / fname
|
|
313
|
-
if not path.exists():
|
|
314
|
-
checks.append({"file": fname, "desc": desc})
|
|
315
|
-
|
|
316
|
-
elif framework == "nuxt":
|
|
317
|
-
entry_files = {
|
|
318
|
-
"package.json": "Node.js dependencies and scripts",
|
|
319
|
-
}
|
|
320
|
-
has_app_vue = (project_root / "app.vue").exists()
|
|
321
|
-
has_pages = (project_root / "pages").exists()
|
|
322
|
-
if not has_app_vue and not has_pages:
|
|
323
|
-
entry_files["app.vue"] = "Nuxt root App component"
|
|
324
|
-
|
|
325
|
-
for fname, desc in entry_files.items():
|
|
326
|
-
path = project_root / fname
|
|
327
|
-
if not path.exists():
|
|
328
|
-
checks.append({"file": fname, "desc": desc})
|
|
329
|
-
|
|
330
|
-
elif framework == "sveltekit":
|
|
331
|
-
entry_files = {
|
|
332
|
-
"package.json": "Node.js dependencies and scripts",
|
|
333
|
-
}
|
|
334
|
-
has_routes = (src_dir / "routes").exists()
|
|
335
|
-
if not has_routes:
|
|
336
|
-
entry_files["src/routes/+page.svelte"] = "SvelteKit root page"
|
|
337
|
-
|
|
338
|
-
for fname, desc in entry_files.items():
|
|
339
|
-
path = project_root / fname
|
|
340
|
-
if not path.exists():
|
|
341
|
-
checks.append({"file": fname, "desc": desc})
|
|
342
|
-
|
|
343
|
-
elif framework in ("remix", "angular"):
|
|
344
|
-
# Minimal checks — just package.json
|
|
345
|
-
if not (project_root / "package.json").exists():
|
|
346
|
-
checks.append({"file": "package.json", "desc": "Node.js dependencies and scripts"})
|
|
347
|
-
|
|
348
|
-
elif has_tsx or has_ts or has_pkg:
|
|
349
|
-
# Default: Vite / vanilla React project (original behavior)
|
|
350
|
-
entry_files = {
|
|
351
|
-
"index.html": "Vite entry point — must reference src/main.tsx",
|
|
352
|
-
"package.json": "Node.js dependencies and scripts (npm run build, npm run dev)",
|
|
353
|
-
"tsconfig.json": "TypeScript compiler configuration",
|
|
354
|
-
}
|
|
355
|
-
# Check src/main.tsx or src/main.ts
|
|
356
|
-
has_main = (
|
|
357
|
-
(src_dir / "main.tsx").exists()
|
|
358
|
-
or (src_dir / "main.ts").exists()
|
|
359
|
-
or (src_dir / "main.jsx").exists()
|
|
360
|
-
or (src_dir / "main.js").exists()
|
|
361
|
-
or (src_dir / "index.tsx").exists()
|
|
362
|
-
or (src_dir / "index.ts").exists()
|
|
363
|
-
)
|
|
364
|
-
if not has_main:
|
|
365
|
-
entry_files["src/main.tsx"] = "React root render — ReactDOM.createRoot + App import"
|
|
366
|
-
|
|
367
|
-
has_vite_cfg = (
|
|
368
|
-
(project_root / "vite.config.ts").exists()
|
|
369
|
-
or (project_root / "vite.config.js").exists()
|
|
370
|
-
)
|
|
371
|
-
if not has_vite_cfg:
|
|
372
|
-
entry_files["vite.config.ts"] = "Vite build configuration with React plugin"
|
|
373
|
-
|
|
374
|
-
for fname, desc in entry_files.items():
|
|
375
|
-
path = project_root / fname
|
|
376
|
-
if not path.exists():
|
|
377
|
-
checks.append({"file": fname, "desc": desc})
|
|
378
|
-
|
|
379
|
-
# Python project detection
|
|
380
|
-
has_py = any(f.suffix == ".py" for f in project_root.rglob("*") if f.is_file())
|
|
381
|
-
if has_py and not (has_tsx or has_ts or has_pkg):
|
|
382
|
-
py_entries = {
|
|
383
|
-
"requirements.txt": "Python dependencies",
|
|
384
|
-
}
|
|
385
|
-
for fname, desc in py_entries.items():
|
|
386
|
-
if not (project_root / fname).exists():
|
|
387
|
-
checks.append({"file": fname, "desc": desc})
|
|
388
|
-
|
|
389
|
-
# ── tsconfig.json deep validation ─────────────────────────────────
|
|
390
|
-
tsconfig_path = project_root / "tsconfig.json"
|
|
391
|
-
if tsconfig_path.exists():
|
|
272
|
+
# Detect workspaces
|
|
273
|
+
workspaces = []
|
|
274
|
+
pkg_path = project_root / "package.json"
|
|
275
|
+
if pkg_path.exists():
|
|
392
276
|
try:
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
# Check "references" — e.g. [{"path": "./tsconfig.node.json"}]
|
|
401
|
-
for ref in tsconfig.get("references", []):
|
|
402
|
-
ref_path = ref.get("path", "")
|
|
403
|
-
if ref_path:
|
|
404
|
-
ref_file = project_root / ref_path
|
|
405
|
-
# If path is a directory, tsconfig.json is implied
|
|
406
|
-
if not ref_file.exists() and not ref_file.with_suffix(".json").exists():
|
|
407
|
-
checks.append({
|
|
408
|
-
"file": ref_path,
|
|
409
|
-
"desc": f"Referenced by tsconfig.json — must exist or build fails (TS6053)",
|
|
410
|
-
})
|
|
277
|
+
pkg = json.loads(pkg_path.read_text(encoding="utf-8"))
|
|
278
|
+
workspaces = pkg.get("workspaces", [])
|
|
279
|
+
if isinstance(workspaces, dict):
|
|
280
|
+
workspaces = workspaces.get("packages", [])
|
|
281
|
+
except Exception:
|
|
282
|
+
pass
|
|
411
283
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
#
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
284
|
+
# If no explicit workspaces, check common folders
|
|
285
|
+
if not workspaces:
|
|
286
|
+
for folder in ["client", "server", "frontend", "backend"]:
|
|
287
|
+
if (project_root / folder).exists() and (project_root / folder).is_dir():
|
|
288
|
+
workspaces.append(folder)
|
|
289
|
+
|
|
290
|
+
# We will perform check on each workspace root, or on the project_root if no workspaces
|
|
291
|
+
targets = []
|
|
292
|
+
if workspaces:
|
|
293
|
+
for ws in workspaces:
|
|
294
|
+
# simple wildcards resolution
|
|
295
|
+
if "*" in ws or "?" in ws:
|
|
296
|
+
import glob
|
|
297
|
+
matched = glob.glob(str(project_root / ws))
|
|
298
|
+
for m in matched:
|
|
299
|
+
targets.append(Path(m))
|
|
300
|
+
else:
|
|
301
|
+
ws_path = project_root / ws
|
|
302
|
+
if ws_path.exists() and ws_path.is_dir():
|
|
303
|
+
targets.append(ws_path)
|
|
304
|
+
|
|
305
|
+
if not targets:
|
|
306
|
+
targets = [project_root]
|
|
307
|
+
|
|
308
|
+
for target in targets:
|
|
309
|
+
# Resolve path relative to project_root to report
|
|
310
|
+
rel_prefix = ""
|
|
311
|
+
if target != project_root:
|
|
312
|
+
rel_prefix = f"{target.relative_to(project_root).as_posix()}/"
|
|
313
|
+
|
|
314
|
+
existing = set()
|
|
315
|
+
for f in target.iterdir():
|
|
316
|
+
if f.is_file():
|
|
317
|
+
existing.add(f.name.lower())
|
|
318
|
+
src_dir = target / "src"
|
|
319
|
+
if src_dir.exists() and src_dir.is_dir():
|
|
320
|
+
for f in src_dir.iterdir():
|
|
321
|
+
if f.is_file():
|
|
322
|
+
existing.add(f"src/{f.name}".lower())
|
|
323
|
+
|
|
324
|
+
# Check project type for this target
|
|
325
|
+
has_tsx = any(f.suffix in (".tsx", ".jsx") for f in target.rglob("*") if f.is_file())
|
|
326
|
+
has_ts = any(f.suffix == ".ts" for f in target.rglob("*") if f.is_file())
|
|
327
|
+
has_pkg = "package.json" in existing
|
|
328
|
+
|
|
329
|
+
framework = _detect_framework(target)
|
|
330
|
+
|
|
331
|
+
# If it is a server-only workspace in a monorepo, only check package.json and tsconfig.json
|
|
332
|
+
is_server_ws = target != project_root and any(x in target.name.lower() for x in ["server", "backend", "api"])
|
|
333
|
+
|
|
334
|
+
if is_server_ws:
|
|
335
|
+
server_files = {
|
|
336
|
+
"package.json": "Node.js dependencies and scripts",
|
|
337
|
+
}
|
|
338
|
+
if has_ts:
|
|
339
|
+
server_files["tsconfig.json"] = "TypeScript compiler configuration"
|
|
340
|
+
# Check for src/index.ts or src/main.ts
|
|
341
|
+
has_server_main = (
|
|
342
|
+
(src_dir / "index.ts").exists()
|
|
343
|
+
or (src_dir / "main.ts").exists()
|
|
344
|
+
or (src_dir / "server.ts").exists()
|
|
345
|
+
)
|
|
346
|
+
if not has_server_main:
|
|
347
|
+
server_files["src/index.ts"] = "Server entry point"
|
|
348
|
+
|
|
349
|
+
for fname, desc in server_files.items():
|
|
350
|
+
path = target / fname
|
|
351
|
+
if not path.exists():
|
|
352
|
+
checks.append({"file": f"{rel_prefix}{fname}", "desc": desc})
|
|
353
|
+
|
|
354
|
+
elif framework == "nextjs":
|
|
355
|
+
entry_files = {
|
|
356
|
+
"package.json": "Node.js dependencies and scripts (npm run dev, npm run build)",
|
|
357
|
+
}
|
|
358
|
+
has_app_router = (
|
|
359
|
+
(src_dir / "app" / "layout.tsx").exists()
|
|
360
|
+
or (src_dir / "app" / "layout.ts").exists()
|
|
361
|
+
or (src_dir / "app" / "layout.jsx").exists()
|
|
362
|
+
or (target / "app" / "layout.tsx").exists()
|
|
363
|
+
)
|
|
364
|
+
has_pages_router = (
|
|
365
|
+
(src_dir / "pages").exists()
|
|
366
|
+
or (target / "pages").exists()
|
|
367
|
+
)
|
|
368
|
+
if not has_app_router and not has_pages_router:
|
|
369
|
+
entry_files["src/app/layout.tsx"] = "Next.js App Router root layout"
|
|
370
|
+
entry_files["src/app/page.tsx"] = "Next.js App Router home page"
|
|
371
|
+
|
|
372
|
+
for fname, desc in entry_files.items():
|
|
373
|
+
path = target / fname
|
|
374
|
+
if not path.exists():
|
|
375
|
+
checks.append({"file": f"{rel_prefix}{fname}", "desc": desc})
|
|
376
|
+
|
|
377
|
+
elif framework == "nuxt":
|
|
378
|
+
entry_files = {
|
|
379
|
+
"package.json": "Node.js dependencies and scripts",
|
|
380
|
+
}
|
|
381
|
+
has_app_vue = (target / "app.vue").exists()
|
|
382
|
+
has_pages = (target / "pages").exists()
|
|
383
|
+
if not has_app_vue and not has_pages:
|
|
384
|
+
entry_files["app.vue"] = "Nuxt root App component"
|
|
385
|
+
|
|
386
|
+
for fname, desc in entry_files.items():
|
|
387
|
+
path = target / fname
|
|
388
|
+
if not path.exists():
|
|
389
|
+
checks.append({"file": f"{rel_prefix}{fname}", "desc": desc})
|
|
390
|
+
|
|
391
|
+
elif framework == "sveltekit":
|
|
392
|
+
entry_files = {
|
|
393
|
+
"package.json": "Node.js dependencies and scripts",
|
|
394
|
+
}
|
|
395
|
+
has_routes = (src_dir / "routes").exists()
|
|
396
|
+
if not has_routes:
|
|
397
|
+
entry_files["src/routes/+page.svelte"] = "SvelteKit root page"
|
|
398
|
+
|
|
399
|
+
for fname, desc in entry_files.items():
|
|
400
|
+
path = target / fname
|
|
401
|
+
if not path.exists():
|
|
402
|
+
checks.append({"file": f"{rel_prefix}{fname}", "desc": desc})
|
|
403
|
+
|
|
404
|
+
elif framework in ("remix", "angular"):
|
|
405
|
+
if not (target / "package.json").exists():
|
|
406
|
+
checks.append({"file": f"{rel_prefix}package.json", "desc": "Node.js dependencies and scripts"})
|
|
407
|
+
|
|
408
|
+
elif has_tsx or has_ts or has_pkg:
|
|
409
|
+
entry_files = {
|
|
410
|
+
"index.html": "Vite entry point — must reference src/main.tsx",
|
|
411
|
+
"package.json": "Node.js dependencies and scripts (npm run build, npm run dev)",
|
|
412
|
+
"tsconfig.json": "TypeScript compiler configuration",
|
|
413
|
+
}
|
|
414
|
+
has_main = (
|
|
415
|
+
(src_dir / "main.tsx").exists()
|
|
416
|
+
or (src_dir / "main.ts").exists()
|
|
417
|
+
or (src_dir / "main.jsx").exists()
|
|
418
|
+
or (src_dir / "main.js").exists()
|
|
419
|
+
or (src_dir / "index.tsx").exists()
|
|
420
|
+
or (src_dir / "index.ts").exists()
|
|
421
|
+
)
|
|
422
|
+
if not has_main:
|
|
423
|
+
entry_files["src/main.tsx"] = "React root render — ReactDOM.createRoot + App import"
|
|
429
424
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
425
|
+
has_vite_cfg = (
|
|
426
|
+
(target / "vite.config.ts").exists()
|
|
427
|
+
or (target / "vite.config.js").exists()
|
|
428
|
+
)
|
|
429
|
+
if not has_vite_cfg:
|
|
430
|
+
entry_files["vite.config.ts"] = "Vite build configuration with React plugin"
|
|
431
|
+
|
|
432
|
+
for fname, desc in entry_files.items():
|
|
433
|
+
path = target / fname
|
|
434
|
+
if not path.exists():
|
|
435
|
+
checks.append({"file": f"{rel_prefix}{fname}", "desc": desc})
|
|
436
|
+
|
|
437
|
+
# Python project detection
|
|
438
|
+
has_py = any(f.suffix == ".py" for f in target.rglob("*") if f.is_file())
|
|
439
|
+
if has_py and not (has_tsx or has_ts or has_pkg):
|
|
440
|
+
py_entries = {
|
|
441
|
+
"requirements.txt": "Python dependencies",
|
|
442
|
+
}
|
|
443
|
+
for fname, desc in py_entries.items():
|
|
444
|
+
if not (target / fname).exists():
|
|
445
|
+
checks.append({"file": f"{rel_prefix}{fname}", "desc": desc})
|
|
446
|
+
|
|
447
|
+
# tsconfig.json deep validation
|
|
448
|
+
tsconfig_path = target / "tsconfig.json"
|
|
449
|
+
if tsconfig_path.exists():
|
|
450
|
+
try:
|
|
451
|
+
raw = tsconfig_path.read_text(encoding="utf-8")
|
|
452
|
+
import re as _re
|
|
453
|
+
cleaned = _re.sub(r'//.*$', '', raw, flags=_re.MULTILINE)
|
|
454
|
+
tsconfig = json.loads(cleaned)
|
|
455
|
+
|
|
456
|
+
for ref in tsconfig.get("references", []):
|
|
457
|
+
ref_path = ref.get("path", "")
|
|
458
|
+
if ref_path:
|
|
459
|
+
ref_file = target / ref_path
|
|
460
|
+
if not ref_file.exists() and not ref_file.with_suffix(".json").exists():
|
|
433
461
|
checks.append({
|
|
434
|
-
"file": f"
|
|
435
|
-
"desc": f"
|
|
462
|
+
"file": f"{rel_prefix}{ref_path}",
|
|
463
|
+
"desc": f"Referenced by tsconfig.json — must exist or build fails (TS6053)",
|
|
436
464
|
})
|
|
437
|
-
except Exception:
|
|
438
|
-
pass
|
|
439
465
|
|
|
440
|
-
|
|
441
|
-
|
|
466
|
+
extends = tsconfig.get("extends", "")
|
|
467
|
+
if extends and not extends.startswith("@"):
|
|
468
|
+
ext_file = target / extends
|
|
469
|
+
if not ext_file.exists():
|
|
470
|
+
checks.append({
|
|
471
|
+
"file": f"{rel_prefix}{extends}",
|
|
472
|
+
"desc": f"Extended by tsconfig.json — must exist or build fails",
|
|
473
|
+
})
|
|
474
|
+
|
|
475
|
+
types_list = tsconfig.get("compilerOptions", {}).get("types", [])
|
|
476
|
+
if types_list and has_pkg:
|
|
477
|
+
try:
|
|
478
|
+
pkg = json.loads((target / "package.json").read_text(encoding="utf-8"))
|
|
479
|
+
all_deps = set(pkg.get("dependencies", {}).keys())
|
|
480
|
+
all_deps |= set(pkg.get("devDependencies", {}).keys())
|
|
481
|
+
|
|
482
|
+
for type_name in types_list:
|
|
483
|
+
types_pkg = f"@types/{type_name}"
|
|
484
|
+
if types_pkg not in all_deps:
|
|
485
|
+
checks.append({
|
|
486
|
+
"file": f"{rel_prefix}package.json (add {types_pkg})",
|
|
487
|
+
"desc": f"tsconfig requires types '{type_name}' but {types_pkg} not in dependencies (TS2688)",
|
|
488
|
+
})
|
|
489
|
+
except Exception:
|
|
490
|
+
pass
|
|
491
|
+
except Exception:
|
|
492
|
+
pass
|
|
442
493
|
|
|
443
494
|
if not checks:
|
|
444
495
|
return ""
|