datavessel-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/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2026 datavessel
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,155 @@
1
+ # datavessel-cli
2
+
3
+ Command-line interface for [datavessel](https://datavessel.io) — run 100+
4
+ read/write analytics and commerce tools (GA4, Search Console, Google/Meta Ads,
5
+ Shopify, WooCommerce, Shopware, …) from your terminal.
6
+
7
+ **The CLI's commands and help are generated from the live backend tool
8
+ catalog.** It fetches `/v1/tools/schemas` and turns each tool's JSON Schema into
9
+ flags, help text, and validation — so when a tool is added or changed on the
10
+ backend, the CLI picks it up automatically with no release. This mirrors how the
11
+ [datavessel MCP server](https://github.com/djr4/datavessel-mcp-public) already
12
+ syncs its tools.
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ npm install -g datavessel-cli
18
+ ```
19
+
20
+ This puts two commands on your PATH — `datavessel` and the short alias `dv`.
21
+ Requires Node.js ≥ 20.11.
22
+
23
+ The CLI defaults to the hosted backend (`https://api.datavessel.io`) and web app
24
+ (`https://app.datavessel.io`); both are configurable (see
25
+ [Configuration](#configuration)) if you run datavessel elsewhere.
26
+
27
+ <details>
28
+ <summary>From source (development)</summary>
29
+
30
+ ```bash
31
+ git clone https://github.com/djr4/datavessel-cli.git
32
+ cd datavessel-cli
33
+ npm install
34
+ npm run build
35
+ npm link # exposes `datavessel` and `dv` on your PATH
36
+
37
+ # or run without building
38
+ npm run dev -- tools list
39
+ ```
40
+ </details>
41
+
42
+ ## Quick start
43
+
44
+ ```bash
45
+ datavessel login # sign in via your browser
46
+ datavessel tools list # browse the catalog
47
+ datavessel tools show run_report # see a tool's parameters
48
+ datavessel run run_report --property-id 123 --metrics sessions --metrics users
49
+ datavessel --json run list_sites # machine-readable output
50
+ ```
51
+
52
+ ## Authentication
53
+
54
+ `datavessel login` opens your browser, signs you in with the normal datavessel
55
+ Google flow, and hands the session back to the CLI over a localhost loopback.
56
+ The backend's authorization server is Supabase; the CLI stores the resulting
57
+ **refresh token** and silently refreshes the short-lived access token, so you
58
+ log in once.
59
+
60
+ ```bash
61
+ datavessel login # browser flow (default)
62
+ datavessel login --no-browser # print the URL instead of opening a browser
63
+ datavessel whoami
64
+ datavessel logout
65
+ ```
66
+
67
+ For CI / headless use, supply a static credential instead of the browser flow:
68
+
69
+ ```bash
70
+ datavessel login --token "$JWT" # store a Bearer JWT
71
+ DATAVESSEL_TOKEN="$JWT" datavessel whoami # or pass it per-invocation
72
+ ```
73
+
74
+ Credentials are stored per-profile under `~/.config/datavessel/credentials.json`
75
+ (mode `0600`). Precedence, highest first:
76
+
77
+ 1. `--token` / `--api-key` flags
78
+ 2. `DATAVESSEL_TOKEN` / `DATAVESSEL_API_KEY` env vars
79
+ 3. stored credential for the active profile (browser-login session)
80
+
81
+ > The browser flow requires the `/cli-auth` page in `datavessel-frontend`. It
82
+ > redirects only to `http://127.0.0.1:<port>` (loopback), echoes a random
83
+ > `state` the CLI verifies, and requires an explicit "Authorize" click.
84
+
85
+ ### Use with coding agents (Claude Code / Cursor)
86
+
87
+ This repo ships [`SKILL.md`](./SKILL.md) — a ready-made agent skill describing
88
+ how to drive the CLI (discover tools, `--json` output, exit codes, auth). Drop
89
+ it into `.claude/skills/datavessel/SKILL.md` for Claude Code, or reference it
90
+ from a Cursor rule.
91
+
92
+ ## Commands
93
+
94
+ | Command | Description |
95
+ | --- | --- |
96
+ | `login` / `logout` / `whoami` | Manage and inspect authentication |
97
+ | `tools list` | List tools (filter with `--provider`, `--access`, `--search`) |
98
+ | `tools show <tool>` | Show a tool's description and parameters |
99
+ | `run <tool> [--flags…]` | Execute a tool; flags come from its schema |
100
+ | `providers` | List providers you've connected |
101
+ | `usage` | Show tier, tool-call quota, billing period |
102
+ | `sync` | Force-refresh the local tool catalog cache |
103
+ | `config show/get/set` | Manage base URL and default profile |
104
+
105
+ ### Running tools
106
+
107
+ Flags are derived from the tool's `inputSchema`:
108
+
109
+ - `--flag value` or `--flag=value`
110
+ - repeat a flag for arrays: `--metrics sessions --metrics users`
111
+ - booleans: `--active` / `--no-active`
112
+ - escape hatches that always work:
113
+ - `--param key=value` (repeatable)
114
+ - `--params-json '{"key":"value"}'`
115
+
116
+ `datavessel run <tool> --help` prints the tool's parameters. Write tools prompt
117
+ for confirmation unless `--yes` is passed.
118
+
119
+ > Global options (`--json`, `--profile`, `--base-url`, …) must come **before**
120
+ > the subcommand, e.g. `datavessel --json run <tool>`. This lets `run` pass any
121
+ > remaining `--flags` straight to the tool.
122
+
123
+ ## Configuration
124
+
125
+ ```bash
126
+ datavessel config show
127
+ datavessel config set base-url https://api.datavessel.io
128
+ datavessel config set app-url https://app.datavessel.io
129
+ datavessel config set default-profile work
130
+ datavessel --profile staging config set base-url https://staging-api.datavessel.io
131
+ ```
132
+
133
+ Environment overrides: `DATAVESSEL_API_URL`, `DATAVESSEL_APP_URL`,
134
+ `DATAVESSEL_PROFILE`, `DATAVESSEL_CONFIG_DIR`, `NO_COLOR`.
135
+
136
+ The tool catalog is cached at `~/.config/datavessel/catalog.json` and refreshed
137
+ when older than 24h, on a base-URL change, or via `datavessel sync`.
138
+
139
+ ## Development
140
+
141
+ ```bash
142
+ npm run dev -- <args> # run from source via tsx
143
+ npm run typecheck # tsc --noEmit
144
+ npm run lint # eslint
145
+ npm test # node test runner via tsx
146
+ npm run build # emit dist/
147
+ ```
148
+
149
+ ### Exit codes
150
+
151
+ `0` ok · `1` error · `2` usage · `3` auth · `4` quota · `5` provider not connected.
152
+
153
+ ## License
154
+
155
+ Apache-2.0
package/dist/api.js ADDED
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Thin HTTP client for the datavessel backend.
3
+ *
4
+ * Wraps `fetch` with auth headers, JSON encoding, a request timeout, and
5
+ * backend-error mapping. Endpoints used here are documented in the backend
6
+ * controllers (tools, providers/execute, auth, integrations, tiers).
7
+ */
8
+ import { CliError, ExitCode, mapBackendError } from './errors.js';
9
+ import { needsRefresh, refreshOAuth } from './session.js';
10
+ export class ApiClient {
11
+ baseUrl;
12
+ credential;
13
+ timeoutMs;
14
+ onRefresh;
15
+ constructor(opts) {
16
+ this.baseUrl = opts.baseUrl.replace(/\/+$/, '');
17
+ this.credential = opts.credential;
18
+ this.timeoutMs = opts.timeoutMs ?? 60_000;
19
+ this.onRefresh = opts.onRefresh;
20
+ }
21
+ /**
22
+ * Build auth headers, transparently refreshing an expired OAuth access token
23
+ * first and persisting the rotated credential via `onRefresh`.
24
+ */
25
+ async authHeaders() {
26
+ let cred = this.credential;
27
+ if (!cred)
28
+ return {};
29
+ if (cred.type === 'oauth' && needsRefresh(cred)) {
30
+ cred = await refreshOAuth(cred);
31
+ this.credential = cred;
32
+ this.onRefresh?.(cred);
33
+ }
34
+ if (cred.type === 'api-key')
35
+ return { 'X-API-Key': cred.token };
36
+ if (cred.type === 'oauth')
37
+ return { Authorization: `Bearer ${cred.accessToken}` };
38
+ return { Authorization: `Bearer ${cred.token}` };
39
+ }
40
+ requireAuth() {
41
+ if (!this.credential) {
42
+ throw new CliError('Not authenticated.', ExitCode.AUTH, 'Run `datavessel login` or set DATAVESSEL_TOKEN.');
43
+ }
44
+ }
45
+ async request(method, path, opts = {}) {
46
+ if (opts.auth)
47
+ this.requireAuth();
48
+ const authHeaders = opts.auth ? await this.authHeaders() : {};
49
+ const url = `${this.baseUrl}${path}`;
50
+ const controller = new AbortController();
51
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
52
+ let res;
53
+ try {
54
+ res = await fetch(url, {
55
+ method,
56
+ headers: {
57
+ Accept: 'application/json',
58
+ ...(opts.body !== undefined ? { 'Content-Type': 'application/json' } : {}),
59
+ ...authHeaders,
60
+ },
61
+ body: opts.body !== undefined ? JSON.stringify(opts.body) : undefined,
62
+ signal: controller.signal,
63
+ });
64
+ }
65
+ catch (err) {
66
+ if (err instanceof Error && err.name === 'AbortError') {
67
+ throw new CliError(`Request timed out after ${this.timeoutMs}ms: ${method} ${path}`);
68
+ }
69
+ const reason = err instanceof Error ? err.message : String(err);
70
+ throw new CliError(`Could not reach the backend at ${this.baseUrl}: ${reason}`, ExitCode.ERROR, 'Check your network and the base URL (`datavessel config get base-url`).');
71
+ }
72
+ finally {
73
+ clearTimeout(timer);
74
+ }
75
+ const text = await res.text();
76
+ let parsed = undefined;
77
+ if (text.length > 0) {
78
+ try {
79
+ parsed = JSON.parse(text);
80
+ }
81
+ catch {
82
+ if (!res.ok) {
83
+ throw new CliError(`Backend error (HTTP ${res.status}): ${text.slice(0, 500)}`);
84
+ }
85
+ throw new CliError('Backend returned a non-JSON response.');
86
+ }
87
+ }
88
+ if (!res.ok) {
89
+ throw mapBackendError(res.status, parsed);
90
+ }
91
+ return parsed;
92
+ }
93
+ // --- Catalog (public, no auth) ---
94
+ /** Full tool catalog with input/output schemas. Public endpoint. */
95
+ listToolSchemas() {
96
+ return this.request('GET', '/v1/tools/schemas');
97
+ }
98
+ // --- Execution (requires auth) ---
99
+ /** Execute a tool by name. Returns the unwrapped `data` payload. */
100
+ async execute(toolName, params) {
101
+ const res = await this.request('POST', '/v1/providers/execute', {
102
+ body: { tool_name: toolName, params },
103
+ auth: true,
104
+ });
105
+ return res.data;
106
+ }
107
+ // --- Account (requires auth) ---
108
+ me() {
109
+ return this.request('GET', '/v1/auth/me', { auth: true });
110
+ }
111
+ connectedSources() {
112
+ return this.request('GET', '/v1/integrations/connected-sources', { auth: true });
113
+ }
114
+ usage() {
115
+ return this.request('GET', '/v1/users/me/usage', { auth: true });
116
+ }
117
+ }
118
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,eAAe,EAAqB,MAAM,aAAa,CAAC;AAErF,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAoB1D,MAAM,OAAO,SAAS;IACX,OAAO,CAAS;IACjB,UAAU,CAAc;IACf,SAAS,CAAS;IAClB,SAAS,CAAoC;IAE9D,YAAY,IAAmB;QAC7B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAChD,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QAClC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,MAAM,CAAC;QAC1C,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;IAClC,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,WAAW;QACvB,IAAI,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC;QAC3B,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,CAAC;QACrB,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;YAChD,IAAI,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;YACvB,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;YAAE,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;QAChE,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO;YAAE,OAAO,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;QAClF,OAAO,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC;IACnD,CAAC;IAEO,WAAW;QACjB,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACrB,MAAM,IAAI,QAAQ,CAChB,oBAAoB,EACpB,QAAQ,CAAC,IAAI,EACb,iDAAiD,CAClD,CAAC;QACJ,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,OAAO,CACnB,MAAsB,EACtB,IAAY,EACZ,OAA2C,EAAE;QAE7C,IAAI,IAAI,CAAC,IAAI;YAAE,IAAI,CAAC,WAAW,EAAE,CAAC;QAClC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAE9D,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,CAAC;QACrC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAEnE,IAAI,GAAa,CAAC;QAClB,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBACrB,MAAM;gBACN,OAAO,EAAE;oBACP,MAAM,EAAE,kBAAkB;oBAC1B,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC1E,GAAG,WAAW;iBACf;gBACD,IAAI,EAAE,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;gBACrE,MAAM,EAAE,UAAU,CAAC,MAAM;aAC1B,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBACtD,MAAM,IAAI,QAAQ,CAAC,2BAA2B,IAAI,CAAC,SAAS,OAAO,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC;YACvF,CAAC;YACD,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAChE,MAAM,IAAI,QAAQ,CAChB,kCAAkC,IAAI,CAAC,OAAO,KAAK,MAAM,EAAE,EAC3D,QAAQ,CAAC,KAAK,EACd,yEAAyE,CAC1E,CAAC;QACJ,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,IAAI,MAAM,GAAY,SAAS,CAAC;QAChC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpB,IAAI,CAAC;gBACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC5B,CAAC;YAAC,MAAM,CAAC;gBACP,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;oBACZ,MAAM,IAAI,QAAQ,CAAC,uBAAuB,GAAG,CAAC,MAAM,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;gBAClF,CAAC;gBACD,MAAM,IAAI,QAAQ,CAAC,uCAAuC,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,eAAe,CAAC,GAAG,CAAC,MAAM,EAAE,MAA8C,CAAC,CAAC;QACpF,CAAC;QACD,OAAO,MAAW,CAAC;IACrB,CAAC;IAED,oCAAoC;IAEpC,oEAAoE;IACpE,eAAe;QACb,OAAO,IAAI,CAAC,OAAO,CAAe,KAAK,EAAE,mBAAmB,CAAC,CAAC;IAChE,CAAC;IAED,oCAAoC;IAEpC,oEAAoE;IACpE,KAAK,CAAC,OAAO,CAAC,QAAgB,EAAE,MAA+B;QAC7D,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAoB,MAAM,EAAE,uBAAuB,EAAE;YACjF,IAAI,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE;YACrC,IAAI,EAAE,IAAI;SACX,CAAC,CAAC;QACH,OAAO,GAAG,CAAC,IAAI,CAAC;IAClB,CAAC;IAED,kCAAkC;IAElC,EAAE;QACA,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,gBAAgB;QACd,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,oCAAoC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACnF,CAAC;IAED,KAAK;QACH,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,oBAAoB,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACnE,CAAC;CACF"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Local cache of the backend tool catalog.
3
+ *
4
+ * The CLI's commands and help are generated from `/v1/tools/schemas`. To keep
5
+ * `--help` fast and avoid a network round-trip on every invocation we cache the
6
+ * catalog on disk, scoped to the base URL it was fetched from, and refresh it
7
+ * when older than the TTL (or on explicit `datavessel sync`).
8
+ */
9
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
10
+ import { ensureDir, _paths } from './config.js';
11
+ const DEFAULT_TTL_MS = 24 * 60 * 60 * 1000; // 24h
12
+ function read() {
13
+ const path = _paths.catalogPath();
14
+ if (!existsSync(path))
15
+ return undefined;
16
+ try {
17
+ return JSON.parse(readFileSync(path, 'utf8'));
18
+ }
19
+ catch {
20
+ return undefined;
21
+ }
22
+ }
23
+ function write(cache) {
24
+ ensureDir();
25
+ writeFileSync(_paths.catalogPath(), JSON.stringify(cache, null, 2) + '\n', { mode: 0o600 });
26
+ }
27
+ function isFresh(cache, baseUrl, ttlMs) {
28
+ return cache.baseUrl === baseUrl && Date.now() - cache.fetchedAt < ttlMs;
29
+ }
30
+ /** Force a refresh from the backend and update the cache. */
31
+ export async function refreshCatalog(client) {
32
+ const tools = await client.listToolSchemas();
33
+ write({ fetchedAt: Date.now(), baseUrl: client.baseUrl, tools });
34
+ return tools;
35
+ }
36
+ /**
37
+ * Return the catalog, fetching from the backend when the cache is missing,
38
+ * stale, or for a different base URL. Pass `forceRefresh` to always re-fetch.
39
+ */
40
+ export async function getCatalog(client, opts = {}) {
41
+ const ttlMs = opts.ttlMs ?? DEFAULT_TTL_MS;
42
+ if (!opts.forceRefresh) {
43
+ const cache = read();
44
+ if (cache && isFresh(cache, client.baseUrl, ttlMs))
45
+ return cache.tools;
46
+ }
47
+ return refreshCatalog(client);
48
+ }
49
+ /** Catalog from cache only (no network); undefined when absent. */
50
+ export function getCachedCatalog(baseUrl) {
51
+ const cache = read();
52
+ return cache && cache.baseUrl === baseUrl ? cache.tools : undefined;
53
+ }
54
+ export function findTool(tools, name) {
55
+ return tools.find((t) => t.toolName === name);
56
+ }
57
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAElE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,cAAc,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,MAAM;AAQlD,SAAS,IAAI;IACX,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IAClC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACxC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAiB,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,SAAS,KAAK,CAAC,KAAmB;IAChC,SAAS,EAAE,CAAC;IACZ,aAAa,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAC9F,CAAC;AAED,SAAS,OAAO,CAAC,KAAmB,EAAE,OAAe,EAAE,KAAa;IAClE,OAAO,KAAK,CAAC,OAAO,KAAK,OAAO,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC;AAC3E,CAAC;AAED,6DAA6D;AAC7D,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAAiB;IACpD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,eAAe,EAAE,CAAC;IAC7C,KAAK,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IACjE,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,MAAiB,EACjB,OAAmD,EAAE;IAErD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,cAAc,CAAC;IAC3C,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,IAAI,EAAE,CAAC;QACrB,IAAI,KAAK,IAAI,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC,KAAK,CAAC;IACzE,CAAC;IACD,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC;AAChC,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,MAAM,KAAK,GAAG,IAAI,EAAE,CAAC;IACrB,OAAO,KAAK,IAAI,KAAK,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAAmB,EAAE,IAAY;IACxD,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC;AAChD,CAAC"}
package/dist/cli.js ADDED
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Assembles the commander program: global options + all subcommands.
3
+ */
4
+ import { readFileSync } from 'node:fs';
5
+ import { Command } from 'commander';
6
+ import { registerAuthCommands } from './commands/auth.js';
7
+ import { registerToolsCommands } from './commands/tools.js';
8
+ import { registerRunCommand } from './commands/run.js';
9
+ import { registerAccountCommands } from './commands/account.js';
10
+ import { registerConfigCommands } from './commands/config.js';
11
+ function version() {
12
+ try {
13
+ const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
14
+ return pkg.version ?? '0.0.0';
15
+ }
16
+ catch {
17
+ return '0.0.0';
18
+ }
19
+ }
20
+ export function buildProgram() {
21
+ const program = new Command();
22
+ program
23
+ .name('datavessel')
24
+ .description('datavessel CLI — run 100+ analytics & commerce tools.\n' +
25
+ 'Commands and tool help are generated from the live backend catalog.')
26
+ .version(version(), '-v, --version', 'Print the CLI version')
27
+ .option('-p, --profile <name>', 'Configuration profile to use')
28
+ .option('--base-url <url>', 'Override the backend API base URL')
29
+ .option('--app-url <url>', 'Override the web app URL used for browser login')
30
+ .option('--token <jwt>', 'Override the Bearer token for this invocation')
31
+ .option('--api-key <key>', 'Override the API key for this invocation')
32
+ .option('--json', 'Output machine-readable JSON', false)
33
+ .option('-y, --yes', 'Skip confirmation prompts (for write tools)', false)
34
+ // Global options must precede the subcommand; required for `run` pass-through.
35
+ .enablePositionalOptions()
36
+ .showHelpAfterError('(add --help for usage)');
37
+ registerAuthCommands(program);
38
+ registerToolsCommands(program);
39
+ registerRunCommand(program);
40
+ registerAccountCommands(program);
41
+ registerConfigCommands(program);
42
+ program.addHelpText('after', '\nQuick start:\n' +
43
+ ' datavessel login Authenticate (paste a token)\n' +
44
+ ' datavessel tools list Browse available tools\n' +
45
+ ' datavessel tools show <tool> See a tool\'s parameters\n' +
46
+ ' datavessel run <tool> --flag v Execute a tool\n' +
47
+ ' datavessel --json run <tool> Machine-readable output\n' +
48
+ '\nEnvironment:\n' +
49
+ ' DATAVESSEL_TOKEN Bearer token (overrides stored credential)\n' +
50
+ ' DATAVESSEL_API_KEY API key\n' +
51
+ ' DATAVESSEL_API_URL Backend base URL\n' +
52
+ ' DATAVESSEL_PROFILE Active profile\n');
53
+ return program;
54
+ }
55
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,SAAS,OAAO;IACd,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QAC1F,OAAO,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,YAAY,CAAC;SAClB,WAAW,CACV,yDAAyD;QACvD,qEAAqE,CACxE;SACA,OAAO,CAAC,OAAO,EAAE,EAAE,eAAe,EAAE,uBAAuB,CAAC;SAC5D,MAAM,CAAC,sBAAsB,EAAE,8BAA8B,CAAC;SAC9D,MAAM,CAAC,kBAAkB,EAAE,mCAAmC,CAAC;SAC/D,MAAM,CAAC,iBAAiB,EAAE,iDAAiD,CAAC;SAC5E,MAAM,CAAC,eAAe,EAAE,+CAA+C,CAAC;SACxE,MAAM,CAAC,iBAAiB,EAAE,0CAA0C,CAAC;SACrE,MAAM,CAAC,QAAQ,EAAE,8BAA8B,EAAE,KAAK,CAAC;SACvD,MAAM,CAAC,WAAW,EAAE,6CAA6C,EAAE,KAAK,CAAC;QAC1E,+EAA+E;SAC9E,uBAAuB,EAAE;SACzB,kBAAkB,CAAC,wBAAwB,CAAC,CAAC;IAEhD,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC9B,qBAAqB,CAAC,OAAO,CAAC,CAAC;IAC/B,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC5B,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACjC,sBAAsB,CAAC,OAAO,CAAC,CAAC;IAEhC,OAAO,CAAC,WAAW,CACjB,OAAO,EACP,kBAAkB;QAChB,mEAAmE;QACnE,6DAA6D;QAC7D,+DAA+D;QAC/D,qDAAqD;QACrD,8DAA8D;QAC9D,kBAAkB;QAClB,qEAAqE;QACrE,kCAAkC;QAClC,2CAA2C;QAC3C,yCAAyC,CAC5C,CAAC;IAEF,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Account commands: `providers` (connected sources) and `usage` (tier/quota).
3
+ */
4
+ import { buildContext } from '../context.js';
5
+ import { printJson, table, info, c } from '../output.js';
6
+ export function registerAccountCommands(program) {
7
+ program
8
+ .command('providers')
9
+ .description('List providers you have connected (OAuth/credentials)')
10
+ .action(async (_opts, cmd) => {
11
+ const ctx = buildContext(cmd);
12
+ const { providers } = await ctx.client.connectedSources();
13
+ if (ctx.global.json) {
14
+ printJson(providers);
15
+ return;
16
+ }
17
+ if (providers.length === 0) {
18
+ info('No connected providers.');
19
+ info(c.dim('Connect accounts in the web app: https://app.datavessel.io/settings'));
20
+ return;
21
+ }
22
+ for (const p of providers.sort())
23
+ info(`${c.green('●')} ${p}`);
24
+ });
25
+ program
26
+ .command('usage')
27
+ .description('Show your tier, tool-call quota, and billing period')
28
+ .action(async (_opts, cmd) => {
29
+ const ctx = buildContext(cmd);
30
+ const u = await ctx.client.usage();
31
+ if (ctx.global.json) {
32
+ printJson(u);
33
+ return;
34
+ }
35
+ const rows = [
36
+ ['Tier', `${u.tier_name ?? u.tier} (${u.tier})`],
37
+ ['Tool calls', `${u.current_tool_calls} / ${u.tool_call_limit} (${u.usage_percentage}%)`],
38
+ ['Remaining', String(u.remaining_tool_calls)],
39
+ ['Schedules', `${u.schedules_current} / ${u.schedules_limit}`],
40
+ ['Daily agent runs', `${u.daily_agent_runs_current} / ${u.daily_agent_runs_limit}`],
41
+ ['Billing period ends', String(u.billing_period_end ?? '')],
42
+ ['Subscription', String(u.subscription_status ?? '')],
43
+ ];
44
+ info(table(['FIELD', 'VALUE'], rows));
45
+ if (u.upgrade_url)
46
+ info(`\n${c.yellow('Upgrade:')} ${u.upgrade_url}`);
47
+ });
48
+ }
49
+ //# sourceMappingURL=account.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account.js","sourceRoot":"","sources":["../../src/commands/account.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,cAAc,CAAC;AAEzD,MAAM,UAAU,uBAAuB,CAAC,OAAgB;IACtD,OAAO;SACJ,OAAO,CAAC,WAAW,CAAC;SACpB,WAAW,CAAC,uDAAuD,CAAC;SACpE,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,GAAY,EAAE,EAAE;QACpC,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC;QAC1D,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACpB,SAAS,CAAC,SAAS,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QACD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,IAAI,CAAC,yBAAyB,CAAC,CAAC;YAChC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,qEAAqE,CAAC,CAAC,CAAC;YACnF,OAAO;QACT,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,SAAS,CAAC,IAAI,EAAE;YAAE,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,qDAAqD,CAAC;SAClE,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,GAAY,EAAE,EAAE;QACpC,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,CAAC,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QACnC,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACpB,SAAS,CAAC,CAAC,CAAC,CAAC;YACb,OAAO;QACT,CAAC;QACD,MAAM,IAAI,GAAe;YACvB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC;YAChD,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC,kBAAkB,MAAM,CAAC,CAAC,eAAe,KAAK,CAAC,CAAC,gBAAgB,IAAI,CAAC;YACzF,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC;YAC7C,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,iBAAiB,MAAM,CAAC,CAAC,eAAe,EAAE,CAAC;YAC9D,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC,wBAAwB,MAAM,CAAC,CAAC,sBAAsB,EAAE,CAAC;YACnF,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC,CAAC,kBAAkB,IAAI,EAAE,CAAC,CAAC;YAC3D,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC;SACtD,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;QACtC,IAAI,CAAC,CAAC,WAAW;YAAE,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Authentication commands: login, logout, whoami.
3
+ *
4
+ * `login` defaults to a browser handoff that yields a refreshable Supabase
5
+ * session (see oauth.ts), then verifies it against `/v1/auth/me`. For CI a
6
+ * static credential can be supplied via `--token` / `--api-key` or the
7
+ * `DATAVESSEL_TOKEN` / `DATAVESSEL_API_KEY` env vars.
8
+ */
9
+ import { buildContext, globalOpts } from '../context.js';
10
+ import { ApiClient } from '../api.js';
11
+ import { clearCredential, resolveConfig, resolveProfileName, saveCredential, } from '../config.js';
12
+ import { loginViaBrowser } from '../oauth.js';
13
+ import { printJson, success, info, c } from '../output.js';
14
+ export function registerAuthCommands(program) {
15
+ program
16
+ .command('login')
17
+ .description('Sign in via your browser (or pass --token / --api-key for CI)')
18
+ .option('--token <jwt>', 'Use a Bearer access token instead of the browser flow')
19
+ .option('--api-key <key>', 'Use an API key instead of the browser flow')
20
+ .option('--no-browser', "Print the login URL instead of opening a browser")
21
+ .option('--no-verify', 'Skip verifying the credential against the backend')
22
+ .action(async (opts, cmd) => {
23
+ const global = globalOpts(cmd);
24
+ const profile = resolveProfileName(global.profile);
25
+ const resolved = resolveConfig(global.profile);
26
+ let credential;
27
+ if (opts.apiKey) {
28
+ credential = { type: 'api-key', token: String(opts.apiKey) };
29
+ }
30
+ else if (opts.token) {
31
+ credential = { type: 'bearer', token: String(opts.token) };
32
+ }
33
+ else {
34
+ // Default: browser-based OAuth handoff. Yields a refreshable session.
35
+ credential = await loginViaBrowser({
36
+ appUrl: global.appUrl || resolved.appUrl,
37
+ open: opts.browser !== false,
38
+ });
39
+ }
40
+ if (opts.verify !== false) {
41
+ const ctx = buildContext(cmd);
42
+ const client = new ApiClient({ baseUrl: ctx.config.baseUrl, credential });
43
+ const me = await client.me();
44
+ saveCredential(profile, credential);
45
+ success(`Logged in as ${c.bold(me.email)} (profile: ${profile})`);
46
+ return;
47
+ }
48
+ saveCredential(profile, credential);
49
+ success(`Saved credential for profile ${c.cyan(profile)} (unverified).`);
50
+ });
51
+ program
52
+ .command('logout')
53
+ .description('Remove the stored credential for the active profile')
54
+ .action((_opts, cmd) => {
55
+ const global = globalOpts(cmd);
56
+ const profile = resolveProfileName(global.profile);
57
+ const removed = clearCredential(profile);
58
+ if (removed)
59
+ success(`Logged out of profile ${c.cyan(profile)}.`);
60
+ else
61
+ info(`No stored credential for profile ${c.cyan(profile)}.`);
62
+ });
63
+ program
64
+ .command('whoami')
65
+ .description('Show the currently authenticated user')
66
+ .action(async (_opts, cmd) => {
67
+ const ctx = buildContext(cmd);
68
+ const me = await ctx.client.me();
69
+ if (ctx.global.json) {
70
+ printJson(me);
71
+ return;
72
+ }
73
+ info(`${c.bold(me.name || me.email)}`);
74
+ info(`${c.dim('email:')} ${me.email}`);
75
+ info(`${c.dim('id:')} ${me.id}`);
76
+ if (me.role)
77
+ info(`${c.dim('role:')} ${me.role}`);
78
+ info(`${c.dim('profile:')} ${ctx.config.profile}`);
79
+ info(`${c.dim('api:')} ${ctx.config.baseUrl}`);
80
+ });
81
+ }
82
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EACL,eAAe,EACf,aAAa,EACb,kBAAkB,EAClB,cAAc,GAEf,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,UAAU,oBAAoB,CAAC,OAAgB;IACnD,OAAO;SACJ,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,+DAA+D,CAAC;SAC5E,MAAM,CAAC,eAAe,EAAE,uDAAuD,CAAC;SAChF,MAAM,CAAC,iBAAiB,EAAE,4CAA4C,CAAC;SACvE,MAAM,CAAC,cAAc,EAAE,kDAAkD,CAAC;SAC1E,MAAM,CAAC,aAAa,EAAE,mDAAmD,CAAC;SAC1E,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,GAAY,EAAE,EAAE;QACnC,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QAC/B,MAAM,OAAO,GAAG,kBAAkB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACnD,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAE/C,IAAI,UAAsB,CAAC;QAC3B,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,UAAU,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/D,CAAC;aAAM,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACtB,UAAU,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7D,CAAC;aAAM,CAAC;YACN,sEAAsE;YACtE,UAAU,GAAG,MAAM,eAAe,CAAC;gBACjC,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM;gBACxC,IAAI,EAAE,IAAI,CAAC,OAAO,KAAK,KAAK;aAC7B,CAAC,CAAC;QACL,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;YAC1B,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;YAC9B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC;YAC1E,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,EAAE,EAAE,CAAC;YAC7B,cAAc,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;YACpC,OAAO,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,OAAO,GAAG,CAAC,CAAC;YAClE,OAAO;QACT,CAAC;QACD,cAAc,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QACpC,OAAO,CAAC,gCAAgC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,qDAAqD,CAAC;SAClE,MAAM,CAAC,CAAC,KAAK,EAAE,GAAY,EAAE,EAAE;QAC9B,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QAC/B,MAAM,OAAO,GAAG,kBAAkB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACnD,MAAM,OAAO,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;QACzC,IAAI,OAAO;YAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;;YAC7D,IAAI,CAAC,oCAAoC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,uCAAuC,CAAC;SACpD,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,GAAY,EAAE,EAAE;QACpC,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QACjC,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACpB,SAAS,CAAC,EAAE,CAAC,CAAC;YACd,OAAO;QACT,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACvC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC;QACzC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QACtC,IAAI,EAAE,CAAC,IAAI;YAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;QACrD,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QACnD,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;AACP,CAAC"}