--- name: mashangjia-deploy description: Deploy the user's current website project to 码上架 with the official mashangjia CLI. Use when the user asks to publish, deploy, host, preview, or put the current website online through 码上架. --- # Deploy to 码上架 Canonical web bootstrap: `https://mashangjia.com/ai`. Machine-readable capability summary: `https://mashangjia.com/.well-known/mashangjia-capabilities.json`(同一事实源的 JSON 版本)。 The user does **not** need to install this Skill. Reading this page is sufficient to follow the deployment contract. An installable full Skill package may also be distributed through the official 码上架 GitHub repository for users who prefer local Skill installation, auditing, or offline reference. Raw HTTP endpoints, request fields, and HTTP error-code contracts are documented in the [OpenAPI specification](../../../docs/agent-api.openapi.yaml). ## Output style (user-facing reports) The deployment report you give the user must be terse. Follow the spirit of the `caveman` skill at — compress, never drop substance: 1. **Two-layer output.** First line = the verdict: deployed (URL) or failed (why). Below it, at most one short code block with the failure reason / next action. Nothing else on success. 2. **Success**: give the authoritative URL verbatim, one line of what it is, stop. No celebration, no recap of steps. 3. **Failure**: verdict line, then a code block with the suspected cause (marked as suspected when it is your inference), then exactly one reminder: keep the diagnostic info and contact support if needed. Follow `failure_help` verbatim when it exists. 4. **Never dump raw logs at the user.** Keep code, commands, URLs, error codes and exact error strings verbatim; drop filler, hedging and pleasantries. 5. **Safety exceptions**: security warnings, destructive-action confirmations, and unclear ordering must be stated in full — never compressed. Example (success): ``` 部署成功:https://site-abc123def456.mashangjia.com/ ``` Example (failure): ``` 部署失败:项目数量已达上限 (PROJECT_LIMIT)。 原因:当前账号已有 5 个运行中站点,达到套餐额度。 解决:删除闲置站点后重试,或升级套餐。 ``` ## Primary command For a website project in the current working directory, use: ```bash mashangjia deploy . --json ``` The CLI owns the deployment mechanics. Do not reimplement them with ad-hoc curl commands when the official CLI is available. Deployment mode can be made explicit when the user's intent is already known: ```bash mashangjia deploy . --mode account --json mashangjia deploy . --mode anonymous --json ``` `--mode auto` is the default. `--mode account` requires an account credential and never falls back to anonymous. `--mode anonymous` ignores local account credentials for route selection and never sends them. ## Preflight and decision boundary Before changing user source, installing dependencies, or uploading any project bytes, run the read-only preflight and consume its single JSON object: ```bash mashangjia preflight . --json ``` If the global command is unavailable but Node/npm are available, use the official `npx mashangjia preflight . --json` form; never install an unrelated package. If the user or Skill context provides `base_url`, pass that exact value with `--base-url ` and keep it for every later command. Never probe or silently switch to another service URL. The script owns deterministic environment/project/safety checks, parallel preparation, isolated dependency installation/builds, progress lines on stderr, and the final deploy JSON. The Skill does not repeat local scanning or build detection. The Skill owns the decision: read `preflight` first; **the anonymous fast path is the default and never asks the user a question**. If the user explicitly specified a mode (anonymous or account), honor it without asking again. Otherwise, for a project accepted by preflight, proceed anonymous immediately. Dockerfile projects can be published anonymously as a temporary dynamic site (container build, about 24 hours, claimable later); claiming a Docker temporary site requires signing in and a paid plan that enables Docker projects, so do not promise that a free account can claim it. For Node SSR, backend signals, or requested server data without a Dockerfile, the CLI returns `ACCOUNT_REQUIRED` during preflight and stops before packaging or upload; anonymous static fallback is not supported. Use account mode with an account credential. Only after that run `deploy`, parse the final JSON, and return `url` (the fixed public address) verbatim. The raw claim capability stays in the CLI's local recovery state and is never printed; claiming happens later on request via `mashangjia claim`. ## Deployment mode: anonymous fast path(“一句话,码上架”) **Anonymous is the default and the fastest path for projects accepted by preflight. Never ask the user a question before deploying.** 通过只读预检后,默认直接执行匿名发布;不询问用户,完成后返回固定公开地址。 - If the user already explicitly asked for anonymous publishing or account publishing, honor that choice and do not ask again. - If the user has not specified a mode, **do not ask**. Use the anonymous fast path for projects accepted by preflight: `mashangjia deploy . --mode anonymous --json`. A server-data project without a Dockerfile is an explicit preflight account boundary. - **Do not ask a second generic “是否同意上传到第三方/码上架” confirmation** at any point. Running anonymous publishing IS the user's authorization. Platform-level tool or network permission prompts may still appear independently. - If your host agent product has its own built-in consent prompt for uploading files, that prompt belongs to the host, not to 码上架 — never attribute it to the platform, and never add a second confirmation round of your own. Do not ask the user to manually create, copy, paste, or reveal a deployment token merely to perform this flow. Account credentials should come from an existing local CLI login or an API Token already supplied by the logged-in dashboard context (the deployment code product was removed; API Token is the account-level credential). ### Anonymous publishing Anonymous is the **default fast path** for projects accepted by preflight: run it whenever the user did not explicitly pick a mode. ```bash mashangjia deploy . --mode anonymous --json ``` For an eligible project, explicit anonymous mode must remain anonymous even when this machine already has a 码上架 CLI login or account credential. It returns a temporary site at a fixed public address; the one-time claim capability is kept in the CLI's local 0600 recovery state, ready for `mashangjia claim`. ### Publish to an existing account Run: ```bash mashangjia deploy . --mode account --json ``` Account mode may use an existing local CLI login, an API Token supplied through `MASHANGJIA_TOKEN`, or the compatibility-only `MASHANGJIA_DEPLOY_TOKEN` deployment credential. If neither account credential is available, stop and tell the user account authentication is required. **Never silently fall back to anonymous publishing.** An account credential is a sensitive deployment capability. Keep it only in the process environment; never write it into source files, project configuration, shell scripts, commits, screenshots, website assets, build output, or public logs. ### Compatibility mode `--mode auto` preserves the historical credential-based routing behavior for compatibility. It is not the Agent conversation's primary path when the user is choosing how to publish. ## What the CLI must do `mashangjia deploy --json` is the Agent-native entry point. It is responsible for: 1. respecting explicit `auto` / `account` / `anonymous` mode selection; 2. respecting an explicitly supplied personal deployment code as an account-bound credential; 3. otherwise checking local 码上架 login state when the selected mode permits account deployment; 4. when locally authenticated, using the local long-lived Bearer only to mint a short-lived in-memory deployment Grant; 5. only when anonymous mode is selected or auto mode has no account credential, using an anonymous temporary deployment; 6. detecting whether the project is already static or needs its existing build script run; 7. selecting the generated static output such as `dist`, `build`, `out`, or another directory that actually contains `index.html`; 8. refusing to package secrets, local environment files, credential directories, private keys, symlinks, VCS metadata, or dependency caches; 9. creating a deterministic ZIP from the prepared static output so unchanged retries are byte-identical; 10. resolving one exact target project or creating it under the authenticated account, or creating a temporary project when anonymous; 11. uploading the package once for a normal operation, and reusing the same Idempotency-Key for a network-uncertain anonymous retry — the CLI now retries uncertain uploads by itself (up to 3 times, same Idempotency-Key) before reporting `SUBMIT_UNCERTAIN`; 12. polling the same deployment until `success`, `failed`, or `reviewing` — the CLI never gives up early: it waits for a terminal state (or an explicit 4xx rejection), so do not add your own deadline or timeout wrapper around `mashangjia deploy`; 13. preserving enough private local recovery state to continue the same anonymous operation after timeout/review instead of creating another project; 14. fetching the final website URL without credentials and only reporting success when it is actually reachable; 15. deleting the temporary local ZIP after the operation. ## The returned URL is authoritative When the CLI returns `verified: true` and `url_authoritative: true`, treat the `url` field as an opaque, authoritative value. Return that URL **verbatim** to the user. Do not shorten a stable URL, rebuild its path, guess a prettier hostname, substitute another URL that happens to return HTTP 200, or perform a second URL-discovery routine. A legacy `preview_url` path such as `/api/public/sites/temp-.../` may still appear for compatibility or debugging, but it is not the user-facing success address. A different HTTP-200 page is still the wrong deployment. ## Human review and recovery Human review is a first-class deployment state, not a timeout and not a failure. The CLI reports it as: ```json { "ok": false, "exit_code": 3, "code": "REVIEW_REQUIRED", "deployment": { "id": 123, "status": "reviewing", "review_required": true }, "failure_help": { "default_expanded": true, "recovery": { "safe_same_operation": true, "command": "mashangjia resume temp_... --base-url https://mashangjia.com --json" } } } ``` Do not upload again when this happens. For anonymous mode, when `failure_help.recovery.safe_same_operation` is true, execute the exact `failure_help.recovery.command` **verbatim**. Do not reconstruct or rewrite it. In particular, if it contains `--base-url`, do not drop or replace that value. The command polls the existing anonymous project and does not create or upload another project. The CLI keeps the private claim capability in its local recovery state; a resumed successful result reports only non-sensitive claim availability (`claim_available`), never the raw capability. If an anonymous submit returns `exit_code: 2` and `failure_help.recovery.safe_same_operation: true`, again execute the exact returned command verbatim. For `SUBMIT_UNCERTAIN`, that command is a mechanical safe retry: the CLI reuses the original Idempotency-Key and the server returns the original project when it already accepted the first request. Do not invent a different deploy command and do not delete the CLI recovery state. Note the CLI already retried the uncertain upload up to 3 times on its own; only after those built-in attempts all failed does it return `SUBMIT_UNCERTAIN`. ## Waiting, unreachable verdicts, and heartbeats The CLI waits for a terminal state by itself. While waiting it writes heartbeat events to **stderr** (never stdout) as JSON lines: ```json {"event":"deployment_heartbeat","waited_seconds":120,"platform_responding":true} ``` `platform_responding: false` with a `retry_attempt` field means the platform did not answer the last probe. If the CLI gives up, it is only for one of three terminal reasons: 1. `success` / `failed` / `reviewing` — the real terminal states; 2. an explicit 4xx rejection (not 408) — a definitive platform answer; 3. `DEPLOYMENT_TIMEOUT` after 3 consecutive unanswered probes (60 s apart) — the platform was unreachable. Temporary 5xx/408/429 answers do NOT count as unreachable; the CLI keeps waiting. Do not add your own deadline around the CLI call, and do not declare a deployment failed while the CLI is still waiting. If the user asks to stop waiting, interrupt the CLI process and keep the printed `failure_help.recovery` information — the operation identity is preserved locally. For account mode, use the same rule. When the CLI marks recovery safe, execute the exact returned `failure_help.recovery.command`. It may be a command such as `mashangjia status --base-url --json`; do not rebuild it from the deployment id or silently fall back to the default service. ## Expected success shapes A successful account result resembles: ```json { "ok": true, "command": "deploy", "mode": "account", "exit_code": 0, "verified": true, "url_authoritative": true, "url": "https://example.mashangjia.com/", "deployment": { "id": 123, "status": "success" }, "site": { "id": 45, "slug": "example" } } ``` A successful anonymous result resembles: ```json { "ok": true, "command": "deploy", "mode": "anonymous", "exit_code": 0, "verified": true, "url_authoritative": true, "url": "https://site-xxxx.mashangjia.com/", "project_id": "temp_...", "deployment": { "id": 123, "status": "success" }, "claim_available": true, "claim_expires_at": "...", "expires_at": "..." } ``` `url` is the site's fixed public address (stable URL): it never changes across claiming, renaming, or ownership transfer. The CLI does NOT return the raw claim capability in its output; the one-time claim capability is stored in a local 0600 recovery file and consumed later by `mashangjia claim`. Never attempt to derive, request, or print the raw claim capability from public URLs or project ids — that is impossible by design. The temporary site preview expires after about 24 hours. The claim capability remains valid for 7 days after that expiry, so the user can still claim the site within that window; claiming restores the site at the SAME fixed public address. ## Final-user output protocol (anonymous receipt) After an anonymous deployment succeeds, show the user only the fixed public address, verbatim from the CLI result `url` field; never rebuild, shorten, or guess a hostname: ```markdown [地址链接](https://site-xxxx.mashangjia.com/) (可分享,认领后地址不变) 预览约 24 小时后过期;如果之后要保存到自己的账号,告诉我「认领这个网站」。 ``` Do NOT print any claim link or raw claim capability in the final reply. Do NOT put claim capabilities into issues, commits, screenshots, website source, public logs, or analytics payloads. ### Claiming on request ("认领这个网站") When the user asks to claim the site into their account: 1. Run `mashangjia claim --json` (or with the fixed public address). The CLI reads the one-time claim capability from its local 0600 recovery state and uses the existing account authorization (CLI login / `MASHANGJIA_TOKEN`). Never ask the user to paste a claim secret. 2. If the CLI reports `AUTH_REQUIRED`, guide the user through `mashangjia login --token ` first (the website console issues API Tokens). 3. If the CLI reports `CLAIM_CAPABILITY_NOT_FOUND`, the capability is not on this machine (already claimed, expired, or deployed elsewhere) — say so plainly; never try to claim from the public URL alone. 4. On success, tell the user: 认领成功,网站已进入你的账号,原分享地址保持不变:``。The address is byte-for-byte identical to the one returned at publish time. A user may also explicitly paste their own claim link to delegate claiming to you. That is an explicit delegation and is supported: pass it to the browser claim flow or the claim API. Even then, never re-print that secret into final shareable content, logs, issues, or commits. After a successful claim the capability is immediately invalidated under the existing single-use/expiry semantics (the backend marks the token used), so a third party cannot reuse it. ## Safety boundary Never upload `.env` or `.env.*`, credential directories such as `.aws`/`.gnupg`/`.ssh`, private keys or certificates, credential config files, VCS metadata, dependency caches, or symlinks that could escape the prepared output directory. If the CLI rejects the project for a safety reason, fix the packaging boundary instead of bypassing the check. ## Build behavior Respect the project that already exists. - If the selected directory already contains a deployable `index.html`, it may be deployed as static output. - If `package.json` defines `scripts.build` **but** a ready-made output directory (`dist`/`build`/`out`/`public`) already contains `index.html`, the CLI deploys that existing output directly instead of running the build. To force a rebuild, remove the stale output directory first, then deploy again. - Otherwise, if `package.json` defines `scripts.build`, run that existing build script with the package manager implied by the project's lockfile. If the build fails because dependencies are missing, run the project's install command (for example `npm install`) first. - Do not invent framework-specific build commands when the project already defines its own build contract. - After the build, deploy the output that actually contains the generated `index.html`. - A prepared directory deployment uploads the generated output as static content; the server must not guess the original source project's build mode again. ## Platform page transformations The platform modifies served pages in limited, documented ways. Do not treat these as content corruption or deployment failure: - Temporary (anonymous) sites get an injected top banner (temporary-preview notice), a watermark badge, and about 2 KB of supporting script/style. - The server fills a **missing or empty** `` / meta description from the site name, but never overwrites a non-empty original one. - Multi-page sites and SPA routes serve the same injected banner. When self-auditing, compare a distinctive text or the original `<title>` from the user's project — not byte-level equality. ## Deployment self-audit This self-audit is an agent-side check, never a user question. Before uploading, verify yourself — silently, without asking the user anything — that the artifact is what the user asked to publish. Never pause the flow to ask the user to confirm the artifact, and never present such a pause as a platform requirement: the platform requires no pre-upload confirmation for the anonymous fast path (the user's deploy instruction IS the confirmation). - the prepared output is the user's own site, with an `index.html` homepage that is directly servable; - the build output directory is the one the project's own build contract produced — not a source directory, a parent directory, or a guessed path; - the package contains no `.env` / `.env.*` files, private keys, or other secrets. The CLI enforces this boundary; never bypass its rejection. ### Thin publication content self-audit (every publish) Before every upload, run a thin, low-cost content self-audit over the pages that will actually be published — the prepared public output (`index.html` and the other servable pages), not the full private source tree and not secrets. It applies to **every publish**, regardless of whether the content was generated by this Agent in this session, written by the user, produced by another tool, or prepared earlier. Do not skip it for a project you already believe is safe. Keep this on the fast path: use lightweight checks, do not turn it into a heavyweight multi-round model review. 1. Identify the exact public surface being published: the prepared output's pages, visible text, and entry points. 2. Scan only that surface for obviously high-risk content: adult/sexual content, gambling/betting, fraud/phishing, violence/terrorism, or content that is plainly illegal. 3. Return one concise status plus the affected pages/category: - `ALLOW` — no obviously high-risk content found; the normal fast path may continue. - `REVIEW` — ambiguous content or content that needs regional/legal confirmation; **the anonymous fast path still continues** (upload normally — the platform decides final publication, and the deployment may enter `reviewing`, which is a normal state handled in the Human review section). Report the affected pages/category in the final receipt; never block on a question. - `BLOCK` — clearly high-risk content; do not upload it on the normal fast path. Stop and state the reason in one line. Never silently rewrite, edit, or delete user content because of this step. For `REVIEW` or `BLOCK`, report the affected pages/category to the user; do not fabricate a clean result. This is a thin local screening layer only. A local `ALLOW` (or any local result) never lets the server skip its authoritative publication gate; the platform still decides final publication. Keep the self-audit free of sensitive-event lists, political keyword dictionaries, classifier thresholds, and bypass instructions, and do not treat regional/political topics as a binary keyword blacklist — they are non-binary categories that may need confirmation and are decided platform-side. After the CLI returns `verified: true` with an authoritative `url`, verify the result yourself before reporting success: fetch the final URL without credentials and compare the served content against the user's site — the page title or a distinctive text from the user's project must match. If the fetched page is not the user's site (wrong content, an error page, or an unrelated HTTP-200 page), do not report success; treat it as a deployment failure and follow the `failure_help` guidance. ## Completion contract Do not say “deployed” merely because an upload request was accepted. Success requires all of the following: 1. the project was prepared and packaged safely; 2. the correct explicit or automatic account-bound/anonymous route was selected from the user's actual context; 3. the deployment reached `success`; 4. the final website URL was fetched successfully without deployment credentials; 5. the CLI returned `ok: true`, `exit_code: 0`, `verified: true`, and `url_authoritative: true`; 6. the user received the CLI's `url` verbatim; 7. for a personal deployment code or explicit account mode, the result stayed in `mode: "account"` and did not fall back to anonymous; 8. for anonymous mode, the user received the fixed public address and the claim availability (`claim_available` / `claim_expires_at`); no raw claim capability was printed. ### 失败态联系方式协议 当部署/发布出错(失败、`BUILD_FAILED`、认领被拒等)时,agent **应当**在错误说明后附上以下联系方式: - 用户交流群二维码:`https://mashangjia.com/landing/assets/qrcode.png` - 客服微信二维码:`https://mashangjia.com/landing/assets/qrcode-square.png` - 官网联系区:`https://mashangjia.com/#contact` 当用户**主动询问**如何联系码上架时,直接给出上述联系方式。 **默认不给**:成功回执、正常流程、未被问及时,不出现任何联系方式或二维码——避免广告感。 以上 URL 只能使用本次服务实际返回值或已知公开资产路径,不许编造域名。 For deployment-related failures on the `deploy` / `status` / `resume` paths, read `failure_help` first and show its guidance expanded by default. A terminal `failed` deployment is not automatically safe to resume, retry, or re-upload. Use a mechanical command only when `failure_help.recovery.safe_same_operation` is true, and then execute the exact returned `failure_help.recovery.command` verbatim without dropping `--base-url`. If recovery is false or absent, follow `next_steps` and use the allowlisted `diagnostic` for support. Never use raw error details as support diagnostics: the diagnostic contains locating fields only and excludes deployment tokens, Bearer/Grant credentials, claim capabilities, secrets, stacks, and raw error details. Failures from unrelated CLI commands such as `login`, `sites`, or `url` are ordinary command errors, not deployment failure guidance. Do not invent a `failure_help` contract for them. ## CLI availability and update Before the first CLI command of the session, make sure the official CLI is present and current. The check is read-only and cheap — run it once per session, not before every command. 1. **Detect**: run `mashangjia --version`. If the command is not found, install the official package: ```bash npm install -g mashangjia ``` If global installation is not permitted on this machine, use the no-install `npx mashangjia ...` form for the whole session instead of changing the system. 2. **Update check**: with the CLI installed, compare local against the latest release: ```bash mashangjia --version npm view mashangjia version ``` If the local version is older, update before deploying: ```bash npm install -g mashangjia@latest ``` 3. **Contract check**: after installing or updating, confirm the help exposes all documented commands: ```bash mashangjia --help ``` It must include `preflight`, `deploy`, and `resume`. An older CLI without `preflight` must not be used as-is; update it first. Only install the official `mashangjia` package from the npm registry. Never install a similarly named third-party package and never fabricate an installation command.