9 files changed
+366
-88
.editorconfig
new
+25
@@ -0,0 +1,25 @@
1
+root = true
2
+
3
+[*]
4
+charset = utf-8
5
+end_of_line = lf
6
+indent_style = space
7
+indent_size = 4
8
+trim_trailing_whitespace = true
9
+insert_final_newline = true
10
+
11
+[*.toml]
12
+indent_size = 4
13
+
14
+[*.md]
15
+trim_trailing_whitespace = false
16
+indent_size = 2
17
+
18
+[*.json]
19
+indent_size = 2
20
+
21
+[*.yml]
22
+indent_size = 2
23
+
24
+[*.yaml]
25
+indent_size = 2
.github/copilot-instructions.md
new
+160
@@ -0,0 +1,160 @@
1
+# GitHub Copilot Instructions — smbcloud-cli
2
+
3
+## Project Overview
4
+
5
+`smbcloud-cli` is a Rust CLI tool that ships as the `smb` binary. It lets users authenticate, manage projects, and trigger deployments on the smbCloud platform. The workspace targets Rust 1.93 (edition 2021) and is built as a Cargo workspace with multiple focused crates.
6
+
7
+## Workspace Structure
8
+
9
+| Crate | Role |
10
+|---|---|
11
+| `crates/cli` | Main binary (`smb`) — all commands, entrypoint |
12
+| `crates/smbcloud-model` | Shared `serde` data models (source of truth for API shapes) |
13
+| `crates/smbcloud-network` | Network config, environment resolution, connectivity check |
14
+| `crates/smbcloud-networking` | Core HTTP client (`SmbClient`) |
15
+| `crates/smbcloud-networking-account` | Account API calls — login, logout, me |
16
+| `crates/smbcloud-networking-project` | Project API calls |
17
+| `crates/smbcloud-utils` | Shared utility helpers |
18
+| `crates/gresiq` | Internal tooling |
19
+
20
+### CLI Source Layout (`crates/cli/src/`)
21
+
22
+```
23
+main.rs — tokio entrypoint, logging setup, command dispatch
24
+lib.rs — crate root, SmbClient accessor
25
+cli/ — Cli struct, Commands enum, CommandResult
26
+account/ — login, logout, me handlers
27
+deploy/ — deploy command handler
28
+project/ — project init, crud, process handlers
29
+token/ — token storage/retrieval
30
+ui/ — terminal output helpers (spinners, styles)
31
+```
32
+
33
+## Dependency Graph
34
+
35
+```
36
+crates/cli
37
+ └── smbcloud-networking-account
38
+ └── smbcloud-networking-project
39
+ └── smbcloud-networking (SmbClient)
40
+ └── smbcloud-model (API types)
41
+ └── smbcloud-network (Environment, connectivity)
42
+ └── smbcloud-utils
43
+```
44
+
45
+All workspace-level dependencies are declared **once** in the root `Cargo.toml` under `[workspace.dependencies]`. Crate-level `Cargo.toml` files must inherit from workspace with `{ workspace = true }`.
46
+
47
+## Coding Guidelines
48
+
49
+### Correctness & Clarity
50
+
51
+- Prioritize correctness and clarity. Performance is a secondary concern unless explicitly stated.
52
+- Comments explain **why**, never **what**. Do not write comments that summarize or re-describe the code.
53
+- Implement new functionality in existing files when it fits logically. Avoid creating many small, single-purpose files.
54
+
55
+### Error Handling
56
+
57
+- Use `?` to propagate errors. Never call `.unwrap()` or `.expect()` outside of test code.
58
+- Never silently discard errors with `let _ =` on fallible operations:
59
+ - Propagate with `?` when the caller should handle it
60
+ - Use explicit `match` or `if let Err(e) = ...` when custom recovery logic is needed
61
+ - Log and ignore only when truly intentional and visibility is preserved
62
+- All command handlers return `anyhow::Result<CommandResult>`. Surface user-facing errors with `anyhow!("descriptive message")`.
63
+- Ensure async errors propagate to the top level so the user sees meaningful terminal output.
64
+
65
+### Naming & Style
66
+
67
+- Use full words for all variable and parameter names — no single-letter names, no abbreviations (e.g. `environment` not `env`, `client` not `c`).
68
+- Use variable shadowing to scope `.clone()` calls inside async closures, minimizing borrow lifetimes:
69
+ ```rust
70
+ cx.spawn({
71
+ let handle = handle.clone();
72
+ async move {
73
+ handle.do_work().await;
74
+ }
75
+ });
76
+ ```
77
+
78
+### Module Structure
79
+
80
+- **Never create `mod.rs` files.** Use `src/some_module.rs` instead of `src/some_module/mod.rs`.
81
+- When creating new crates, set `[lib] path = "src/<crate_name>.rs"` in `Cargo.toml` instead of relying on the default `lib.rs`.
82
+
83
+### Panics & Bounds
84
+
85
+- Avoid any operation that can panic at runtime: no `.unwrap()`, no unchecked indexing, no `.expect()` in production code.
86
+- When iterating or slicing, always validate bounds or use safe alternatives like `.get()`.
87
+
88
+## Architecture Patterns
89
+
90
+### Adding a New Command
91
+
92
+1. Add a variant to the `Commands` enum in `crates/cli/src/cli/`
93
+2. Create a handler function in `crates/cli/src/<domain>/`
94
+3. Wire it in the `match cli.command { ... }` block in `main.rs`
95
+4. Mark commands that require internet access in the `needs_internet` match block
96
+
97
+### Adding a New API Call
98
+
99
+1. Add or update the request/response types in `crates/smbcloud-model/src/`
100
+2. Implement the call in the relevant `crates/smbcloud-networking-*/src/` crate using `SmbClient`
101
+3. Call the networking function from the CLI command handler
102
+
103
+### Environment & Auth
104
+
105
+- The `Environment` type (from `smbcloud-network`) is threaded through all command handlers — always accept it as the first parameter.
106
+- Auth tokens are managed through the `token` module — never hardcode credentials.
107
+- The `CLI_CLIENT_SECRET` comes from the `.env` file via `dotenv_codegen` at compile time.
108
+
109
+### Terminal Output
110
+
111
+- Use the `ui` module helpers for consistent spinner, progress, and styled output.
112
+- Use `console::style(...)` for coloured terminal text.
113
+- Errors are printed in red with a `✘` prefix (handled in `main.rs`).
114
+
115
+## Build & Test Commands
116
+
117
+```bash
118
+# Verify compilation across the whole workspace
119
+cargo check --workspace
120
+
121
+# Build release binary
122
+cargo build --release
123
+
124
+# Run all tests
125
+cargo test --all-features
126
+
127
+# Lint — treat warnings as errors
128
+cargo clippy --workspace --tests -- -D warnings
129
+
130
+# Format
131
+cargo fmt --all
132
+
133
+# Check formatting without modifying files
134
+cargo fmt --all -- --check
135
+
136
+# Publish all workspace crates (requires cargo-workspaces)
137
+cargo workspaces publish --publish-as-is
138
+```
139
+
140
+## Common Pitfalls
141
+
142
+1. **`.env` must exist** with `CLI_CLIENT_SECRET` before building. CI generates it from secrets; locally you must create it manually.
143
+2. **No `mod.rs`** — always use named files for submodules.
144
+3. **All new dependencies go in the root `Cargo.toml`** under `[workspace.dependencies]`, then inherit them in each crate with `{ workspace = true }`.
145
+4. **`#[tokio::main]` lives only in `main.rs`** — all other async entry points are plain `async fn`.
146
+5. **The binary is named `smb`**, not `smbcloud-cli` — it comes from `[[bin]] name = "smb"` in `crates/cli/Cargo.toml`.
147
+6. **`SmbClient` is a zero-cost static reference** — obtain it with the `client()` helper in `lib.rs`, don't construct it ad-hoc.
148
+7. **Do not add crate-local dependencies** without first checking the workspace root — duplicate version declarations break the workspace resolver.
149
+
150
+## Pull Request Conventions
151
+
152
+- Use a clear, imperative PR title: `Fix crash when project name is empty`, not `fixed stuff`.
153
+- No conventional-commit prefixes (`feat:`, `fix:`, etc.) in the PR title.
154
+- Include a `Release Notes:` section at the end of the PR body:
155
+ ```
156
+ Release Notes:
157
+
158
+ - Fixed ...
159
+ ```
160
+ Use `- N/A` for non-user-facing changes.
.github/pull_request_template.md
+37
-3
@@ -1,6 +1,40 @@
1
-<!--- A reference to a related issue in your repository, if any. -->
1
+## Related Issue
2
+
3
+Fixes # <!-- issue number, or remove this line if not applicable -->
4
5
## Description
4
-<!--- A description of the changes proposed in the pull request. -->
6
6
-<!--- @mentions of the person or team responsible for reviewing proposed changes. -->
7
+<!-- What does this PR do? Why is this change needed? -->
8
+
9
+## Type of Change
10
+
11
+<!-- Mark the relevant option with an [x] -->
12
+
13
+- [ ] Bug fix
14
+- [ ] New feature
15
+- [ ] Refactor (no functional change)
16
+- [ ] Documentation update
17
+- [ ] CI / tooling change
18
+
19
+## How Has This Been Tested?
20
+
21
+<!-- Describe the tests you ran or why tests are not applicable -->
22
+
23
+- [ ] `cargo test --all-features`
24
+- [ ] Manual testing (`smb <command>`)
25
+
26
+## Checklist
27
+
28
+- [ ] `cargo check --workspace` passes
29
+- [ ] `cargo clippy --workspace --tests -- -D warnings` passes
30
+- [ ] `cargo fmt --all -- --check` passes
31
+- [ ] No new `unwrap()` or `expect()` calls in production code
32
+- [ ] No new `mod.rs` files introduced
33
+- [ ] New dependencies added to root `Cargo.toml` and inherited with `{ workspace = true }`
34
+- [ ] Error messages are user-friendly and surfaced to the terminal
35
+
36
+## Release Notes
37
+
38
+<!-- One bullet. Use "- Added ...", "- Fixed ...", or "- Improved ..." for user-facing changes. Use "- N/A" otherwise. -->
39
+
40
+-
.gitignore
+1
@@ -3,6 +3,7 @@
3
4
# Editor
5
.zed
6
+.vscode
7
8
# Secrets
9
.env
.vscode/settings.json
deleted
-12
@@ -1,12 +0,0 @@
1
-{
2
- "rust-analyzer.server.path": null,
3
- "rust-analyzer.linkedProjects": [
4
- "Cargo.toml",
5
- "gems/model/ext/model/Cargo.toml"
6
- ],
7
- "java.jdt.ls.java.home": "/Users/setoelka/.local/share/mise/installs/java/openjdk-21.0.2",
8
- "java.import.gradle.java.home": "/Users/setoelka/.local/share/mise/installs/java/openjdk-21.0.2",
9
- "debug.javascript.defaultRuntimeExecutable": {
10
- "pwa-node": "/Users/setoelka/.local/share/mise/shims/node"
11
- }
12
-}
\ No newline at end of file
AGENTS.md
new
+27
@@ -0,0 +1,27 @@
1
+# Rust coding guidelines
2
+
3
+- Prioritize code correctness and clarity. Speed and efficiency are secondary priorities unless otherwise specified.
4
+- Do not write organizational or comments that summarize the code. Comments should only be written in order to explain "why" the code is written in some way in the case there is a reason that is tricky / non-obvious.
5
+- Prefer implementing functionality in existing files unless it is a new logical component. Avoid creating many small files.
6
+- Avoid using functions that panic like `unwrap()`, instead use mechanisms like `?` to propagate errors.
7
+- Be careful with operations like indexing which may panic if the indexes are out of bounds.
8
+- Never silently discard errors with `let _ =` on fallible operations. Always handle errors appropriately:
9
+ - Propagate errors with `?` when the calling function should handle them
10
+ - Use `.log_err()` or similar when you need to ignore errors but want visibility
11
+ - Use explicit error handling with `match` or `if let Err(...)` when you need custom logic
12
+ - Example: avoid `let _ = client.request(...).await?;` - use `client.request(...).await?;` instead
13
+- When implementing async operations that may fail, ensure errors propagate to the UI layer so users get meaningful feedback.
14
+- Never create files with `mod.rs` paths - prefer `src/some_module.rs` instead of `src/some_module/mod.rs`.
15
+- When creating new crates, prefer specifying the library root path in `Cargo.toml` using `[lib] path = "...rs"` instead of the default `lib.rs`, to maintain consistent and descriptive naming (e.g., `gpui.rs` or `main.rs`).
16
+- Avoid creative additions unless explicitly requested
17
+- Use full words for variable names (no abbreviations like "q" for "queue")
18
+- Use variable shadowing to scope clones in async contexts for clarity, minimizing the lifetime of borrowed references.
19
+ Example:
20
+ ```rust
21
+ executor.spawn({
22
+ let task_ran = task_ran.clone();
23
+ async move {
24
+ *task_ran.borrow_mut() = true;
25
+ }
26
+ });
27
+ ```
CLAUDE.md
new
+1
@@ -0,0 +1 @@
1
+@AGENTS.md
CONTRIBUTING.md
+114
-72
@@ -1,113 +1,155 @@
1
# Contributing to smbcloud-cli
2
3
-Thank you for considering contributing to smbcloud-cli! This document outlines the process for contributing to this project.
3
+Thank you for considering contributing to smbcloud-cli! This document covers everything you need to get up and running.
4
5
## Code of Conduct
6
7
-By participating in this project, you agree to abide by our Code of Conduct. Please be respectful and considerate of others.
7
+By participating in this project you agree to abide by our [Code of Conduct](CODE_OF_CONDUCT.md). Please be respectful and considerate of others.
8
9
-## Getting Started
10
-
11
-### Prerequisites
9
+## Prerequisites
10
13
-- Git
14
-- Node.js (recommended version: 14.x or later)
15
-- npm or yarn
11
+- [Rust](https://rustup.rs/) — toolchain version is pinned in `rust-toolchain.toml` (currently 1.93)
12
+- [cargo-workspaces](https://github.com/pksunkara/cargo-workspaces) — for publishing (`cargo install cargo-workspaces`)
13
+- A `.env` file in the repo root containing `CLI_CLIENT_SECRET=<value>` — required at compile time by `dotenv_codegen`
14
17
-### Setting up your development environment
15
+## Getting Started
16
17
1. Fork the repository on GitHub
20
-2. Clone your fork locally:
21
- ```
18
+2. Clone your fork:
19
+ ```sh
20
git clone https://github.com/your-username/smbcloud-cli.git
21
cd smbcloud-cli
22
```
25
-3. Install dependencies:
23
+3. Create the `.env` file (ask a maintainer for the value, or use a local stub for offline work):
24
+ ```sh
25
+ echo "CLI_CLIENT_SECRET=your_secret_here" > .env
26
```
27
- npm install
27
+4. Verify everything compiles:
28
+ ```sh
29
+ cargo check --workspace
30
```
29
- or if you use yarn:
30
- ```
31
- yarn install
32
- ```
33
-4. Create a branch for your work:
34
- ```
35
- git checkout -b feature/your-feature-name
31
+5. Create a branch for your work:
32
+ ```sh
33
+ git checkout -b your-feature-or-fix
34
```
35
36
## Development Workflow
37
40
-1. Make your changes in your feature branch
41
-2. Add tests for your changes
42
-3. Ensure all tests pass with `npm test`
43
-4. Ensure your code follows the style guidelines with `npm run lint`
44
-5. Commit your changes (see Commit Message Guidelines below)
45
-6. Push to your fork and submit a pull request
38
+### Build
39
47
-### Commit Message Guidelines
40
+```sh
41
+# Debug build
42
+cargo build
43
49
-We follow conventional commit messages. Each commit message should consist of:
44
+# Release build
45
+cargo build --release
46
+```
47
51
-- **type**: What kind of change is this?
52
- - `feat`: A new feature
53
- - `fix`: A bug fix
54
- - `docs`: Documentation changes
55
- - `style`: Code style changes (formatting, missing semicolons, etc)
56
- - `refactor`: Code changes that neither fix bugs nor add features
57
- - `perf`: Performance improvements
58
- - `test`: Adding or updating tests
59
- - `chore`: Changes to build process or auxiliary tools
48
+The compiled binary is at `target/release/smb`.
49
61
-Example:
50
+### Test
51
+
52
+```sh
53
+cargo test --all-features
54
+```
55
+
56
+### Lint
57
+
58
+```sh
59
+cargo clippy --workspace --tests -- -D warnings
60
```
63
-feat: add command to list SMB shares
61
+
62
+Fix any warnings before opening a PR — CI treats warnings as errors.
63
+
64
+### Format
65
+
66
+```sh
67
+# Apply formatting
68
+cargo fmt --all
69
+
70
+# Check only (what CI runs)
71
+cargo fmt --all -- --check
72
```
73
66
-## Pull Request Process
74
+## Project Structure
75
+
76
+This is a Cargo workspace. Each crate has a focused responsibility:
77
+
78
+| Crate | Purpose |
79
+| ------------------------------------ | ------------------------------------------ |
80
+| `crates/cli` | Main binary (`smb`) — commands, entrypoint |
81
+| `crates/smbcloud-model` | Shared API data types (`serde` structs) |
82
+| `crates/smbcloud-network` | Network config and environment resolution |
83
+| `crates/smbcloud-networking` | Core HTTP client (`SmbClient`) |
84
+| `crates/smbcloud-networking-account` | Account API calls |
85
+| `crates/smbcloud-networking-project` | Project API calls |
86
+| `crates/smbcloud-utils` | Shared utilities |
87
+
88
+All workspace-level dependencies are declared **once** in the root `Cargo.toml` under `[workspace.dependencies]`. When adding a dependency to a crate, add it to the root table first, then inherit it with `{ workspace = true }` in the crate's own `Cargo.toml`.
89
68
-1. Update the README.md or documentation with details of your changes, if appropriate
69
-2. Ensure your code passes all tests and linting
70
-3. The PR should address a single concern and be reasonably sized
71
-4. A project maintainer will review your changes and may request modifications
72
-5. Once approved, your PR will be merged
90
+## Coding Guidelines
91
74
-## Testing
92
+These rules are enforced in code review and by CI:
93
76
-- All new features should include appropriate tests
77
-- Run the existing test suite with `npm test` to ensure your changes don't break existing functionality
78
-- For testing CLI commands, consider using a tool like [commander](https://github.com/tj/commander.js/) or [oclif](https://oclif.io/)
94
+- Use `?` to propagate errors — never `.unwrap()` or `.expect()` in production code.
95
+- Never silently discard errors with `let _ =` on fallible operations.
96
+- Do not create `mod.rs` files — use `src/some_module.rs` instead of `src/some_module/mod.rs`.
97
+- Use full words for variable names — no abbreviations.
98
+- Comments explain _why_, not _what_. Do not write comments that summarize code.
99
+- Prefer adding to existing files over creating many small new files.
100
+
101
+The full guidelines are in [AGENTS.md](AGENTS.md).
102
+
103
+## Submitting a Pull Request
104
+
105
+1. Ensure all of the following pass locally before pushing:
106
+ ```sh
107
+ cargo check --workspace
108
+ cargo test --all-features
109
+ cargo clippy --workspace --tests -- -D warnings
110
+ cargo fmt --all -- --check
111
+ ```
112
+2. Push your branch and open a PR against `main`.
113
+3. Fill out the pull request template — in particular the **Release Notes** section.
114
+4. A maintainer will review your changes and may request modifications.
115
+5. Once approved, your PR will be merged.
116
80
-## Style Guide
117
+### PR Title Convention
118
82
-- We use ESLint to enforce code style
83
-- Run `npm run lint` to check your code
84
-- Ideally, configure your editor to show ESLint errors/warnings
119
+Use a clear, imperative title that describes the change:
120
86
-## Issue Reporting
121
+- ✅ `Fix crash when project name contains spaces`
122
+- ✅ `Add logout command`
123
+- ❌ `feat: add logout` (no conventional-commit prefixes)
124
+- ❌ `Fixed some stuff.` (no past tense, no trailing punctuation)
125
88
-- Use the GitHub issue tracker to report bugs or suggest features
89
-- For bugs, please include:
90
- - A clear description of the issue
91
- - Steps to reproduce
92
- - Expected behavior
93
- - Actual behavior
94
- - Your environment details (OS, Node.js version, etc.)
95
-- For feature requests, please include:
96
- - A clear description of the feature
97
- - Any relevant examples or use cases
126
+## Reporting Bugs
127
99
-## Documentation
128
+Use the GitHub issue tracker and fill out the bug report template. Please include:
129
101
-- Keep documentation up to date as you make changes
102
-- Document all public APIs and CLI commands
103
-- Update the README.md if adding new features or changing existing behavior
130
+- A clear description of the problem
131
+- Steps to reproduce
132
+- Expected vs. actual behaviour
133
+- Your OS and the output of `smb --version`
134
+
135
+## Requesting Features
136
+
137
+Use the GitHub issue tracker and fill out the feature request template. Describe the use case clearly — what problem does the feature solve?
138
139
## Releasing
140
107
-Project maintainers will handle the release process. Generally, we follow semantic versioning (MAJOR.MINOR.PATCH).
141
+Releases are handled by maintainers using [cargo-workspaces](https://github.com/pksunkara/cargo-workspaces):
142
109
-## Questions?
143
+```sh
144
+# Bump versions interactively
145
+cargo workspaces version
146
111
-If you have any questions about contributing, please reach out to the project maintainers through GitHub issues.
147
+# Publish all crates
148
+cargo workspaces publish --publish-as-is
149
+```
150
+
151
+GitHub Actions workflows handle the GitHub release and npm wrapper publish automatically on tag push.
152
+
153
+## Questions?
154
113
-Thank you for your contributions!
155
+Open a GitHub issue or reach out to the maintainers. We're happy to help.
crates/cli/Cargo.toml
+1
-1
@@ -3,7 +3,7 @@ name = "smbcloud-cli"
3
version = "0.3.31"
4
edition = "2021"
5
authors = ["Seto Elkahfi <hej@setoelkahfi.se>"]
6
-description = "Command line tool for deploying NextJS app on the smbCloud platform."
6
+description = "smbCloud command line interface."
7
license = "Apache-2.0"
8
repository = "https://github.com/smbcloudXYZ/smbcloud-cli"
9
documentation = "https://docs.smbcloud.xyz/cli"