Skip to content
Noite
Esc
↑↓navigate↵open⌘Jpreview
On this page

CLI

Deploy prebuilt dist directories over Git smart-HTTP with @noitenow/cli.

@noitenow/cli deploys a CI-built dist plus wrangler.jsonc as a synthetic fast-forward commit over Git smart-HTTP — zero server build. Same auth as git push (Basic git + profile API key, push role suffices, never force).

Install

Node 20+ must be on the machine that runs it (ships as a plain Node bundle — Bun works too):

bun add -g @noitenow/cli   # Bun
npm i -g @noitenow/cli     # npm/pnpm/yarn — same tarball
bunx @noitenow/cli deploy  # one-off, no install
bunx @noitenow/cli deploy --slug <slug> --url https://git.<domain> --token $NOITE_API_KEY

Flags

Flags fall back to env, then to GitHub Actions context:

Flag Env Actions default
--dist — dist
--slug NOITE_SLUG repo name, slugified
--url GIT_PUBLIC_BASE / NOITE_BASE —
--token NOITE_API_KEY / NOITE_GIT_TOKEN —
--wrangler — wrangler.jsonc
--message — deploy <sha12>
--comment — update (create / off)

A slug that spells a platform host is refused: the configured control subdomain (app in prod), api/git under every tenant base, and the hidden pod labels. With the control UI on the bare domain (the dev default) app is an ordinary tenant slug. The tree carries dist/* + wrangler.jsonc with no package.json, so the runner skips to release → celld deploy. Commits parent the remote tip (fast-forward); values are never logged, and the token is passed to git as its HTTP Basic auth header through the environment — never in the remote URL, the process arguments or the workdir’s .git/config, so a retained temp dir holds no key.

Workflow

- run: bun run build
- run: bunx @noitenow/cli deploy --comment update
  env:
    NOITE_API_KEY: ${{ secrets.NOITE_API_KEY }}
    NOITE_BASE: https://git.<domain>

Outputs and PR comments

In Actions it writes url= + sha= to $GITHUB_OUTPUT for downstream steps, and posts (or updates via marker) a PR comment with gh — no GitHub App needed. The URL is the tenant host, https://<slug>.<domain> (http://<slug>.noite.localhost:9080 for a localhost git base) — the same origin stdout and the comment link to.

  • --comment update (default): one comment per PR, updated on each deploy.
  • --comment create: a new comment per deploy.
  • --comment off: no comment.

Reporting soft-fails: a missing gh, a missing token, a non-zero gh exit, no PR number, or a $GITHUB_OUTPUT write error only warns — by then the deploy is already live.

Environments

noite environments manages an app’s preview environments — list, create, delete, redeploy, public toggle and variable overrides:

noite environments list --slug my-app
noite environments create --slug my-app --branch feature-x
noite environments deploy staging --slug my-app
noite environments public staging on --slug my-app      # or `off`
noite environments vars get staging --slug my-app
noite environments vars set staging API_URL https://api.example.com --slug my-app
noite environments vars unset staging API_URL --slug my-app
noite environments delete staging --slug my-app

An environment is named by its label (e.g. staging) or its id. The app is resolved from --slug/NOITE_SLUG/the repo name, and the API key from --token/NOITE_API_KEY — the same profile key deploy uses, which needs view to read, push to create, redeploy or set overrides, and admin to delete or toggle public.

These commands do not use Git: they talk to the control UI’s MCP endpoint (Agents), so they need the control UI’s origin rather than the git base. --app-url/NOITE_APP_URL names it; without either it is derived from --url: https://git.<domain> → https://app.<domain>, and the bare base on a localhost install (http://git.noite.localhost:9080 → http://noite.localhost:9080, where control runs).

The same flags (--slug, --token, --url, --app-url) apply to every subcommand. Nothing is written to $GITHUB_OUTPUT, and no PR comment is posted: these are interactive commands, not the deploy step.

The agent loop from a terminal

Every command below is a thin client of the MCP tools: the role gates, the merge rules and the wording are the server’s own, so the CLI and an agent cannot disagree.

noite pr list --slug my-app                    # --state open|closed|merged|all, --limit N
noite pr view 12 --slug my-app                 # state, mergeability, reviews, checks, preview
noite pr create --head feature-x --title "Add the thing" --slug my-app
noite pr merge 12 --slug my-app --delete-branch
noite logs --slug my-app --limit 100           # --environment staging for a preview
noite rollback --sha 1a2b3c4 --slug my-app     # --environment staging for a preview

noite deploy keeps its push behaviour and gains two subcommands, which carry the same connection flags as every other command:

noite deploy status --slug my-app              # this app's deploy state and recent deploys
noite deploy wait --slug my-app                # bounded long poll, re-armed until it settles
noite deploy wait --slug my-app --sha 1a2b3c4 --max-wait 25 --timeout 900
noite deploy wait --slug my-app --environment staging

deploy wait re-calls wait_for_deploy (at most 25 s per call by default) until the deploy reaches a terminal status, then prints it; --timeout (default 900 s) bounds the whole wait. --deploy-id, --sha and --environment choose which row it follows.

Every one of these talks to the control UI’s MCP endpoint, so they need the control origin rather than the git base: --app-url/NOITE_APP_URL, else derived from --url as described above.

Was this page helpful?