@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
@@ -0,0 +1,148 @@
1
+ import { access, chmod, mkdir, readFile, rm, writeFile, } from "node:fs/promises";
2
+ import { homedir } from "node:os";
3
+ import { dirname, join } from "node:path";
4
+ import { createCliConfigError, createCliValidationError } from "./errors.js";
5
+ export const DEFAULT_PUBLIC_BACKEND_URL = "https://api.quantbrasil.com.br";
6
+ export const CLI_CONFIG_FILENAME = "config.json";
7
+ export const CLI_API_KEY_PREFIX_FAMILY = "qb_live_";
8
+ export function resolveCliConfigPath(env = process.env) {
9
+ const configHome = resolveCliConfigHome(env);
10
+ return join(configHome, "quantbrasil", CLI_CONFIG_FILENAME);
11
+ }
12
+ export function resolveCliBackendUrl(env = process.env) {
13
+ const override = env.QB_BACKEND_URL?.trim();
14
+ return stripTrailingSlash(override || DEFAULT_PUBLIC_BACKEND_URL);
15
+ }
16
+ export function resolveCliBackendSource(env = process.env) {
17
+ return env.QB_BACKEND_URL?.trim() ? "override" : "default";
18
+ }
19
+ export async function readCliConfig(env = process.env) {
20
+ const configPath = resolveCliConfigPath(env);
21
+ try {
22
+ const raw = await readFile(configPath, "utf8");
23
+ const parsed = JSON.parse(raw);
24
+ if (!isPlainObject(parsed)) {
25
+ throw createCliConfigError("root must be an object");
26
+ }
27
+ const apiKey = parsed.apiKey;
28
+ if (apiKey === undefined) {
29
+ return {};
30
+ }
31
+ if (typeof apiKey !== "string" || !apiKey.trim()) {
32
+ throw createCliConfigError("apiKey must be a non-empty string");
33
+ }
34
+ return {
35
+ apiKey: normalizeCliApiKey(apiKey),
36
+ };
37
+ }
38
+ catch (error) {
39
+ if (isMissingFileError(error)) {
40
+ return {};
41
+ }
42
+ throw createCliConfigError(`Invalid config file at ${configPath}. Fix or remove the file.`);
43
+ }
44
+ }
45
+ export async function saveCliApiKey(apiKey, env = process.env) {
46
+ const normalizedApiKey = normalizeApiKey(apiKey);
47
+ const configPath = resolveCliConfigPath(env);
48
+ await mkdir(dirname(configPath), {
49
+ recursive: true,
50
+ mode: 0o700,
51
+ });
52
+ await writeFile(configPath, JSON.stringify({ apiKey: normalizedApiKey }, null, 2).concat("\n"), {
53
+ mode: 0o600,
54
+ });
55
+ await chmod(configPath, 0o600);
56
+ return configPath;
57
+ }
58
+ export async function clearCliStoredAuth(env = process.env) {
59
+ const configPath = resolveCliConfigPath(env);
60
+ const removed = await fileExists(configPath);
61
+ await rm(configPath, { force: true });
62
+ return {
63
+ configPath,
64
+ removed,
65
+ };
66
+ }
67
+ export async function resolveCliAuth(env = process.env) {
68
+ const envApiKey = env.QUANTBRASIL_API_KEY?.trim();
69
+ if (envApiKey) {
70
+ return {
71
+ apiKey: normalizeCliApiKey(envApiKey),
72
+ source: "env",
73
+ };
74
+ }
75
+ const config = await readCliConfig(env);
76
+ if (config.apiKey) {
77
+ return {
78
+ apiKey: config.apiKey,
79
+ source: "config",
80
+ };
81
+ }
82
+ return null;
83
+ }
84
+ export async function resolveCliStatusSnapshot(env = process.env) {
85
+ const configPath = resolveCliConfigPath(env);
86
+ const config = await readCliConfig(env);
87
+ const resolvedAuth = await resolveCliAuth(env);
88
+ return {
89
+ backendUrl: resolveCliBackendUrl(env),
90
+ backendSource: resolveCliBackendSource(env),
91
+ configPath,
92
+ storedApiKey: Boolean(config.apiKey),
93
+ authSource: resolvedAuth?.source ?? "none",
94
+ isReady: resolvedAuth !== null,
95
+ };
96
+ }
97
+ function resolveCliConfigHome(env) {
98
+ const xdgConfigHome = env.XDG_CONFIG_HOME?.trim();
99
+ if (xdgConfigHome) {
100
+ return xdgConfigHome;
101
+ }
102
+ const home = env.HOME?.trim() || homedir();
103
+ if (!home) {
104
+ throw createCliConfigError("Could not resolve the HOME directory for the CLI.");
105
+ }
106
+ return join(home, ".config");
107
+ }
108
+ function normalizeApiKey(apiKey) {
109
+ const normalizedApiKey = apiKey.trim();
110
+ if (!normalizedApiKey) {
111
+ throw createCliValidationError("API key cannot be empty.");
112
+ }
113
+ return normalizeCliApiKey(normalizedApiKey);
114
+ }
115
+ export function normalizeCliApiKey(apiKey) {
116
+ const normalizedApiKey = apiKey.trim();
117
+ const keyPrefixSeparator = normalizedApiKey.indexOf(".");
118
+ if (!normalizedApiKey) {
119
+ throw createCliValidationError("API key cannot be empty.");
120
+ }
121
+ if (keyPrefixSeparator <= 0 ||
122
+ keyPrefixSeparator === normalizedApiKey.length - 1 ||
123
+ !normalizedApiKey.startsWith(CLI_API_KEY_PREFIX_FAMILY)) {
124
+ throw createCliValidationError("Invalid API key format. Use qb_live_<id>.<secret>.");
125
+ }
126
+ return normalizedApiKey;
127
+ }
128
+ function stripTrailingSlash(value) {
129
+ return value.endsWith("/") ? value.slice(0, -1) : value;
130
+ }
131
+ function isPlainObject(value) {
132
+ return typeof value === "object" && value !== null && !Array.isArray(value);
133
+ }
134
+ function isMissingFileError(error) {
135
+ return (error instanceof Error &&
136
+ "code" in error &&
137
+ typeof error.code === "string" &&
138
+ error.code === "ENOENT");
139
+ }
140
+ async function fileExists(path) {
141
+ try {
142
+ await access(path);
143
+ return true;
144
+ }
145
+ catch {
146
+ return false;
147
+ }
148
+ }
@@ -0,0 +1,40 @@
1
+ export declare const CLI_ERROR_CODES: readonly ["auth_required", "auth_failed", "backend_error", "backend_unavailable", "config_error", "mutation_failed", "network_error", "not_found", "rate_limited", "unexpected_error", "validation_error"];
2
+ export type CliErrorCode = (typeof CLI_ERROR_CODES)[number];
3
+ export type CliErrorCategory = "auth" | "backend" | "config" | "network" | "unexpected" | "validation";
4
+ export interface CliErrorOptions extends ErrorOptions {
5
+ category: CliErrorCategory;
6
+ exitCode?: number;
7
+ status?: number;
8
+ path?: string;
9
+ requestId?: string;
10
+ }
11
+ export interface CliErrorPayload {
12
+ ok: false;
13
+ error: {
14
+ code: CliErrorCode;
15
+ message: string;
16
+ category: CliErrorCategory;
17
+ exit_code: number;
18
+ status?: number;
19
+ path?: string;
20
+ request_id?: string;
21
+ };
22
+ }
23
+ export declare class CliError extends Error {
24
+ readonly code: CliErrorCode;
25
+ readonly category: CliErrorCategory;
26
+ readonly exitCode: number;
27
+ readonly status?: number;
28
+ readonly path?: string;
29
+ readonly requestId?: string;
30
+ constructor(code: CliErrorCode, message: string, options: CliErrorOptions);
31
+ }
32
+ export declare function createCliValidationError(message: string): CliError;
33
+ export declare function createCliConfigError(message: string): CliError;
34
+ export declare function createCliAuthRequiredError(message: string): CliError;
35
+ export declare function createCliMutationFailedError(message: string): CliError;
36
+ export declare function normalizeCliError(error: unknown): CliError;
37
+ export declare function shouldEmitJsonError(argv: readonly string[]): boolean;
38
+ export declare function formatCliErrorMessage(error: CliError): string;
39
+ export declare function buildCliErrorPayload(error: CliError): CliErrorPayload;
40
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/cli/errors.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,4MAYlB,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5D,MAAM,MAAM,gBAAgB,GACxB,MAAM,GACN,SAAS,GACT,QAAQ,GACR,SAAS,GACT,YAAY,GACZ,YAAY,CAAC;AAEjB,MAAM,WAAW,eAAgB,SAAQ,YAAY;IACnD,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE;QACL,IAAI,EAAE,YAAY,CAAC;QACnB,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,gBAAgB,CAAC;QAC3B,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED,qBAAa,QAAS,SAAQ,KAAK;IACjC,SAAgB,IAAI,EAAE,YAAY,CAAC;IACnC,SAAgB,QAAQ,EAAE,gBAAgB,CAAC;IAC3C,SAAgB,QAAQ,EAAE,MAAM,CAAC;IACjC,SAAgB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChC,SAAgB,IAAI,CAAC,EAAE,MAAM,CAAC;IAC9B,SAAgB,SAAS,CAAC,EAAE,MAAM,CAAC;gBAEvB,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe;CAU1E;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,CAIlE;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,CAI9D;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,CAIpE;AAED,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,CAItE;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,CAqC1D;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAEpE;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAE7D;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,QAAQ,GAAG,eAAe,CAwBrE"}
@@ -0,0 +1,122 @@
1
+ export const CLI_ERROR_CODES = [
2
+ "auth_required",
3
+ "auth_failed",
4
+ "backend_error",
5
+ "backend_unavailable",
6
+ "config_error",
7
+ "mutation_failed",
8
+ "network_error",
9
+ "not_found",
10
+ "rate_limited",
11
+ "unexpected_error",
12
+ "validation_error",
13
+ ];
14
+ export class CliError extends Error {
15
+ code;
16
+ category;
17
+ exitCode;
18
+ status;
19
+ path;
20
+ requestId;
21
+ constructor(code, message, options) {
22
+ super(message, options);
23
+ this.name = "CliError";
24
+ this.code = code;
25
+ this.category = options.category;
26
+ this.exitCode = options.exitCode ?? 1;
27
+ this.status = options.status;
28
+ this.path = options.path;
29
+ this.requestId = options.requestId;
30
+ }
31
+ }
32
+ export function createCliValidationError(message) {
33
+ return new CliError("validation_error", message, {
34
+ category: "validation",
35
+ });
36
+ }
37
+ export function createCliConfigError(message) {
38
+ return new CliError("config_error", message, {
39
+ category: "config",
40
+ });
41
+ }
42
+ export function createCliAuthRequiredError(message) {
43
+ return new CliError("auth_required", message, {
44
+ category: "auth",
45
+ });
46
+ }
47
+ export function createCliMutationFailedError(message) {
48
+ return new CliError("mutation_failed", message, {
49
+ category: "validation",
50
+ });
51
+ }
52
+ export function normalizeCliError(error) {
53
+ if (error instanceof CliError) {
54
+ return error;
55
+ }
56
+ if (isCommanderError(error)) {
57
+ return createCliValidationError(stripCommanderErrorPrefix(error.message));
58
+ }
59
+ if (error instanceof Error) {
60
+ if (error.name === "DeskConfigError") {
61
+ return createCliConfigError(error.message);
62
+ }
63
+ if (error.name === "DeskJsonCompatibilityError") {
64
+ return new CliError("validation_error", error.message, {
65
+ category: "validation",
66
+ cause: error,
67
+ });
68
+ }
69
+ if (isLikelyNetworkError(error)) {
70
+ return new CliError("network_error", error.message, {
71
+ category: "network",
72
+ cause: error,
73
+ });
74
+ }
75
+ return new CliError("unexpected_error", error.message, {
76
+ category: "unexpected",
77
+ cause: error,
78
+ });
79
+ }
80
+ return new CliError("unexpected_error", "Unexpected CLI failure.", {
81
+ category: "unexpected",
82
+ });
83
+ }
84
+ export function shouldEmitJsonError(argv) {
85
+ return argv.includes("--json");
86
+ }
87
+ export function formatCliErrorMessage(error) {
88
+ return `[${error.code}] ${error.message}`;
89
+ }
90
+ export function buildCliErrorPayload(error) {
91
+ const payload = {
92
+ ok: false,
93
+ error: {
94
+ code: error.code,
95
+ message: error.message,
96
+ category: error.category,
97
+ exit_code: error.exitCode,
98
+ },
99
+ };
100
+ if (error.status !== undefined) {
101
+ payload.error.status = error.status;
102
+ }
103
+ if (error.path !== undefined) {
104
+ payload.error.path = error.path;
105
+ }
106
+ if (error.requestId !== undefined) {
107
+ payload.error.request_id = error.requestId;
108
+ }
109
+ return payload;
110
+ }
111
+ function isCommanderError(error) {
112
+ return (error instanceof Error &&
113
+ "code" in error &&
114
+ typeof error.code === "string" &&
115
+ error.code.startsWith("commander."));
116
+ }
117
+ function stripCommanderErrorPrefix(message) {
118
+ return message.replace(/^error:\s*/i, "");
119
+ }
120
+ function isLikelyNetworkError(error) {
121
+ return (error.name === "TypeError" && /fetch|network|failed/i.test(error.message));
122
+ }
@@ -0,0 +1,30 @@
1
+ import { Command } from "commander";
2
+ import { type CapabilitiesCommandIO, runCapabilitiesCommand } from "../commands/capabilities.js";
3
+ import { runMarketAssetsCommand, runMarketPriceCommand } from "../commands/market.js";
4
+ import { runInitCommand } from "../commands/init.js";
5
+ import { runPortfolioAddAssetsCommand, runPortfolioCreateCommand, runPortfolioGetCommand, runPortfolioListCommand, runPortfolioRemoveAssetsCommand, runPortfolioRenameCommand } from "../commands/portfolios.js";
6
+ import { runSkillsInstallCommand } from "../commands/skills.js";
7
+ import { runStatusCommand } from "../commands/status.js";
8
+ import { type TerminalWriter } from "./terminal.js";
9
+ export interface CliProgramOptions {
10
+ io?: CapabilitiesCommandIO;
11
+ env?: NodeJS.ProcessEnv;
12
+ fetch?: typeof fetch;
13
+ prompt?: (promptLabel: string) => Promise<string>;
14
+ stderr?: TerminalWriter;
15
+ suppressCommanderErrors?: boolean;
16
+ }
17
+ export interface CliRunOptions extends CliProgramOptions {
18
+ stderr?: TerminalWriter;
19
+ }
20
+ export declare function createCliProgram(options?: CliProgramOptions): Command;
21
+ export declare function run(argv?: string[], options?: CliRunOptions): Promise<void>;
22
+ export { runBetaCommand, runHistoricalReturnCommand, runVarCommand, } from "../commands/analytics.js";
23
+ export { runAuthLoginCommand, runAuthLogoutCommand } from "../commands/auth.js";
24
+ export { runAssetOverviewCommand } from "../commands/assets.js";
25
+ export { runCapabilitiesCommand, runStatusCommand };
26
+ export { runInitCommand };
27
+ export { runMarketAssetsCommand, runMarketPriceCommand };
28
+ export { runPortfolioAddAssetsCommand, runPortfolioCreateCommand, runPortfolioGetCommand, runPortfolioListCommand, runPortfolioRemoveAssetsCommand, runPortfolioRenameCommand, };
29
+ export { runSkillsInstallCommand };
30
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAapC,OAAO,EACL,KAAK,qBAAqB,EAE1B,sBAAsB,EACvB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAGL,sBAAsB,EACtB,qBAAqB,EACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAGL,cAAc,EACf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAGL,4BAA4B,EAC5B,yBAAyB,EACzB,sBAAsB,EACtB,uBAAuB,EACvB,+BAA+B,EAC/B,yBAAyB,EAC1B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAGL,uBAAuB,EACxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAGL,gBAAgB,EACjB,MAAM,uBAAuB,CAAC;AAO/B,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAEvE,MAAM,WAAW,iBAAiB;IAChC,EAAE,CAAC,EAAE,qBAAqB,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;AAED,MAAM,WAAW,aAAc,SAAQ,iBAAiB;IACtD,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB;AAED,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CA+DzE;AAED,wBAAsB,GAAG,CACvB,IAAI,WAAe,EACnB,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,IAAI,CAAC,CA0Bf;AAiBD,OAAO,EACL,cAAc,EACd,0BAA0B,EAC1B,aAAa,GACd,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAChF,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,CAAC;AAC1B,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,CAAC;AACzD,OAAO,EACL,4BAA4B,EAC5B,yBAAyB,EACzB,sBAAsB,EACtB,uBAAuB,EACvB,+BAA+B,EAC/B,yBAAyB,GAC1B,CAAC;AACF,OAAO,EAAE,uBAAuB,EAAE,CAAC"}
@@ -0,0 +1,112 @@
1
+ import { Command } from "commander";
2
+ import { registerAnalyticsCommands, } from "../commands/analytics.js";
3
+ import { registerAssetsCommands, } from "../commands/assets.js";
4
+ import { registerAuthCommands, } from "../commands/auth.js";
5
+ import { registerCapabilitiesCommand, runCapabilitiesCommand, } from "../commands/capabilities.js";
6
+ import { registerMarketCommands, runMarketAssetsCommand, runMarketPriceCommand, } from "../commands/market.js";
7
+ import { registerInitCommand, runInitCommand, } from "../commands/init.js";
8
+ import { registerPortfoliosCommands, runPortfolioAddAssetsCommand, runPortfolioCreateCommand, runPortfolioGetCommand, runPortfolioListCommand, runPortfolioRemoveAssetsCommand, runPortfolioRenameCommand, } from "../commands/portfolios.js";
9
+ import { registerSkillsCommands, runSkillsInstallCommand, } from "../commands/skills.js";
10
+ import { registerStatusFlag, runStatusCommand, } from "../commands/status.js";
11
+ import { buildCliErrorPayload, formatCliErrorMessage, normalizeCliError, shouldEmitJsonError, } from "./errors.js";
12
+ import { styleErrorMessage } from "./terminal.js";
13
+ export function createCliProgram(options = {}) {
14
+ const program = new Command();
15
+ const authContext = {
16
+ io: options.io,
17
+ env: options.env,
18
+ fetch: options.fetch,
19
+ };
20
+ const assetsContext = {
21
+ io: options.io,
22
+ env: options.env,
23
+ fetch: options.fetch,
24
+ };
25
+ const analyticsContext = {
26
+ io: options.io,
27
+ env: options.env,
28
+ fetch: options.fetch,
29
+ };
30
+ const marketContext = {
31
+ io: options.io,
32
+ env: options.env,
33
+ fetch: options.fetch,
34
+ };
35
+ const initContext = {
36
+ io: options.io,
37
+ env: options.env,
38
+ fetch: options.fetch,
39
+ prompt: options.prompt,
40
+ };
41
+ const portfoliosContext = {
42
+ io: options.io,
43
+ env: options.env,
44
+ fetch: options.fetch,
45
+ };
46
+ const skillsContext = {
47
+ io: options.io,
48
+ env: options.env,
49
+ };
50
+ const statusContext = {
51
+ io: options.io,
52
+ env: options.env,
53
+ };
54
+ program
55
+ .name("quantbrasil")
56
+ .description("Public QuantBrasil CLI for deterministic operations")
57
+ .version("0.0.0")
58
+ .exitOverride()
59
+ .showHelpAfterError()
60
+ .showSuggestionAfterError();
61
+ configureCommanderOutput(program, options);
62
+ registerCapabilitiesCommand(program, options.io);
63
+ registerAuthCommands(program, authContext);
64
+ registerAssetsCommands(program, assetsContext);
65
+ registerAnalyticsCommands(program, analyticsContext);
66
+ registerInitCommand(program, initContext);
67
+ registerMarketCommands(program, marketContext);
68
+ registerPortfoliosCommands(program, portfoliosContext);
69
+ registerSkillsCommands(program, skillsContext);
70
+ registerStatusFlag(program, statusContext);
71
+ return program;
72
+ }
73
+ export async function run(argv = process.argv, options = {}) {
74
+ const emitJsonError = shouldEmitJsonError(argv);
75
+ const program = createCliProgram({
76
+ ...options,
77
+ suppressCommanderErrors: emitJsonError,
78
+ });
79
+ const stderr = options.stderr ?? process.stderr;
80
+ const env = options.env ?? process.env;
81
+ try {
82
+ await program.parseAsync(argv);
83
+ }
84
+ catch (error) {
85
+ const cliError = normalizeCliError(error);
86
+ if (emitJsonError) {
87
+ stderr.write(`${JSON.stringify(buildCliErrorPayload(cliError), null, 2)}\n`);
88
+ }
89
+ else {
90
+ stderr.write(`${styleErrorMessage(formatCliErrorMessage(cliError), stderr, env)}\n`);
91
+ }
92
+ process.exitCode = cliError.exitCode;
93
+ }
94
+ }
95
+ function configureCommanderOutput(program, options) {
96
+ const stderr = options.stderr ?? process.stderr;
97
+ program.configureOutput({
98
+ writeErr: chunk => {
99
+ if (!options.suppressCommanderErrors) {
100
+ stderr.write(chunk);
101
+ }
102
+ },
103
+ });
104
+ }
105
+ export { runBetaCommand, runHistoricalReturnCommand, runVarCommand, } from "../commands/analytics.js";
106
+ export { runAuthLoginCommand, runAuthLogoutCommand } from "../commands/auth.js";
107
+ export { runAssetOverviewCommand } from "../commands/assets.js";
108
+ export { runCapabilitiesCommand, runStatusCommand };
109
+ export { runInitCommand };
110
+ export { runMarketAssetsCommand, runMarketPriceCommand };
111
+ export { runPortfolioAddAssetsCommand, runPortfolioCreateCommand, runPortfolioGetCommand, runPortfolioListCommand, runPortfolioRemoveAssetsCommand, runPortfolioRenameCommand, };
112
+ export { runSkillsInstallCommand };
@@ -0,0 +1,2 @@
1
+ export declare function promptForSecret(promptLabel: string): Promise<string>;
2
+ //# sourceMappingURL=prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/cli/prompt.ts"],"names":[],"mappings":"AAyBA,wBAAsB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAwB1E"}
@@ -0,0 +1,40 @@
1
+ import { stdin as input, stdout as output } from "node:process";
2
+ import { createInterface } from "node:readline/promises";
3
+ import { Writable } from "node:stream";
4
+ import { createCliConfigError } from "./errors.js";
5
+ class MutedWritable extends Writable {
6
+ target;
7
+ muted = false;
8
+ constructor(target) {
9
+ super();
10
+ this.target = target;
11
+ }
12
+ _write(chunk, encoding, callback) {
13
+ if (!this.muted) {
14
+ this.target.write(chunk, encoding);
15
+ }
16
+ callback();
17
+ }
18
+ }
19
+ export async function promptForSecret(promptLabel) {
20
+ if (!input.isTTY || !output.isTTY) {
21
+ throw createCliConfigError("Interactive setup requires a TTY. Pass --api-key or set QUANTBRASIL_API_KEY.");
22
+ }
23
+ const mutedOutput = new MutedWritable(output);
24
+ const readline = createInterface({
25
+ input,
26
+ output: mutedOutput,
27
+ terminal: true,
28
+ });
29
+ try {
30
+ const answerPromise = readline.question(promptLabel);
31
+ mutedOutput.muted = true;
32
+ const answer = await answerPromise;
33
+ output.write("\n");
34
+ return answer.trim();
35
+ }
36
+ finally {
37
+ mutedOutput.muted = false;
38
+ readline.close();
39
+ }
40
+ }
@@ -0,0 +1,26 @@
1
+ export type SupportedSkillClientId = "codex" | "claude" | "agents";
2
+ export interface SkillInstallTarget {
3
+ id: SupportedSkillClientId;
4
+ label: string;
5
+ rootDir: string;
6
+ skillsDir: string;
7
+ installDir: string;
8
+ }
9
+ export interface InstalledSkillTarget {
10
+ id: SupportedSkillClientId;
11
+ label: string;
12
+ installDir: string;
13
+ }
14
+ export interface SkippedSkillTarget {
15
+ id: SupportedSkillClientId;
16
+ label: string;
17
+ rootDir: string;
18
+ }
19
+ export interface SkillInstallResult {
20
+ installed: InstalledSkillTarget[];
21
+ skipped: SkippedSkillTarget[];
22
+ }
23
+ export declare function installBundledSkillEverywhere(env?: NodeJS.ProcessEnv): Promise<SkillInstallResult>;
24
+ export declare function resolveSkillInstallTargets(env?: NodeJS.ProcessEnv): SkillInstallTarget[];
25
+ export declare function resolveBundledSkillSourcePath(): string;
26
+ //# sourceMappingURL=skills.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/cli/skills.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,sBAAsB,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEnE,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,sBAAsB,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,sBAAsB,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,sBAAsB,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,oBAAoB,EAAE,CAAC;IAClC,OAAO,EAAE,kBAAkB,EAAE,CAAC;CAC/B;AAcD,wBAAsB,6BAA6B,CACjD,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAAC,kBAAkB,CAAC,CAmD7B;AAED,wBAAgB,0BAA0B,CACxC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,kBAAkB,EAAE,CAetB;AAED,wBAAgB,6BAA6B,IAAI,MAAM,CAEtD"}
@@ -0,0 +1,94 @@
1
+ import { access, cp, mkdir, rm } from "node:fs/promises";
2
+ import { homedir } from "node:os";
3
+ import { dirname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { createCliConfigError } from "./errors.js";
6
+ const BUNDLED_SKILL_NAME = "quantbrasil";
7
+ const AGENT_SKILLS_CONVENTION_ID = "agents";
8
+ const SUPPORTED_SKILL_CLIENTS = [
9
+ { id: "codex", label: "Codex", rootDirName: ".codex" },
10
+ { id: "claude", label: "Claude", rootDirName: ".claude" },
11
+ { id: "agents", label: "Agent Skills", rootDirName: ".agents" },
12
+ ];
13
+ export async function installBundledSkillEverywhere(env = process.env) {
14
+ const bundledSkillPath = resolveBundledSkillSourcePath();
15
+ await assertBundledSkillExists(bundledSkillPath);
16
+ const targets = resolveSkillInstallTargets(env);
17
+ const installed = [];
18
+ const skipped = [];
19
+ for (const target of targets) {
20
+ if (target.id !== AGENT_SKILLS_CONVENTION_ID &&
21
+ !(await pathExists(target.rootDir))) {
22
+ skipped.push({
23
+ id: target.id,
24
+ label: target.label,
25
+ rootDir: target.rootDir,
26
+ });
27
+ continue;
28
+ }
29
+ await mkdir(dirname(target.installDir), {
30
+ recursive: true,
31
+ mode: 0o700,
32
+ });
33
+ await rm(target.installDir, {
34
+ recursive: true,
35
+ force: true,
36
+ });
37
+ await cp(bundledSkillPath, target.installDir, {
38
+ recursive: true,
39
+ });
40
+ installed.push({
41
+ id: target.id,
42
+ label: target.label,
43
+ installDir: target.installDir,
44
+ });
45
+ }
46
+ if (installed.length === 0) {
47
+ const checkedRoots = targets.map(target => target.rootDir).join(", ");
48
+ throw createCliConfigError(`No supported agent clients detected. Checked: ${checkedRoots}.`);
49
+ }
50
+ return {
51
+ installed,
52
+ skipped,
53
+ };
54
+ }
55
+ export function resolveSkillInstallTargets(env = process.env) {
56
+ const home = resolveCliHomeDirectory(env);
57
+ return SUPPORTED_SKILL_CLIENTS.map(client => {
58
+ const rootDir = join(home, client.rootDirName);
59
+ const skillsDir = join(rootDir, "skills");
60
+ return {
61
+ id: client.id,
62
+ label: client.label,
63
+ rootDir,
64
+ skillsDir,
65
+ installDir: join(skillsDir, BUNDLED_SKILL_NAME),
66
+ };
67
+ });
68
+ }
69
+ export function resolveBundledSkillSourcePath() {
70
+ return fileURLToPath(new URL("../../skills/quantbrasil", import.meta.url));
71
+ }
72
+ async function assertBundledSkillExists(skillPath) {
73
+ const skillEntryPath = join(skillPath, "SKILL.md");
74
+ if (await pathExists(skillEntryPath)) {
75
+ return;
76
+ }
77
+ throw createCliConfigError(`Bundled QuantBrasil skill not found at ${skillEntryPath}. Reinstall the CLI package.`);
78
+ }
79
+ function resolveCliHomeDirectory(env) {
80
+ const home = env.HOME?.trim() || homedir();
81
+ if (!home) {
82
+ throw createCliConfigError("Could not resolve the HOME directory for skill install.");
83
+ }
84
+ return home;
85
+ }
86
+ async function pathExists(path) {
87
+ try {
88
+ await access(path);
89
+ return true;
90
+ }
91
+ catch {
92
+ return false;
93
+ }
94
+ }
@@ -0,0 +1,18 @@
1
+ export interface TerminalWriter {
2
+ write(chunk: string): boolean;
3
+ isTTY?: boolean;
4
+ }
5
+ export interface TerminalTheme {
6
+ enabled: boolean;
7
+ accent(text: string): string;
8
+ bold(text: string): string;
9
+ dim(text: string): string;
10
+ success(text: string): string;
11
+ warning(text: string): string;
12
+ danger(text: string): string;
13
+ info(text: string): string;
14
+ label(text: string): string;
15
+ }
16
+ export declare function createTerminalTheme(writer: TerminalWriter, env?: NodeJS.ProcessEnv): TerminalTheme;
17
+ export declare function styleErrorMessage(message: string, writer: TerminalWriter, env?: NodeJS.ProcessEnv): string;
18
+ //# sourceMappingURL=terminal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../src/cli/terminal.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CAC7B;AAUD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,cAAc,EACtB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,aAAa,CAef;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,cAAc,EACtB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAGR"}