@samva/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md ADDED
@@ -0,0 +1,14 @@
1
+ # Samva CLI consumer guide
2
+
3
+ Use `samva --help` and `samva <command> --help` as the command contract. For automation, prefer
4
+ `SAMVA_API_KEY`, `--json` for one bounded result, and `--jsonl` with `--all` for streamed lists.
5
+ Machine-readable results go to stdout; warnings and typed errors go to stderr.
6
+
7
+ `samva templates init` creates a project whose `devDependencies` include `@samva/markup`,
8
+ `@samva/vite`, and Vite. Run `npm install` in that project before `samva templates push`; the CLI
9
+ loads the project's installed authoring toolchain so its compiler and editor versions stay pinned
10
+ by the project lockfile. Template authoring commands require Node.js 22 or newer; other CLI commands
11
+ remain self-contained.
12
+
13
+ The platform-specific `@samva/cli-*` packages are installer artifacts. Depend on `@samva/cli`, not
14
+ on a native package directly.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Arya Labs, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,243 @@
1
+ # @samva/cli
2
+
3
+ The `samva` CLI sends and operates email from a terminal. Ordinary commands are
4
+ self-contained and require neither Bun nor Node. Template authoring commands run
5
+ the project's `@samva/vite` toolchain under Node.js 22 or newer.
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ npm install -g @samva/cli
11
+ samva --help
12
+ ```
13
+
14
+ The npm package selects the matching macOS or Linux executable. Compiled
15
+ binaries are also available from [GitHub releases](https://github.com/AryaLabsHQ/samva/releases).
16
+
17
+ ## Shell completions
18
+
19
+ Generate a completion script from the installed CLI. Regenerate it after upgrading the CLI.
20
+
21
+ ```sh
22
+ # Bash
23
+ samva --completions bash >> ~/.bashrc
24
+
25
+ # Zsh
26
+ mkdir -p ~/.zsh/completions
27
+ samva --completions zsh > ~/.zsh/completions/_samva
28
+ # Add ~/.zsh/completions to fpath, then run `autoload -Uz compinit && compinit` in .zshrc.
29
+
30
+ # Fish
31
+ mkdir -p ~/.config/fish/completions
32
+ samva --completions fish > ~/.config/fish/completions/samva.fish
33
+
34
+ # sh is an alias for the Bash-compatible script
35
+ samva --completions sh
36
+ ```
37
+
38
+ ## Authentication and execution context
39
+
40
+ For agents and CI, set an organization-scoped API key:
41
+
42
+ ```sh
43
+ export SAMVA_API_KEY="samva_sk_live_..."
44
+ ```
45
+
46
+ For interactive use, sign in with OAuth and choose an organization:
47
+
48
+ ```sh
49
+ samva login
50
+ samva org list
51
+ samva org use <slug>
52
+ ```
53
+
54
+ `SAMVA_API_KEY` takes precedence over a stored OAuth credential. An API key is already scoped to
55
+ one organization, so `--org` and `SAMVA_ORG` are rejected when it is set. With OAuth, organization
56
+ selection resolves as `--org`, then `SAMVA_ORG`, then the selected profile's organization.
57
+
58
+ `samva login` is interactive. In a non-TTY, use `SAMVA_API_KEY` for automation or explicitly choose
59
+ the device flow with `samva login --no-browser`; `--no-input`, `--json`, and `--jsonl` reject login.
60
+ If a stored OAuth record is malformed, run `samva logout` and then `samva login`; API-key calls do
61
+ not read or decode stored OAuth credentials.
62
+
63
+ Profiles hold non-secret target and organization settings. Credentials stay in the OS keyring.
64
+
65
+ ```sh
66
+ samva profile create local --target local
67
+ samva profile use local
68
+ samva --profile local email doctor
69
+ ```
70
+
71
+ The profile resolves as `--profile`, then `SAMVA_PROFILE`, then the active profile, then `default`.
72
+ The API URL resolves as `--api-url`, then `SAMVA_API_URL`, then the profile target. `local` targets
73
+ `http://127.0.0.1:8787`; `production` targets `https://api.samva.dev`.
74
+
75
+ ## Common operations
76
+
77
+ ```sh
78
+ # Send an inline email. --to is repeatable.
79
+ samva email send --to ada@example.com --subject "Hello" --text "Hi!"
80
+
81
+ # Pipe the plain-text body from stdin.
82
+ printf 'Hi from a pipeline' | samva email send \
83
+ --to ada@example.com --subject "Hello" --text -
84
+
85
+ # Pipe a rendered HTML body from stdin.
86
+ render-email | samva email send \
87
+ --to ada@example.com --subject "Hello" --html -
88
+
89
+ # Render a published template.
90
+ samva email send --to ada@example.com --template-slug welcome-email \
91
+ --template-data '{"name":"Ada"}'
92
+
93
+ # Wait for delivery or a terminal delivery outcome.
94
+ samva email send --to ada@example.com --subject "Hello" --text "Hi!" \
95
+ --wait --timeout 2m
96
+
97
+ # Inspect a message and its events.
98
+ samva messages get <message-id>
99
+ samva messages events <message-id> --json
100
+
101
+ # Inspect configuration and remote email state without mutating it.
102
+ samva email doctor --json
103
+ ```
104
+
105
+ ## Template projects
106
+
107
+ Scaffold a project with the Samva TSX runtime, visual editor, and pinned authoring dependencies:
108
+
109
+ ```sh
110
+ mkdir transactional-email && cd transactional-email
111
+ samva templates init
112
+ npm install
113
+ npm run samva:dev
114
+ ```
115
+
116
+ The generated project lists `@samva/markup` and `@samva/vite` as development dependencies and Vite
117
+ as the editor peer. The compiled CLI deliberately loads `@samva/vite/build` from the current
118
+ project, so preview and push use the compiler version recorded in that project's lockfile.
119
+
120
+ ```sh
121
+ samva templates push --dir emails --dry-run
122
+ samva templates push --dir emails
123
+ ```
124
+
125
+ Inline email requires `--subject` and exactly one body source: `--html` or `--text`. Pass `-` as
126
+ the value to read that body from stdin: `--text -` reads a plain-text body and `--html -` reads an
127
+ HTML body. Only one body may come from stdin, so passing both `--text -` and `--html -` is rejected.
128
+ Template sends use exactly one of `--template-id` or `--template-slug`, with optional
129
+ `--template-data`, and omit `--subject`.
130
+
131
+ `--wait` polls until the message is delivered or read, or reaches a terminal failure. It defaults
132
+ to a two-minute timeout. `--timeout` is valid only with `--wait`, and `--wait` cannot combine with
133
+ `--dry-run`, since a dry run makes no API call and has nothing to wait on. A timeout or terminal
134
+ delivery failure returns non-zero after printing the last message state.
135
+
136
+ ## Scheduling and campaigns
137
+
138
+ ```sh
139
+ samva scheduled-messages create --to ada@example.com --template-slug welcome-email \
140
+ --template-data '{"name":"Ada"}' --at 2026-08-01T09:00:00Z \
141
+ --timezone America/New_York --idempotency-key welcome-ada
142
+ samva scheduled-messages list --status pending
143
+ samva scheduled-messages get <scheduled-message-id>
144
+ samva scheduled-messages cancel <scheduled-message-id> --yes
145
+
146
+ samva campaigns create --name "August launch" --template-slug august-launch \
147
+ --include-tags newsletter
148
+ samva campaigns runs create <campaign-id> --at 2026-08-01T09:00:00Z \
149
+ --idempotency-key august-launch
150
+ samva campaigns runs recipients <campaign-id> <run-id> --status failed
151
+ ```
152
+
153
+ `--at` is an absolute ISO 8601 instant. `--timezone` is display and audit metadata for a
154
+ scheduled message. Campaign definitions freeze after their first run. Cancelling a scheduled
155
+ message or campaign run requires confirmation, and dispatch already in progress may still finish.
156
+
157
+ ## Automation contract
158
+
159
+ Use `--dry-run` on supported mutations to validate input and preview the intended request. `email
160
+ send --dry-run` does not use credentials or call the API. Other previews may read state when needed
161
+ to show the resulting change. Destructive operations prompt in a TTY; automation must use `--yes`,
162
+ or it fails without changing state. `--no-input` prevents prompts and browser launches.
163
+
164
+ ```sh
165
+ # Review a request without authentication or an API call.
166
+ samva email send --to ada@example.com --subject "Hello" --text "Hi!" --dry-run --json
167
+
168
+ # Traverse every page as one JSON record per line.
169
+ samva messages list --all --jsonl
170
+
171
+ # Suppress successful human output.
172
+ samva --quiet profile use local
173
+ ```
174
+
175
+ `--json` writes one bounded, versioned result envelope to stdout:
176
+ `{schemaVersion:1,type:"result",command,data}`. For resource lists, `--jsonl` writes one flat,
177
+ independently parseable outer result envelope per resource. Errors use the corresponding
178
+ `{schemaVersion:1,type:"error",command,reason,message,next?}` envelope on stderr and exit
179
+ non-zero. `--json`, `--jsonl`, and `--quiet` are mutually exclusive; assignment forms such as
180
+ `--json=true` are usage errors. `--quiet` suppresses successful output only. In machine modes,
181
+ stdout contains only result data; warnings and errors go to stderr.
182
+
183
+ Lists are paginated by default. Use `--page` and `--limit` for a bounded page. `--all` requires
184
+ `--jsonl`, so an automated traversal stays streamable rather than producing an unbounded JSON
185
+ document. `--all` changes traversal only: bounded and unbounded JSONL records have the same outer
186
+ envelope, with the resource itself in `data`. Empty lists emit no records.
187
+
188
+ Exit codes are stable for automation:
189
+
190
+ | Code | Meaning |
191
+ | ----: | ------------------------------------------------------------------------ |
192
+ | `0` | Success |
193
+ | `1` | API, operational, or terminal delivery failure |
194
+ | `2` | Command syntax, validation, configuration, or confirmation failure |
195
+ | `4` | Authentication or organization-context failure, incl. an expired session |
196
+ | `124` | Wait or credential timeout |
197
+ | `130` | Interrupted with `SIGINT` |
198
+ | `143` | Terminated with `SIGTERM` |
199
+
200
+ When `--json` or `--jsonl` is set, failures are emitted as JSON diagnostics on stderr, while stdout
201
+ remains a clean data stream. Lifecycle timeout, terminal delivery failure, and a later observation
202
+ failure are the intentional exception: they first preserve the last authoritative Message in a
203
+ result envelope with `partial:true` on stdout.
204
+
205
+ `samva webhooks test` is another result-bearing failure: an endpoint timeout, transport failure, or
206
+ non-2xx response preserves the complete test result on stdout, emits a typed diagnostic on stderr,
207
+ and exits `1`. Unlike lifecycle polling, that result is complete and does not set `partial:true`.
208
+
209
+ ## Help and command map
210
+
211
+ ```sh
212
+ samva --help
213
+ samva help --json
214
+ samva email send --help
215
+ ```
216
+
217
+ Released top-level commands are `login`, `logout`, `org`, `email`, `messages`, `campaigns`,
218
+ `scheduled-messages`, `templates`, `webhooks`, `profile`, and `help`. Use `samva <command> --help`
219
+ for flags and runnable examples.
220
+
221
+ Test a configured webhook against its real endpoint with an optional JSON payload. `--data` accepts
222
+ inline JSON or `@file`; omit it for Samva's default test event. `--dry-run` validates and previews
223
+ the request without credentials, an API call, or an endpoint delivery.
224
+
225
+ ```sh
226
+ samva webhooks test wep_abc123 --dry-run
227
+ samva webhooks test wep_abc123 --data '{"event":"webhook.test"}' --json
228
+ samva webhooks test wep_abc123 --data @payload.json --json
229
+ ```
230
+
231
+ `samva email doctor` reports resolved profile, target, API URL, auth source, organization access,
232
+ sending domains, senders, and domain-verification readback. It is read-only and does not inspect
233
+ receiving configuration, verify DNS, send an email, replay fixtures, or check provider readiness.
234
+ Use `samva email receiving status <domain-id>` to read a domain's receiving prerequisite status.
235
+ `samva email receiving enable <domain-id> ...` acts by default; its `--dry-run` is offline and does
236
+ not require credentials or call the API. Each check is `passed`, `failed`, or
237
+ `unavailable`. A `failed` check carries the underlying error detail; `unavailable`, such as no
238
+ sending domain configured yet, is informational. The command always prints the full report, then
239
+ exits `1` if any check failed and `0` otherwise. The `--json` result's `data` adds an aggregate
240
+ `ok` boolean, and human output marks checks with `✓`, `!`, and `✗` respectively.
241
+
242
+ A command that needs a subcommand, such as a bare `samva` or a group like `samva email`, prints its
243
+ help to stdout and exits `2`, so a script never mistakes a missing subcommand for success.
package/bin/samva ADDED
@@ -0,0 +1,3 @@
1
+ #!/bin/sh
2
+ echo "samva: native executable was not installed; reinstall @samva/cli with lifecycle scripts enabled" >&2
3
+ exit 1
package/install.cjs ADDED
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { chmodSync, copyFileSync, renameSync, rmSync } = require("node:fs");
4
+ const { dirname, join } = require("node:path");
5
+
6
+ const target = `${process.platform}-${process.arch}`;
7
+ const supported = new Set(["darwin-arm64", "darwin-x64", "linux-arm64", "linux-x64"]);
8
+
9
+ if (!supported.has(target)) {
10
+ console.error(
11
+ `samva: unsupported platform ${target}; supported platforms are ${[...supported].join(", ")}`,
12
+ );
13
+ process.exit(1);
14
+ }
15
+
16
+ const packageName = `@samva/cli-${target}`;
17
+ let manifest;
18
+ // oxlint-disable-next-line samva/no-try-catch-or-throw -- install-time CommonJS boundary must report a missing optional platform package
19
+ try {
20
+ manifest = require.resolve(`${packageName}/package.json`, { paths: [__dirname] });
21
+ } catch {
22
+ console.error(
23
+ `samva: ${packageName} is missing; reinstall @samva/cli without omitting optional dependencies`,
24
+ );
25
+ process.exit(1);
26
+ }
27
+
28
+ const source = join(dirname(manifest), "samva");
29
+ const destination = join(__dirname, "bin", "samva");
30
+ const temporary = `${destination}.installing`;
31
+
32
+ rmSync(temporary, { force: true });
33
+ copyFileSync(source, temporary);
34
+ chmodSync(temporary, 0o755);
35
+ renameSync(temporary, destination);
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@samva/cli",
3
+ "version": "0.1.0",
4
+ "description": "Samva CLI — email and platform operations from your terminal",
5
+ "keywords": [
6
+ "cli",
7
+ "cpaas",
8
+ "email",
9
+ "messaging",
10
+ "samva"
11
+ ],
12
+ "homepage": "https://samva.dev",
13
+ "bugs": {
14
+ "url": "https://github.com/AryaLabsHQ/samva/issues"
15
+ },
16
+ "license": "MIT",
17
+ "author": "Arya Labs, Inc.",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/AryaLabsHQ/samva.git",
21
+ "directory": "apps/cli"
22
+ },
23
+ "bin": {
24
+ "samva": "./bin/samva"
25
+ },
26
+ "files": [
27
+ "bin/samva",
28
+ "install.cjs",
29
+ "package.json",
30
+ "README.md",
31
+ "AGENTS.md",
32
+ "LICENSE"
33
+ ],
34
+ "type": "module",
35
+ "publishConfig": {
36
+ "access": "public"
37
+ },
38
+ "scripts": {
39
+ "samva": "bun src/bin.ts",
40
+ "build": "tsdown",
41
+ "build:release-artifacts": "bun run scripts/build-release-artifacts.ts",
42
+ "test:package": "vitest run --root ../.. --project cli apps/cli/tests/package-install.e2e.test.ts",
43
+ "test": "vitest run --root ../.. --project cli",
44
+ "typecheck": "tsgo --noEmit"
45
+ },
46
+ "dependencies": {
47
+ "@effect/platform-bun": "4.0.0-beta.102",
48
+ "@samva/contracts": "0.0.0",
49
+ "@samva/core": "0.0.0",
50
+ "@samva/markup": "0.0.0",
51
+ "@samva/vite": "0.1.0",
52
+ "effect": "4.0.0-beta.102",
53
+ "samva": "0.0.1"
54
+ },
55
+ "devDependencies": {
56
+ "@effect/vitest": "4.0.0-beta.102",
57
+ "@types/node": "^26.1.1",
58
+ "tsdown": "^0.22.13",
59
+ "typescript": "^6.0.3",
60
+ "vite": "~8.2.0",
61
+ "vitest": "^4.1.10"
62
+ },
63
+ "peerDependencies": {
64
+ "vite": "^7.0.0 || ^8.0.0"
65
+ },
66
+ "peerDependenciesMeta": {
67
+ "vite": {
68
+ "optional": true
69
+ }
70
+ }
71
+ }