layero 0.9.5 → 0.10.1
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/LICENSE +21 -0
- package/README.md +203 -167
- package/dist/agent.js +130 -2
- package/dist/api.js +125 -0
- package/dist/bin/layero.js +92 -33
- package/dist/commands/claim.js +141 -0
- package/dist/commands/data-api.js +578 -0
- package/dist/commands/data-probe.js +541 -0
- package/dist/commands/data.js +4 -1
- package/dist/commands/db.js +2 -2
- package/dist/commands/deploy.js +80 -10
- package/dist/commands/envs.js +44 -0
- package/dist/commands/hooks.js +29 -32
- package/dist/commands/init.js +63 -91
- package/dist/commands/link.js +12 -25
- package/dist/commands/logout.js +2 -2
- package/dist/commands/orgs.js +11 -15
- package/dist/commands/projects.js +179 -12
- package/dist/commands/sources.js +127 -0
- package/dist/commands/whoami.js +9 -10
- package/dist/config.js +1 -0
- package/dist/exit-codes.js +102 -0
- package/dist/project-config.js +2 -0
- package/dist/project-ref.js +20 -0
- package/package.json +10 -5
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Layero platform
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,70 +1,93 @@
|
|
|
1
1
|
# layero
|
|
2
2
|
|
|
3
|
-
CLI for [Layero](https://layero.ru) —
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
`
|
|
16
|
-
|
|
17
|
-
|
|
3
|
+
CLI for [Layero](https://layero.ru) — hosting with build servers in Russia.
|
|
4
|
+
Deploy a directory or connect a repository with one command; every command
|
|
5
|
+
speaks JSON for AI agents and CI.
|
|
6
|
+
|
|
7
|
+
Source: [github.com/LayeroInfra/cli](https://github.com/LayeroInfra/cli)
|
|
8
|
+
(public mirror of the `cli/` directory of the platform monorepo).
|
|
9
|
+
Docs: [docs.layero.ru/cli](https://docs.layero.ru/cli/).
|
|
10
|
+
|
|
11
|
+
## For AI agents (Cursor, Claude Code, Codex, Aider…)
|
|
12
|
+
|
|
13
|
+
The canonical agent skill lives in
|
|
14
|
+
[LayeroInfra/layero-agents](https://github.com/LayeroInfra/layero-agents):
|
|
15
|
+
`npx skills add LayeroInfra/layero-agents`, or for Claude Code
|
|
16
|
+
`claude plugin marketplace add LayeroInfra/layero-agents && claude plugin install layero@layero`.
|
|
17
|
+
Agent docs: [docs.layero.ru/agents](https://docs.layero.ru/agents/).
|
|
18
|
+
|
|
19
|
+
Three paths — pick by situation:
|
|
20
|
+
|
|
21
|
+
1. **The user has a repository** (GitHub, GitVerse, GitLab, GitFlic,
|
|
22
|
+
SourceCraft): connect it, then push to a branch = preview, push to `main`
|
|
23
|
+
= production.
|
|
24
|
+
```bash
|
|
25
|
+
npx layero@latest projects create --repo github:owner/repo --json
|
|
26
|
+
```
|
|
27
|
+
2. **The user has a directory with code**: the CLI packs it, the platform
|
|
28
|
+
builds it. No git repository is needed for this path.
|
|
29
|
+
```bash
|
|
30
|
+
npx layero@latest deploy --json
|
|
31
|
+
```
|
|
32
|
+
3. **The site is already on Layero**: `diagnose`, `logs`, `rollback`,
|
|
33
|
+
`envs list`, `domains`, `env`, `analytics`, `data` — or the MCP server
|
|
34
|
+
`https://mcp.layero.ru/mcp` (`npx -y add-mcp https://mcp.layero.ru/mcp`).
|
|
35
|
+
|
|
36
|
+
`layero deploy --json` prints `{"event":"ready","url":"https://…"}` on
|
|
37
|
+
success. Show `url` to the user as-is. Not logged in? The command starts the
|
|
38
|
+
browser device flow itself and prints `auth_required` with a `url` — render
|
|
39
|
+
it as a link and keep waiting. No account at all? `--claim` (see below).
|
|
18
40
|
|
|
19
41
|
## Install
|
|
20
42
|
|
|
21
43
|
```bash
|
|
22
|
-
#
|
|
23
|
-
npm install -D layero
|
|
24
|
-
# or one-shot:
|
|
25
|
-
npx layero@latest deploy
|
|
26
|
-
|
|
27
|
-
# System-wide (advanced; needs sudo on most setups):
|
|
28
|
-
npm install -g layero
|
|
44
|
+
npx layero@latest deploy # one-shot, always the current version
|
|
45
|
+
npm install -D layero # project-local
|
|
29
46
|
```
|
|
30
47
|
|
|
31
|
-
Requires Node.js ≥ 20.
|
|
48
|
+
Requires Node.js ≥ 20. Do not `npm install -g layero`: without `@latest` a
|
|
49
|
+
bare `npx layero` call then runs the globally installed copy for years.
|
|
32
50
|
|
|
33
51
|
## Quick start
|
|
34
52
|
|
|
35
53
|
```bash
|
|
36
|
-
layero login # device
|
|
54
|
+
layero login # device flow: prints a URL + code, sign in once (email code or Yandex ID)
|
|
37
55
|
cd my-site
|
|
38
|
-
layero deploy #
|
|
56
|
+
layero deploy # detects the framework, packs, uploads, builds, ships
|
|
39
57
|
```
|
|
40
58
|
|
|
41
59
|
The first `layero deploy` in a directory creates a project and links it via
|
|
42
|
-
`./.layero/project.json`.
|
|
43
|
-
re-run `layero deploy`.
|
|
60
|
+
`./.layero/project.json`. Later runs reuse the same project.
|
|
44
61
|
|
|
45
62
|
> **A plain `layero deploy` is not a preview.** For a project created from the
|
|
46
|
-
> CLI, direct uploads auto-promote: every run replaces what visitors see at
|
|
47
|
-
>
|
|
48
|
-
>
|
|
49
|
-
>
|
|
50
|
-
>
|
|
51
|
-
> ignored for direct uploads.
|
|
63
|
+
> CLI, direct uploads auto-promote: every run replaces what visitors see at
|
|
64
|
+
> `ready.url`. `--branch` is **refused** with `branch_unsupported` (exit 4):
|
|
65
|
+
> archive uploads always land in the reserved `cli` environment, so the flag
|
|
66
|
+
> cannot give you a preview. Isolated previews come from pushing a branch of
|
|
67
|
+
> a connected repository — `layero projects create --repo …`.
|
|
52
68
|
|
|
53
69
|
## Commands
|
|
54
70
|
|
|
55
71
|
| Command | Description |
|
|
56
72
|
|---|---|
|
|
57
|
-
| `layero init` | Scaffold `.layero/project.json`
|
|
58
|
-
| `layero login` |
|
|
59
|
-
| `layero
|
|
60
|
-
| `layero
|
|
61
|
-
| `layero projects
|
|
62
|
-
| `layero
|
|
63
|
-
| `layero
|
|
64
|
-
| `layero
|
|
65
|
-
| `layero
|
|
66
|
-
| `layero
|
|
67
|
-
| `layero
|
|
73
|
+
| `layero init` | Scaffold `.layero/project.json` and write a Layero block into `AGENTS.md` / `CLAUDE.md` / `.cursorrules` (compact index; full skill in `layero-agents`). |
|
|
74
|
+
| `layero login` / `logout` / `whoami` | Browser device-flow sign-in, sign-out, current account. |
|
|
75
|
+
| `layero deploy` | Pack the current directory, build on the platform, publish. `--claim` — without an account. |
|
|
76
|
+
| `layero projects list` | Projects on your account with addresses. |
|
|
77
|
+
| `layero projects create --repo <provider>:<owner/repo>` | Create a project from a repository of a connected provider. Events: `project_created`, `source_connected`, `webhook_installed` \| `webhook_unavailable`. |
|
|
78
|
+
| `layero projects delete <slug> --yes` | Delete a project. Irreversible; needs a token with scope `admin`. |
|
|
79
|
+
| `layero sources list` | Git providers the platform supports and the organization's connections. |
|
|
80
|
+
| `layero sources connect <provider> --token-stdin` | Connect a provider by personal access token (read from stdin so it never lands in shell history). |
|
|
81
|
+
| `layero sources repos <connection_id>` | Repositories visible to a connection. |
|
|
82
|
+
| `layero envs list` | Environments (branches) of a project with their addresses. |
|
|
83
|
+
| `layero deploys list` / `rollback` / `promote` | Deploy history, roll back, pin the apex. |
|
|
84
|
+
| `layero diagnose` / `logs` | Why a deploy is in its state; build and runtime logs. |
|
|
85
|
+
| `layero claim status` / `claim accept <code>` | Claimable project: status of the claim, open the claim page. |
|
|
86
|
+
| `layero domains …` / `env …` / `analytics …` / `perf …` | Custom domains, environment variables, Yandex Metrika, performance checks. |
|
|
87
|
+
| `layero db …` / `data …` | Postgres databases and the Data API. |
|
|
88
|
+
| `layero hooks list/create/delete` | Deploy hooks — URL tokens that trigger builds from CMS / cron / external CI. |
|
|
89
|
+
| `layero token create <name>` | Long-lived token for CI and agents (`--scope read,deploy,admin`). |
|
|
90
|
+
| `layero link <id_or_slug>` | Link the current directory to an existing project. |
|
|
68
91
|
|
|
69
92
|
Run `layero <cmd> --help` for full options.
|
|
70
93
|
|
|
@@ -72,29 +95,48 @@ Run `layero <cmd> --help` for full options.
|
|
|
72
95
|
|
|
73
96
|
- `--type <preset>` — framework override: `vite`, `vitepress`, `next`,
|
|
74
97
|
`astro`, `cra`, `sveltekit`, `nuxt`, `gatsby`, `docusaurus`, `eleventy`
|
|
75
|
-
(alias `11ty`), `hugo`, `static
|
|
76
|
-
`
|
|
98
|
+
(alias `11ty`), `hugo`, `static`; runtime kinds `node_web`, `python_web`,
|
|
99
|
+
`flask`, `streamlit`, `gradio`, `ssr_next` (aliases `express`, `fastapi`,
|
|
100
|
+
`django`, …). **Optional** — auto-detected when omitted.
|
|
77
101
|
- `--prebuilt [dir]` — ship an already-built artifact instead of building
|
|
78
|
-
remotely. Without an argument, picks the first existing of
|
|
79
|
-
`
|
|
80
|
-
`docs/.vitepress/dist/`, `.vitepress/dist/`.
|
|
81
|
-
|
|
82
|
-
pipeline, Webflow / Framer exports, or whenever you don't want the
|
|
83
|
-
platform to run install/build for you.
|
|
84
|
-
- `--root <dir>` — monorepo: tell the builder the app lives in a
|
|
85
|
-
subdirectory of the repo (e.g. `--root apps/web`). Saved on the
|
|
86
|
-
project; future GitHub-push and hook triggers use the same value.
|
|
87
|
-
CLI auto-detect honours it: framework signals are looked up inside
|
|
88
|
-
`<cwd>/<root>` so a `package.json` workspace at the repo root
|
|
89
|
-
doesn't shadow the real app's stack.
|
|
102
|
+
remotely. Without an argument, picks the first existing of `dist/`,
|
|
103
|
+
`build/`, `public/`, `out/`, `_site/`, `.output/public/`,
|
|
104
|
+
`docs/.vitepress/dist/`, `.vitepress/dist/`.
|
|
105
|
+
- `--root <dir>` — monorepo: the app lives in a subdirectory (`--root apps/web`).
|
|
90
106
|
- `--name <name>` — project name (only on first deploy).
|
|
91
107
|
- `--project <id_or_slug>` — deploy into an existing project, ignoring
|
|
92
|
-
`./.layero/project.json` (
|
|
93
|
-
- `--prod` — target the production environment of a repository-linked
|
|
94
|
-
|
|
95
|
-
- `--
|
|
108
|
+
`./.layero/project.json` (use this in CI, not `--name`).
|
|
109
|
+
- `--prod` — target the production environment of a repository-linked
|
|
110
|
+
project. Redundant for CLI projects: they auto-promote on every deploy.
|
|
111
|
+
- `--branch <name>` — **refused** (`branch_unsupported`, exit 4), see above.
|
|
112
|
+
- `--claim` — deploy without an account: a temporary project for 72 hours
|
|
113
|
+
plus a `claim_url` for a human to take it over. Turns on by itself when
|
|
114
|
+
there is no token, the run is non-interactive (an agent, not CI) and
|
|
115
|
+
`--yes` is passed. In CI a missing `LAYERO_TOKEN` stays an error.
|
|
116
|
+
- `--org <slug>` — organization for first-time project creation.
|
|
96
117
|
- `--yes` / `-y` — non-interactive mode.
|
|
97
|
-
- `--json` —
|
|
118
|
+
- `--json` — JSON-lines events on stdout (for agents and CI).
|
|
119
|
+
|
|
120
|
+
## Deploy without an account (`--claim`)
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
npx layero@latest deploy --claim --json
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The platform creates a temporary project and a token for it; the CLI deploys
|
|
127
|
+
with that token and prints, before `ready`:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
{"event":"claimable","url":"https://swift-fox.layero.app","claim_url":"https://app.layero.ru/claim?code=…","expires_at":"…"}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The site lives for 72 hours. A human opens `claim_url`, signs in and takes
|
|
134
|
+
the project into their account — the CLI cannot accept a claim by itself.
|
|
135
|
+
The claim code is saved in `.layero/project.json`; the temporary token stays
|
|
136
|
+
in `~/.layero/config.json`, so `layero deploy` in the same directory keeps
|
|
137
|
+
updating the same site until the claim expires or is accepted.
|
|
138
|
+
`layero claim status` shows where things stand; `layero claim accept` opens
|
|
139
|
+
the page in a browser (in agent mode it prints the link).
|
|
98
140
|
|
|
99
141
|
## Framework auto-detection
|
|
100
142
|
|
|
@@ -120,8 +162,7 @@ Run `layero <cmd> --help` for full options.
|
|
|
120
162
|
|
|
121
163
|
Auto-detection above is a default, not a decision. Drop a `layero.json` at the
|
|
122
164
|
root of the repository and Layero uses what you set there instead — for the
|
|
123
|
-
CLI, the dashboard and pushes alike. It
|
|
124
|
-
differ per branch, and it beats any dashboard setting.
|
|
165
|
+
CLI, the dashboard and pushes alike. It beats any dashboard setting.
|
|
125
166
|
|
|
126
167
|
```json title="layero.json"
|
|
127
168
|
{
|
|
@@ -134,25 +175,30 @@ differ per branch, and it beats any dashboard setting.
|
|
|
134
175
|
}
|
|
135
176
|
```
|
|
136
177
|
|
|
137
|
-
Every field is optional; `{}` is valid
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
of an edit button — an edit there would be undone by the next build.
|
|
178
|
+
Every field is optional; `{}` is valid. An error in the file never fails a
|
|
179
|
+
build: unreadable values become warnings in the build log.
|
|
180
|
+
Full reference: https://docs.layero.ru/deploys/layero-json
|
|
141
181
|
|
|
142
|
-
|
|
143
|
-
the build log.
|
|
182
|
+
## Repositories: `sources` and `projects create`
|
|
144
183
|
|
|
145
|
-
|
|
184
|
+
```bash
|
|
185
|
+
layero sources list # providers + connections
|
|
186
|
+
echo "$GITVERSE_TOKEN" | layero sources connect gitverse --token-stdin
|
|
187
|
+
layero sources repos <connection_id>
|
|
188
|
+
layero projects create --repo gitverse:acme/site --branch main --json
|
|
189
|
+
```
|
|
146
190
|
|
|
147
|
-
|
|
191
|
+
GitHub is connected by installing the Layero GitHub App in the dashboard; the
|
|
192
|
+
other providers take a personal access token. `projects create` validates the
|
|
193
|
+
repository against the connection, creates the project and installs the
|
|
194
|
+
webhook. If the provider refuses the webhook (token permissions, or
|
|
195
|
+
SourceCraft, which has no outgoing webhooks), the CLI says so with
|
|
196
|
+
`webhook_unavailable` and the URL to register by hand — the repository is
|
|
197
|
+
connected either way, only push-triggered builds wait for the webhook.
|
|
148
198
|
|
|
149
|
-
|
|
150
|
-
publishing content, a cron job, an external CI pipeline — create a
|
|
151
|
-
deploy hook. You get back an opaque URL; whoever POSTs to it fires a
|
|
152
|
-
deploy.
|
|
199
|
+
## Deploy hooks — webhook URLs that trigger builds
|
|
153
200
|
|
|
154
201
|
```bash
|
|
155
|
-
# Inside a linked project directory:
|
|
156
202
|
layero hooks create strapi-content # preview-target, default branch
|
|
157
203
|
layero hooks create publish --prod # production-target hook
|
|
158
204
|
layero hooks create staging --branch=dev # explicit branch
|
|
@@ -160,64 +206,37 @@ layero hooks list
|
|
|
160
206
|
layero hooks delete <id> # revoke immediately
|
|
161
207
|
```
|
|
162
208
|
|
|
163
|
-
The
|
|
164
|
-
it
|
|
165
|
-
cron job — any tool that can POST to a URL. Token = credential; rotate
|
|
166
|
-
by `delete` + `create`. There is no per-token rate limit yet; rely on
|
|
167
|
-
the platform's natural in-flight-commit dedup if the same commit gets
|
|
168
|
-
fired more than once.
|
|
209
|
+
The URL (`https://api.layero.ru/hooks/<token>`) is a credential: anyone who
|
|
210
|
+
has it can start a build. Rotate with `delete` + `create`.
|
|
169
211
|
|
|
170
212
|
## Bring-your-own-build (`--prebuilt`)
|
|
171
213
|
|
|
172
|
-
If you already build your site yourself — in CI, via a desktop tool like
|
|
173
|
-
Webflow/Framer, or because you want a guaranteed deterministic artifact —
|
|
174
|
-
skip the platform's install/build entirely:
|
|
175
|
-
|
|
176
214
|
```bash
|
|
177
|
-
#
|
|
178
|
-
layero deploy --prebuilt
|
|
179
|
-
|
|
180
|
-
# Or point at a specific one:
|
|
181
|
-
layero deploy --prebuilt ./dist
|
|
182
|
-
layero deploy --prebuilt ./build/static
|
|
215
|
+
layero deploy --prebuilt # auto-pick the output directory
|
|
216
|
+
layero deploy --prebuilt ./dist # or point at a specific one
|
|
183
217
|
```
|
|
184
218
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
⚠️ The flip side of ignoring `.gitignore`: `--prebuilt .` at your project
|
|
191
|
-
root publishes **everything there** except the built-in denylist, including
|
|
192
|
-
drafts you hid via `.gitignore` (verified on a live deploy — such a file comes
|
|
193
|
-
back with a 200). Secrets are still safe: `.env`, `.env.*`, `.git`,
|
|
194
|
-
`node_modules` and the rule files are excluded on this path too, nested
|
|
195
|
-
directories included. Even so, name the directory explicitly rather than
|
|
196
|
-
using `.`.
|
|
197
|
-
|
|
198
|
-
Override anything by editing `.layero/project.json` after the first `layero init`.
|
|
219
|
+
Only the files inside that directory are uploaded and shipped verbatim — no
|
|
220
|
+
detect, no install, no build. `.gitignore` is **not** applied on this path
|
|
221
|
+
(`.env*`, `.git`, `node_modules` and the rule files are still excluded), so
|
|
222
|
+
name the directory explicitly rather than using `.`.
|
|
199
223
|
|
|
200
224
|
## In CI
|
|
201
225
|
|
|
202
226
|
`layero login` opens a browser — there isn't one on a runner, so a pipeline
|
|
203
|
-
authenticates with a long-lived token
|
|
204
|
-
[app.layero.ru/settings/cli](https://app.layero.ru/settings/cli)
|
|
205
|
-
through the environment:
|
|
227
|
+
authenticates with a long-lived token. Create it with `layero token create ci`
|
|
228
|
+
or at [app.layero.ru/settings/cli](https://app.layero.ru/settings/cli):
|
|
206
229
|
|
|
207
230
|
```bash
|
|
208
|
-
LAYERO_TOKEN=... npx layero@latest deploy --
|
|
231
|
+
LAYERO_TOKEN=... npx layero@latest deploy --project <slug> --json --yes
|
|
209
232
|
```
|
|
210
233
|
|
|
211
|
-
`LAYERO_TOKEN` is read **before** `~/.layero/config.json
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
234
|
+
`LAYERO_TOKEN` is read **before** `~/.layero/config.json`. `--yes` skips the
|
|
235
|
+
confirmation that would otherwise wait forever. `--project`, not `--name`:
|
|
236
|
+
`--name` only names a project on creation, and a clean checkout without
|
|
237
|
+
`.layero/project.json` would create a new project on every run.
|
|
215
238
|
|
|
216
|
-
|
|
217
|
-
repository — then a leak is contained to that repository. Revoke on the same
|
|
218
|
-
page; running builds start failing immediately.
|
|
219
|
-
|
|
220
|
-
On GitHub Actions there is an official action that wraps the above:
|
|
239
|
+
On GitHub Actions there is an official action:
|
|
221
240
|
|
|
222
241
|
```yaml
|
|
223
242
|
- uses: LayeroInfra/deploy-action@v1
|
|
@@ -226,85 +245,102 @@ On GitHub Actions there is an official action that wraps the above:
|
|
|
226
245
|
prod: true
|
|
227
246
|
```
|
|
228
247
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
does not have, then ship the result with `prebuilt: dist`.
|
|
233
|
-
|
|
248
|
+
If the repository is already connected to a Layero project, a push builds it
|
|
249
|
+
automatically — reach for CI only when the build itself needs secrets the
|
|
250
|
+
platform does not have, then ship the result with `--prebuilt`.
|
|
234
251
|
Full guide: <https://docs.layero.ru/cli/github-actions>
|
|
235
252
|
|
|
236
253
|
## Agent / JSON mode
|
|
237
254
|
|
|
238
|
-
`layero`
|
|
255
|
+
`layero` switches to non-interactive, structured output when any of these holds:
|
|
239
256
|
|
|
240
|
-
- `--json` flag
|
|
241
|
-
- `
|
|
242
|
-
- `CURSOR_AGENT`, `CLAUDECODE`, `LAYERO_AGENT` env vars set
|
|
257
|
+
- `--json` flag or `LAYERO_JSON=1`
|
|
258
|
+
- `CURSOR_AGENT`, `CLAUDECODE`, `LAYERO_AGENT` env vars
|
|
243
259
|
- `CI=1` (non-interactive only; JSON-lines requires explicit opt-in)
|
|
244
260
|
- stdout is not a TTY
|
|
245
261
|
|
|
246
|
-
|
|
262
|
+
Every command emits events — one JSON object per line on stdout:
|
|
247
263
|
|
|
248
264
|
```
|
|
249
265
|
{"event":"auth_required","url":"…","user_code":"…"}
|
|
250
266
|
{"event":"authorized","user":"…"}
|
|
251
|
-
{"event":"
|
|
252
|
-
{"event":"
|
|
267
|
+
{"event":"me","id":"…","username":"…","email":"…"}
|
|
268
|
+
{"event":"projects","projects":[{"slug":"…","url":"https://…","repo":null,…}]}
|
|
269
|
+
{"event":"organizations","organizations":[{"slug":"…","kind":"personal","role":"admin"}]}
|
|
270
|
+
{"event":"project_created","project_id":"…","slug":"…","organization":"…","url":"…","repo":"…","branch":"…"}
|
|
271
|
+
{"event":"project_linked","project_id":"…","slug":"…","url":"…"}
|
|
272
|
+
{"event":"source_connected","org":"…","connection_id":"…","provider":"…","account":"…"}
|
|
273
|
+
{"event":"webhook_installed","project":"…","url":"…"} | {"event":"webhook_unavailable","project":"…","url":"…","hint":"…"}
|
|
274
|
+
{"event":"sources","org":"…","providers":[…],"connections":[…]}
|
|
275
|
+
{"event":"source_repos","org":"…","connection_id":"…","repos":[…]}
|
|
276
|
+
{"event":"environments","project":"…","environments":[{"branch":"main","url":"https://…","production":true,…}]}
|
|
253
277
|
{"event":"detected","framework":"…","build_cmd":"…","output_dir":"…","confident":true}
|
|
254
278
|
{"event":"packing","files":N,"bytes":N,"sha256":"…"}
|
|
255
|
-
{"event":"uploading"}
|
|
256
|
-
{"event":"uploaded","archive_key":"…"}
|
|
257
|
-
{"event":"setup_applied"}
|
|
279
|
+
{"event":"uploading"} {"event":"uploaded","archive_key":"…"}
|
|
258
280
|
{"event":"deploy_started","deploy_id":"…"}
|
|
259
281
|
{"event":"build_log","line":"…","stream":"…"}
|
|
260
282
|
{"event":"stage","name":"…"}
|
|
261
|
-
{"event":"
|
|
262
|
-
{"event":"
|
|
283
|
+
{"event":"claimable","project_id":"…","slug":"…","url":"…","claim_url":"…","expires_at":"…"}
|
|
284
|
+
{"event":"ready","url":"…","dashboard_url":"…","deploy_id":"…"}
|
|
285
|
+
{"event":"hooks","project":"…","hooks":[…]} {"event":"hook_created",…} {"event":"hook_deleted",…}
|
|
286
|
+
{"event":"project_deleted","project_id":"…","slug":"…"}
|
|
287
|
+
{"event":"claim_status","code":"…","status":"…","claimed":false,"expires_at":"…","url":"…","claim_url":"…"}
|
|
288
|
+
{"event":"claim_accept","code":"…","claim_url":"…","opened":false}
|
|
289
|
+
{"event":"logged_out","config_path":"…"}
|
|
263
290
|
{"event":"error","code":"…","next_action":"…","message":"…"}
|
|
264
291
|
```
|
|
265
292
|
|
|
266
|
-
On `ready`, `url` is the **live public site** —
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
will be wrong for one of the two. `dashboard_url` is the management page, not
|
|
271
|
-
the site.
|
|
272
|
-
|
|
273
|
-
`preview_url`, `edge_ready` and `edge_eta_seconds` are legacy fields from the
|
|
274
|
-
era when user sites sat behind a CDN that needed warming. They no longer do —
|
|
275
|
-
sites are served straight from the platform edge. `preview_url` is `null` for
|
|
276
|
-
projects in the `layero.app` zone. **Do not gate on `edge_ready`**: waiting for
|
|
277
|
-
it means waiting for something that will not arrive.
|
|
278
|
-
|
|
279
|
-
Not logged in? `deploy` starts the device-flow itself (`auth_required`).
|
|
293
|
+
On `ready`, `url` is the **live public site** — show it as-is and never
|
|
294
|
+
rebuild the hostname from a template. `dashboard_url` is the management page,
|
|
295
|
+
not the site. `preview_url`, `edge_ready` and `edge_eta_seconds` are legacy
|
|
296
|
+
fields; do not wait for them.
|
|
280
297
|
|
|
281
298
|
Errors carry a stable `code` (`auth_required`, `auth_expired`, `auth_timeout`,
|
|
282
299
|
`project_unknown`, `project_not_found`, `cli_deploys_disabled`, `invalid_type`,
|
|
283
|
-
`prebuilt_no_dir`, `prebuilt_no_index`, `
|
|
284
|
-
`internal`, and
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
`
|
|
300
|
+
`prebuilt_no_dir`, `prebuilt_no_index`, `branch_unsupported`,
|
|
301
|
+
`deploy_not_started`, `deploy_failed`, `internal`, and command-specific ones)
|
|
302
|
+
plus a `next_action` hint. The failure code is assembled as `deploy_<status>`
|
|
303
|
+
and a deploy only has `ready`, `building`, `failed` and `cancelled` — so
|
|
304
|
+
`deploy_error`, `deploy_timed_out` and `not_logged_in` do not exist.
|
|
305
|
+
Full reference: <https://docs.layero.ru/cli/json-events>
|
|
306
|
+
|
|
307
|
+
### Exit codes
|
|
308
|
+
|
|
309
|
+
| Code | Class | Error codes |
|
|
310
|
+
|---|---|---|
|
|
311
|
+
| 0 | success | |
|
|
312
|
+
| 1 | other | `plan_limit`, `forbidden`, `confirmation_required`, `repeated_failure`, … |
|
|
313
|
+
| 2 | sign-in needed | `auth_required`, `auth_expired`, `auth_timeout` |
|
|
314
|
+
| 3 | not found | `project_unknown`, `project_not_found`, `org_unknown`, `hook_not_found`, `connection_not_found`, `claim_unknown`, … |
|
|
315
|
+
| 4 | invalid input | `invalid_type`, `prebuilt_no_dir`, `prebuilt_no_index`, `branch_unsupported`, `repo_format`, `token_missing`, `bad_format`, … |
|
|
316
|
+
| 5 | remote failure | `deploy_failed`, `deploy_cancelled`, `deploy_not_started`, `internal`, 5xx from the platform |
|
|
288
317
|
|
|
289
318
|
## Ignore rules
|
|
290
319
|
|
|
291
|
-
`layero deploy` honours `.gitignore` and `.layeroignore`.
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
they have no business being on the web, and they list exactly the filenames
|
|
295
|
-
you chose to hide. Maximum archive size is 200 MB.
|
|
320
|
+
`layero deploy` honours `.gitignore` and `.layeroignore`. Always excluded:
|
|
321
|
+
`node_modules`, `.git`, `dist`, `build`, `.next`, `.env*`, `.DS_Store`, and
|
|
322
|
+
the rule files themselves. Maximum archive size is 200 MB.
|
|
296
323
|
|
|
297
324
|
## Config
|
|
298
325
|
|
|
299
|
-
- Auth token: `~/.layero/config.json` (chmod 600).
|
|
326
|
+
- Auth token: `~/.layero/config.json` (chmod 600). Claim tokens of temporary
|
|
327
|
+
projects live there too, keyed by project.
|
|
300
328
|
- Per-project link: `./.layero/project.json` — `project_id`, `slug`,
|
|
301
|
-
`organization_slug`, `apex_hostname` are managed by the CLI;
|
|
329
|
+
`organization_slug`, `apex_hostname`, `claim` are managed by the CLI;
|
|
302
330
|
`framework_hint`, `build_cmd`, `output_dir`, `analytics_enabled`,
|
|
303
331
|
`env_vars` are user-editable and override auto-detection.
|
|
304
332
|
|
|
333
|
+
## Contributing
|
|
334
|
+
|
|
335
|
+
The package is developed in the `cli/` directory of the platform monorepo and
|
|
336
|
+
mirrored to [LayeroInfra/cli](https://github.com/LayeroInfra/cli) on every
|
|
337
|
+
release (`git subtree push --prefix=cli https://github.com/LayeroInfra/cli main`,
|
|
338
|
+
`make cli-mirror`). Issues and pull requests are welcome on the mirror.
|
|
339
|
+
`npm test` runs the unit tests; `npm run build` compiles with `tsc`.
|
|
340
|
+
|
|
305
341
|
## Links
|
|
306
342
|
|
|
307
|
-
-
|
|
308
|
-
-
|
|
343
|
+
- Docs: https://docs.layero.ru/cli/
|
|
344
|
+
- For agents: https://docs.layero.ru/agents/ · skill: https://github.com/LayeroInfra/layero-agents
|
|
345
|
+
- Source: https://github.com/LayeroInfra/cli · issues: https://github.com/LayeroInfra/cli/issues
|
|
309
346
|
- Support: https://docs.layero.ru/contacts/
|
|
310
|
-
- MCP server / IDE plugin: https://docs.layero.ru/en/plugin/intro
|