@quantbrasil/cli 0.1.0-beta.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 (102) hide show
  1. package/README.md +272 -0
  2. package/bin/quantbrasil.js +4 -0
  3. package/dist/cli/auth.d.ts +20 -0
  4. package/dist/cli/auth.d.ts.map +1 -0
  5. package/dist/cli/auth.js +76 -0
  6. package/dist/cli/client.d.ts +17 -0
  7. package/dist/cli/client.d.ts.map +1 -0
  8. package/dist/cli/client.js +112 -0
  9. package/dist/cli/config.d.ts +33 -0
  10. package/dist/cli/config.d.ts.map +1 -0
  11. package/dist/cli/config.js +148 -0
  12. package/dist/cli/errors.d.ts +40 -0
  13. package/dist/cli/errors.d.ts.map +1 -0
  14. package/dist/cli/errors.js +122 -0
  15. package/dist/cli/index.d.ts +30 -0
  16. package/dist/cli/index.d.ts.map +1 -0
  17. package/dist/cli/index.js +112 -0
  18. package/dist/cli/prompt.d.ts +2 -0
  19. package/dist/cli/prompt.d.ts.map +1 -0
  20. package/dist/cli/prompt.js +40 -0
  21. package/dist/cli/skills.d.ts +26 -0
  22. package/dist/cli/skills.d.ts.map +1 -0
  23. package/dist/cli/skills.js +94 -0
  24. package/dist/cli/terminal.d.ts +18 -0
  25. package/dist/cli/terminal.d.ts.map +1 -0
  26. package/dist/cli/terminal.js +43 -0
  27. package/dist/commands/analytics.d.ts +131 -0
  28. package/dist/commands/analytics.d.ts.map +1 -0
  29. package/dist/commands/analytics.js +291 -0
  30. package/dist/commands/assets.d.ts +69 -0
  31. package/dist/commands/assets.d.ts.map +1 -0
  32. package/dist/commands/assets.js +350 -0
  33. package/dist/commands/auth.d.ts +17 -0
  34. package/dist/commands/auth.d.ts.map +1 -0
  35. package/dist/commands/auth.js +48 -0
  36. package/dist/commands/capabilities.d.ts +25 -0
  37. package/dist/commands/capabilities.d.ts.map +1 -0
  38. package/dist/commands/capabilities.js +61 -0
  39. package/dist/commands/init.d.ts +17 -0
  40. package/dist/commands/init.d.ts.map +1 -0
  41. package/dist/commands/init.js +89 -0
  42. package/dist/commands/market.d.ts +45 -0
  43. package/dist/commands/market.d.ts.map +1 -0
  44. package/dist/commands/market.js +162 -0
  45. package/dist/commands/portfolios.d.ts +60 -0
  46. package/dist/commands/portfolios.d.ts.map +1 -0
  47. package/dist/commands/portfolios.js +298 -0
  48. package/dist/commands/skills.d.ts +17 -0
  49. package/dist/commands/skills.d.ts.map +1 -0
  50. package/dist/commands/skills.js +38 -0
  51. package/dist/commands/status.d.ts +15 -0
  52. package/dist/commands/status.d.ts.map +1 -0
  53. package/dist/commands/status.js +52 -0
  54. package/dist/index.d.ts +14 -0
  55. package/dist/index.d.ts.map +1 -0
  56. package/dist/index.js +13 -0
  57. package/dist/vendor/core/capabilities/analytics.d.ts +187 -0
  58. package/dist/vendor/core/capabilities/analytics.d.ts.map +1 -0
  59. package/dist/vendor/core/capabilities/analytics.js +214 -0
  60. package/dist/vendor/core/capabilities/assets.d.ts +48 -0
  61. package/dist/vendor/core/capabilities/assets.d.ts.map +1 -0
  62. package/dist/vendor/core/capabilities/assets.js +66 -0
  63. package/dist/vendor/core/capabilities/index.d.ts +8 -0
  64. package/dist/vendor/core/capabilities/index.d.ts.map +1 -0
  65. package/dist/vendor/core/capabilities/index.js +7 -0
  66. package/dist/vendor/core/capabilities/market.d.ts +90 -0
  67. package/dist/vendor/core/capabilities/market.d.ts.map +1 -0
  68. package/dist/vendor/core/capabilities/market.js +114 -0
  69. package/dist/vendor/core/capabilities/portfolios.d.ts +224 -0
  70. package/dist/vendor/core/capabilities/portfolios.d.ts.map +1 -0
  71. package/dist/vendor/core/capabilities/portfolios.js +244 -0
  72. package/dist/vendor/core/capabilities/registry.d.ts +1083 -0
  73. package/dist/vendor/core/capabilities/registry.d.ts.map +1 -0
  74. package/dist/vendor/core/capabilities/registry.js +14 -0
  75. package/dist/vendor/core/capabilities/shared.d.ts +3 -0
  76. package/dist/vendor/core/capabilities/shared.d.ts.map +1 -0
  77. package/dist/vendor/core/capabilities/shared.js +2 -0
  78. package/dist/vendor/core/capabilities/types.d.ts +75 -0
  79. package/dist/vendor/core/capabilities/types.d.ts.map +1 -0
  80. package/dist/vendor/core/capabilities/types.js +1 -0
  81. package/dist/vendor/core/errors.d.ts +22 -0
  82. package/dist/vendor/core/errors.d.ts.map +1 -0
  83. package/dist/vendor/core/errors.js +42 -0
  84. package/dist/vendor/core/http/client.d.ts +45 -0
  85. package/dist/vendor/core/http/client.d.ts.map +1 -0
  86. package/dist/vendor/core/http/client.js +170 -0
  87. package/dist/vendor/core/http/index.d.ts +2 -0
  88. package/dist/vendor/core/http/index.d.ts.map +1 -0
  89. package/dist/vendor/core/http/index.js +1 -0
  90. package/dist/vendor/core/index.d.ts +5 -0
  91. package/dist/vendor/core/index.d.ts.map +1 -0
  92. package/dist/vendor/core/index.js +4 -0
  93. package/dist/vendor/core/invoke.d.ts +17 -0
  94. package/dist/vendor/core/invoke.d.ts.map +1 -0
  95. package/dist/vendor/core/invoke.js +70 -0
  96. package/package.json +57 -0
  97. package/skills/quantbrasil/SKILL.md +29 -0
  98. package/skills/quantbrasil/references/cli.md +77 -0
  99. package/skills/quantbrasil/references/costs.md +30 -0
  100. package/skills/quantbrasil/references/errors.md +128 -0
  101. package/skills/quantbrasil/references/unsupported.md +20 -0
  102. package/skills/quantbrasil/references/workflows.md +99 -0
package/README.md ADDED
@@ -0,0 +1,272 @@
1
+ # QuantBrasil CLI
2
+
3
+ Public QuantBrasil CLI for deterministic operations.
4
+
5
+ ## Running locally
6
+
7
+ The local package binary lives at `bin/quantbrasil.js`.
8
+
9
+ ### From the package directory
10
+
11
+ ```bash
12
+ # from monorepo/packages/cli
13
+ pnpm build
14
+ node ./bin/quantbrasil.js --status
15
+ ```
16
+
17
+ ### From the repository root
18
+
19
+ ```bash
20
+ pnpm --dir monorepo/packages/cli build
21
+ pnpm --dir monorepo/packages/cli exec node ./bin/quantbrasil.js --status
22
+ ```
23
+
24
+ `node ./bin/quantbrasil.js ...` does not work from the repository root because
25
+ that file only exists inside this package.
26
+
27
+ ## Local authentication flow
28
+
29
+ ```bash
30
+ # from monorepo/packages/cli
31
+ node ./bin/quantbrasil.js auth login --api-key qb_live_<id>.<secret>
32
+ node ./bin/quantbrasil.js skills install --all
33
+ node ./bin/quantbrasil.js --status
34
+ node ./bin/quantbrasil.js auth logout
35
+ ```
36
+
37
+ The `auth login` command validates two things before saving:
38
+
39
+ 1. the key format locally (`qb_live_<id>.<secret>`)
40
+ 2. the key against the target backend with an authenticated read request
41
+
42
+ If the target backend does not expose `/api/desk/api-keys/me` yet, login fails with
43
+ a remote validation error. During development, point `QB_BACKEND_URL` to a
44
+ compatible local or staging backend.
45
+
46
+ ## First read command
47
+
48
+ ```bash
49
+ quantbrasil market assets
50
+ quantbrasil market assets --type B3
51
+ quantbrasil market assets --json
52
+ quantbrasil market price PETR4
53
+ quantbrasil market price PETR4 --date 2026-04-10
54
+ quantbrasil market price PETR4 --json
55
+ quantbrasil assets overview PETR4 --sections price,performance
56
+ quantbrasil assets overview PETR4 --sections price,technicals
57
+ quantbrasil assets overview PETR4 --sections price,fundamentals --json
58
+ quantbrasil portfolios list
59
+ quantbrasil portfolios get 93
60
+ quantbrasil portfolios get 93 --json
61
+ quantbrasil portfolios create "Dividendos"
62
+ quantbrasil portfolios rename 93 "Longo Prazo"
63
+ quantbrasil portfolios add-assets 93 PETR4 VALE3
64
+ quantbrasil portfolios remove-assets 93 PETR4
65
+ quantbrasil analytics historical-return --portfolio 93 --from 2025-01-01 --to 2026-01-01
66
+ quantbrasil analytics beta --portfolio 93 --years 3
67
+ quantbrasil analytics var --portfolio 93 --years 1 --confidence 95
68
+ ```
69
+
70
+ ## Local config
71
+
72
+ Config path:
73
+
74
+ - `$XDG_CONFIG_HOME/quantbrasil/config.json`
75
+ - fallback: `~/.config/quantbrasil/config.json`
76
+
77
+ Current shape:
78
+
79
+ ```json
80
+ {
81
+ "apiKey": "qb_live_<id>.<secret>"
82
+ }
83
+ ```
84
+
85
+ ## Target backend
86
+
87
+ Published default:
88
+
89
+ - `https://api.quantbrasil.com.br`
90
+
91
+ Internal override for local or staging development:
92
+
93
+ ```bash
94
+ QB_BACKEND_URL=http://127.0.0.1:8000 node ./bin/quantbrasil.js --status
95
+ QB_BACKEND_URL=https://staging-api.quantbrasil.com.br node ./bin/quantbrasil.js --status
96
+ ```
97
+
98
+ ## Usage after publish/install
99
+
100
+ After publish and global install, the binary becomes:
101
+
102
+ ```bash
103
+ quantbrasil init
104
+ quantbrasil --status
105
+ quantbrasil auth login --api-key qb_live_<id>.<secret>
106
+ quantbrasil skills install --all
107
+ ```
108
+
109
+ ## Publishing
110
+
111
+ Publish from `monorepo/packages/cli`. The package build vendors the private
112
+ workspace core into `dist/vendor/core`, so the published package does not
113
+ depend on unpublished workspace packages.
114
+
115
+ Before publishing, run the packed-package smoke test:
116
+
117
+ ```bash
118
+ pnpm pack:smoke
119
+ ```
120
+
121
+ That command builds the package, packs it into a local tarball, installs the
122
+ temporary tarball in a clean temporary environment, and verifies:
123
+
124
+ - `quantbrasil --status`
125
+ - `quantbrasil capabilities --json`
126
+ - `quantbrasil skills install --all`
127
+
128
+ To create a tarball artifact without publishing:
129
+
130
+ ```bash
131
+ npm version 0.1.0-beta.0 --no-git-tag-version
132
+ pnpm build
133
+ pnpm pack --pack-destination ./artifacts
134
+ ```
135
+
136
+ The tarball can be tested on another machine with:
137
+
138
+ ```bash
139
+ npm exec --yes --package ./artifacts/quantbrasil-cli-0.1.0-beta.0.tgz -- quantbrasil --status
140
+ npm exec --yes --package ./artifacts/quantbrasil-cli-0.1.0-beta.0.tgz -- quantbrasil init
141
+ ```
142
+
143
+ Manual publish:
144
+
145
+ ```bash
146
+ npm version 0.1.0-beta.0 --no-git-tag-version
147
+ pnpm pack:smoke
148
+ pnpm publish --access public --tag beta --no-git-checks
149
+ ```
150
+
151
+ After publishing with the `beta` tag:
152
+
153
+ ```bash
154
+ npx -y @quantbrasil/cli@beta init
155
+ ```
156
+
157
+ After promoting to `latest`:
158
+
159
+ ```bash
160
+ npx -y @quantbrasil/cli@latest init
161
+ ```
162
+
163
+ The GitHub `Publish CLI` workflow runs the same package validation and supports
164
+ dry-run publishes before releasing to npm. It requires an `NPM_TOKEN` repository
165
+ secret with publish access to the `@quantbrasil` npm scope.
166
+
167
+ ## Error output
168
+
169
+ Human errors include a stable code:
170
+
171
+ ```text
172
+ [auth_failed] Authentication failed for the target backend. Run quantbrasil auth login again or update QUANTBRASIL_API_KEY.
173
+ ```
174
+
175
+ For commands that expose `--json`, failures are written to stderr as JSON:
176
+
177
+ ```json
178
+ {
179
+ "ok": false,
180
+ "error": {
181
+ "code": "auth_failed",
182
+ "message": "Authentication failed for the target backend. Run quantbrasil auth login again or update QUANTBRASIL_API_KEY.",
183
+ "category": "auth",
184
+ "exit_code": 1,
185
+ "status": 401,
186
+ "path": "/api/desk/tools/portfolio/list",
187
+ "request_id": "req_..."
188
+ }
189
+ }
190
+ ```
191
+
192
+ Scripts and agents should branch on `error.code`, not message text.
193
+
194
+ Stable codes:
195
+
196
+ - `auth_required`
197
+ - `auth_failed`
198
+ - `validation_error`
199
+ - `not_found`
200
+ - `rate_limited`
201
+ - `mutation_failed`
202
+ - `backend_error`
203
+ - `backend_unavailable`
204
+ - `network_error`
205
+ - `config_error`
206
+ - `unexpected_error`
207
+
208
+ ## One-command setup
209
+
210
+ ```bash
211
+ quantbrasil init
212
+ quantbrasil init --api-key qb_live_<id>.<secret>
213
+ ```
214
+
215
+ `quantbrasil init`:
216
+
217
+ - uses existing authentication if already configured
218
+ - otherwise prompts for an API key or accepts `--api-key`
219
+ - validates and stores the key locally
220
+ - installs the bundled public skill into supported agent clients
221
+ - prints a final ready summary
222
+
223
+ ## Skill install
224
+
225
+ `quantbrasil skills install --all` installs the bundled public QuantBrasil skill
226
+ into supported user-level agent skill directories.
227
+
228
+ Bundled source of truth:
229
+
230
+ - `monorepo/packages/cli/skills/quantbrasil/`
231
+
232
+ Targets:
233
+
234
+ - `~/.agents/skills/quantbrasil` as the shared Agent Skills path
235
+ - `~/.codex/skills/quantbrasil` if `~/.codex` already exists
236
+ - `~/.claude/skills/quantbrasil` if `~/.claude` already exists
237
+
238
+ Installer behavior:
239
+
240
+ 1. resolve the bundled skill from the installed CLI package
241
+ 2. install the shared cross-client copy into `~/.agents/skills/quantbrasil`
242
+ 3. if `~/.codex` exists, also install a compatibility mirror into
243
+ `~/.codex/skills/quantbrasil`
244
+ 4. if `~/.claude` exists, also install a compatibility mirror into
245
+ `~/.claude/skills/quantbrasil`
246
+ 5. replace any existing `quantbrasil` target directory before copying
247
+
248
+ Important:
249
+
250
+ - the installer does **not** create fake client homes like `~/.codex` or
251
+ `~/.claude`
252
+ - it **does** create `~/.agents/skills/quantbrasil` as the shared interop path
253
+ - it overwrites only the `quantbrasil` skill directory, not the whole
254
+ surrounding `skills/` tree
255
+
256
+ Precedence:
257
+
258
+ - the installer only manages **user-level** paths
259
+ - it does **not** install project-local skills such as
260
+ `<project>/.agents/skills/quantbrasil`
261
+ - project-level skills should override user-level skills when names collide
262
+ - for user-level installs, precedence between `~/.agents/skills/quantbrasil`
263
+ and client-specific mirrors should not matter for QuantBrasil because the
264
+ installer copies the same content to every target
265
+
266
+ Scope limits:
267
+
268
+ - no remote skill downloads
269
+ - no GitHub-based skill installation
270
+ - no arbitrary `skills add <url>`
271
+ - no project-local installation
272
+ - no per-client custom variants of the QuantBrasil skill
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { run } = await import("../dist/cli/index.js");
4
+ await run();
@@ -0,0 +1,20 @@
1
+ export interface VerifyCliApiKeyOptions {
2
+ env?: NodeJS.ProcessEnv;
3
+ fetch?: typeof fetch;
4
+ }
5
+ export interface VerifiedCliApiKey {
6
+ ok: true;
7
+ callerType: "api_key";
8
+ userId: number;
9
+ email: string;
10
+ name: string;
11
+ isPremium: boolean;
12
+ apiKey: {
13
+ id: number;
14
+ name: string;
15
+ keyPrefix: string;
16
+ scopes: string[];
17
+ };
18
+ }
19
+ export declare function verifyCliApiKey(apiKey: string, options?: VerifyCliApiKeyOptions): Promise<VerifiedCliApiKey>;
20
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/cli/auth.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,sBAAsB;IACrC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,IAAI,CAAC;IACT,UAAU,EAAE,SAAS,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE;QACN,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,EAAE,CAAC;KAClB,CAAC;CACH;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,iBAAiB,CAAC,CA2G5B"}
@@ -0,0 +1,76 @@
1
+ import { createDeskHttpClient, DeskHttpError } from "../vendor/core/index.js";
2
+ import { normalizeCliApiKey, resolveCliBackendUrl } from "./config.js";
3
+ import { CliError } from "./errors.js";
4
+ export async function verifyCliApiKey(apiKey, options = {}) {
5
+ const normalizedApiKey = normalizeCliApiKey(apiKey);
6
+ const client = createDeskHttpClient({
7
+ baseUrl: resolveCliBackendUrl(options.env ?? process.env),
8
+ fetch: options.fetch,
9
+ });
10
+ try {
11
+ const response = await client.request({
12
+ method: "GET",
13
+ path: "/api/desk/api-keys/me",
14
+ authHeaders: {
15
+ authorization: `Bearer ${normalizedApiKey}`,
16
+ },
17
+ });
18
+ return {
19
+ ok: true,
20
+ callerType: response.data.caller_type,
21
+ userId: response.data.user_id,
22
+ email: response.data.email,
23
+ name: response.data.name,
24
+ isPremium: response.data.is_premium,
25
+ apiKey: {
26
+ id: response.data.api_key.id,
27
+ name: response.data.api_key.name,
28
+ keyPrefix: response.data.api_key.key_prefix,
29
+ scopes: response.data.api_key.scopes,
30
+ },
31
+ };
32
+ }
33
+ catch (error) {
34
+ if (error instanceof CliError) {
35
+ throw error;
36
+ }
37
+ if (error instanceof DeskHttpError) {
38
+ if (error.status === 401 || error.status === 403) {
39
+ throw new CliError("auth_failed", "Invalid API key or backend access denied.", {
40
+ category: "auth",
41
+ status: error.status,
42
+ path: error.path,
43
+ requestId: error.requestId,
44
+ cause: error,
45
+ });
46
+ }
47
+ if (error.status === 404) {
48
+ throw new CliError("not_found", "The target backend does not expose /api/desk/api-keys/me yet. Use QB_BACKEND_URL to point to a compatible backend.", {
49
+ category: "backend",
50
+ status: error.status,
51
+ path: error.path,
52
+ requestId: error.requestId,
53
+ cause: error,
54
+ });
55
+ }
56
+ throw new CliError(error.status === 429
57
+ ? "rate_limited"
58
+ : error.status >= 502 && error.status <= 504
59
+ ? "backend_unavailable"
60
+ : "backend_error", `Could not validate the API key against the backend (${error.status}).`, {
61
+ category: "backend",
62
+ status: error.status,
63
+ path: error.path,
64
+ requestId: error.requestId,
65
+ cause: error,
66
+ });
67
+ }
68
+ if (error instanceof Error) {
69
+ throw new CliError("network_error", `Could not validate the API key: ${error.message}`, {
70
+ category: "network",
71
+ cause: error,
72
+ });
73
+ }
74
+ throw error;
75
+ }
76
+ }
@@ -0,0 +1,17 @@
1
+ import { DeskHttpError, type CapabilityId, type JsonValue } from "../vendor/core/index.js";
2
+ import { type ResolvedCliAuth } from "./config.js";
3
+ import { CliError } from "./errors.js";
4
+ export interface CliInvokeContext {
5
+ env?: NodeJS.ProcessEnv;
6
+ fetch?: typeof fetch;
7
+ }
8
+ export interface CliCapabilityInvocationOptions {
9
+ capability: CapabilityId;
10
+ input?: JsonValue;
11
+ env?: NodeJS.ProcessEnv;
12
+ fetch?: typeof fetch;
13
+ }
14
+ export declare function resolveRequiredCliAuth(env?: NodeJS.ProcessEnv): Promise<ResolvedCliAuth>;
15
+ export declare function invokeCliCapability<T extends JsonValue = JsonValue>(options: CliCapabilityInvocationOptions): Promise<import("../vendor/core/index.js").CapabilityInvocationResult<T>>;
16
+ export declare function mapCliDeskHttpError(error: DeskHttpError): CliError;
17
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/cli/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,aAAa,EAEb,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,YAAY,CAAC;AACpB,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,QAAQ,EAA8B,MAAM,aAAa,CAAC;AAEnE,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,MAAM,WAAW,8BAA8B;IAC7C,UAAU,EAAE,YAAY,CAAC;IACzB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,wBAAsB,sBAAsB,CAC1C,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAAC,eAAe,CAAC,CAU1B;AAED,wBAAsB,mBAAmB,CAAC,CAAC,SAAS,SAAS,GAAG,SAAS,EACvE,OAAO,EAAE,8BAA8B,+DAyBxC;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,aAAa,GAAG,QAAQ,CAgElE"}
@@ -0,0 +1,112 @@
1
+ import { createDeskHttpClient, DeskHttpError, invokeCapability, } from "../vendor/core/index.js";
2
+ import { resolveCliAuth, resolveCliBackendUrl, } from "./config.js";
3
+ import { CliError, createCliAuthRequiredError } from "./errors.js";
4
+ export async function resolveRequiredCliAuth(env = process.env) {
5
+ const resolvedAuth = await resolveCliAuth(env);
6
+ if (!resolvedAuth) {
7
+ throw createCliAuthRequiredError("Authentication not configured. Run quantbrasil auth login --api-key <key> or set QUANTBRASIL_API_KEY.");
8
+ }
9
+ return resolvedAuth;
10
+ }
11
+ export async function invokeCliCapability(options) {
12
+ const env = options.env ?? process.env;
13
+ const auth = await resolveRequiredCliAuth(env);
14
+ const client = createDeskHttpClient({
15
+ baseUrl: resolveCliBackendUrl(env),
16
+ fetch: options.fetch,
17
+ });
18
+ try {
19
+ return await invokeCapability({
20
+ capability: options.capability,
21
+ input: options.input,
22
+ client,
23
+ authHeaders: {
24
+ authorization: `Bearer ${auth.apiKey}`,
25
+ },
26
+ });
27
+ }
28
+ catch (error) {
29
+ if (error instanceof DeskHttpError) {
30
+ throw mapCliDeskHttpError(error);
31
+ }
32
+ throw error;
33
+ }
34
+ }
35
+ export function mapCliDeskHttpError(error) {
36
+ const detail = resolveErrorDetail(error.body);
37
+ if (error.status === 401) {
38
+ return new CliError("auth_failed", "Authentication failed for the target backend. Run quantbrasil auth login again or update QUANTBRASIL_API_KEY.", buildHttpErrorOptions(error, "auth"));
39
+ }
40
+ if (error.status === 403) {
41
+ return new CliError("backend_error", detail ?? "Access denied by the target backend.", buildHttpErrorOptions(error, "backend"));
42
+ }
43
+ if (error.status === 404) {
44
+ return new CliError("not_found", detail ?? `Resource not found for backend path ${error.path}.`, buildHttpErrorOptions(error, "backend"));
45
+ }
46
+ if (error.status === 422 && detail) {
47
+ return new CliError("validation_error", `Invalid command input: ${detail}`, buildHttpErrorOptions(error, "validation"));
48
+ }
49
+ if (error.status === 400 && detail) {
50
+ return createHttpValidationError(error, detail);
51
+ }
52
+ if (error.status === 429) {
53
+ return new CliError("rate_limited", detail ?? "Rate limit exceeded. Wait before retrying.", buildHttpErrorOptions(error, "backend"));
54
+ }
55
+ if (detail) {
56
+ return new CliError(error.status >= 502 && error.status <= 504
57
+ ? "backend_unavailable"
58
+ : "backend_error", detail, buildHttpErrorOptions(error, "backend"));
59
+ }
60
+ return new CliError(error.status >= 502 && error.status <= 504
61
+ ? "backend_unavailable"
62
+ : "backend_error", `The backend request failed with status ${error.status} for ${error.path}.`, buildHttpErrorOptions(error, "backend"));
63
+ }
64
+ function createHttpValidationError(error, detail) {
65
+ const message = detail.trim() || `Invalid command input for backend path ${error.path}.`;
66
+ return new CliError("validation_error", message, buildHttpErrorOptions(error, "validation"));
67
+ }
68
+ function buildHttpErrorOptions(error, category) {
69
+ return {
70
+ category,
71
+ status: error.status,
72
+ path: error.path,
73
+ requestId: error.requestId,
74
+ cause: error,
75
+ };
76
+ }
77
+ function resolveErrorDetail(payload) {
78
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
79
+ return null;
80
+ }
81
+ const detail = payload.detail;
82
+ const message = payload.message;
83
+ if (typeof detail === "string" && detail.trim()) {
84
+ return detail;
85
+ }
86
+ if (Array.isArray(detail)) {
87
+ const validationDetails = detail
88
+ .map(formatValidationDetail)
89
+ .filter(Boolean);
90
+ if (validationDetails.length > 0) {
91
+ return validationDetails.join("; ");
92
+ }
93
+ }
94
+ if (typeof message === "string" && message.trim()) {
95
+ return message;
96
+ }
97
+ return null;
98
+ }
99
+ function formatValidationDetail(value) {
100
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
101
+ return null;
102
+ }
103
+ const detail = value;
104
+ const message = typeof detail.msg === "string" ? detail.msg : null;
105
+ const loc = Array.isArray(detail.loc)
106
+ ? detail.loc.filter(item => typeof item === "string").join(".")
107
+ : null;
108
+ if (message && loc) {
109
+ return `${loc}: ${message}`;
110
+ }
111
+ return message;
112
+ }
@@ -0,0 +1,33 @@
1
+ export declare const DEFAULT_PUBLIC_BACKEND_URL = "https://api.quantbrasil.com.br";
2
+ export declare const CLI_CONFIG_FILENAME = "config.json";
3
+ export declare const CLI_API_KEY_PREFIX_FAMILY = "qb_live_";
4
+ export type CliAuthSource = "env" | "config" | "none";
5
+ export type CliBackendSource = "default" | "override";
6
+ export interface CliStoredConfig {
7
+ apiKey?: string;
8
+ }
9
+ export interface ResolvedCliAuth {
10
+ apiKey: string;
11
+ source: Exclude<CliAuthSource, "none">;
12
+ }
13
+ export interface CliStatusSnapshot {
14
+ backendUrl: string;
15
+ backendSource: CliBackendSource;
16
+ configPath: string;
17
+ storedApiKey: boolean;
18
+ authSource: CliAuthSource;
19
+ isReady: boolean;
20
+ }
21
+ export declare function resolveCliConfigPath(env?: NodeJS.ProcessEnv): string;
22
+ export declare function resolveCliBackendUrl(env?: NodeJS.ProcessEnv): string;
23
+ export declare function resolveCliBackendSource(env?: NodeJS.ProcessEnv): CliBackendSource;
24
+ export declare function readCliConfig(env?: NodeJS.ProcessEnv): Promise<CliStoredConfig>;
25
+ export declare function saveCliApiKey(apiKey: string, env?: NodeJS.ProcessEnv): Promise<string>;
26
+ export declare function clearCliStoredAuth(env?: NodeJS.ProcessEnv): Promise<{
27
+ configPath: string;
28
+ removed: boolean;
29
+ }>;
30
+ export declare function resolveCliAuth(env?: NodeJS.ProcessEnv): Promise<ResolvedCliAuth | null>;
31
+ export declare function resolveCliStatusSnapshot(env?: NodeJS.ProcessEnv): Promise<CliStatusSnapshot>;
32
+ export declare function normalizeCliApiKey(apiKey: string): string;
33
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/cli/config.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,0BAA0B,mCAAmC,CAAC;AAC3E,eAAO,MAAM,mBAAmB,gBAAgB,CAAC;AACjD,eAAO,MAAM,yBAAyB,aAAa,CAAC;AAEpD,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AACtD,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,UAAU,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,gBAAgB,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,aAAa,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,oBAAoB,CAClC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAGR;AAED,wBAAgB,oBAAoB,CAClC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAGR;AAED,wBAAgB,uBAAuB,CACrC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,gBAAgB,CAElB;AAED,wBAAsB,aAAa,CACjC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAAC,eAAe,CAAC,CAgC1B;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAAC,MAAM,CAAC,CAkBjB;AAED,wBAAsB,kBAAkB,CACtC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAUnD;AAED,wBAAsB,cAAc,CAClC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAkBjC;AAED,wBAAsB,wBAAwB,CAC5C,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAAC,iBAAiB,CAAC,CAa5B;AA2BD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAmBzD"}