@ravi-hq/ravi 0.1.0 → 0.2.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.
Files changed (63) hide show
  1. package/README.md +56 -6
  2. package/dist/auth.d.ts +39 -0
  3. package/dist/auth.d.ts.map +1 -0
  4. package/dist/auth.js +97 -0
  5. package/dist/auth.js.map +1 -0
  6. package/dist/bin/ravi-secrets.d.ts +23 -0
  7. package/dist/bin/ravi-secrets.d.ts.map +1 -0
  8. package/dist/bin/ravi-secrets.js +113 -0
  9. package/dist/bin/ravi-secrets.js.map +1 -0
  10. package/dist/cli.d.ts.map +1 -1
  11. package/dist/cli.js +142 -188
  12. package/dist/cli.js.map +1 -1
  13. package/dist/client.d.ts +4 -1
  14. package/dist/client.d.ts.map +1 -1
  15. package/dist/client.js +26 -17
  16. package/dist/client.js.map +1 -1
  17. package/dist/crypto.d.ts +13 -0
  18. package/dist/crypto.d.ts.map +1 -1
  19. package/dist/crypto.js +45 -5
  20. package/dist/crypto.js.map +1 -1
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +68 -46
  23. package/dist/index.js.map +1 -1
  24. package/dist/service.d.ts +7 -0
  25. package/dist/service.d.ts.map +1 -1
  26. package/dist/service.js +11 -0
  27. package/dist/service.js.map +1 -1
  28. package/dist/sse.d.ts +9 -0
  29. package/dist/sse.d.ts.map +1 -1
  30. package/dist/sse.js +20 -2
  31. package/dist/sse.js.map +1 -1
  32. package/dist/tools/email-send.js +1 -1
  33. package/dist/tools/email-send.js.map +1 -1
  34. package/dist/tools/feedback.d.ts +2 -3
  35. package/dist/tools/feedback.d.ts.map +1 -1
  36. package/dist/tools/feedback.js +26 -18
  37. package/dist/tools/feedback.js.map +1 -1
  38. package/dist/tools/inbox.d.ts.map +1 -1
  39. package/dist/tools/inbox.js +15 -56
  40. package/dist/tools/inbox.js.map +1 -1
  41. package/dist/tools/passwords.d.ts.map +1 -1
  42. package/dist/tools/passwords.js +21 -51
  43. package/dist/tools/passwords.js.map +1 -1
  44. package/dist/tools/vault.d.ts.map +1 -1
  45. package/dist/tools/vault.js +4 -8
  46. package/dist/tools/vault.js.map +1 -1
  47. package/dist/types.d.ts +10 -9
  48. package/dist/types.d.ts.map +1 -1
  49. package/dist/utils.d.ts +6 -0
  50. package/dist/utils.d.ts.map +1 -1
  51. package/dist/utils.js +18 -0
  52. package/dist/utils.js.map +1 -1
  53. package/openclaw.plugin.json +3 -23
  54. package/package.json +5 -3
  55. package/skills/CLAUDE.md +0 -36
  56. package/skills/ravi/SKILL.md +0 -46
  57. package/skills/ravi-email-send/SKILL.md +0 -44
  58. package/skills/ravi-feedback/SKILL.md +0 -37
  59. package/skills/ravi-identity/SKILL.md +0 -50
  60. package/skills/ravi-inbox/SKILL.md +0 -58
  61. package/skills/ravi-login/SKILL.md +0 -42
  62. package/skills/ravi-passwords/SKILL.md +0 -48
  63. package/skills/ravi-vault/SKILL.md +0 -54
package/README.md CHANGED
@@ -10,7 +10,7 @@ encrypted vault through a single plugin.
10
10
  ## Features
11
11
 
12
12
  - **2 messaging channels** -- real-time email and SMS via Server-Sent Events
13
- - **17 agent tools** -- manage identities, inboxes, passwords, vault secrets, and more
13
+ - **19 agent tools** -- manage identities, inboxes, passwords, vault secrets, and more
14
14
  - **E2E encryption** -- PIN-based Argon2id + NaCl SealedBox, compatible with Ravi CLI
15
15
  - **DM policy controls** -- allowlist or open policy per channel account
16
16
  - **Lazy crypto** -- encryption keys derived on first use, not at startup
@@ -106,7 +106,9 @@ Real-time email channel powered by SSE events from the Ravi backend.
106
106
 
107
107
  ### Ravi SMS
108
108
 
109
- Real-time SMS channel powered by the same SSE stream.
109
+ Real-time SMS channel powered by the same SSE stream. **Only active when the
110
+ identity has a provisioned phone number** -- identities without a phone skip SMS
111
+ registration silently.
110
112
 
111
113
  - **Threading model:** All messages from one phone number form a single session.
112
114
  A new `from_number` creates a new session; subsequent messages from that number
@@ -118,7 +120,7 @@ Real-time SMS channel powered by the same SSE stream.
118
120
 
119
121
  ## Agent Tools
120
122
 
121
- The plugin registers 17 tools that agents can invoke.
123
+ The plugin registers 19 tools that agents can invoke.
122
124
 
123
125
  ### Identity
124
126
 
@@ -137,12 +139,13 @@ The plugin registers 17 tools that agents can invoke.
137
139
  | `ravi_email_compose` | Compose and send a new email | `to`, `subject`, `body` (all required) |
138
140
  | `ravi_email_reply` | Reply to an existing email | `message_id` (number, required), `body` (required), `reply_all` |
139
141
 
140
- ### SMS Inbox
142
+ ### SMS
141
143
 
142
144
  | Tool | Description | Parameters |
143
145
  |------|-------------|------------|
144
146
  | `ravi_inbox_sms` | List SMS conversations, optionally unread only | `unread` (boolean) |
145
147
  | `ravi_read_sms` | Read all messages in an SMS conversation | `conversation_id` (string, required) |
148
+ | `ravi_sms_send` | Send an SMS from the active identity's phone | `to_number` (E.164, required), `body` (required) |
146
149
 
147
150
  ### Passwords
148
151
 
@@ -160,6 +163,7 @@ The plugin registers 17 tools that agents can invoke.
160
163
  | `ravi_vault_list` | List all secret keys in the vault | -- |
161
164
  | `ravi_vault_get` | Get a secret by key (auto-decrypted) | `key` (string, required) |
162
165
  | `ravi_vault_set` | Store a secret (auto-encrypted) | `key` (string, required), `value` (string, required) |
166
+ | `ravi_vault_delete` | Delete a secret by UUID | `uuid` (string, required) |
163
167
 
164
168
  ### Feedback
165
169
 
@@ -191,6 +195,37 @@ end-to-end using a 6-digit PIN.
191
195
  The crypto layer is lazy-initialized: keys are only derived when a tool actually
192
196
  needs encryption or decryption.
193
197
 
198
+ ## Secrets Provider
199
+
200
+ The plugin ships a `ravi-secrets` binary that implements the OpenClaw exec
201
+ secrets protocol, letting you use the Ravi vault as a secrets provider. The
202
+ binary is installed automatically with the package.
203
+
204
+ ### Configuration
205
+
206
+ Add the provider to your OpenClaw config:
207
+
208
+ ```yaml
209
+ secrets:
210
+ providers:
211
+ ravi:
212
+ source: exec
213
+ command: ravi-secrets
214
+ ```
215
+
216
+ Then reference vault secrets anywhere a secret is accepted:
217
+
218
+ ```yaml
219
+ { source: "exec", provider: "ravi", id: "my-api-key" }
220
+ ```
221
+
222
+ ### Requirements
223
+
224
+ - You must run `openclaw ravi login` first -- the binary reads credentials
225
+ from `~/.ravi/auth.json`.
226
+ - Vault secrets are decrypted automatically using the E2E keypair stored
227
+ during login. If no keypair is found, raw (encrypted) values are returned.
228
+
194
229
  ## Architecture
195
230
 
196
231
  ```text
@@ -200,7 +235,7 @@ Agent (OpenClaw runtime)
200
235
  | '-- SSE stream --> GET /api/events/stream/
201
236
  | Events arrive in plaintext (server decrypts before dispatch)
202
237
  |
203
- +-- Tools (17 agent tools)
238
+ +-- Tools (19 agent tools)
204
239
  | '-- REST calls --> GET/POST/DELETE /api/...
205
240
  | Identity-scoped via X-Ravi-Identity header
206
241
  |
@@ -233,7 +268,19 @@ Key points:
233
268
  npm install
234
269
  ```
235
270
 
236
- ### Scripts
271
+ ### Build Targets
272
+
273
+ ```bash
274
+ make build # Local dev build (reads .env.local for API URL)
275
+ make build-prod # Production build (always uses https://ravi.app)
276
+ make test # Run all tests
277
+ make lint # Type-check without emitting (tsc --noEmit)
278
+ ```
279
+
280
+ Publishing to npm happens only via GitHub Actions -- there is no local
281
+ publish target.
282
+
283
+ ### npm Scripts
237
284
 
238
285
  ```bash
239
286
  npm run build # Compile TypeScript to dist/
@@ -253,6 +300,8 @@ src/
253
300
  crypto.ts # E2E encryption (Argon2id + NaCl SealedBox)
254
301
  service.ts # Background listener service (manages SSE connections)
255
302
  cli.ts # CLI commands (login, status, setup)
303
+ bin/
304
+ ravi-secrets.ts # OpenClaw exec secrets provider binary
256
305
  channels/
257
306
  email.ts # ravi-email channel definition
258
307
  sms.ts # ravi-sms channel definition
@@ -260,6 +309,7 @@ src/
260
309
  identity.ts # Identity management tools
261
310
  inbox.ts # Email and SMS inbox tools
262
311
  email-send.ts # Email compose and reply tools
312
+ sms-send.ts # SMS send tool
263
313
  passwords.ts # Password manager tools
264
314
  vault.ts # Vault secret tools
265
315
  feedback.ts # Feedback tool
package/dist/auth.d.ts ADDED
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Auth and config persistence for the Ravi plugin.
3
+ *
4
+ * Mirrors the Go CLI's config package — reads/writes ~/.ravi/auth.json
5
+ * and ~/.ravi/config.json with the same format and permissions.
6
+ *
7
+ * @module auth
8
+ */
9
+ /** Auth config matching the Go CLI's AuthConfig struct. */
10
+ export interface AuthConfig {
11
+ access_token: string;
12
+ refresh_token: string;
13
+ expires_at?: string;
14
+ user_email?: string;
15
+ pin_salt?: string;
16
+ public_key?: string;
17
+ private_key?: string;
18
+ }
19
+ /** Identity config matching the Go CLI's Config struct. */
20
+ export interface IdentityConfig {
21
+ identity_uuid?: string;
22
+ identity_name?: string;
23
+ }
24
+ /** Returns the global config directory (~/.ravi/). */
25
+ export declare function configDir(): string;
26
+ /** Load auth config from ~/.ravi/auth.json. Returns null if file doesn't exist. */
27
+ export declare function loadAuth(): AuthConfig | null;
28
+ /** Save auth config to ~/.ravi/auth.json with 0600 permissions. */
29
+ export declare function saveAuth(cfg: AuthConfig): void;
30
+ /** Update specific fields in auth.json without overwriting the rest.
31
+ * Not safe for concurrent callers — serialize externally (e.g. via RaviClient's refreshPromise). */
32
+ export declare function updateAuth(updates: Partial<AuthConfig>): void;
33
+ /** Load identity config from ~/.ravi/config.json. Returns null if file doesn't exist. */
34
+ export declare function loadConfig(): IdentityConfig | null;
35
+ /** Save identity config to ~/.ravi/config.json with 0600 permissions. */
36
+ export declare function saveConfig(cfg: IdentityConfig): void;
37
+ /** Save recovery key to ~/.ravi/recovery-key.txt with 0600 permissions. */
38
+ export declare function saveRecoveryKey(key: string): string;
39
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAaH,2DAA2D;AAC3D,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,2DAA2D;AAC3D,MAAM,WAAW,cAAc;IAC7B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,sDAAsD;AACtD,wBAAgB,SAAS,IAAI,MAAM,CAElC;AASD,mFAAmF;AACnF,wBAAgB,QAAQ,IAAI,UAAU,GAAG,IAAI,CAiB5C;AAED,mEAAmE;AACnE,wBAAgB,QAAQ,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CAI9C;AAED;qGACqG;AACrG,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI,CAQ7D;AAID,yFAAyF;AACzF,wBAAgB,UAAU,IAAI,cAAc,GAAG,IAAI,CAiBlD;AAED,yEAAyE;AACzE,wBAAgB,UAAU,CAAC,GAAG,EAAE,cAAc,GAAG,IAAI,CAIpD;AAID,2EAA2E;AAC3E,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKnD"}
package/dist/auth.js ADDED
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Auth and config persistence for the Ravi plugin.
3
+ *
4
+ * Mirrors the Go CLI's config package — reads/writes ~/.ravi/auth.json
5
+ * and ~/.ravi/config.json with the same format and permissions.
6
+ *
7
+ * @module auth
8
+ */
9
+ import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
10
+ import { join } from "node:path";
11
+ import { homedir } from "node:os";
12
+ const CONFIG_DIR_NAME = ".ravi";
13
+ const AUTH_FILE_NAME = "auth.json";
14
+ const CONFIG_FILE_NAME = "config.json";
15
+ const RECOVERY_KEY_FILE_NAME = "recovery-key.txt";
16
+ const DIR_PERM = 0o700;
17
+ const FILE_PERM = 0o600;
18
+ /** Returns the global config directory (~/.ravi/). */
19
+ export function configDir() {
20
+ return join(homedir(), CONFIG_DIR_NAME);
21
+ }
22
+ /** Ensure ~/.ravi/ exists with 0700 permissions. */
23
+ function ensureDir() {
24
+ mkdirSync(configDir(), { recursive: true, mode: DIR_PERM });
25
+ }
26
+ // ─── Auth ─────────────────────────────────────────────────────────────────────
27
+ /** Load auth config from ~/.ravi/auth.json. Returns null if file doesn't exist. */
28
+ export function loadAuth() {
29
+ const filePath = join(configDir(), AUTH_FILE_NAME);
30
+ let data;
31
+ try {
32
+ data = readFileSync(filePath, "utf-8");
33
+ }
34
+ catch (err) {
35
+ if (err.code === "ENOENT")
36
+ return null;
37
+ throw err;
38
+ }
39
+ try {
40
+ return JSON.parse(data);
41
+ }
42
+ catch {
43
+ throw new Error(`Failed to parse ${filePath}: file may be corrupted. ` +
44
+ `Delete it and run 'openclaw ravi login' to re-authenticate.`);
45
+ }
46
+ }
47
+ /** Save auth config to ~/.ravi/auth.json with 0600 permissions. */
48
+ export function saveAuth(cfg) {
49
+ ensureDir();
50
+ const data = JSON.stringify(cfg, null, 2) + "\n";
51
+ writeFileSync(join(configDir(), AUTH_FILE_NAME), data, { mode: FILE_PERM });
52
+ }
53
+ /** Update specific fields in auth.json without overwriting the rest.
54
+ * Not safe for concurrent callers — serialize externally (e.g. via RaviClient's refreshPromise). */
55
+ export function updateAuth(updates) {
56
+ const existing = loadAuth();
57
+ if (!existing) {
58
+ throw new Error("Cannot update auth: ~/.ravi/auth.json not found. Run 'openclaw ravi login' first.");
59
+ }
60
+ saveAuth({ ...existing, ...updates });
61
+ }
62
+ // ─── Config (identity selector) ───────────────────────────────────────────────
63
+ /** Load identity config from ~/.ravi/config.json. Returns null if file doesn't exist. */
64
+ export function loadConfig() {
65
+ const filePath = join(configDir(), CONFIG_FILE_NAME);
66
+ let data;
67
+ try {
68
+ data = readFileSync(filePath, "utf-8");
69
+ }
70
+ catch (err) {
71
+ if (err.code === "ENOENT")
72
+ return null;
73
+ throw err;
74
+ }
75
+ try {
76
+ return JSON.parse(data);
77
+ }
78
+ catch {
79
+ throw new Error(`Failed to parse ${filePath}: file may be corrupted. ` +
80
+ `Delete it and run 'openclaw ravi login' to reconfigure.`);
81
+ }
82
+ }
83
+ /** Save identity config to ~/.ravi/config.json with 0600 permissions. */
84
+ export function saveConfig(cfg) {
85
+ ensureDir();
86
+ const data = JSON.stringify(cfg, null, 2) + "\n";
87
+ writeFileSync(join(configDir(), CONFIG_FILE_NAME), data, { mode: FILE_PERM });
88
+ }
89
+ // ─── Recovery Key ─────────────────────────────────────────────────────────────
90
+ /** Save recovery key to ~/.ravi/recovery-key.txt with 0600 permissions. */
91
+ export function saveRecoveryKey(key) {
92
+ ensureDir();
93
+ const filePath = join(configDir(), RECOVERY_KEY_FILE_NAME);
94
+ writeFileSync(filePath, key + "\n", { mode: FILE_PERM });
95
+ return filePath;
96
+ }
97
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * OpenClaw exec secrets provider for Ravi vault.
4
+ *
5
+ * Implements the OpenClaw exec secrets protocol:
6
+ * stdin: { "protocolVersion": 1, "provider": "ravi", "ids": ["key1", "key2"] }
7
+ * stdout: { "protocolVersion": 1, "values": { "key1": "val1", "key2": "val2" } }
8
+ *
9
+ * Reads auth credentials from ~/.ravi/auth.json (written by `openclaw ravi login`).
10
+ * Decrypts vault secrets using the stored E2E keypair.
11
+ *
12
+ * Usage in OpenClaw config:
13
+ * secrets:
14
+ * providers:
15
+ * ravi:
16
+ * source: exec
17
+ * command: ravi-secrets
18
+ *
19
+ * Then reference secrets:
20
+ * { source: "exec", provider: "ravi", id: "my-api-key" }
21
+ */
22
+ export {};
23
+ //# sourceMappingURL=ravi-secrets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ravi-secrets.d.ts","sourceRoot":"","sources":["../../src/bin/ravi-secrets.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;GAmBG"}
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * OpenClaw exec secrets provider for Ravi vault.
4
+ *
5
+ * Implements the OpenClaw exec secrets protocol:
6
+ * stdin: { "protocolVersion": 1, "provider": "ravi", "ids": ["key1", "key2"] }
7
+ * stdout: { "protocolVersion": 1, "values": { "key1": "val1", "key2": "val2" } }
8
+ *
9
+ * Reads auth credentials from ~/.ravi/auth.json (written by `openclaw ravi login`).
10
+ * Decrypts vault secrets using the stored E2E keypair.
11
+ *
12
+ * Usage in OpenClaw config:
13
+ * secrets:
14
+ * providers:
15
+ * ravi:
16
+ * source: exec
17
+ * command: ravi-secrets
18
+ *
19
+ * Then reference secrets:
20
+ * { source: "exec", provider: "ravi", id: "my-api-key" }
21
+ */
22
+ import { RAVI_API_URL } from "../config.js";
23
+ import { RaviClient } from "../client.js";
24
+ import { createCryptoManagerFromKeyPair } from "../crypto.js";
25
+ import { loadAuth } from "../auth.js";
26
+ async function main() {
27
+ // Read JSON request from stdin
28
+ const chunks = [];
29
+ for await (const chunk of process.stdin) {
30
+ chunks.push(chunk);
31
+ }
32
+ const input = Buffer.concat(chunks).toString("utf-8").trim();
33
+ if (!input) {
34
+ writeError("No input received on stdin");
35
+ return;
36
+ }
37
+ let request;
38
+ try {
39
+ request = JSON.parse(input);
40
+ }
41
+ catch {
42
+ writeError("Invalid JSON on stdin");
43
+ return;
44
+ }
45
+ if (request.protocolVersion !== 1) {
46
+ writeError(`Unsupported protocol version: ${request.protocolVersion}`);
47
+ return;
48
+ }
49
+ if (!Array.isArray(request.ids) || request.ids.length === 0) {
50
+ writeResponse({ protocolVersion: 1, values: {} });
51
+ return;
52
+ }
53
+ // Load auth
54
+ const auth = loadAuth();
55
+ if (!auth?.access_token) {
56
+ writeError("Not authenticated. Run 'openclaw ravi login' first.");
57
+ return;
58
+ }
59
+ // Create client
60
+ const client = new RaviClient({
61
+ apiUrl: RAVI_API_URL,
62
+ token: auth.access_token,
63
+ refreshToken: auth.refresh_token,
64
+ });
65
+ // Create crypto manager for decryption
66
+ let decrypt;
67
+ if (auth.public_key && auth.private_key) {
68
+ try {
69
+ const crypto = createCryptoManagerFromKeyPair(auth.public_key, auth.private_key);
70
+ decrypt = (value) => crypto.decrypt(value);
71
+ }
72
+ catch {
73
+ // Continue without decryption — return raw (encrypted) values
74
+ }
75
+ }
76
+ // Fetch each requested secret
77
+ const values = {};
78
+ const errors = {};
79
+ await Promise.all(request.ids.map(async (key) => {
80
+ try {
81
+ const secret = await client.getSecret(key);
82
+ let value = secret.value;
83
+ if (decrypt && value) {
84
+ try {
85
+ value = await decrypt(value);
86
+ }
87
+ catch {
88
+ // Return raw value if decryption fails
89
+ }
90
+ }
91
+ values[key] = value;
92
+ }
93
+ catch (err) {
94
+ errors[key] = err instanceof Error ? err.message : String(err);
95
+ }
96
+ }));
97
+ const response = { protocolVersion: 1, values };
98
+ if (Object.keys(errors).length > 0) {
99
+ response.errors = errors;
100
+ }
101
+ writeResponse(response);
102
+ }
103
+ function writeResponse(response) {
104
+ process.stdout.write(JSON.stringify(response) + "\n");
105
+ }
106
+ function writeError(message) {
107
+ writeResponse({ protocolVersion: 1, values: {}, errors: { _: message } });
108
+ }
109
+ main().catch((err) => {
110
+ writeError(err instanceof Error ? err.message : String(err));
111
+ process.exit(1);
112
+ });
113
+ //# sourceMappingURL=ravi-secrets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ravi-secrets.js","sourceRoot":"","sources":["../../src/bin/ravi-secrets.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA8FnD,+EAA+E;AAC/E,MAAM,WAAW,UAAU;IACzB,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;OAMG;IACH,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,gBAAgB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACxE;AAID;;;;;GAKG;AACH,eAAO,MAAM,WAAW,EAAE,UAAU,EA8UnC,CAAC"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA2GnD,+EAA+E;AAC/E,MAAM,WAAW,UAAU;IACzB,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;OAMG;IACH,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,gBAAgB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACxE;AAID;;;;;GAKG;AACH,eAAO,MAAM,WAAW,EAAE,UAAU,EA8QnC,CAAC"}