layero 0.7.3 → 0.7.5

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/agent.js CHANGED
@@ -107,7 +107,9 @@ function renderHuman(event) {
107
107
  process.stdout.write(`→ Project ${event.slug}\n`);
108
108
  break;
109
109
  case "detected":
110
- process.stdout.write(`→ Detected ${event.framework} (build: ${event.build_cmd}, output: ${event.output_dir})\n`);
110
+ process.stdout.write(event.runtime_kind
111
+ ? `→ Detected ${event.runtime_kind} runtime app — will deploy as a scale-to-zero container\n`
112
+ : `→ Detected ${event.framework} (build: ${event.build_cmd}, output: ${event.output_dir})\n`);
111
113
  break;
112
114
  case "prebuilt":
113
115
  process.stdout.write(`→ Prebuilt mode: shipping ${event.dir}\n`);
package/dist/detect.js CHANGED
@@ -26,6 +26,25 @@ async function fileExists(cwd, ...candidates) {
26
26
  }
27
27
  return false;
28
28
  }
29
+ // Python runtime: `app.py` entry + a runtime lib in requirements.txt.
30
+ // Lockstep with detect_runtime() (backend) / runtime_detect.py (builder):
31
+ // app.py + requirements.txt mentioning streamlit | gradio | flask.
32
+ async function detectPythonRuntime(cwd) {
33
+ if (!(await fileExists(cwd, "app.py")))
34
+ return null;
35
+ let reqs;
36
+ try {
37
+ reqs = (await fs.readFile(path.join(cwd, "requirements.txt"), "utf-8")).toLowerCase();
38
+ }
39
+ catch {
40
+ return null;
41
+ }
42
+ for (const lib of ["streamlit", "gradio", "flask"]) {
43
+ if (reqs.includes(lib))
44
+ return lib;
45
+ }
46
+ return null;
47
+ }
29
48
  // Mirrors `frameworks/nextjs.py:_NEXT_STATIC_EXPORT_RE` and
30
49
  // `next_config_static_export()` so CLI and builder can't disagree on
31
50
  // what counts as a static-export Next.js project. The class-of-bug we
@@ -312,6 +331,32 @@ export async function detectProject(cwd) {
312
331
  confident: true,
313
332
  };
314
333
  }
334
+ // package.json present but no framework matched → a custom Node build,
335
+ // NOT a static site. Mirrors the backend's detect(): `pkg is None →
336
+ // _STATIC`, otherwise `_GENERIC` (npm run build → dist). Falling through
337
+ // to the static fallback here shipped the unbuilt sources — exactly the
338
+ // `diplomtest` case (Express app + custom build script detected as static
339
+ // by the CLI but `generic` by the backend).
340
+ return {
341
+ framework_hint: "generic",
342
+ build_cmd: buildCmd(pkg, "npm run build"),
343
+ output_dir: "dist",
344
+ confident: false,
345
+ };
346
+ }
347
+ // Python runtimes (Streamlit / Gradio / Flask): an `app.py` entry plus a
348
+ // runtime lib in requirements.txt. Mirrors detect_runtime() / runtime_detect.py.
349
+ // No package.json, so without this they fall to the static fallback and ship
350
+ // `app.py` as a static file (never runs) — the `streamlit-hello` case.
351
+ const pyRuntime = await detectPythonRuntime(cwd);
352
+ if (pyRuntime) {
353
+ return {
354
+ framework_hint: "static",
355
+ build_cmd: "true",
356
+ output_dir: ".",
357
+ confident: true,
358
+ runtime_kind: pyRuntime,
359
+ };
315
360
  }
316
361
  // Non-Node SSGs (Hugo today). Recognise repos without package.json
317
362
  // before we fall back to "static" with a no-op build command — Hugo
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "layero",
3
- "version": "0.7.3",
3
+ "version": "0.7.5",
4
4
  "description": "Layero CLI — publish a local site with one command. No git, no GitHub, agent-friendly (Cursor, Claude Code).",
5
5
  "license": "MIT",
6
6
  "type": "module",