@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 +14 -0
- package/LICENSE +21 -0
- package/README.md +243 -0
- package/bin/samva +3 -0
- package/install.cjs +35 -0
- package/package.json +71 -0
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
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
|
+
}
|