diff --git a/README.md b/README.md index 0fce020..3d0d355 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Official AI Agent Skills for developing and deploying projects on [EdgeOne Maker ## Installation -### Option A — `npx skills` (Claude Code / Cursor / Codex / CodeBuddy CLI 等) +### Option A — `npx skills` (Claude Code / Cursor / Codex / CodeBuddy CLI etc.) ```bash npx skills add TencentEdgeOne/edgeone-makers-tools diff --git a/_meta.json b/_meta.json index 7330a7d..a720286 100644 --- a/_meta.json +++ b/_meta.json @@ -2,7 +2,7 @@ "ownerId": "442102", "publishedAt": 1781766512723, "slug": "edgeone-makers-tools", - "version": "2.0.0", + "version": "2.3.1", "files": [ "skills/edgeone-makers-tools/SKILL.md", "skills/edgeone-makers-tools/references/makers-agents/SKILL.md", @@ -33,6 +33,7 @@ "skills/edgeone-makers-tools/references/makers-cloud-functions/references/python-functions.md", "skills/edgeone-makers-tools/references/makers-cloud-functions/references/troubleshooting.md", "skills/edgeone-makers-tools/references/makers-deploy/SKILL.md", + "skills/edgeone-makers-tools/references/makers-deploy/references/anonymous-deploy.md", "skills/edgeone-makers-tools/references/makers-deploy/references/command-reference.md", "skills/edgeone-makers-tools/references/makers-edge-functions/SKILL.md", "skills/edgeone-makers-tools/references/makers-env-adaption/SKILL.md", diff --git a/codex/makers-cli.md b/codex/makers-cli.md index 90437ca..7c01cda 100644 --- a/codex/makers-cli.md +++ b/codex/makers-cli.md @@ -5,7 +5,7 @@ description: >- Use when running edgeone CLI commands for dev, build, deploy, env management. metadata: author: edgeone - version: "1.0.0" + version: "1.2.1" --- # EdgeOne Makers CLI Reference @@ -28,6 +28,9 @@ Verify: `edgeone -v` | `edgeone makers deploy -n ` | Deploy as a new project | | `edgeone makers deploy -t ` | Deploy with API token (CI/headless) | | `edgeone makers deploy -e preview` | Deploy to preview environment | +| `edgeone makers deploy --anonymous --json` | Deploy without login; claim later (CLI ≥ 1.6.29) | +| `edgeone makers deploy --anonymous --site china\|global --json` | Anonymous deploy to a specific site (omit `--site` to auto-detect by IP) | +| `edgeone makers claim --sid ` | Claim an anonymously-deployed project (requires login) | | `edgeone makers link` | Link local project to remote EdgeOne project | | `edgeone makers env pull` | Pull remote env vars to local `.env` | | `edgeone makers env set ` | Set a remote environment variable | @@ -36,8 +39,11 @@ Verify: `edgeone -v` | `edgeone login` | Login (browser-based) | | `edgeone login --site china` | Login to China site | | `edgeone login --site global` | Login to Global site | +| `edgeone login --claim --local --json` | Background listener: prints the login+claim link for an anonymous deploy, then auto-links the claimed project | | `edgeone whoami` | Check current login status | +> Anonymous deploy and `claim` require CLI `>= 1.6.29` (the general CLI floor is `1.6.0`). The claim parameter is `--sid` (the anonymous token); `-t` is the account API token — they are different credentials. Tell the user the link expires in 60 minutes; never show the raw `expiresAt`. The claim link you present comes from `edgeone login --claim` (`claimLoginUrl`), not the bare `claimUrl` in the deploy JSON. Details: [makers-deploy/references/anonymous-deploy.md](../makers-deploy/references/anonymous-deploy.md). + ## Environment Variable Before any `edgeone` command, set: diff --git a/codex/makers-deploy.md b/codex/makers-deploy.md index c83ec64..9478ceb 100644 --- a/codex/makers-deploy.md +++ b/codex/makers-deploy.md @@ -8,6 +8,10 @@ description: >- "go live", "release", "publish a new version", "redeploy", "上线", "发布", "发一版", "重新部署", "搭建并部署", "开发并上线", "build and deploy", "create and deploy". + Also trigger for login-free deployment and project claiming: + "deploy without login", "no account yet", "anonymous deploy", + "claim project", "claim my deployment", + "免登录部署", "匿名部署", "还没有账号", "认领项目". ⚠️ Also trigger when any agent is about to execute `edgeone makers deploy` or `edgeone makers deploy` commands — the skill contains critical rules for parsing deploy output and presenting access URLs. Do NOT trigger for post-deployment runtime errors (e.g. CORS issues, 500 errors after deploy — @@ -20,7 +24,7 @@ validate: message: "edgeone whoami does not accept -t. Check the exit code instead: 0 = logged in, 1 = not." metadata: author: edgeone - version: "2.2.0" + version: "2.12.1" --- # EdgeOne Makers Deployment Skill @@ -29,7 +33,7 @@ Deploy any project to **EdgeOne Makers**. ## ⛔ Critical Rules (never skip) -1. **CLI version ≥ `1.6.0`** — reinstall if lower. Versions below `1.6.0` lack the non-interactive fixes (whoami fail-fast, `--json` output) and will hang in Agent/CI environments. Never proceed with an outdated version. +1. **CLI version ≥ `1.6.0`** — reinstall if lower. Versions below `1.6.0` lack the non-interactive fixes (whoami fail-fast, `--json` output) and hang in Agent/CI environments. Never proceed with an outdated version. **Anonymous deploy and `claim` additionally require `1.6.29`** — that is a higher, feature-specific floor; see **Anonymous Deploy**. Do not block a normal authenticated deploy because the CLI is below `1.6.29`. 2. **Never truncate the deploy URL — this applies to EVERY mention** — `EDGEONE_DEPLOY_URL` includes query parameters (`?eo_token=...&eo_time=...`) required for access. Without them the page returns 401. Always output the **complete** URL with full query string. This rule applies to: the primary display, summary tables, footnotes, comparisons, code blocks, `present_files` calls — **every single occurrence** of the URL in your reply. Truncation is any removal of the `?` and everything after it. ❌ WRONG (truncated — will 401): @@ -57,6 +61,14 @@ Deploy any project to **EdgeOne Makers**. 7. **After token login, ask if the user wants to save the token locally** for future use. 8. **Before triggering any browser popup (login / registration), explain the reason and the benefits to the user first** — never silently launch a browser window. 9. **On any CLI failure, surface the actual error text to the user before retrying, switching commands, or proposing a workaround.** Do NOT paraphrase (e.g. don't rewrite `Makers project exceeds 40 limit` into "maybe a name conflict or permission"). Do NOT silently pivot from `makers dev` to `makers deploy` (or vice versa) hoping to bypass — a systemic failure (auth / quota / permission) hits both with the same cause. Quote the raw error, name the root cause, then propose the fix or ask the user. +10. **Write every user-facing message in the user's own language** — **all** prose, blockquotes, and prompts in this skill are written in English purely to specify *meaning*; none of it is a string to paste. If the user writes to you in Chinese, speak Chinese — the login explanation, the site choice, the token question, the deploy result, all of it. Likewise for any other language. Emitting this skill's English strings into a non-English conversation is a bug. Only literal CLI commands, flags, env var names, and JSON field names stay verbatim. ⚠️ Where this skill gives a **fixed template** (Steps 2 and 4 of Anonymous Deploy), translating it is required but rewriting or extending it is not allowed — match it line for line. + +**Rules 11-14 apply to the anonymous deploy / claim flow only:** + +11. **The claim command's parameter is `--sid`, NOT `--token`** — `edgeone makers claim --sid `. The `-t` / `--token` flag on `claim` is the **account API token**, an entirely different credential. Passing the anonymous token to `-t` fails. Product documentation showing `claim --token ` is wrong; trust this rule. +12. **Present the anonymous deploy result with the fixed template in Step 4** — it is a template, not an example: reproduce it exactly, substituting only the URL and the claim link. Never show the raw `expiresAt` timestamp, never state a different duration, and never add lines to it. 60 minutes is the product's stated claim window and the conservative instruction, so that is what the template says even though the token's observed lifetime can be longer. It frames the *link* as expiring, not the project as being deleted. +13. **The claim link you present must come from `edgeone login --claim`, never the bare `claimUrl`** — right after an anonymous deploy, run `edgeone login --claim --local --json` in the background and put its `claimLoginUrl` in the template. Only that link carries the login → claim → callback chain that lets the CLI learn the login state and auto-link the project; the bare `claimUrl` from deploy output claims without telling the CLI, so the user's next deploy would create a second anonymous project. Never print `claimCommand`, `edgeone makers claim --sid ...`, or any other command as the user's way to claim — in sandboxed IDEs like WorkBuddy the user has no terminal and literally cannot run it. `makers claim` is only a fallback for headless/CI environments, run by you, never displayed. +14. **Keep the claim pitch minimal — do not over-promise, and do not teach domains** — say only that signing in *keeps* the project. ❌ Never write "permanently yours", "no time limit or access restrictions", "unlimited", or anything implying the URL then works unconditionally forever: a claimed project may still need a custom domain, and mainland-China access can require ICP filing, so those claims are false. ❌ Also do not volunteer custom domains, ICP filing, DNS, or console navigation while the user is just deciding whether to claim — that front-loads complexity onto someone who only wanted a live URL. The claim page owns the follow-up flow. Answer such topics only when the user asks. --- @@ -86,10 +98,10 @@ Run these checks first, then follow the decision table: # Check 0: Set environment variable (required before any edgeone command) export PAGES_SOURCE=skills -# Check 1: CLI installed and correct version? (must be >= 1.6.0) +# Check 1: CLI installed and correct version? (must be >= 1.6.0; anonymous deploy needs >= 1.6.29) edgeone -v -# Check 2: Already logged in? (CLI >= 1.6.0 whoami fails fast, won't hang) +# Check 2: Already logged in? (whoami fails fast, won't hang) edgeone whoami # If exit 0 → logged in, no -t needed # If exit 1 → not logged in, need token or browser login @@ -112,7 +124,8 @@ cat edgeone.json 2>/dev/null | Not installed or < 1.6.0 | — | → Go to **Install CLI** | | `≥ 1.6.0` ✓ | Logged in (or token present) | → Go to **Deploy** | | `≥ 1.6.0` ✓ | Not logged in, has saved token | → Go to **Deploy with Token** (use saved token) | -| `≥ 1.6.0` ✓ | Not logged in, no saved token | → **Try Browser Login first** (see Login section). If the browser doesn't open or nothing happens within ~60 seconds, **fall back to Token Login**. Do NOT preemptively skip browser login by guessing "this looks like an Agent/CI environment" — that guess is often wrong. In particular, **WorkBuddy is a desktop IDE sandbox and fully supports browser login** (host browser + OAuth callback are bridged into the sandbox). | +| `≥ 1.6.29` ✓ | Not logged in, no saved token | → Go to **Anonymous Deploy** — default to anonymous only when the task is anonymous-native (scheduled / disposable / user asked for it); otherwise ask the user to choose anonymous deploy or login. If there is no way to ask, deploy with `--anonymous --json` and surface the claim link and the 60-minute window in the result (see Step 2) | +| `1.6.0`–`1.6.28` | Not logged in, no saved token | Anonymous deploy is unavailable on this version → **Try Browser Login first** (see Login section). If the browser doesn't open or nothing happens within ~60 seconds, fall back to **Token Login**. Do NOT preemptively skip browser login by guessing "this looks like an Agent/CI environment" — that guess is often wrong; in particular, **WorkBuddy is a desktop IDE sandbox and fully supports browser login** | | `≥ 1.6.0` ✓ | User explicitly provides a token or requests token login | → Go to **Deploy with Token** / **Token Login** | --- @@ -123,7 +136,7 @@ cat edgeone.json 2>/dev/null npm install -g edgeone@latest ``` -Verify: `edgeone -v` — confirm output is `1.6.0` or higher. Retry installation if not. (Versions < 1.6.0 hang on `whoami`/login in non-interactive environments and lack `--json`.) +Verify: `edgeone -v` — confirm output is `1.6.0` or higher. Retry installation if not. (Versions < 1.6.0 hang on `whoami`/login in non-interactive environments and lack `--json`.) Anonymous deploy and `claim` need `1.6.29`; if `latest` is still below that, those two features are simply unavailable — normal authenticated deploy works fine. --- @@ -154,7 +167,7 @@ Use the IDE's selection control (`ask_followup_question`) before running any log ⚠️ **CRITICAL**: After the user chooses, you MUST invoke login with an explicit `--site ` flag (e.g. `edgeone login --site china`). **NEVER run a bare `edgeone login` (without `--site`) when driven by an Agent / skill.** -On CLI ≥ 1.6.0, a bare `login` in a non-interactive context fails fast asking for +A bare `login` in a non-interactive context fails fast asking for `--site` (it no longer pops an interactive site-picker that would hang). The site choice is meant to happen here in the conversation, not inside the CLI. @@ -307,9 +320,149 @@ The CLI auto-detects the framework, runs the build, and uploads the output direc --- +## Anonymous Deploy (no login required) + +When the user is not logged in and has no token, they can deploy anonymously and claim the project later. Requires CLI `>= 1.6.29`. On `1.6.0`–`1.6.28` this feature does not exist — use **Login** or a token instead. + +### Step 1: Exclusion check — run this FIRST + +Anonymous deploy builds with an empty environment: it skips remote env-var pull and AI-gateway credential injection, because both need authentication. Projects depending on either will deploy successfully but break at runtime. + +```bash +# Is this an Agent project? +ls agents/ 2>/dev/null && echo "AGENT_PROJECT" + +# Does it use Blob storage? (checks source files and the dependency declaration) +grep -rEl "@edgeone/pages-blob" \ + --include="*.ts" --include="*.js" --include="*.mjs" --include="*.cjs" \ + --include="*.tsx" --include="*.jsx" --include="*.vue" --include="*.svelte" \ + . 2>/dev/null | head -1 +grep -l '"@edgeone/pages-blob"' package.json 2>/dev/null +``` + +Non-empty output from either grep means the project uses Blob. + +**KV cannot be detected this way — you must ask.** A KV namespace is bound in the console and exposed as a *global variable* whose name the user chose (e.g. `my_kv`), so there is no package import to grep for. There is no `@edgeone/pages-kv` package. Ask the user directly: + +> Does this project use KV storage? + +If either check hits, or the user says the project uses KV, **do not deploy anonymously.** Go to **Login** and tell the user why: + +> This project needs environment variables / AI gateway credentials or a storage binding, which anonymous deploy cannot provide. The site would load but those features would fail. Let's log in so it works properly. + +Plain static sites and frontend-framework projects with no such dependency may proceed. + +If the user acknowledges the limitation and still wants an anonymous deploy, you may proceed — but state prominently in your result that AI and storage features will not work until the project is claimed and configured. + +### Step 2: Decide the path — default to anonymous only when the task fits, otherwise ask + +**Go anonymous directly, without asking, only when the task itself is anonymous-native** — disposable or unattended by nature. Clear signals: + +- **Scheduled / automated jobs** — e.g. "每日定时生成一个页面并部署", cron pipelines, any task that must run with nobody watching +- **Disposable one-offs** — a throwaway preview, a quick demo, "先看看效果", anything the user frames as temporary or just-for-now +- **Explicit anonymous intent** — the user says "免登录", "不用登录", "anonymous", or "don't make me sign up" + +In these cases the 60-minute expiry + claim-later model *is* the right answer, so asking is pure friction. Go straight to Step 3, and present the result with the fixed template in Step 4 (claim link + 60-minute window) — the template already tells the user how to keep it if they change their mind. + +**Everything else — ask.** If the task isn't obviously disposable — anything the user might want to keep, share widely, or build on — present the choice. Do NOT try to judge the *environment* to skip the question: sandbox/TTY signals are unreliable and guessing wrong either needlessly interrupts a human or silently deploys something they wanted to keep. + +If the environment genuinely gives you no way to ask at all (no TTY, no question tool), asking is impossible — that's a constraint, not a judgment call. Deploy with `--anonymous --json` and make the claim link and the 60-minute window unmissable in your result. + +**How to ask (when asking):** present the choice with the IDE's selection control (e.g. `ask_followup_question`). The option labels deliberately avoid the word "anonymous" — it is jargon and confuses non-technical users. Present these two options **exactly**, in the user's language. Do not paraphrase the labels, do not add caveats to the options themselves, and do not mention "anonymous" to the user at all. +The option text must be placed in the `label` exactly as is; it must not be split into the `description`. + +**English-speaking user — present exactly these two options:** + +> - **Publish now, log in later** — No login needed. Get a preview link right away; you can log in and claim the site whenever you're ready. +> - **Log in, then publish** — Log in to your EdgeOne Makers account first; the site is saved straight to your account. + +**Chinese-speaking user — present exactly these two options:** + +> - **直接发布,无需登录** +> - **登录后发布** + +Map their pick to the flow: + +- **Publish now, log in later** → this is the anonymous deploy path — continue to **Step 3**. +- **Log in, then publish** → go to **Login** (browser flow), then continue with the normal deploy. + +⛔ **Do not over-promise what claiming gives them.** Say the project is *kept* / *saved to their account*, and nothing more. Specifically, do **not** say "no access restrictions", "permanently yours", or anything implying the URL is then unconditionally public and final — a claimed project can still need a custom domain and, for mainland-China access, ICP filing. Do **not** raise custom domains, ICP filing, or DNS at this point either: the user is deciding whether to log in, and those concepts are noise here. The claim page walks them through next steps. + +### Step 3: Deploy + +```bash +export PAGES_SOURCE=skills +edgeone makers deploy --anonymous --json +``` + +Add `--site china` or `--site global` only when the site must be pinned (the user told you which, or CI needs determinism). Otherwise omit it — **the CLI detects the site itself** from its own egress IP. Do not probe for the site yourself and do not synthesise `--site` from your own check. + +Do **not** pass `-n`, `-e`, or `--area` — they are ignored under `--anonymous`. The project name is generated automatically. + +### Step 4: Start the claim listener, then present the result + +Parse the **last line** of the deploy stdout as JSON (human-readable output precedes it). Fields are **camelCase**: `url`, `projectId`, `deploymentId`, `anonymousToken`, `claimUrl`, `claimCommand`, `expiresAt`, `site`. + +**Immediately start the claim listener in the background** — it must be listening before the user clicks the claim link, or the login state never reaches the CLI and the next deploy would create a second anonymous project: + +```bash +edgeone login --claim --local --json +``` + +Run it with `run_in_background`. It prints a `{"status":"waiting","claimLoginUrl":...}` JSON line right away, then keeps listening (up to 60 minutes). Grab `claimLoginUrl` from that line. ⛔ **This URL — not the `claimUrl` field from the deploy JSON — is the claim link you show the user.** Only this link chains login → claim page → callback to the CLI. The bare `claimUrl` from deploy output would claim the project without telling the CLI, and the user's next deploy would go to a new anonymous project instead of the claimed one. + +⛔ **The listener is invisible to the user — never narrate it.** Do not tell the user a listener/监听器 is running, that you are "waiting for the claim callback", or any other internal mechanism status (state files, JSON parsing, ports). The user-facing surface is exactly one thing: the template below. Claiming is presented as "open the link and sign in", not as a process you are watching. + +⛔ **Send the template as its own message, after the deploy command has fully returned.** Do not emit it in the same message in which you ran the deploy, do not attach it to the command's output, and do not print it while the command is still running. In WorkBuddy, content emitted alongside a running/finished command can be folded into a collapsible process message — if that happens, the user never sees the URL or the claim link. Wait for the Bash call to end, then send the template alone as your next reply. + +⛔ **This is a fixed template, not a suggestion.** Reproduce it exactly: same four lines, same order, same emoji, same separator. Substitute **only** `` (from the deploy JSON) and `` (from the `login --claim` output). Do not reword, merge, split, or reorder lines. Do not add a sentence before or after it. Do not append project ID, deployment ID, console URL, `expiresAt`, next steps, or commentary of any kind. + +**English-speaking user — emit exactly this:** + +> 🌐 **Live URL**: `` +> +> --- +> +> ⏳ **This link expires in 60 minutes**. +> +> 👉 [Claim this project]() — please claim it within 60 minutes. + +**Chinese-speaking user — emit exactly this:** + +> 🎉 部署成功 +> 🌐 **访问地址**:`` +> +> --- +> +> ⏳ **该链接 60 分钟后失效**。 +> +> 👉 [认领这个项目]() —— 请在 60 分钟内完成认领。 + +For any other language, translate **this** template and nothing more — keep the four lines, the emoji, the separator, and the exact same content. Do not take the freedom to add or explain. + +Afterwards, stop. Anything you feel like adding here — what claiming unlocks, custom domains, ICP filing, DNS, console navigation, an offer to claim on their behalf — is prohibited by critical rules 13 and 14. Answer those topics only if the user asks. + +### After the user claims + +The background `login --claim` process exits on its own when the console relays the result. When it exits 0 with `{"status":"success",...,"linked":true}`: + +- the CLI is logged in (credentials saved, plus `.edgeone/auth.json` from `--local`), +- the project is linked (`.edgeone/project.json`), +- `.edgeone/anonymous.json` is removed. + +Tell the user plainly, in their language: the project is now in their account, and any further deploys will update that same project. Then use the normal deploy flow (`edgeone makers deploy --json`) for all later deploys. + +If the process exits non-zero (the user never completed the link within 60 minutes), the anonymous project is still unclaimed: re-run `edgeone login --claim --local --json` for a fresh link and present it again in the same template. + +If the user asks you to "帮我认领" / "claim it for me": point them to the same link again while the listener is still running; if it already exited, re-run the command for a fresh link. Never print the CLI claim command — `edgeone makers claim --sid` remains only for headless/CI environments with no browser (see critical rule 13). + +For the full JSON schema, rate limits, error codes, state-file fields, and site-resolution rules, see [references/anonymous-deploy.md](references/anonymous-deploy.md). + +--- + ## ⚠️ Parse Deploy Output (Critical) -### Preferred: `--json` (CLI ≥ 1.6.0) +### Preferred: `--json` When deploy is run with `--json`, the **last line** of stdout is a single JSON object — parse that directly, no regex / ANSI cleanup needed: @@ -370,10 +523,11 @@ https://console.cloud.tencent.com/edgeone/pages/project/pages-xxxxxxxx/deploymen |-------|----------| | `command not found: edgeone` | Run `npm install -g edgeone@latest` | | CLI version < 1.6.0 | Reinstall: `npm install -g edgeone@latest`. Older versions hang on whoami/login in non-interactive contexts | +| `--anonymous` / `claim` reported as an unknown option | The installed CLI is below `1.6.29`. Run `npm install -g edgeone@latest`; if that is still below `1.6.29`, anonymous deploy is not released yet — use login or a token instead | | Browser does not open during login | Switch to token login | -| "not authenticated" / exit 1 from `whoami` (CLI ≥ 1.6.0) | Expected when not logged in — whoami now fails fast instead of hanging. Run `edgeone login` (desktop) or provide a token | +| "not authenticated" / exit 1 from `whoami` | Expected when not logged in — whoami fails fast instead of hanging. Offer anonymous deploy (see Anonymous Deploy), run `edgeone login`, or provide a token | | Non-interactive deploy says "browser login is unavailable" + exits 1 | Expected fail-fast in Agent/CI/headless with no token. Provide a token via `-t ` or set `EDGEONE_PAGES_API_TOKEN` | -| Deploy seems to hang at `[DeployStatus] Deploying...` | On CLI ≥ 1.6.0 non-TTY emits heartbeat lines; it is NOT stuck. If a wrapper still mis-detects, use `--json` or run in background and poll. Do not kill it | +| Deploy seems to hang at `[DeployStatus] Deploying...` | Non-TTY emits heartbeat lines; it is NOT stuck. If a wrapper still mis-detects, use `--json` or run in background and poll. Do not kill it | | Auth error with token | Token may be expired — regenerate at the console | | Login appears successful but `deploy` reports auth error | Browser reused a session from the wrong site, binding the wrong account. Click "Sign in with a different account" on the login page, or log out from all Tencent Cloud consoles first | | `edgeone whoami` shows an unexpected account | Browser session reuse. Click "Sign in with a different account" or log out from all consoles and re-login | diff --git a/codex/makers-env-adaption.md b/codex/makers-env-adaption.md index 6921ae9..995aa0f 100644 --- a/codex/makers-env-adaption.md +++ b/codex/makers-env-adaption.md @@ -17,7 +17,7 @@ validate: message: "Use 127.0.0.1, not localhost — in the sandbox localhost resolves to ::1 and yields false 404s." metadata: author: edgeone - version: "1.1.1" + version: "1.4.2" --- # Runtime Environment Adaptation Guide @@ -295,6 +295,7 @@ If the project named by `--name` does not exist remotely, the `link` command cre | Framework/package | Minimum version | Reason | |---------|---------|------| | EdgeOne CLI | >= 1.6.7 | Non-interactive fixes, whoami fail-fast, --json support | +| EdgeOne CLI (anonymous deploy / `claim` only) | >= 1.6.29 | `--anonymous` and `claim` do not exist below this | | Next.js | 16.x | The framework adapter tracks new versions | | @edgeone/pages-blob | >= 0.0.14 | Older versions have known bugs | @@ -307,3 +308,24 @@ Use `create-next-app@latest` rather than manually pinning an older version. WorkBuddy's right-side preview panel does NOT render `window.alert()` / `window.confirm()` / `window.prompt()`. The call returns immediately without user interaction, so any handler gated on `if (confirm("Delete?"))` silently no-ops (a delete button appears to do nothing). The same page works fine in the user's real Chrome / Safari. **Rule**: for any confirmation, prompt, or notification in the page, use an **in-page custom modal** (a `
` overlay with buttons wired via JS). Do NOT rely on the browser's built-in `alert` / `confirm` / `prompt` — the code looks correct in code review, works when the user opens the deployed URL in their own browser, and is silently broken in the WorkBuddy preview during dev/verification. + +### 14. Never hand the user a command to run + +The user has **no terminal** in the WorkBuddy sandbox. Any command you print as an instruction is dead text — they cannot execute it, and a non-technical user cannot read it either. + +| Situation | Do this | Not this | +|---|---|---| +| Anonymous project needs claiming | Run `edgeone login --claim --local --json` in the background and present its `claimLoginUrl` as a clickable link; the listener auto-links the project when the user finishes claiming | ❌ Printing `edgeone makers claim --sid `, or presenting the bare `claimUrl` from the deploy JSON (the CLI never learns the login state) | +| The user needs to log in | Explain, then run `edgeone login --site --local` yourself | ❌ "Run `edgeone login` in your terminal" | +| Something needs installing | Run it yourself in Bash | ❌ "Please run `npm install -g edgeone`" | + +You are the one with shell access — use it. Only ask the user to type something when it genuinely cannot be automated (e.g. completing a login in the browser window you opened), and say plainly what you need from them. + +### 14.1 Never let the key result get folded into a process message + +WorkBuddy can collapse content emitted in the same message as a running or just-finished Bash command into a collapsible process entry. When the user asks to deploy, the deploy URL and claim link must never land there — if they do, the user sees nothing. + +| Situation | Do this | Not this | +|---|---|---| +| A deploy just finished | Wait for the Bash call to fully return, then send the result (URL + claim link) **as its own message** | ❌ Emitting the result in the same message where the deploy ran, or attaching it to the command's stdout | +| Running a long command | Report progress only in later messages, after the tool call returns | ❌ Writing "here is your URL" inside the same turn as the command output | diff --git a/cursor/rules/makers-cli.mdc b/cursor/rules/makers-cli.mdc index 90437ca..7c01cda 100644 --- a/cursor/rules/makers-cli.mdc +++ b/cursor/rules/makers-cli.mdc @@ -5,7 +5,7 @@ description: >- Use when running edgeone CLI commands for dev, build, deploy, env management. metadata: author: edgeone - version: "1.0.0" + version: "1.2.1" --- # EdgeOne Makers CLI Reference @@ -28,6 +28,9 @@ Verify: `edgeone -v` | `edgeone makers deploy -n ` | Deploy as a new project | | `edgeone makers deploy -t ` | Deploy with API token (CI/headless) | | `edgeone makers deploy -e preview` | Deploy to preview environment | +| `edgeone makers deploy --anonymous --json` | Deploy without login; claim later (CLI ≥ 1.6.29) | +| `edgeone makers deploy --anonymous --site china\|global --json` | Anonymous deploy to a specific site (omit `--site` to auto-detect by IP) | +| `edgeone makers claim --sid ` | Claim an anonymously-deployed project (requires login) | | `edgeone makers link` | Link local project to remote EdgeOne project | | `edgeone makers env pull` | Pull remote env vars to local `.env` | | `edgeone makers env set ` | Set a remote environment variable | @@ -36,8 +39,11 @@ Verify: `edgeone -v` | `edgeone login` | Login (browser-based) | | `edgeone login --site china` | Login to China site | | `edgeone login --site global` | Login to Global site | +| `edgeone login --claim --local --json` | Background listener: prints the login+claim link for an anonymous deploy, then auto-links the claimed project | | `edgeone whoami` | Check current login status | +> Anonymous deploy and `claim` require CLI `>= 1.6.29` (the general CLI floor is `1.6.0`). The claim parameter is `--sid` (the anonymous token); `-t` is the account API token — they are different credentials. Tell the user the link expires in 60 minutes; never show the raw `expiresAt`. The claim link you present comes from `edgeone login --claim` (`claimLoginUrl`), not the bare `claimUrl` in the deploy JSON. Details: [makers-deploy/references/anonymous-deploy.md](../makers-deploy/references/anonymous-deploy.md). + ## Environment Variable Before any `edgeone` command, set: diff --git a/cursor/rules/makers-deploy.mdc b/cursor/rules/makers-deploy.mdc index c83ec64..9478ceb 100644 --- a/cursor/rules/makers-deploy.mdc +++ b/cursor/rules/makers-deploy.mdc @@ -8,6 +8,10 @@ description: >- "go live", "release", "publish a new version", "redeploy", "上线", "发布", "发一版", "重新部署", "搭建并部署", "开发并上线", "build and deploy", "create and deploy". + Also trigger for login-free deployment and project claiming: + "deploy without login", "no account yet", "anonymous deploy", + "claim project", "claim my deployment", + "免登录部署", "匿名部署", "还没有账号", "认领项目". ⚠️ Also trigger when any agent is about to execute `edgeone makers deploy` or `edgeone makers deploy` commands — the skill contains critical rules for parsing deploy output and presenting access URLs. Do NOT trigger for post-deployment runtime errors (e.g. CORS issues, 500 errors after deploy — @@ -20,7 +24,7 @@ validate: message: "edgeone whoami does not accept -t. Check the exit code instead: 0 = logged in, 1 = not." metadata: author: edgeone - version: "2.2.0" + version: "2.12.1" --- # EdgeOne Makers Deployment Skill @@ -29,7 +33,7 @@ Deploy any project to **EdgeOne Makers**. ## ⛔ Critical Rules (never skip) -1. **CLI version ≥ `1.6.0`** — reinstall if lower. Versions below `1.6.0` lack the non-interactive fixes (whoami fail-fast, `--json` output) and will hang in Agent/CI environments. Never proceed with an outdated version. +1. **CLI version ≥ `1.6.0`** — reinstall if lower. Versions below `1.6.0` lack the non-interactive fixes (whoami fail-fast, `--json` output) and hang in Agent/CI environments. Never proceed with an outdated version. **Anonymous deploy and `claim` additionally require `1.6.29`** — that is a higher, feature-specific floor; see **Anonymous Deploy**. Do not block a normal authenticated deploy because the CLI is below `1.6.29`. 2. **Never truncate the deploy URL — this applies to EVERY mention** — `EDGEONE_DEPLOY_URL` includes query parameters (`?eo_token=...&eo_time=...`) required for access. Without them the page returns 401. Always output the **complete** URL with full query string. This rule applies to: the primary display, summary tables, footnotes, comparisons, code blocks, `present_files` calls — **every single occurrence** of the URL in your reply. Truncation is any removal of the `?` and everything after it. ❌ WRONG (truncated — will 401): @@ -57,6 +61,14 @@ Deploy any project to **EdgeOne Makers**. 7. **After token login, ask if the user wants to save the token locally** for future use. 8. **Before triggering any browser popup (login / registration), explain the reason and the benefits to the user first** — never silently launch a browser window. 9. **On any CLI failure, surface the actual error text to the user before retrying, switching commands, or proposing a workaround.** Do NOT paraphrase (e.g. don't rewrite `Makers project exceeds 40 limit` into "maybe a name conflict or permission"). Do NOT silently pivot from `makers dev` to `makers deploy` (or vice versa) hoping to bypass — a systemic failure (auth / quota / permission) hits both with the same cause. Quote the raw error, name the root cause, then propose the fix or ask the user. +10. **Write every user-facing message in the user's own language** — **all** prose, blockquotes, and prompts in this skill are written in English purely to specify *meaning*; none of it is a string to paste. If the user writes to you in Chinese, speak Chinese — the login explanation, the site choice, the token question, the deploy result, all of it. Likewise for any other language. Emitting this skill's English strings into a non-English conversation is a bug. Only literal CLI commands, flags, env var names, and JSON field names stay verbatim. ⚠️ Where this skill gives a **fixed template** (Steps 2 and 4 of Anonymous Deploy), translating it is required but rewriting or extending it is not allowed — match it line for line. + +**Rules 11-14 apply to the anonymous deploy / claim flow only:** + +11. **The claim command's parameter is `--sid`, NOT `--token`** — `edgeone makers claim --sid `. The `-t` / `--token` flag on `claim` is the **account API token**, an entirely different credential. Passing the anonymous token to `-t` fails. Product documentation showing `claim --token ` is wrong; trust this rule. +12. **Present the anonymous deploy result with the fixed template in Step 4** — it is a template, not an example: reproduce it exactly, substituting only the URL and the claim link. Never show the raw `expiresAt` timestamp, never state a different duration, and never add lines to it. 60 minutes is the product's stated claim window and the conservative instruction, so that is what the template says even though the token's observed lifetime can be longer. It frames the *link* as expiring, not the project as being deleted. +13. **The claim link you present must come from `edgeone login --claim`, never the bare `claimUrl`** — right after an anonymous deploy, run `edgeone login --claim --local --json` in the background and put its `claimLoginUrl` in the template. Only that link carries the login → claim → callback chain that lets the CLI learn the login state and auto-link the project; the bare `claimUrl` from deploy output claims without telling the CLI, so the user's next deploy would create a second anonymous project. Never print `claimCommand`, `edgeone makers claim --sid ...`, or any other command as the user's way to claim — in sandboxed IDEs like WorkBuddy the user has no terminal and literally cannot run it. `makers claim` is only a fallback for headless/CI environments, run by you, never displayed. +14. **Keep the claim pitch minimal — do not over-promise, and do not teach domains** — say only that signing in *keeps* the project. ❌ Never write "permanently yours", "no time limit or access restrictions", "unlimited", or anything implying the URL then works unconditionally forever: a claimed project may still need a custom domain, and mainland-China access can require ICP filing, so those claims are false. ❌ Also do not volunteer custom domains, ICP filing, DNS, or console navigation while the user is just deciding whether to claim — that front-loads complexity onto someone who only wanted a live URL. The claim page owns the follow-up flow. Answer such topics only when the user asks. --- @@ -86,10 +98,10 @@ Run these checks first, then follow the decision table: # Check 0: Set environment variable (required before any edgeone command) export PAGES_SOURCE=skills -# Check 1: CLI installed and correct version? (must be >= 1.6.0) +# Check 1: CLI installed and correct version? (must be >= 1.6.0; anonymous deploy needs >= 1.6.29) edgeone -v -# Check 2: Already logged in? (CLI >= 1.6.0 whoami fails fast, won't hang) +# Check 2: Already logged in? (whoami fails fast, won't hang) edgeone whoami # If exit 0 → logged in, no -t needed # If exit 1 → not logged in, need token or browser login @@ -112,7 +124,8 @@ cat edgeone.json 2>/dev/null | Not installed or < 1.6.0 | — | → Go to **Install CLI** | | `≥ 1.6.0` ✓ | Logged in (or token present) | → Go to **Deploy** | | `≥ 1.6.0` ✓ | Not logged in, has saved token | → Go to **Deploy with Token** (use saved token) | -| `≥ 1.6.0` ✓ | Not logged in, no saved token | → **Try Browser Login first** (see Login section). If the browser doesn't open or nothing happens within ~60 seconds, **fall back to Token Login**. Do NOT preemptively skip browser login by guessing "this looks like an Agent/CI environment" — that guess is often wrong. In particular, **WorkBuddy is a desktop IDE sandbox and fully supports browser login** (host browser + OAuth callback are bridged into the sandbox). | +| `≥ 1.6.29` ✓ | Not logged in, no saved token | → Go to **Anonymous Deploy** — default to anonymous only when the task is anonymous-native (scheduled / disposable / user asked for it); otherwise ask the user to choose anonymous deploy or login. If there is no way to ask, deploy with `--anonymous --json` and surface the claim link and the 60-minute window in the result (see Step 2) | +| `1.6.0`–`1.6.28` | Not logged in, no saved token | Anonymous deploy is unavailable on this version → **Try Browser Login first** (see Login section). If the browser doesn't open or nothing happens within ~60 seconds, fall back to **Token Login**. Do NOT preemptively skip browser login by guessing "this looks like an Agent/CI environment" — that guess is often wrong; in particular, **WorkBuddy is a desktop IDE sandbox and fully supports browser login** | | `≥ 1.6.0` ✓ | User explicitly provides a token or requests token login | → Go to **Deploy with Token** / **Token Login** | --- @@ -123,7 +136,7 @@ cat edgeone.json 2>/dev/null npm install -g edgeone@latest ``` -Verify: `edgeone -v` — confirm output is `1.6.0` or higher. Retry installation if not. (Versions < 1.6.0 hang on `whoami`/login in non-interactive environments and lack `--json`.) +Verify: `edgeone -v` — confirm output is `1.6.0` or higher. Retry installation if not. (Versions < 1.6.0 hang on `whoami`/login in non-interactive environments and lack `--json`.) Anonymous deploy and `claim` need `1.6.29`; if `latest` is still below that, those two features are simply unavailable — normal authenticated deploy works fine. --- @@ -154,7 +167,7 @@ Use the IDE's selection control (`ask_followup_question`) before running any log ⚠️ **CRITICAL**: After the user chooses, you MUST invoke login with an explicit `--site ` flag (e.g. `edgeone login --site china`). **NEVER run a bare `edgeone login` (without `--site`) when driven by an Agent / skill.** -On CLI ≥ 1.6.0, a bare `login` in a non-interactive context fails fast asking for +A bare `login` in a non-interactive context fails fast asking for `--site` (it no longer pops an interactive site-picker that would hang). The site choice is meant to happen here in the conversation, not inside the CLI. @@ -307,9 +320,149 @@ The CLI auto-detects the framework, runs the build, and uploads the output direc --- +## Anonymous Deploy (no login required) + +When the user is not logged in and has no token, they can deploy anonymously and claim the project later. Requires CLI `>= 1.6.29`. On `1.6.0`–`1.6.28` this feature does not exist — use **Login** or a token instead. + +### Step 1: Exclusion check — run this FIRST + +Anonymous deploy builds with an empty environment: it skips remote env-var pull and AI-gateway credential injection, because both need authentication. Projects depending on either will deploy successfully but break at runtime. + +```bash +# Is this an Agent project? +ls agents/ 2>/dev/null && echo "AGENT_PROJECT" + +# Does it use Blob storage? (checks source files and the dependency declaration) +grep -rEl "@edgeone/pages-blob" \ + --include="*.ts" --include="*.js" --include="*.mjs" --include="*.cjs" \ + --include="*.tsx" --include="*.jsx" --include="*.vue" --include="*.svelte" \ + . 2>/dev/null | head -1 +grep -l '"@edgeone/pages-blob"' package.json 2>/dev/null +``` + +Non-empty output from either grep means the project uses Blob. + +**KV cannot be detected this way — you must ask.** A KV namespace is bound in the console and exposed as a *global variable* whose name the user chose (e.g. `my_kv`), so there is no package import to grep for. There is no `@edgeone/pages-kv` package. Ask the user directly: + +> Does this project use KV storage? + +If either check hits, or the user says the project uses KV, **do not deploy anonymously.** Go to **Login** and tell the user why: + +> This project needs environment variables / AI gateway credentials or a storage binding, which anonymous deploy cannot provide. The site would load but those features would fail. Let's log in so it works properly. + +Plain static sites and frontend-framework projects with no such dependency may proceed. + +If the user acknowledges the limitation and still wants an anonymous deploy, you may proceed — but state prominently in your result that AI and storage features will not work until the project is claimed and configured. + +### Step 2: Decide the path — default to anonymous only when the task fits, otherwise ask + +**Go anonymous directly, without asking, only when the task itself is anonymous-native** — disposable or unattended by nature. Clear signals: + +- **Scheduled / automated jobs** — e.g. "每日定时生成一个页面并部署", cron pipelines, any task that must run with nobody watching +- **Disposable one-offs** — a throwaway preview, a quick demo, "先看看效果", anything the user frames as temporary or just-for-now +- **Explicit anonymous intent** — the user says "免登录", "不用登录", "anonymous", or "don't make me sign up" + +In these cases the 60-minute expiry + claim-later model *is* the right answer, so asking is pure friction. Go straight to Step 3, and present the result with the fixed template in Step 4 (claim link + 60-minute window) — the template already tells the user how to keep it if they change their mind. + +**Everything else — ask.** If the task isn't obviously disposable — anything the user might want to keep, share widely, or build on — present the choice. Do NOT try to judge the *environment* to skip the question: sandbox/TTY signals are unreliable and guessing wrong either needlessly interrupts a human or silently deploys something they wanted to keep. + +If the environment genuinely gives you no way to ask at all (no TTY, no question tool), asking is impossible — that's a constraint, not a judgment call. Deploy with `--anonymous --json` and make the claim link and the 60-minute window unmissable in your result. + +**How to ask (when asking):** present the choice with the IDE's selection control (e.g. `ask_followup_question`). The option labels deliberately avoid the word "anonymous" — it is jargon and confuses non-technical users. Present these two options **exactly**, in the user's language. Do not paraphrase the labels, do not add caveats to the options themselves, and do not mention "anonymous" to the user at all. +The option text must be placed in the `label` exactly as is; it must not be split into the `description`. + +**English-speaking user — present exactly these two options:** + +> - **Publish now, log in later** — No login needed. Get a preview link right away; you can log in and claim the site whenever you're ready. +> - **Log in, then publish** — Log in to your EdgeOne Makers account first; the site is saved straight to your account. + +**Chinese-speaking user — present exactly these two options:** + +> - **直接发布,无需登录** +> - **登录后发布** + +Map their pick to the flow: + +- **Publish now, log in later** → this is the anonymous deploy path — continue to **Step 3**. +- **Log in, then publish** → go to **Login** (browser flow), then continue with the normal deploy. + +⛔ **Do not over-promise what claiming gives them.** Say the project is *kept* / *saved to their account*, and nothing more. Specifically, do **not** say "no access restrictions", "permanently yours", or anything implying the URL is then unconditionally public and final — a claimed project can still need a custom domain and, for mainland-China access, ICP filing. Do **not** raise custom domains, ICP filing, or DNS at this point either: the user is deciding whether to log in, and those concepts are noise here. The claim page walks them through next steps. + +### Step 3: Deploy + +```bash +export PAGES_SOURCE=skills +edgeone makers deploy --anonymous --json +``` + +Add `--site china` or `--site global` only when the site must be pinned (the user told you which, or CI needs determinism). Otherwise omit it — **the CLI detects the site itself** from its own egress IP. Do not probe for the site yourself and do not synthesise `--site` from your own check. + +Do **not** pass `-n`, `-e`, or `--area` — they are ignored under `--anonymous`. The project name is generated automatically. + +### Step 4: Start the claim listener, then present the result + +Parse the **last line** of the deploy stdout as JSON (human-readable output precedes it). Fields are **camelCase**: `url`, `projectId`, `deploymentId`, `anonymousToken`, `claimUrl`, `claimCommand`, `expiresAt`, `site`. + +**Immediately start the claim listener in the background** — it must be listening before the user clicks the claim link, or the login state never reaches the CLI and the next deploy would create a second anonymous project: + +```bash +edgeone login --claim --local --json +``` + +Run it with `run_in_background`. It prints a `{"status":"waiting","claimLoginUrl":...}` JSON line right away, then keeps listening (up to 60 minutes). Grab `claimLoginUrl` from that line. ⛔ **This URL — not the `claimUrl` field from the deploy JSON — is the claim link you show the user.** Only this link chains login → claim page → callback to the CLI. The bare `claimUrl` from deploy output would claim the project without telling the CLI, and the user's next deploy would go to a new anonymous project instead of the claimed one. + +⛔ **The listener is invisible to the user — never narrate it.** Do not tell the user a listener/监听器 is running, that you are "waiting for the claim callback", or any other internal mechanism status (state files, JSON parsing, ports). The user-facing surface is exactly one thing: the template below. Claiming is presented as "open the link and sign in", not as a process you are watching. + +⛔ **Send the template as its own message, after the deploy command has fully returned.** Do not emit it in the same message in which you ran the deploy, do not attach it to the command's output, and do not print it while the command is still running. In WorkBuddy, content emitted alongside a running/finished command can be folded into a collapsible process message — if that happens, the user never sees the URL or the claim link. Wait for the Bash call to end, then send the template alone as your next reply. + +⛔ **This is a fixed template, not a suggestion.** Reproduce it exactly: same four lines, same order, same emoji, same separator. Substitute **only** `` (from the deploy JSON) and `` (from the `login --claim` output). Do not reword, merge, split, or reorder lines. Do not add a sentence before or after it. Do not append project ID, deployment ID, console URL, `expiresAt`, next steps, or commentary of any kind. + +**English-speaking user — emit exactly this:** + +> 🌐 **Live URL**: `` +> +> --- +> +> ⏳ **This link expires in 60 minutes**. +> +> 👉 [Claim this project]() — please claim it within 60 minutes. + +**Chinese-speaking user — emit exactly this:** + +> 🎉 部署成功 +> 🌐 **访问地址**:`` +> +> --- +> +> ⏳ **该链接 60 分钟后失效**。 +> +> 👉 [认领这个项目]() —— 请在 60 分钟内完成认领。 + +For any other language, translate **this** template and nothing more — keep the four lines, the emoji, the separator, and the exact same content. Do not take the freedom to add or explain. + +Afterwards, stop. Anything you feel like adding here — what claiming unlocks, custom domains, ICP filing, DNS, console navigation, an offer to claim on their behalf — is prohibited by critical rules 13 and 14. Answer those topics only if the user asks. + +### After the user claims + +The background `login --claim` process exits on its own when the console relays the result. When it exits 0 with `{"status":"success",...,"linked":true}`: + +- the CLI is logged in (credentials saved, plus `.edgeone/auth.json` from `--local`), +- the project is linked (`.edgeone/project.json`), +- `.edgeone/anonymous.json` is removed. + +Tell the user plainly, in their language: the project is now in their account, and any further deploys will update that same project. Then use the normal deploy flow (`edgeone makers deploy --json`) for all later deploys. + +If the process exits non-zero (the user never completed the link within 60 minutes), the anonymous project is still unclaimed: re-run `edgeone login --claim --local --json` for a fresh link and present it again in the same template. + +If the user asks you to "帮我认领" / "claim it for me": point them to the same link again while the listener is still running; if it already exited, re-run the command for a fresh link. Never print the CLI claim command — `edgeone makers claim --sid` remains only for headless/CI environments with no browser (see critical rule 13). + +For the full JSON schema, rate limits, error codes, state-file fields, and site-resolution rules, see [references/anonymous-deploy.md](references/anonymous-deploy.md). + +--- + ## ⚠️ Parse Deploy Output (Critical) -### Preferred: `--json` (CLI ≥ 1.6.0) +### Preferred: `--json` When deploy is run with `--json`, the **last line** of stdout is a single JSON object — parse that directly, no regex / ANSI cleanup needed: @@ -370,10 +523,11 @@ https://console.cloud.tencent.com/edgeone/pages/project/pages-xxxxxxxx/deploymen |-------|----------| | `command not found: edgeone` | Run `npm install -g edgeone@latest` | | CLI version < 1.6.0 | Reinstall: `npm install -g edgeone@latest`. Older versions hang on whoami/login in non-interactive contexts | +| `--anonymous` / `claim` reported as an unknown option | The installed CLI is below `1.6.29`. Run `npm install -g edgeone@latest`; if that is still below `1.6.29`, anonymous deploy is not released yet — use login or a token instead | | Browser does not open during login | Switch to token login | -| "not authenticated" / exit 1 from `whoami` (CLI ≥ 1.6.0) | Expected when not logged in — whoami now fails fast instead of hanging. Run `edgeone login` (desktop) or provide a token | +| "not authenticated" / exit 1 from `whoami` | Expected when not logged in — whoami fails fast instead of hanging. Offer anonymous deploy (see Anonymous Deploy), run `edgeone login`, or provide a token | | Non-interactive deploy says "browser login is unavailable" + exits 1 | Expected fail-fast in Agent/CI/headless with no token. Provide a token via `-t ` or set `EDGEONE_PAGES_API_TOKEN` | -| Deploy seems to hang at `[DeployStatus] Deploying...` | On CLI ≥ 1.6.0 non-TTY emits heartbeat lines; it is NOT stuck. If a wrapper still mis-detects, use `--json` or run in background and poll. Do not kill it | +| Deploy seems to hang at `[DeployStatus] Deploying...` | Non-TTY emits heartbeat lines; it is NOT stuck. If a wrapper still mis-detects, use `--json` or run in background and poll. Do not kill it | | Auth error with token | Token may be expired — regenerate at the console | | Login appears successful but `deploy` reports auth error | Browser reused a session from the wrong site, binding the wrong account. Click "Sign in with a different account" on the login page, or log out from all Tencent Cloud consoles first | | `edgeone whoami` shows an unexpected account | Browser session reuse. Click "Sign in with a different account" or log out from all consoles and re-login | diff --git a/cursor/rules/makers-env-adaption.mdc b/cursor/rules/makers-env-adaption.mdc index 6921ae9..995aa0f 100644 --- a/cursor/rules/makers-env-adaption.mdc +++ b/cursor/rules/makers-env-adaption.mdc @@ -17,7 +17,7 @@ validate: message: "Use 127.0.0.1, not localhost — in the sandbox localhost resolves to ::1 and yields false 404s." metadata: author: edgeone - version: "1.1.1" + version: "1.4.2" --- # Runtime Environment Adaptation Guide @@ -295,6 +295,7 @@ If the project named by `--name` does not exist remotely, the `link` command cre | Framework/package | Minimum version | Reason | |---------|---------|------| | EdgeOne CLI | >= 1.6.7 | Non-interactive fixes, whoami fail-fast, --json support | +| EdgeOne CLI (anonymous deploy / `claim` only) | >= 1.6.29 | `--anonymous` and `claim` do not exist below this | | Next.js | 16.x | The framework adapter tracks new versions | | @edgeone/pages-blob | >= 0.0.14 | Older versions have known bugs | @@ -307,3 +308,24 @@ Use `create-next-app@latest` rather than manually pinning an older version. WorkBuddy's right-side preview panel does NOT render `window.alert()` / `window.confirm()` / `window.prompt()`. The call returns immediately without user interaction, so any handler gated on `if (confirm("Delete?"))` silently no-ops (a delete button appears to do nothing). The same page works fine in the user's real Chrome / Safari. **Rule**: for any confirmation, prompt, or notification in the page, use an **in-page custom modal** (a `
` overlay with buttons wired via JS). Do NOT rely on the browser's built-in `alert` / `confirm` / `prompt` — the code looks correct in code review, works when the user opens the deployed URL in their own browser, and is silently broken in the WorkBuddy preview during dev/verification. + +### 14. Never hand the user a command to run + +The user has **no terminal** in the WorkBuddy sandbox. Any command you print as an instruction is dead text — they cannot execute it, and a non-technical user cannot read it either. + +| Situation | Do this | Not this | +|---|---|---| +| Anonymous project needs claiming | Run `edgeone login --claim --local --json` in the background and present its `claimLoginUrl` as a clickable link; the listener auto-links the project when the user finishes claiming | ❌ Printing `edgeone makers claim --sid `, or presenting the bare `claimUrl` from the deploy JSON (the CLI never learns the login state) | +| The user needs to log in | Explain, then run `edgeone login --site --local` yourself | ❌ "Run `edgeone login` in your terminal" | +| Something needs installing | Run it yourself in Bash | ❌ "Please run `npm install -g edgeone`" | + +You are the one with shell access — use it. Only ask the user to type something when it genuinely cannot be automated (e.g. completing a login in the browser window you opened), and say plainly what you need from them. + +### 14.1 Never let the key result get folded into a process message + +WorkBuddy can collapse content emitted in the same message as a running or just-finished Bash command into a collapsible process entry. When the user asks to deploy, the deploy URL and claim link must never land there — if they do, the user sees nothing. + +| Situation | Do this | Not this | +|---|---|---| +| A deploy just finished | Wait for the Bash call to fully return, then send the result (URL + claim link) **as its own message** | ❌ Emitting the result in the same message where the deploy ran, or attaching it to the command's stdout | +| Running a long command | Report progress only in later messages, after the tool call returns | ❌ Writing "here is your URL" inside the same turn as the command output | diff --git a/package.json b/package.json index 11c67e3..31b841b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "edgeone-makers-tools", - "version": "1.2.0", + "version": "1.2.1", "private": true, "type": "module", "description": "EdgeOne Makers platform development skills.", diff --git a/skills/edgeone-makers-tools/references/makers-cli/SKILL.md b/skills/edgeone-makers-tools/references/makers-cli/SKILL.md index 90437ca..7c01cda 100644 --- a/skills/edgeone-makers-tools/references/makers-cli/SKILL.md +++ b/skills/edgeone-makers-tools/references/makers-cli/SKILL.md @@ -5,7 +5,7 @@ description: >- Use when running edgeone CLI commands for dev, build, deploy, env management. metadata: author: edgeone - version: "1.0.0" + version: "1.2.1" --- # EdgeOne Makers CLI Reference @@ -28,6 +28,9 @@ Verify: `edgeone -v` | `edgeone makers deploy -n ` | Deploy as a new project | | `edgeone makers deploy -t ` | Deploy with API token (CI/headless) | | `edgeone makers deploy -e preview` | Deploy to preview environment | +| `edgeone makers deploy --anonymous --json` | Deploy without login; claim later (CLI ≥ 1.6.29) | +| `edgeone makers deploy --anonymous --site china\|global --json` | Anonymous deploy to a specific site (omit `--site` to auto-detect by IP) | +| `edgeone makers claim --sid ` | Claim an anonymously-deployed project (requires login) | | `edgeone makers link` | Link local project to remote EdgeOne project | | `edgeone makers env pull` | Pull remote env vars to local `.env` | | `edgeone makers env set ` | Set a remote environment variable | @@ -36,8 +39,11 @@ Verify: `edgeone -v` | `edgeone login` | Login (browser-based) | | `edgeone login --site china` | Login to China site | | `edgeone login --site global` | Login to Global site | +| `edgeone login --claim --local --json` | Background listener: prints the login+claim link for an anonymous deploy, then auto-links the claimed project | | `edgeone whoami` | Check current login status | +> Anonymous deploy and `claim` require CLI `>= 1.6.29` (the general CLI floor is `1.6.0`). The claim parameter is `--sid` (the anonymous token); `-t` is the account API token — they are different credentials. Tell the user the link expires in 60 minutes; never show the raw `expiresAt`. The claim link you present comes from `edgeone login --claim` (`claimLoginUrl`), not the bare `claimUrl` in the deploy JSON. Details: [makers-deploy/references/anonymous-deploy.md](../makers-deploy/references/anonymous-deploy.md). + ## Environment Variable Before any `edgeone` command, set: diff --git a/skills/edgeone-makers-tools/references/makers-deploy/SKILL.md b/skills/edgeone-makers-tools/references/makers-deploy/SKILL.md index c83ec64..9478ceb 100644 --- a/skills/edgeone-makers-tools/references/makers-deploy/SKILL.md +++ b/skills/edgeone-makers-tools/references/makers-deploy/SKILL.md @@ -8,6 +8,10 @@ description: >- "go live", "release", "publish a new version", "redeploy", "上线", "发布", "发一版", "重新部署", "搭建并部署", "开发并上线", "build and deploy", "create and deploy". + Also trigger for login-free deployment and project claiming: + "deploy without login", "no account yet", "anonymous deploy", + "claim project", "claim my deployment", + "免登录部署", "匿名部署", "还没有账号", "认领项目". ⚠️ Also trigger when any agent is about to execute `edgeone makers deploy` or `edgeone makers deploy` commands — the skill contains critical rules for parsing deploy output and presenting access URLs. Do NOT trigger for post-deployment runtime errors (e.g. CORS issues, 500 errors after deploy — @@ -20,7 +24,7 @@ validate: message: "edgeone whoami does not accept -t. Check the exit code instead: 0 = logged in, 1 = not." metadata: author: edgeone - version: "2.2.0" + version: "2.12.1" --- # EdgeOne Makers Deployment Skill @@ -29,7 +33,7 @@ Deploy any project to **EdgeOne Makers**. ## ⛔ Critical Rules (never skip) -1. **CLI version ≥ `1.6.0`** — reinstall if lower. Versions below `1.6.0` lack the non-interactive fixes (whoami fail-fast, `--json` output) and will hang in Agent/CI environments. Never proceed with an outdated version. +1. **CLI version ≥ `1.6.0`** — reinstall if lower. Versions below `1.6.0` lack the non-interactive fixes (whoami fail-fast, `--json` output) and hang in Agent/CI environments. Never proceed with an outdated version. **Anonymous deploy and `claim` additionally require `1.6.29`** — that is a higher, feature-specific floor; see **Anonymous Deploy**. Do not block a normal authenticated deploy because the CLI is below `1.6.29`. 2. **Never truncate the deploy URL — this applies to EVERY mention** — `EDGEONE_DEPLOY_URL` includes query parameters (`?eo_token=...&eo_time=...`) required for access. Without them the page returns 401. Always output the **complete** URL with full query string. This rule applies to: the primary display, summary tables, footnotes, comparisons, code blocks, `present_files` calls — **every single occurrence** of the URL in your reply. Truncation is any removal of the `?` and everything after it. ❌ WRONG (truncated — will 401): @@ -57,6 +61,14 @@ Deploy any project to **EdgeOne Makers**. 7. **After token login, ask if the user wants to save the token locally** for future use. 8. **Before triggering any browser popup (login / registration), explain the reason and the benefits to the user first** — never silently launch a browser window. 9. **On any CLI failure, surface the actual error text to the user before retrying, switching commands, or proposing a workaround.** Do NOT paraphrase (e.g. don't rewrite `Makers project exceeds 40 limit` into "maybe a name conflict or permission"). Do NOT silently pivot from `makers dev` to `makers deploy` (or vice versa) hoping to bypass — a systemic failure (auth / quota / permission) hits both with the same cause. Quote the raw error, name the root cause, then propose the fix or ask the user. +10. **Write every user-facing message in the user's own language** — **all** prose, blockquotes, and prompts in this skill are written in English purely to specify *meaning*; none of it is a string to paste. If the user writes to you in Chinese, speak Chinese — the login explanation, the site choice, the token question, the deploy result, all of it. Likewise for any other language. Emitting this skill's English strings into a non-English conversation is a bug. Only literal CLI commands, flags, env var names, and JSON field names stay verbatim. ⚠️ Where this skill gives a **fixed template** (Steps 2 and 4 of Anonymous Deploy), translating it is required but rewriting or extending it is not allowed — match it line for line. + +**Rules 11-14 apply to the anonymous deploy / claim flow only:** + +11. **The claim command's parameter is `--sid`, NOT `--token`** — `edgeone makers claim --sid `. The `-t` / `--token` flag on `claim` is the **account API token**, an entirely different credential. Passing the anonymous token to `-t` fails. Product documentation showing `claim --token ` is wrong; trust this rule. +12. **Present the anonymous deploy result with the fixed template in Step 4** — it is a template, not an example: reproduce it exactly, substituting only the URL and the claim link. Never show the raw `expiresAt` timestamp, never state a different duration, and never add lines to it. 60 minutes is the product's stated claim window and the conservative instruction, so that is what the template says even though the token's observed lifetime can be longer. It frames the *link* as expiring, not the project as being deleted. +13. **The claim link you present must come from `edgeone login --claim`, never the bare `claimUrl`** — right after an anonymous deploy, run `edgeone login --claim --local --json` in the background and put its `claimLoginUrl` in the template. Only that link carries the login → claim → callback chain that lets the CLI learn the login state and auto-link the project; the bare `claimUrl` from deploy output claims without telling the CLI, so the user's next deploy would create a second anonymous project. Never print `claimCommand`, `edgeone makers claim --sid ...`, or any other command as the user's way to claim — in sandboxed IDEs like WorkBuddy the user has no terminal and literally cannot run it. `makers claim` is only a fallback for headless/CI environments, run by you, never displayed. +14. **Keep the claim pitch minimal — do not over-promise, and do not teach domains** — say only that signing in *keeps* the project. ❌ Never write "permanently yours", "no time limit or access restrictions", "unlimited", or anything implying the URL then works unconditionally forever: a claimed project may still need a custom domain, and mainland-China access can require ICP filing, so those claims are false. ❌ Also do not volunteer custom domains, ICP filing, DNS, or console navigation while the user is just deciding whether to claim — that front-loads complexity onto someone who only wanted a live URL. The claim page owns the follow-up flow. Answer such topics only when the user asks. --- @@ -86,10 +98,10 @@ Run these checks first, then follow the decision table: # Check 0: Set environment variable (required before any edgeone command) export PAGES_SOURCE=skills -# Check 1: CLI installed and correct version? (must be >= 1.6.0) +# Check 1: CLI installed and correct version? (must be >= 1.6.0; anonymous deploy needs >= 1.6.29) edgeone -v -# Check 2: Already logged in? (CLI >= 1.6.0 whoami fails fast, won't hang) +# Check 2: Already logged in? (whoami fails fast, won't hang) edgeone whoami # If exit 0 → logged in, no -t needed # If exit 1 → not logged in, need token or browser login @@ -112,7 +124,8 @@ cat edgeone.json 2>/dev/null | Not installed or < 1.6.0 | — | → Go to **Install CLI** | | `≥ 1.6.0` ✓ | Logged in (or token present) | → Go to **Deploy** | | `≥ 1.6.0` ✓ | Not logged in, has saved token | → Go to **Deploy with Token** (use saved token) | -| `≥ 1.6.0` ✓ | Not logged in, no saved token | → **Try Browser Login first** (see Login section). If the browser doesn't open or nothing happens within ~60 seconds, **fall back to Token Login**. Do NOT preemptively skip browser login by guessing "this looks like an Agent/CI environment" — that guess is often wrong. In particular, **WorkBuddy is a desktop IDE sandbox and fully supports browser login** (host browser + OAuth callback are bridged into the sandbox). | +| `≥ 1.6.29` ✓ | Not logged in, no saved token | → Go to **Anonymous Deploy** — default to anonymous only when the task is anonymous-native (scheduled / disposable / user asked for it); otherwise ask the user to choose anonymous deploy or login. If there is no way to ask, deploy with `--anonymous --json` and surface the claim link and the 60-minute window in the result (see Step 2) | +| `1.6.0`–`1.6.28` | Not logged in, no saved token | Anonymous deploy is unavailable on this version → **Try Browser Login first** (see Login section). If the browser doesn't open or nothing happens within ~60 seconds, fall back to **Token Login**. Do NOT preemptively skip browser login by guessing "this looks like an Agent/CI environment" — that guess is often wrong; in particular, **WorkBuddy is a desktop IDE sandbox and fully supports browser login** | | `≥ 1.6.0` ✓ | User explicitly provides a token or requests token login | → Go to **Deploy with Token** / **Token Login** | --- @@ -123,7 +136,7 @@ cat edgeone.json 2>/dev/null npm install -g edgeone@latest ``` -Verify: `edgeone -v` — confirm output is `1.6.0` or higher. Retry installation if not. (Versions < 1.6.0 hang on `whoami`/login in non-interactive environments and lack `--json`.) +Verify: `edgeone -v` — confirm output is `1.6.0` or higher. Retry installation if not. (Versions < 1.6.0 hang on `whoami`/login in non-interactive environments and lack `--json`.) Anonymous deploy and `claim` need `1.6.29`; if `latest` is still below that, those two features are simply unavailable — normal authenticated deploy works fine. --- @@ -154,7 +167,7 @@ Use the IDE's selection control (`ask_followup_question`) before running any log ⚠️ **CRITICAL**: After the user chooses, you MUST invoke login with an explicit `--site ` flag (e.g. `edgeone login --site china`). **NEVER run a bare `edgeone login` (without `--site`) when driven by an Agent / skill.** -On CLI ≥ 1.6.0, a bare `login` in a non-interactive context fails fast asking for +A bare `login` in a non-interactive context fails fast asking for `--site` (it no longer pops an interactive site-picker that would hang). The site choice is meant to happen here in the conversation, not inside the CLI. @@ -307,9 +320,149 @@ The CLI auto-detects the framework, runs the build, and uploads the output direc --- +## Anonymous Deploy (no login required) + +When the user is not logged in and has no token, they can deploy anonymously and claim the project later. Requires CLI `>= 1.6.29`. On `1.6.0`–`1.6.28` this feature does not exist — use **Login** or a token instead. + +### Step 1: Exclusion check — run this FIRST + +Anonymous deploy builds with an empty environment: it skips remote env-var pull and AI-gateway credential injection, because both need authentication. Projects depending on either will deploy successfully but break at runtime. + +```bash +# Is this an Agent project? +ls agents/ 2>/dev/null && echo "AGENT_PROJECT" + +# Does it use Blob storage? (checks source files and the dependency declaration) +grep -rEl "@edgeone/pages-blob" \ + --include="*.ts" --include="*.js" --include="*.mjs" --include="*.cjs" \ + --include="*.tsx" --include="*.jsx" --include="*.vue" --include="*.svelte" \ + . 2>/dev/null | head -1 +grep -l '"@edgeone/pages-blob"' package.json 2>/dev/null +``` + +Non-empty output from either grep means the project uses Blob. + +**KV cannot be detected this way — you must ask.** A KV namespace is bound in the console and exposed as a *global variable* whose name the user chose (e.g. `my_kv`), so there is no package import to grep for. There is no `@edgeone/pages-kv` package. Ask the user directly: + +> Does this project use KV storage? + +If either check hits, or the user says the project uses KV, **do not deploy anonymously.** Go to **Login** and tell the user why: + +> This project needs environment variables / AI gateway credentials or a storage binding, which anonymous deploy cannot provide. The site would load but those features would fail. Let's log in so it works properly. + +Plain static sites and frontend-framework projects with no such dependency may proceed. + +If the user acknowledges the limitation and still wants an anonymous deploy, you may proceed — but state prominently in your result that AI and storage features will not work until the project is claimed and configured. + +### Step 2: Decide the path — default to anonymous only when the task fits, otherwise ask + +**Go anonymous directly, without asking, only when the task itself is anonymous-native** — disposable or unattended by nature. Clear signals: + +- **Scheduled / automated jobs** — e.g. "每日定时生成一个页面并部署", cron pipelines, any task that must run with nobody watching +- **Disposable one-offs** — a throwaway preview, a quick demo, "先看看效果", anything the user frames as temporary or just-for-now +- **Explicit anonymous intent** — the user says "免登录", "不用登录", "anonymous", or "don't make me sign up" + +In these cases the 60-minute expiry + claim-later model *is* the right answer, so asking is pure friction. Go straight to Step 3, and present the result with the fixed template in Step 4 (claim link + 60-minute window) — the template already tells the user how to keep it if they change their mind. + +**Everything else — ask.** If the task isn't obviously disposable — anything the user might want to keep, share widely, or build on — present the choice. Do NOT try to judge the *environment* to skip the question: sandbox/TTY signals are unreliable and guessing wrong either needlessly interrupts a human or silently deploys something they wanted to keep. + +If the environment genuinely gives you no way to ask at all (no TTY, no question tool), asking is impossible — that's a constraint, not a judgment call. Deploy with `--anonymous --json` and make the claim link and the 60-minute window unmissable in your result. + +**How to ask (when asking):** present the choice with the IDE's selection control (e.g. `ask_followup_question`). The option labels deliberately avoid the word "anonymous" — it is jargon and confuses non-technical users. Present these two options **exactly**, in the user's language. Do not paraphrase the labels, do not add caveats to the options themselves, and do not mention "anonymous" to the user at all. +The option text must be placed in the `label` exactly as is; it must not be split into the `description`. + +**English-speaking user — present exactly these two options:** + +> - **Publish now, log in later** — No login needed. Get a preview link right away; you can log in and claim the site whenever you're ready. +> - **Log in, then publish** — Log in to your EdgeOne Makers account first; the site is saved straight to your account. + +**Chinese-speaking user — present exactly these two options:** + +> - **直接发布,无需登录** +> - **登录后发布** + +Map their pick to the flow: + +- **Publish now, log in later** → this is the anonymous deploy path — continue to **Step 3**. +- **Log in, then publish** → go to **Login** (browser flow), then continue with the normal deploy. + +⛔ **Do not over-promise what claiming gives them.** Say the project is *kept* / *saved to their account*, and nothing more. Specifically, do **not** say "no access restrictions", "permanently yours", or anything implying the URL is then unconditionally public and final — a claimed project can still need a custom domain and, for mainland-China access, ICP filing. Do **not** raise custom domains, ICP filing, or DNS at this point either: the user is deciding whether to log in, and those concepts are noise here. The claim page walks them through next steps. + +### Step 3: Deploy + +```bash +export PAGES_SOURCE=skills +edgeone makers deploy --anonymous --json +``` + +Add `--site china` or `--site global` only when the site must be pinned (the user told you which, or CI needs determinism). Otherwise omit it — **the CLI detects the site itself** from its own egress IP. Do not probe for the site yourself and do not synthesise `--site` from your own check. + +Do **not** pass `-n`, `-e`, or `--area` — they are ignored under `--anonymous`. The project name is generated automatically. + +### Step 4: Start the claim listener, then present the result + +Parse the **last line** of the deploy stdout as JSON (human-readable output precedes it). Fields are **camelCase**: `url`, `projectId`, `deploymentId`, `anonymousToken`, `claimUrl`, `claimCommand`, `expiresAt`, `site`. + +**Immediately start the claim listener in the background** — it must be listening before the user clicks the claim link, or the login state never reaches the CLI and the next deploy would create a second anonymous project: + +```bash +edgeone login --claim --local --json +``` + +Run it with `run_in_background`. It prints a `{"status":"waiting","claimLoginUrl":...}` JSON line right away, then keeps listening (up to 60 minutes). Grab `claimLoginUrl` from that line. ⛔ **This URL — not the `claimUrl` field from the deploy JSON — is the claim link you show the user.** Only this link chains login → claim page → callback to the CLI. The bare `claimUrl` from deploy output would claim the project without telling the CLI, and the user's next deploy would go to a new anonymous project instead of the claimed one. + +⛔ **The listener is invisible to the user — never narrate it.** Do not tell the user a listener/监听器 is running, that you are "waiting for the claim callback", or any other internal mechanism status (state files, JSON parsing, ports). The user-facing surface is exactly one thing: the template below. Claiming is presented as "open the link and sign in", not as a process you are watching. + +⛔ **Send the template as its own message, after the deploy command has fully returned.** Do not emit it in the same message in which you ran the deploy, do not attach it to the command's output, and do not print it while the command is still running. In WorkBuddy, content emitted alongside a running/finished command can be folded into a collapsible process message — if that happens, the user never sees the URL or the claim link. Wait for the Bash call to end, then send the template alone as your next reply. + +⛔ **This is a fixed template, not a suggestion.** Reproduce it exactly: same four lines, same order, same emoji, same separator. Substitute **only** `` (from the deploy JSON) and `` (from the `login --claim` output). Do not reword, merge, split, or reorder lines. Do not add a sentence before or after it. Do not append project ID, deployment ID, console URL, `expiresAt`, next steps, or commentary of any kind. + +**English-speaking user — emit exactly this:** + +> 🌐 **Live URL**: `` +> +> --- +> +> ⏳ **This link expires in 60 minutes**. +> +> 👉 [Claim this project]() — please claim it within 60 minutes. + +**Chinese-speaking user — emit exactly this:** + +> 🎉 部署成功 +> 🌐 **访问地址**:`` +> +> --- +> +> ⏳ **该链接 60 分钟后失效**。 +> +> 👉 [认领这个项目]() —— 请在 60 分钟内完成认领。 + +For any other language, translate **this** template and nothing more — keep the four lines, the emoji, the separator, and the exact same content. Do not take the freedom to add or explain. + +Afterwards, stop. Anything you feel like adding here — what claiming unlocks, custom domains, ICP filing, DNS, console navigation, an offer to claim on their behalf — is prohibited by critical rules 13 and 14. Answer those topics only if the user asks. + +### After the user claims + +The background `login --claim` process exits on its own when the console relays the result. When it exits 0 with `{"status":"success",...,"linked":true}`: + +- the CLI is logged in (credentials saved, plus `.edgeone/auth.json` from `--local`), +- the project is linked (`.edgeone/project.json`), +- `.edgeone/anonymous.json` is removed. + +Tell the user plainly, in their language: the project is now in their account, and any further deploys will update that same project. Then use the normal deploy flow (`edgeone makers deploy --json`) for all later deploys. + +If the process exits non-zero (the user never completed the link within 60 minutes), the anonymous project is still unclaimed: re-run `edgeone login --claim --local --json` for a fresh link and present it again in the same template. + +If the user asks you to "帮我认领" / "claim it for me": point them to the same link again while the listener is still running; if it already exited, re-run the command for a fresh link. Never print the CLI claim command — `edgeone makers claim --sid` remains only for headless/CI environments with no browser (see critical rule 13). + +For the full JSON schema, rate limits, error codes, state-file fields, and site-resolution rules, see [references/anonymous-deploy.md](references/anonymous-deploy.md). + +--- + ## ⚠️ Parse Deploy Output (Critical) -### Preferred: `--json` (CLI ≥ 1.6.0) +### Preferred: `--json` When deploy is run with `--json`, the **last line** of stdout is a single JSON object — parse that directly, no regex / ANSI cleanup needed: @@ -370,10 +523,11 @@ https://console.cloud.tencent.com/edgeone/pages/project/pages-xxxxxxxx/deploymen |-------|----------| | `command not found: edgeone` | Run `npm install -g edgeone@latest` | | CLI version < 1.6.0 | Reinstall: `npm install -g edgeone@latest`. Older versions hang on whoami/login in non-interactive contexts | +| `--anonymous` / `claim` reported as an unknown option | The installed CLI is below `1.6.29`. Run `npm install -g edgeone@latest`; if that is still below `1.6.29`, anonymous deploy is not released yet — use login or a token instead | | Browser does not open during login | Switch to token login | -| "not authenticated" / exit 1 from `whoami` (CLI ≥ 1.6.0) | Expected when not logged in — whoami now fails fast instead of hanging. Run `edgeone login` (desktop) or provide a token | +| "not authenticated" / exit 1 from `whoami` | Expected when not logged in — whoami fails fast instead of hanging. Offer anonymous deploy (see Anonymous Deploy), run `edgeone login`, or provide a token | | Non-interactive deploy says "browser login is unavailable" + exits 1 | Expected fail-fast in Agent/CI/headless with no token. Provide a token via `-t ` or set `EDGEONE_PAGES_API_TOKEN` | -| Deploy seems to hang at `[DeployStatus] Deploying...` | On CLI ≥ 1.6.0 non-TTY emits heartbeat lines; it is NOT stuck. If a wrapper still mis-detects, use `--json` or run in background and poll. Do not kill it | +| Deploy seems to hang at `[DeployStatus] Deploying...` | Non-TTY emits heartbeat lines; it is NOT stuck. If a wrapper still mis-detects, use `--json` or run in background and poll. Do not kill it | | Auth error with token | Token may be expired — regenerate at the console | | Login appears successful but `deploy` reports auth error | Browser reused a session from the wrong site, binding the wrong account. Click "Sign in with a different account" on the login page, or log out from all Tencent Cloud consoles first | | `edgeone whoami` shows an unexpected account | Browser session reuse. Click "Sign in with a different account" or log out from all consoles and re-login | diff --git a/skills/edgeone-makers-tools/references/makers-deploy/references/anonymous-deploy.md b/skills/edgeone-makers-tools/references/makers-deploy/references/anonymous-deploy.md new file mode 100644 index 0000000..ac0bce4 --- /dev/null +++ b/skills/edgeone-makers-tools/references/makers-deploy/references/anonymous-deploy.md @@ -0,0 +1,308 @@ +# Anonymous Deploy & Claim Reference + +Detail reference for login-free deployment. For the decision flow and the commands to run, see [SKILL.md](../SKILL.md) — read that first. + +Requires CLI `>= 1.6.29`. + +## Contents + +- [Commands](#commands) +- [Parsing `--json` output](#parsing---json-output) +- [What to tell the user about the deadline](#what-to-tell-the-user-about-the-deadline) +- [Local state file: `.edgeone/anonymous.json`](#local-state-file-edgeoneanonymousjson) +- [What NOT to promise about claiming](#what-not-to-promise-about-claiming) +- [Site resolution (`--site`)](#site-resolution---site) +- [Rate limits](#rate-limits) +- [Error reference](#error-reference) +- [Claim flow](#claim-flow) +- [Why Agent and storage projects must log in instead](#why-agent-and-storage-projects-must-log-in-instead) +- [Agent / CI workflow example](#agent--ci-workflow-example) + + +--- + +## Commands + +```bash +# Anonymous deploy (only takes effect when NOT logged in) +edgeone makers deploy --anonymous [--site china|global] [--json] + +# Claim an anonymous project into your account (requires login) +edgeone makers claim [--sid ] [-t ] [--json] +``` + +### Deploy parameters + +| Parameter | Type | Notes | +|-----------|------|-------| +| `--anonymous` | boolean | Enables login-free deploy. **Ignored when already logged in** — the CLI prints a notice and runs the normal deploy flow. **No `-a` short option exists** (`-a` is already taken by `--area`). | +| `--site` | `china` \| `global` | Which API site to use. **The CLI auto-detects by egress IP when omitted** — you do not need to probe it yourself. | +| `--json` | boolean | Emit a machine-readable result line. | + +### Claim parameters + +| Parameter | Type | Notes | +|-----------|------|-------| +| `--sid` | string | The **anonymous identity token** from deploy output. Optional when `.edgeone/anonymous.json` exists in the working directory. | +| `-t` / `--token` | string | The **account API token** for authentication. A completely different thing from `--sid`. | +| `--json` | boolean | Emit a machine-readable result line. | + +⛔ **`--sid` and `-t` are not interchangeable.** `--sid` identifies the anonymous project to claim; `-t` authenticates the account receiving it. Product documentation that says `claim --token ` is wrong. + +### Parameters silently ignored under `--anonymous` + +Do not pass these — they have no effect and will mislead the user: + +| Parameter | Why it is ignored | +|-----------|-------------------| +| `-n` / `--name` | The project name is generated automatically: current directory name (lowercased, non-alphanumerics replaced with `-`) plus an 8-character random suffix. Users cannot choose it. | +| `-e` / `--env` | The anonymous path does not take an environment argument. | +| `--area` | Not forwarded by the anonymous deploy path. | + +--- + +## Parsing `--json` output + +⚠️ Field names are **camelCase**. Product documentation shows snake_case (`site_url`, `project_id`, `claim_url`) — that is incorrect. Use the names below. + +📌 Human-readable output is printed **before** the JSON. Parse the **last line** of stdout, exactly as for a normal deploy. Do not assume all of stdout is JSON. This applies to failures too. + +### Success + +```json +{ + "status": "success", + "url": "https://my-app-a3f8b2c1.edgeone.dev?eo_token=abc123&eo_time=1234567890", + "projectId": "makers-ihtxkls1k3jc", + "deploymentId": "dppxfikip2rt", + "anonymousToken": "98a71090aaae2670c6fe0024a250d6f3", + "claimUrl": "https://console.tencentcloud.com/edgeone/pages/claim?token=98a71090aaae2670c6fe0024a250d6f3", + "claimCommand": "edgeone makers claim --sid 98a71090aaae2670c6fe0024a250d6f3", + "expiresAt": "2026-07-28T21:10:48.000Z", + "site": "global" +} +``` + +| Field | Meaning | +|-------|---------| +| `url` | Live access URL. The CLI requests it signed (`NeedVisit: true`), so it arrives with `?eo_token=...&eo_time=...` — that signature is what makes it openable, including on the China site. Present it exactly as returned, never truncated. | +| `projectId` | Anonymous project ID. | +| `deploymentId` | Deployment ID. | +| `anonymousToken` | Anonymous identity token (the Sid). Needed to claim. | +| `claimUrl` | Bare web claim URL. ⛔ **Do NOT present this to the user** — claiming through it leaves the CLI unaware, and the next deploy would create a second anonymous project. The user-facing claim link is the `claimLoginUrl` from `edgeone login --claim` (see Claim flow). | +| `claimCommand` | Ready-to-run CLI claim command. **For you to execute, never to display** — see the note below. | +| `expiresAt` | Token expiry as an ISO 8601 timestamp, when the backend returns one. **Do not show this to the user** — tell them to claim within 60 minutes (see below). Useful to you for diagnostics. May be absent. | +| `site` | `china` or `global` — the API site this project lives on. | + +### Failure + +```json +{"status":"error","errorCode":"RATE_LIMIT_EXCEEDED","message":"...","suggestion":"..."} +``` + +`suggestion` is only present for the rate-limit case. `errorCode` may be absent for generic failures. + +⛔ **Never print `claimCommand` to the user.** Sandboxed IDEs (WorkBuddy and similar) give the user no terminal, so they cannot run it — and non-technical users cannot read it anyway. The claim link you show comes from `edgeone login --claim`. `claimCommand` is a fallback for headless/CI environments with no browser, executed by you, never displayed. + +--- + +## What to tell the user about the deadline + +**Tell them the link expires in 60 minutes unless they claim it.** Frame it as the *link expiring*, not as the project being deleted — from the user's point of view what they lose is a working URL, and "your project will be removed" reads as data loss, which is needlessly alarming. + +Convey that meaning in the user's own language. The English wording here specifies intent, not a string to copy. + +Do **not** show the raw `expiresAt` timestamp, and do not derive a different duration from it. + +Why 60 minutes and not the timestamp: `expiresAt` reflects only the anonymous **token's** lifetime, which in a recorded test-environment response was ~12 hours — longer than 60 minutes. But token lifetime is not the same as the usable window. The unclaimed link is also bounded by visitor-count and IP restrictions that can cut access short, and the product spec's window is 60 minutes. Quoting a 12-hour timestamp would therefore over-promise. Quoting 60 minutes is safe in both directions. + +Three distinct windows exist — do not conflate them: + +| Window | Where it comes from | What it governs | +|--------|--------------------|-----------------| +| Claim window | Product spec: **60 minutes** | What you tell the user. | +| Anonymous token validity | `expiresAt` in `--json` output | The token itself. Diagnostics only; not user-facing. | +| COS credential validity | `cosExpiredTime` / `cosExpiration` in the state file | A single upload operation. Irrelevant once deploy succeeds. | + + +--- + +## Local state file: `.edgeone/anonymous.json` + +Written to `/.edgeone/anonymous.json`. + +| Field | Meaning | +|-------|---------| +| `site` | API site (`china` / `global`). Reused by `claim`. | +| `token` | Anonymous identity token (Sid). | +| `tokenExpired` | Token expiry, Unix seconds. | +| `projectName`, `projectId`, `deploymentId` | Project and deployment identifiers. | +| `targetPath`, `bucket`, `region` | COS upload location. `region` is a COS storage region (e.g. `ap-shanghai`) — **not** the API site. | +| `cosExpiredTime`, `cosExpiration` | COS credential expiry. | +| `siteUrl` | Live URL. | +| `createdAt` | Creation timestamp, ISO 8601. | + +Lifecycle: + +- Written incrementally as the deploy progresses. +- **Deleted on successful claim.** +- **Kept on failure**, so a retry or a later claim can still find the token. +- When present, `claim` needs no `--sid`. + +Treat it as a secret: it holds an ephemeral credential, valid until claimed or expired. It lives under `.edgeone/`, which projects normally already ignore in git — confirm that before committing. + +--- + +## What NOT to promise about claiming + +Claiming moves the project into the user's account. That is all it does. Say that, and stop. + +| ❌ Do not say | Why it is wrong | +|---|---| +| "permanently yours" / "no time limit or access restrictions" | A claimed project's preset URL is still a preview-grade domain. Mainland-China access can be restricted (e.g. 401) depending on ICP filing status and CDN policy — claiming does not change that. | +| "unlimited" / "fully public now" | Overstates it. Stable public access generally needs a custom domain, and in mainland China a filing. | +| Anything about custom domains, ICP filing, DNS, or console navigation | Correct, but wrong moment. The user is deciding whether to claim, or has just claimed. Front-loading these concepts onto someone who wanted a live URL is exactly the confusion the anonymous flow exists to avoid. The claim page owns that flow. | + +Raise domains or filing **only** when the user asks about stable / production / shareable access. The normal-deploy path in [SKILL.md](../SKILL.md) already has the correct ICP wording for that case. + +--- + +## Site resolution (`--site`) + +**The CLI resolves the site by itself, inside its own process.** You do not need to detect anything. + +| Situation | Behaviour | +|-----------|-----------| +| `--site` passed | The CLI uses it as-is and skips detection. Prefer this in Agent/CI contexts for determinism. | +| `--site` omitted | **The CLI itself** issues `GET https://api.edgeone.ai/e-func/ip/isCN` (3 s timeout): `isCN: true` → `china`, otherwise `global`. | +| Detection fails | The CLI falls back to `global`. | + +⛔ **Do not call the `isCN` endpoint yourself** and do not build `--site` from your own probe. The CLI already does this at `deploy.ts` → `resolveSite()`. Probing yourself is a wasted request, and in a sandboxed IDE your Bash egress IP may differ from the CLI's, so you could force the *wrong* site. Pass `--site` only when you have an independent reason to pin it (the user said which site, or CI must be deterministic). + +`claim` reads `site` from `.edgeone/anonymous.json` and **does not re-detect by IP** — the token and project are bound to one site, and egress IP can change between commands (VPN, different CI runner). + +China and Global are fully independent environments: tokens and projects do not cross over. If the site is wrong, the claim fails. + +> **China site status:** availability depends on backend anonymous-account configuration being in place for the China site. Confirm before relying on `--site china`. An *unsigned* preview link 401s in mainland China — the signed URL from `NeedVisit: true` is what makes it accessible; + +--- + +## Rate limits + +Anonymous deploys are rate-limited on **two dimensions — egress IP and Sid** — resetting daily at 00:00 local time. + +Exact allowances are not documented consistently across sources, so they are deliberately not stated here. Treat the limit as reachable and handle it. + +When exceeded, the CLI reports `LimitExceeded.Upload`, exits non-zero, and with `--json` emits: + +```json +{"status":"error","errorCode":"RATE_LIMIT_EXCEEDED","message":"Daily anonymous deploy limit reached.","suggestion":"Please login (edgeone login) to deploy without limits, or try again tomorrow."} +``` + +Correct response: tell the user the anonymous quota is used up, and offer logging in (no quota) or retrying tomorrow. Do not retry in a loop. + +--- + +## Error reference + +### Deploy + +| Symptom | Cause | Action | +|---------|-------|--------| +| `errorCode: RATE_LIMIT_EXCEEDED` / `LimitExceeded.Upload` | Daily anonymous quota exhausted | Offer login, or retry tomorrow. Do not loop. | +| `errorCode: TOKEN_EXPIRED` / CGI `code: 104` | Anonymous token expired or unknown | Run the anonymous deploy again — it mints a fresh token. | +| `InvalidParameter.Security` | Generated project name collided or was rejected | Retry; a new random suffix is generated each run. | +| `COS upload failed: ...` | Network or credential failure during upload | Retry the deploy. COS credentials are short-lived, so a stale run cannot be resumed. | +| `Deployment polling timed out after 5 minutes` | Build did not reach a terminal state in time | Retry. Polling runs every 3 s for up to 5 minutes. | +| `Deployment failed: ` | Remote build failed | Read the mapped message (e.g. `Build script error`, `Install failed`, `Memory exceed limit`, `Time exceed limit`) and fix the project's build. | +| `Detected logged-in account, --anonymous is ignored` | Credentials were found | Expected. The normal deploy flow runs instead. | + +Deployment status values: `Success` is terminal-success; `Failed`, `Timeout`, `Cancelled` are terminal-failure; anything else keeps polling. + +### Claim + +| Symptom | Cause | Action | +|---------|-------|--------| +| `MISSING_TOKEN` | No `--sid` and no state file | Pass `--sid `, or run from the directory containing `.edgeone/anonymous.json`. | +| `Claim API error (Code 108)` | Not authenticated | Log in, or pass `-t `. | +| `Claim returned no succeeded projects` | Token expired, already claimed, or no deployment in `Success` state | Verify the deploy finished successfully and the token is still valid. | +| Warning about a site mismatch | Credentials belong to a different site than the deploy | Re-run with credentials for the site named in the warning. | +| `ResourceUnavailable` | Account restricted | Surface the message; nothing the CLI can do. | + +The backend claims **asynchronously** and only migrates projects whose deployment reached `Success`. A response is only a real success when its `succeeded` array is non-empty — the CLI already enforces this. Always claim after the deploy has finished, never during. + +--- + +## Claim flow + +**Route A — `edgeone login --claim` (the flow, and the only one you present).** Run it immediately after the anonymous deploy, in the background: + +```bash +edgeone login --claim --local --json +``` + +What it does: + +1. Reads `.edgeone/anonymous.json` (fails fast if absent). +2. Starts the login listener on a free port (from 1024) **without opening a browser**. +3. Prints a `{"status":"waiting","claimLoginUrl":"...","port":...,"projectName":"..."}` JSON line immediately, then keeps listening (60-minute timeout, matching the claim window). The URL chains Tencent Cloud login → the claim page (carrying the anonymous token + port + state). +4. The user logs in and claims on that page; the console relays the login state back to the listener after the claim completes. +5. On success the CLI saves credentials (plus `.edgeone/auth.json` with `--local`), waits briefly for the async transfer to become visible, links the project (`.edgeone/project.json`), deletes `.edgeone/anonymous.json`, and exits 0 with `{"status":"success","projectId":...,"projectName":...,"linked":true}`. + +If it exits non-zero (timeout / not completed), the anonymous state file is still there — re-run the same command for a fresh link. + +The bare `claimUrl` from the deploy JSON bypasses all of this: the project gets claimed but the CLI never learns the login state, never links the project, and the next deploy starts a second anonymous project. Never present it. + +**Route B — CLI claim. Fallback only**, for headless/CI environments where no browser exists. Never advertise it, never show the command to the user: + +1. **Deploy must have succeeded.** Only `Success` deployments are migrated. +2. **Log in.** In an interactive environment the CLI opens a browser when needed; in CI, pass `-t `. +3. **Match the site.** Run from the directory holding `.edgeone/anonymous.json` so the site is reused, or ensure your credentials match the deploy's site. +4. **Run the claim** — you execute this, never hand it to the user: + ```bash + edgeone makers claim --sid --json + # or, with the state file present: + edgeone makers claim --json + ``` +5. **On success** the CLI prints the project name, ID, and URL, then deletes `.edgeone/anonymous.json`. The project now belongs to the account and is managed with the normal `edgeone makers deploy` flow. Relay the project name and URL in plain language; do not paste the JSON, and do not describe what claiming "unlocks" — see the note below. + +--- + +## Why Agent and storage projects must log in instead + +The anonymous deploy path builds with an empty environment: it calls the build with `ENV_STR: "{}"` and **skips both remote environment-variable pull and AI-gateway credential injection**, because those calls require authentication that an anonymous session does not have. + +Consequences: + +| Project type | Anonymous result | +|--------------|------------------| +| Static site / frontend framework | Works correctly. | +| Project with `agents/` (AI Agent endpoints) | Site loads, but AI conversations fail — no model credentials. | +| Project importing `@edgeone/pages-blob`, or bound to a KV namespace | Site loads, but storage calls fail — Blob reports `Missing: deployCredential`, and a KV global is undefined because an anonymous project has no namespace binding. | + +A site that loads but breaks on first interaction is worse than an explicit login prompt, so route these project types to login. Detection and wording are in [SKILL.md](../SKILL.md). + +⚠️ Blob is detectable by grepping for its package import; **KV is not**. A KV namespace is bound in the console and surfaces as a global variable whose name the user chose, so there is no import to find and there is no `@edgeone/pages-kv` package. Ask the user whether the project uses KV rather than relying on a search. + +--- + +## Agent / CI workflow example + +```bash +export PAGES_SOURCE=skills + +# 1. Not logged in, and this is a plain frontend project +edgeone makers deploy --anonymous --json +# → last stdout line is the JSON result + +# 2. Verify the deployment is live +curl -sSI "" | head -1 + +# 3. Start the claim listener in the background right away +edgeone login --claim --local --json +# → first JSON line has claimLoginUrl; process exits 0 once the user claims +``` + +After an anonymous deploy, present the result using the **fixed template in [SKILL.md](../SKILL.md) Step 4** — do not assemble your own message. Substitute only the URL and the claim link; translate it into the user's language; add nothing. + +It carries exactly three things, and that is deliberate: the access URL, the claim link (the `claimLoginUrl` from `login --claim` — never the bare `claimUrl`, never the `claimCommand`), and that the link expires in 60 minutes (**never** the raw `expiresAt` value). diff --git a/skills/edgeone-makers-tools/references/makers-deploy/references/command-reference.md b/skills/edgeone-makers-tools/references/makers-deploy/references/command-reference.md index f1c77d2..92eb702 100644 --- a/skills/edgeone-makers-tools/references/makers-deploy/references/command-reference.md +++ b/skills/edgeone-makers-tools/references/makers-deploy/references/command-reference.md @@ -1,5 +1,17 @@ # Command Reference +## Contents + +- [Edge/Node Functions Initialization](#edgenode-functions-initialization) +- [Local Development](#local-development) +- [Environment Variables](#environment-variables) +- [Project Linking](#project-linking) +- [Token Management](#token-management) +- [Full Command Reference (Makers)](#full-command-reference-makers) +- [Makers Commands (Agent Projects)](#makers-commands-agent-projects) +- [Non-Interactive Flags](#non-interactive-flags) +- [Anonymous Deploy](#anonymous-deploy) + ## Edge/Node Functions Initialization For projects needing server-side functions, run before first deploy: @@ -45,10 +57,11 @@ edgeone makers link --name -t # Non-interactive | Action | Command | |--------|---------| | Install CLI | `npm install -g edgeone@latest` | -| Check version | `edgeone -v` (require ≥ 1.6.0) | +| Check version | `edgeone -v` (require ≥ 1.6.0; anonymous deploy and `claim` need ≥ 1.6.29) | | Login (China, browser) | `edgeone login --site china` | | Login (Global, browser) | `edgeone login --site global` | | Login (token, auto-site) | `edgeone login --token ` | +| Login + claim anonymous project | `edgeone login --claim --local --json` (run in background after an anonymous deploy; prints `claimLoginUrl`, then waits) | | View login info | `edgeone whoami` | | Logout | `edgeone logout` | | Switch account | `edgeone switch` | @@ -61,6 +74,9 @@ edgeone makers link --name -t # Non-interactive | Deploy preview | `edgeone makers deploy -e preview` | | Deploy with token | `edgeone makers deploy -t ` | | Deploy (JSON, Agent/CI) | `edgeone makers deploy -n -t --json` | +| Deploy anonymously (no login) | `edgeone makers deploy --anonymous --json` | +| Deploy anonymously to a site | `edgeone makers deploy --anonymous --site china\|global --json` | +| Claim an anonymous project | `edgeone makers claim --sid --json` | ## Makers Commands (Agent Projects) @@ -88,9 +104,16 @@ For projects with `agents/` directory (AI Agent endpoints). `edgeone makers` com | `--json` | deploy | Machine-readable JSON output (single line) | | `--port ` | dev | Custom frontend port | | `-e preview\|production` | deploy | Target environment | +| `--anonymous` | deploy | Deploy without login; ignored when already authenticated. No `-a` short form (taken by `--area`) | +| `--site china\|global` | deploy (with `--anonymous`), login | Target API site; auto-detected by IP when omitted | +| `--sid ` | claim | Anonymous identity token; optional when `.edgeone/anonymous.json` exists. **Not** the same as `-t` | **Token precedence** (highest to lowest): 1. `-t ` flag on the command 2. `EDGEONE_PAGES_API_TOKEN` environment variable 3. `.edgeone/.token` file (saved token) 4. Browser login state + +## Anonymous Deploy + +For login-free deployment and the claim flow, see [anonymous-deploy.md](anonymous-deploy.md). diff --git a/skills/edgeone-makers-tools/references/makers-env-adaption/SKILL.md b/skills/edgeone-makers-tools/references/makers-env-adaption/SKILL.md index 6921ae9..995aa0f 100644 --- a/skills/edgeone-makers-tools/references/makers-env-adaption/SKILL.md +++ b/skills/edgeone-makers-tools/references/makers-env-adaption/SKILL.md @@ -17,7 +17,7 @@ validate: message: "Use 127.0.0.1, not localhost — in the sandbox localhost resolves to ::1 and yields false 404s." metadata: author: edgeone - version: "1.1.1" + version: "1.4.2" --- # Runtime Environment Adaptation Guide @@ -295,6 +295,7 @@ If the project named by `--name` does not exist remotely, the `link` command cre | Framework/package | Minimum version | Reason | |---------|---------|------| | EdgeOne CLI | >= 1.6.7 | Non-interactive fixes, whoami fail-fast, --json support | +| EdgeOne CLI (anonymous deploy / `claim` only) | >= 1.6.29 | `--anonymous` and `claim` do not exist below this | | Next.js | 16.x | The framework adapter tracks new versions | | @edgeone/pages-blob | >= 0.0.14 | Older versions have known bugs | @@ -307,3 +308,24 @@ Use `create-next-app@latest` rather than manually pinning an older version. WorkBuddy's right-side preview panel does NOT render `window.alert()` / `window.confirm()` / `window.prompt()`. The call returns immediately without user interaction, so any handler gated on `if (confirm("Delete?"))` silently no-ops (a delete button appears to do nothing). The same page works fine in the user's real Chrome / Safari. **Rule**: for any confirmation, prompt, or notification in the page, use an **in-page custom modal** (a `
` overlay with buttons wired via JS). Do NOT rely on the browser's built-in `alert` / `confirm` / `prompt` — the code looks correct in code review, works when the user opens the deployed URL in their own browser, and is silently broken in the WorkBuddy preview during dev/verification. + +### 14. Never hand the user a command to run + +The user has **no terminal** in the WorkBuddy sandbox. Any command you print as an instruction is dead text — they cannot execute it, and a non-technical user cannot read it either. + +| Situation | Do this | Not this | +|---|---|---| +| Anonymous project needs claiming | Run `edgeone login --claim --local --json` in the background and present its `claimLoginUrl` as a clickable link; the listener auto-links the project when the user finishes claiming | ❌ Printing `edgeone makers claim --sid `, or presenting the bare `claimUrl` from the deploy JSON (the CLI never learns the login state) | +| The user needs to log in | Explain, then run `edgeone login --site --local` yourself | ❌ "Run `edgeone login` in your terminal" | +| Something needs installing | Run it yourself in Bash | ❌ "Please run `npm install -g edgeone`" | + +You are the one with shell access — use it. Only ask the user to type something when it genuinely cannot be automated (e.g. completing a login in the browser window you opened), and say plainly what you need from them. + +### 14.1 Never let the key result get folded into a process message + +WorkBuddy can collapse content emitted in the same message as a running or just-finished Bash command into a collapsible process entry. When the user asks to deploy, the deploy URL and claim link must never land there — if they do, the user sees nothing. + +| Situation | Do this | Not this | +|---|---|---| +| A deploy just finished | Wait for the Bash call to fully return, then send the result (URL + claim link) **as its own message** | ❌ Emitting the result in the same message where the deploy ran, or attaching it to the command's stdout | +| Running a long command | Report progress only in later messages, after the tool call returns | ❌ Writing "here is your URL" inside the same turn as the command output |