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.
@@ -12,4 +12,4 @@ def _get_version() -> str:
12
12
  except Exception:
13
13
  pass
14
14
  return "0.0.0"
15
- __version__ = "0.3.6"
15
+ __version__ = "0.3.7"
@@ -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
- has_tsx = any(f.suffix in (".tsx", ".jsx") for f in project_root.rglob("*") if f.is_file())
285
- has_ts = any(f.suffix == ".ts" for f in project_root.rglob("*") if f.is_file())
286
- has_pkg = "package.json" in existing
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
- # Strip comments (tsconfig allows // comments)
394
- raw = tsconfig_path.read_text(encoding="utf-8")
395
- # Remove single-line comments
396
- import re as _re
397
- cleaned = _re.sub(r'//.*$', '', raw, flags=_re.MULTILINE)
398
- tsconfig = json.loads(cleaned)
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
- # Check "extends" e.g. "./tsconfig.node.json"
413
- extends = tsconfig.get("extends", "")
414
- if extends and not extends.startswith("@"):
415
- ext_file = project_root / extends
416
- if not ext_file.exists():
417
- checks.append({
418
- "file": extends,
419
- "desc": f"Extended by tsconfig.json — must exist or build fails",
420
- })
421
-
422
- # Check "compilerOptions.types" → need @types/* in package.json
423
- types_list = tsconfig.get("compilerOptions", {}).get("types", [])
424
- if types_list and has_pkg:
425
- try:
426
- pkg = json.loads((project_root / "package.json").read_text(encoding="utf-8"))
427
- all_deps = set(pkg.get("dependencies", {}).keys())
428
- all_deps |= set(pkg.get("devDependencies", {}).keys())
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
- for type_name in types_list:
431
- types_pkg = f"@types/{type_name}"
432
- if types_pkg not in all_deps:
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"package.json (add {types_pkg})",
435
- "desc": f"tsconfig requires types '{type_name}' but {types_pkg} not in dependencies (TS2688)",
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
- except Exception:
441
- pass # tsconfig parse error — skip validation
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 ""
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adelie-ai",
3
- "version": "0.3.6",
3
+ "version": "0.3.7",
4
4
  "description": "Adelie — Self-Communicating Autonomous AI Loop CLI",
5
5
  "bin": {
6
6
  "adelie": "bin/adelie.js"