|
| 1 | +# Public, open-source repository |
| 2 | + |
| 3 | +`smbcloud-cli` is published on GitHub as **open source**. Everything you commit here — code, comments, docs, and `.agents/skills/*` — is **world-readable and permanent** (git history outlives any later deletion). Before writing anything, ask: "is this safe on a public repo forever?" |
| 4 | + |
| 5 | +Do **not** add internal smbCloud infrastructure detail or secrets: |
| 6 | + |
| 7 | +- server hostnames/IPs and operational endpoints beyond what the CLI already targets in source — e.g. account-scoped SSH key names (`id_<n>@smbcloud`), `api-1.smbcloud.xyz`, internal health ports |
| 8 | +- account/user IDs and which user or tenant owns which project |
| 9 | +- real customer/app domains, PM2 process names, the production port → app → domain registry |
| 10 | +- workspace/project IDs and `frontend_app_id` / `deploy_repo_id` values |
| 11 | +- secrets/config: API keys, tokens, `.env` values, connection strings, real auth/CORS origins |
| 12 | +- commands that read local credentials to enumerate the API (e.g. `cat ~/.smb/token | curl …`) |
| 13 | +- incident logs or examples that name real apps, tenants, customers, or dated rollouts |
| 14 | + |
| 15 | +Keep docs and skills **generic** — describe how the tool behaves, using placeholders (`example.com`, `<app>`, `<source>`, `<port>`, `<n>`). The base API host (`api.smbcloud.xyz`) is already in the source, so it is not a new leak; the items above are. Fleet-specific operational detail and the internal deploy reference live only in the private `smbcloud` repo. |
| 16 | + |
| 17 | +--- |
| 18 | + |
1 | 19 | # Rust coding guidelines |
2 | 20 |
|
3 | 21 | - Prioritize code correctness and clarity. Speed and efficiency are secondary priorities unless otherwise specified. |
|
25 | 43 | } |
26 | 44 | }); |
27 | 45 | ``` |
| 46 | + |
| 47 | +--- |
| 48 | + |
| 49 | +# Build, test, and run |
| 50 | + |
| 51 | +This is a Cargo workspace pinned to stable Rust (`rust-toolchain.toml`). The CLI binary is named **`smb`** (crate `smbcloud-cli`, in `crates/cli`). |
| 52 | + |
| 53 | +```sh |
| 54 | +cargo build # build everything (debug) |
| 55 | +cargo run -p smbcloud-cli -- <args> # run the CLI, e.g. -- me, -- deploy, -- --help |
| 56 | +cargo run -p smbcloud-cli -- -e dev me # talk to a local API (Environment::Dev -> http://localhost:8088) |
| 57 | +``` |
| 58 | + |
| 59 | +CI gate (mirror it locally before pushing — see `.github/workflows/ci.yml`): |
| 60 | + |
| 61 | +```sh |
| 62 | +cargo fmt --all -- --check |
| 63 | +cargo clippy --workspace --exclude smbcloud-auth-sdk-wasm --tests -- -D warnings # warnings are denied |
| 64 | +cargo test --workspace --exclude smbcloud-auth-sdk-wasm |
| 65 | +cargo test -p smbcloud-model app_auth::tests::some_test # a single test |
| 66 | +``` |
| 67 | + |
| 68 | +`smbcloud-auth-sdk-wasm` targets `wasm32-unknown-unknown` and cannot build or test on the host — it is always excluded from workspace clippy/test and checked separately: `cargo check -p smbcloud-auth-sdk-wasm --target wasm32-unknown-unknown`. |
| 69 | + |
| 70 | +`CLI_CLIENT_SECRET` (see `.env.example`) is the OAuth client-credentials secret read at runtime; tests and `cargo check` don't need it, but login flows against a real API do. |
| 71 | + |
| 72 | +## Releases |
| 73 | + |
| 74 | +Releases are prepared on the `development` branch with a clean tree via the Makefile, which drives `cargo workspaces` to bump every crate in lockstep, then syncs the package-manager manifests (npm/nuget/pypi) and regenerates the SDK lockfiles: |
| 75 | + |
| 76 | +```sh |
| 77 | +make patch | make minor | make major | make custom VERSION=0.x.y |
| 78 | +``` |
| 79 | + |
| 80 | +It commits `Release <version>` and tags `v<version>` locally; pushing is manual. Crate publishing is separate and manual (`cargo workspaces publish`, see `docs/development.md`). The per-target release workflows (`release-*.yml`) build the distributable artifacts. |
| 81 | + |
| 82 | +--- |
| 83 | + |
| 84 | +# Architecture |
| 85 | + |
| 86 | +`smb` is a thin async (`tokio`) `clap` front-end over a set of `smbcloud-*` library crates that talk to the smbCloud REST API. The product purpose is **deploying apps** (Node.js/Next.js, Ruby/Rails, Rust, Swift/Vapor, static/Vite) from the terminal. |
| 87 | + |
| 88 | +## Request flow |
| 89 | + |
| 90 | +`crates/cli/src/main.rs` → `cli/mod.rs` (the `Cli`/`Commands` clap tree) → a `process_*` handler under `account/`, `project/`, `deploy/`, or `mail/`. Each handler returns a `CommandResult` (a spinner + final symbol/message); `main` prints it and sets the exit code. The top-level `--environment` (`dev`/`production`, default production) threads through every handler and selects the API host and the on-disk state dir (`.smb` vs `.smb-dev`, see `smbcloud-network/src/environment.rs`). |
| 91 | + |
| 92 | +Two cross-cutting globals are resolved once in `main` before any handler runs: |
| 93 | +- **CI mode** (`crates/cli/src/ci.rs`): `--ci` / `SMB_CI=1` / conventional `CI` env. Stored in a process-global `AtomicBool` (`ci::is_ci()`) rather than threaded through signatures, so deep prompt code can fail fast instead of blocking on a missing TTY. New interactive prompts must check `is_ci()` and use `ci::interactive_message(...)`. |
| 94 | +- **Logging**: bunyan JSON to `~/<smb_dir>/smbcloud-cli.log` (not stdout); user-facing output is `console`/spinner styling. |
| 95 | + |
| 96 | +## Crate layout (workspace) |
| 97 | + |
| 98 | +- `smbcloud-model` — shared serde types (`Project`, `User`, `Runner`, deploy config, `ErrorCode`/`ErrorResponse`). `crate-type = ["cdylib","rlib"]` because the SDK crates re-export it. Most unit tests live here. |
| 99 | +- `smbcloud-network` — `Environment` enum (host/protocol/state-dir resolution) and connectivity checks. |
| 100 | +- `smbcloud-networking` — `SmbClient` (the OAuth client identity) and the low-level HTTP client/constants. |
| 101 | +- `smbcloud-networking-project` — typed REST calls for projects, deploy repos, frontend apps, deploy config, and deployments (the `crud_*` files). |
| 102 | +- `smbcloud-auth` / `smbcloud-auth-sdk` — auth flows (login, signup, OIDC, Apple, client-credentials, reset/verify). `auth` is the in-CLI implementation; `auth-sdk` is the embeddable client. |
| 103 | +- `smbcloud-auth-sdk-wasm` / `-py` (+ `sdk/`) — language bindings: WASM/`wasm-bindgen` for npm, PyO3 `cdylib` for Python, and a separate `rb_sys` Cargo workspace under `sdk/gems` for the Ruby gem. These wrap `smbcloud-auth-sdk`. |
| 104 | +- `smbcloud-mail`, `smbcloud-gresiq`(`-sdk`), `smbcloud-s6n` — clients for the Mail, GresIQ (serverless Postgres), and S6n (S3-compatible storage) products. |
| 105 | +- `smbcloud-utils` — `.smb/config.toml` (`Config`) parsing and SSH key-path resolution. |
| 106 | + |
| 107 | +## Deploy subsystem (`crates/cli/src/deploy/`) |
| 108 | + |
| 109 | +The most involved area. `process_deploy.rs` loads `.smb/config.toml` (running interactive `setup_project` if missing), overlays server-side config, validates project access, then **dispatches by `config.project.kind`** to a per-stack path: `vite-spa`, `nextjs-ssr`, `rails`, `rust`, `swift` each have their own `process_deploy_*.rs`. If `kind` is unset it falls back to `deployment_method`: `Rsync` (build locally, upload over rsync, restart over SSH) or `Git` (push to a remote git hook), with `detect_runner.rs` sniffing the framework from `package.json`/`Gemfile`/`Package.swift`/`Cargo.toml`. |
| 110 | + |
| 111 | +**Monorepo**: `runner = Monorepo` with a `[[projects]]` array in config; `smb deploy --project <name>` (or an interactive picker) swaps `config.project` to the named sub-project before the dispatch above. `migrate.rs`/`smb migrate` pushes local deploy fields up to the server. |
| 112 | + |
| 113 | +When editing a deploy path, keep the public-repo policy above in mind: SSH key names, hosts, ports, app/tenant identifiers, and PM2 process names must stay as placeholders — concrete fleet detail belongs only in the private `smbcloud` repo. |
0 commit comments