@moda-ai/cli 1.13.0 → 1.13.2
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/dist/auth-storage.d.ts +35 -0
- package/dist/auth-storage.js +159 -0
- package/dist/auth.d.ts +17 -13
- package/dist/auth.js +350 -173
- package/dist/cli-session.d.ts +26 -0
- package/dist/cli-session.js +169 -0
- package/dist/cli.d.ts +10 -0
- package/dist/cli.js +52 -0
- package/dist/command-context.d.ts +7 -0
- package/dist/command-context.js +12 -0
- package/dist/init/index.js +8 -3
- package/dist/init/tenant.d.ts +34 -2
- package/dist/init/tenant.js +218 -26
- package/dist/profile-commands.js +10 -1
- package/dist/provision.d.ts +28 -0
- package/dist/provision.js +104 -0
- package/package.json +1 -1
- package/skills/integration/index.json +2 -2
- package/skills/moda-cli/SKILL.md +171 -4
package/skills/moda-cli/SKILL.md
CHANGED
|
@@ -44,10 +44,12 @@ the user specifically asked for `moda prompts sync` or `moda prompts promote`.
|
|
|
44
44
|
|
|
45
45
|
## Required inputs
|
|
46
46
|
|
|
47
|
-
Before running any command except `moda init
|
|
47
|
+
Before running any command except `moda init`, `moda provision`, and the
|
|
48
|
+
`moda auth ...` session commands (which use the browser/CLI session instead):
|
|
48
49
|
|
|
49
50
|
- `MODA_API_KEY` env var must be set (`moda_sk_...`). If missing, run
|
|
50
|
-
`moda init`
|
|
51
|
+
`moda init` (interactive) or `moda provision` (headless, needs an existing
|
|
52
|
+
session) to provision one, or have the user export it.
|
|
51
53
|
|
|
52
54
|
Optional:
|
|
53
55
|
|
|
@@ -78,6 +80,103 @@ npx -p @moda-ai/cli moda <command>
|
|
|
78
80
|
export MODA_API_KEY="moda_sk_..." # from moda.dev/settings
|
|
79
81
|
```
|
|
80
82
|
|
|
83
|
+
### Headless provisioning (CI / agents): `moda provision`
|
|
84
|
+
|
|
85
|
+
`moda provision` mints (or reuses) a tenant API key with zero prompts and
|
|
86
|
+
prints a single JSON credentials document to stdout — in every output mode,
|
|
87
|
+
even on an interactive terminal, so it composes directly:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
KEY=$(moda provision --tenant-id t1 | jq -r .apiKey)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Output shape:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"apiKey": "moda_sk_...",
|
|
98
|
+
"tenantId": "t1",
|
|
99
|
+
"tenantName": "Acme",
|
|
100
|
+
"tenantSlug": "acme",
|
|
101
|
+
"ingestUrl": "https://moda-ingest.modas.workers.dev",
|
|
102
|
+
"baseUrl": "https://moda.dev",
|
|
103
|
+
"reused": false
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Rules and limitations:
|
|
108
|
+
|
|
109
|
+
- **Requires an existing CLI session.** There is no browserless signup or
|
|
110
|
+
login: with no stored session it exits `4` (`auth_required`) telling you to
|
|
111
|
+
run `moda auth login` on a machine with a browser first, or to skip
|
|
112
|
+
provisioning and export `MODA_API_KEY` directly.
|
|
113
|
+
- **Never prompts, even on a TTY.** A single-tenant account auto-selects;
|
|
114
|
+
with multiple tenants you must pass `--tenant-id=<id>` (or set
|
|
115
|
+
`MODA_TENANT_ID`), otherwise it exits `5` (`needs_input`) with per-tenant
|
|
116
|
+
`resume_flags`.
|
|
117
|
+
- `reused: true` means a previously stored key for that tenant passed a
|
|
118
|
+
liveness probe and was reused instead of minting a new one (same dedup +
|
|
119
|
+
idempotent bootstrap machinery as `moda init`).
|
|
120
|
+
- **Does not write `~/.moda/config.json` by default** — headless callers own
|
|
121
|
+
their credential storage. Pass `--save` to opt into the init-style
|
|
122
|
+
persistence.
|
|
123
|
+
- `--label=<text>` names the created key (default: machine hostname);
|
|
124
|
+
`--profile=NAME` scopes the session lookup.
|
|
125
|
+
- stdout carries a live credential — a warning is printed to stderr; never
|
|
126
|
+
pipe provision stdout into logs.
|
|
127
|
+
|
|
128
|
+
**When to use which:** `moda init` is the interactive first-time onboarding
|
|
129
|
+
wizard for a repo (harness discovery, skills, prompts, validation);
|
|
130
|
+
`moda provision` is for CI jobs and agents that already have a session and
|
|
131
|
+
just need credentials.
|
|
132
|
+
|
|
133
|
+
### Auth session inspection and token composition
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
moda auth login # browser PKCE sign-in; stores a moda_ct_ session token
|
|
137
|
+
moda auth logout # revoke the session server-side, then delete it locally
|
|
138
|
+
moda auth status # local session state; exit 0 logged in, exit 4 logged out
|
|
139
|
+
moda auth status --online # additionally probe GET /api/cli/context
|
|
140
|
+
moda auth token # print the raw bearer token + newline, nothing else
|
|
141
|
+
curl -H "Authorization: Bearer $(moda auth token)" https://moda.dev/api/cli/context
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
- `moda auth login` opens the browser consent flow at `{MODA_BASE_URL}/auth/cli`
|
|
145
|
+
with a localhost callback (ports 8432-8435, first free). Approving in the
|
|
146
|
+
browser hands the CLI a one-time code that it exchanges for a `moda_ct_...`
|
|
147
|
+
session token (sliding 30-day expiry, renewed automatically in the
|
|
148
|
+
background while you keep using the CLI). If the browser cannot reach the
|
|
149
|
+
machine, paste the callback URL or the code shown on the consent page into
|
|
150
|
+
the terminal.
|
|
151
|
+
- `moda auth logout` revokes the stored `moda_ct_` session server-side
|
|
152
|
+
(best-effort) and deletes the local credential; legacy sessions are just
|
|
153
|
+
deleted locally.
|
|
154
|
+
- `moda auth status` reports
|
|
155
|
+
`{ "loggedIn": <bool>, "profile": <string|null>, "expiresAt": <ISO|null> }`
|
|
156
|
+
plus `"user": { "email": <string> }` when the stored session carries an
|
|
157
|
+
email (PKCE `moda_ct_` sessions do; legacy sessions omit it), and exits `4`
|
|
158
|
+
when logged out. That exit is an **expected state signal, not
|
|
159
|
+
an error**: the payload is clean data (no error block, no stderr noise), and
|
|
160
|
+
no browser is ever opened. With `--online` the payload adds
|
|
161
|
+
`{ "online": { "reachable": <bool>, "ok": <bool>, "tenantCount": <n> } }`:
|
|
162
|
+
`reachable: true` means any HTTP response arrived (even a 401/500), `ok`
|
|
163
|
+
reflects HTTP success, and `tenantCount` is present only when the response
|
|
164
|
+
was ok and carried a tenants array. A network failure or probe timeout
|
|
165
|
+
(5 s) yields `reachable: false`; the exit code always follows local session
|
|
166
|
+
validity only, never the probe.
|
|
167
|
+
- `moda auth token` writes exactly the bare token plus a trailing newline to
|
|
168
|
+
stdout in **every** output mode — including piped/json/agent, because
|
|
169
|
+
command substitution is a pipe — so `$(moda auth token)` composes safely
|
|
170
|
+
with no envelope to strip. When logged out it prints a stderr message and
|
|
171
|
+
exits `4`; with an explicit `--json` flag it instead prints
|
|
172
|
+
`{"error":"not_authenticated"}` to stdout (still exit `4`).
|
|
173
|
+
- `moda auth token` prints whichever credential kind is stored. Newer logins
|
|
174
|
+
store a `moda_ct_...` CLI session token, which authenticates **`/api/cli/*`
|
|
175
|
+
endpoints only** — it is not accepted by the Data API (`/api/v1/data/*`
|
|
176
|
+
wants a `moda_sk_...` API key) or other dashboard endpoints. Legacy
|
|
177
|
+
sessions print the Auth0 bearer token as before.
|
|
178
|
+
- Both respect `--profile=NAME` and `MODA_PROFILE`.
|
|
179
|
+
|
|
81
180
|
## Agent protocol
|
|
82
181
|
|
|
83
182
|
Run `moda manifest --json` first when integrating with the CLI. It returns the
|
|
@@ -117,10 +216,73 @@ Branch on the exit code; it is stable and cheaper than parsing the payload:
|
|
|
117
216
|
| `0` | ok — answer is grounded in Moda Cloud intelligence | Trust it. |
|
|
118
217
|
| `1` | error — bad input, API/network failure, or unexpected failure | Read `errors[]`; retry only when the code is retryable. |
|
|
119
218
|
| `3` | degraded — Moda Cloud was unavailable; answer synthesized from local Data API evidence | Answer is present but lower-trust; verify before acting. |
|
|
120
|
-
| `4` | auth required | Run `
|
|
121
|
-
| `5` | input required | Pick a choice
|
|
219
|
+
| `4` | auth required — credentials are missing or expired | Run the `login_command` from the `auth` payload (`moda auth login`), then re-run `resume_command`. |
|
|
220
|
+
| `5` | input required — a choice is needed that the non-interactive run could not answer | Pick a choice from the `input_request` payload and re-invoke the same command with that choice's `resume_flags` appended. |
|
|
122
221
|
| `130` | cancelled | Treat as interrupted or closed pipe; do not retry blindly. |
|
|
123
222
|
|
|
223
|
+
Exit codes `4` and `5` are recoverable-by-caller failures: the envelope's
|
|
224
|
+
`errors[]` entry carries the exact commands/flags to recover with, as argv
|
|
225
|
+
arrays (execute element-wise; join with spaces only for display).
|
|
226
|
+
|
|
227
|
+
#### `auth_required` payload (exit `4`)
|
|
228
|
+
|
|
229
|
+
The envelope's `errors[]` entry carries the recovery data on its `auth` field
|
|
230
|
+
(in `--agent --stream` mode the same error arrives as an NDJSON event with
|
|
231
|
+
`"event": "auth_required"`):
|
|
232
|
+
|
|
233
|
+
```json
|
|
234
|
+
{
|
|
235
|
+
"code": "auth_required",
|
|
236
|
+
"message": "Browser authentication is required before non-interactive init can continue.",
|
|
237
|
+
"suggested_commands": ["moda auth login", "moda init --yes"],
|
|
238
|
+
"blocking": true,
|
|
239
|
+
"auth": {
|
|
240
|
+
"reason": "no_stored_credentials",
|
|
241
|
+
"login_command": ["moda", "auth", "login"],
|
|
242
|
+
"resume_command": ["moda", "init", "--yes"]
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
`reason` is one of:
|
|
248
|
+
|
|
249
|
+
- `no_stored_credentials` — no session stored. Run `login_command`, then
|
|
250
|
+
`resume_command` (when present).
|
|
251
|
+
- `token_expired` — the stored session expired. Run `login_command`, then
|
|
252
|
+
`resume_command`.
|
|
253
|
+
- `token_revoked` — the stored `moda_ct_` CLI session token was revoked
|
|
254
|
+
server-side (e.g. from the dashboard). Run `login_command`, then
|
|
255
|
+
`resume_command`.
|
|
256
|
+
- `renew_failed` — the API rejected an **unexpired** `moda_ct_` token but the
|
|
257
|
+
renewal check could not reach the server, so this is likely transient:
|
|
258
|
+
**retry the command; do not re-login.**
|
|
259
|
+
|
|
260
|
+
#### `needs_input` payload (exit `5`)
|
|
261
|
+
|
|
262
|
+
The envelope's `errors[]` entry carries the recovery data on its
|
|
263
|
+
`input_request` field (in `--agent --stream` mode the event type is
|
|
264
|
+
`"needs_input"`):
|
|
265
|
+
|
|
266
|
+
```json
|
|
267
|
+
{
|
|
268
|
+
"code": "needs_input",
|
|
269
|
+
"message": "An organization must be selected to continue.",
|
|
270
|
+
"blocking": true,
|
|
271
|
+
"input_request": {
|
|
272
|
+
"id": "init_tenant_selection",
|
|
273
|
+
"question": "Select organization",
|
|
274
|
+
"kind": "select",
|
|
275
|
+
"choices": [
|
|
276
|
+
{ "value": "tnt_a", "label": "Acme (owner)", "resume_flags": ["--tenant-id", "tnt_a"] },
|
|
277
|
+
{ "value": "tnt_b", "label": "Beta (viewer)", "resume_flags": ["--tenant-id", "tnt_b"] }
|
|
278
|
+
]
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Re-invoke the original command with the chosen `resume_flags` appended (here:
|
|
284
|
+
`moda init --tenant-id tnt_a`).
|
|
285
|
+
|
|
124
286
|
### The `moda.agent.v1` envelope
|
|
125
287
|
|
|
126
288
|
Fields an agent should read:
|
|
@@ -584,6 +746,11 @@ npx: `npx -p @moda-ai/cli moda <command>`.
|
|
|
584
746
|
| Command | Purpose |
|
|
585
747
|
|---|---|
|
|
586
748
|
| `moda init` | Browser auth + provision API key + install agent rules |
|
|
749
|
+
| `moda provision` | Headless tenant + API key provisioning; single JSON credentials doc on stdout (exit `4` without a session, `5` when `--tenant-id` is needed) |
|
|
750
|
+
| `moda auth login` | Browser PKCE sign-in; stores a revocable `moda_ct_` session token |
|
|
751
|
+
| `moda auth logout` | Revoke the CLI session server-side, then delete it locally |
|
|
752
|
+
| `moda auth status` | Local auth session state (exit `4` = logged out — expected, not an error) |
|
|
753
|
+
| `moda auth token` | Print the raw bearer token for `$(moda auth token)` composition |
|
|
587
754
|
| `moda search "<query>"` | **Message-grain semantic/keyword/hybrid search (incl. tool calls); primary content-discovery path** |
|
|
588
755
|
| `moda overview` | Dashboard KPIs, top clusters, recent activity |
|
|
589
756
|
| `moda ask "<question>"` | Natural-language production/harness answer with evidence (exit `3` = degraded local fallback) |
|