adelie-ai 0.3.0 → 0.3.2

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.0"
15
+ __version__ = "0.3.2"
@@ -81,7 +81,11 @@ def _read_existing_files(workspace_root: Path, filepaths: list[str]) -> str:
81
81
 
82
82
  # Auto-include key config files if not already in the list
83
83
  key_configs = [
84
- "package.json", "tsconfig.json", "vite.config.ts", "vite.config.js",
84
+ "package.json", "tsconfig.json",
85
+ "vite.config.ts", "vite.config.js",
86
+ "next.config.js", "next.config.mjs", "next.config.ts",
87
+ "nuxt.config.ts", "nuxt.config.js",
88
+ "svelte.config.js", "remix.config.js", "angular.json",
85
89
  "index.html", "requirements.txt", "pyproject.toml",
86
90
  ]
87
91
  filepath_set = set(filepaths)
@@ -249,8 +253,11 @@ def run_coder(
249
253
  continue
250
254
 
251
255
  # Sanitize — prevent writing outside staging area
252
- # Check both Unix absolute paths (/...) and Windows (C:\...)
253
- if filepath.startswith("/") or ".." in filepath:
256
+ # Check absolute paths and genuine parent-directory traversal.
257
+ # Use Path.parts for segment-level check so bracket paths like
258
+ # [..nextauth] or [...slug] (Next.js catch-all routes) are allowed.
259
+ parts = Path(filepath).parts
260
+ if filepath.startswith("/") or ".." in parts:
254
261
  console.print(
255
262
  f"[yellow]⚠️ Skipped unsafe path: {filepath}[/yellow]"
256
263
  )
@@ -199,6 +199,62 @@ Source files found:
199
199
 
200
200
  {advice}"""
201
201
 
202
+ def _detect_framework(project_root) -> str:
203
+ """
204
+ Detect the JS/TS framework used in the project.
205
+ Returns one of: 'nextjs', 'nuxt', 'remix', 'sveltekit', 'angular', 'vite', 'unknown'.
206
+ """
207
+ # Next.js: next.config.js / next.config.mjs / next.config.ts
208
+ for ext in (".js", ".mjs", ".ts"):
209
+ if (project_root / f"next.config{ext}").exists():
210
+ return "nextjs"
211
+
212
+ # Nuxt: nuxt.config.ts / nuxt.config.js
213
+ for ext in (".ts", ".js"):
214
+ if (project_root / f"nuxt.config{ext}").exists():
215
+ return "nuxt"
216
+
217
+ # Remix: remix.config.js
218
+ if (project_root / "remix.config.js").exists():
219
+ return "remix"
220
+
221
+ # SvelteKit: svelte.config.js
222
+ if (project_root / "svelte.config.js").exists():
223
+ return "sveltekit"
224
+
225
+ # Angular: angular.json
226
+ if (project_root / "angular.json").exists():
227
+ return "angular"
228
+
229
+ # Check package.json dependencies as fallback
230
+ pkg_path = project_root / "package.json"
231
+ if pkg_path.exists():
232
+ try:
233
+ pkg = json.loads(pkg_path.read_text(encoding="utf-8"))
234
+ all_deps = set(pkg.get("dependencies", {}).keys())
235
+ all_deps |= set(pkg.get("devDependencies", {}).keys())
236
+
237
+ if "next" in all_deps:
238
+ return "nextjs"
239
+ if "nuxt" in all_deps:
240
+ return "nuxt"
241
+ if "@remix-run/react" in all_deps:
242
+ return "remix"
243
+ if "@sveltejs/kit" in all_deps:
244
+ return "sveltekit"
245
+ if "@angular/core" in all_deps:
246
+ return "angular"
247
+ except Exception:
248
+ pass
249
+
250
+ # Vite: vite.config.ts / vite.config.js
251
+ for ext in (".ts", ".js"):
252
+ if (project_root / f"vite.config{ext}").exists():
253
+ return "vite"
254
+
255
+ return "unknown"
256
+
257
+
202
258
  def _get_scaffolding_need() -> str:
203
259
  """
204
260
  프로젝트 진입 파일 존재 여부 검사.
@@ -225,12 +281,72 @@ def _get_scaffolding_need() -> str:
225
281
  # Define scaffolding checks per project type
226
282
  checks: list[dict] = []
227
283
 
228
- # React/Vite project detection
229
284
  has_tsx = any(f.suffix in (".tsx", ".jsx") for f in project_root.rglob("*") if f.is_file())
230
285
  has_ts = any(f.suffix == ".ts" for f in project_root.rglob("*") if f.is_file())
231
286
  has_pkg = "package.json" in existing
232
287
 
233
- if has_tsx or has_ts or has_pkg:
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)
234
350
  entry_files = {
235
351
  "index.html": "Vite entry point — must reference src/main.tsx",
236
352
  "package.json": "Node.js dependencies and scripts (npm run build, npm run dev)",
package/adelie/config.py CHANGED
@@ -25,6 +25,7 @@ GEMINI_MODEL: str = os.getenv("GEMINI_MODEL", "gemini-2.0-flash")
25
25
  OLLAMA_BASE_URL: str = os.getenv("OLLAMA_BASE_URL", "http://localhost:11434")
26
26
  OLLAMA_MODEL: str = os.getenv("OLLAMA_MODEL", "llama3.2")
27
27
  OLLAMA_API_KEY: str = os.getenv("OLLAMA_API_KEY", "") # For Ollama Cloud
28
+ LLM_TIMEOUT: int = int(os.getenv("LLM_TIMEOUT", "300")) # Request timeout in seconds
28
29
 
29
30
  # ── Model Fallback ───────────────────────────────────────────────────────────
30
31
  # Comma-separated fallback chain, e.g. "gemini:gemini-2.5-flash,gemini:gemini-2.0-flash,ollama:llama3.2"
@@ -23,6 +23,7 @@ from adelie.config import (
23
23
  GEMINI_API_KEY,
24
24
  GEMINI_MODEL,
25
25
  LLM_PROVIDER,
26
+ LLM_TIMEOUT,
26
27
  OLLAMA_API_KEY,
27
28
  OLLAMA_BASE_URL,
28
29
  OLLAMA_MODEL,
@@ -362,7 +363,7 @@ def _generate_ollama_model(
362
363
  headers["Authorization"] = f"Bearer {OLLAMA_API_KEY}"
363
364
 
364
365
  try:
365
- resp = requests.post(url, json=payload, headers=headers, timeout=120)
366
+ resp = requests.post(url, json=payload, headers=headers, timeout=LLM_TIMEOUT)
366
367
  resp.raise_for_status()
367
368
  except requests.ConnectionError:
368
369
  raise ConnectionError(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adelie-ai",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Adelie — Self-Communicating Autonomous AI Loop CLI",
5
5
  "bin": {
6
6
  "adelie": "bin/adelie.js"