@quantbrasil/cli 0.1.0-beta.6 → 0.1.0-beta.7

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/README.md CHANGED
@@ -72,6 +72,39 @@ quantbrasil holdings historical-return 182 --from 2025-01-01 --to 2026-01-01
72
72
  quantbrasil holdings historical-return 182 --period 1y
73
73
  quantbrasil holdings beta 182 --years 3
74
74
  quantbrasil holdings var 182 --years 1 --confidence 95
75
+ quantbrasil screening universes
76
+ quantbrasil screening run --system acoes-mais-liquidas --query-file ./screening.json
77
+ quantbrasil screening run --watchlist 93 --query-file ./screening.json --limit 25
78
+ cat ./screening.json | quantbrasil screening run --holding 182 --query-file -
79
+ ```
80
+
81
+ Example `screening.json`:
82
+
83
+ ```json
84
+ {
85
+ "query": {
86
+ "comparison": {
87
+ "left": {
88
+ "indicator": {
89
+ "name": "RSI",
90
+ "timeframe": "D1",
91
+ "offset": 0,
92
+ "params": {
93
+ "period": 14
94
+ }
95
+ }
96
+ },
97
+ "operator": "lt",
98
+ "right": {
99
+ "constant": {
100
+ "value": 30
101
+ }
102
+ }
103
+ }
104
+ },
105
+ "limit": 50,
106
+ "sort": "ticker"
107
+ }
75
108
  ```
76
109
 
77
110
  ## Local config
@@ -3,6 +3,7 @@ import { type CapabilitiesCommandIO, runCapabilitiesCommand } from "../commands/
3
3
  import { runMarketAssetsCommand, runMarketPriceCommand } from "../commands/market.js";
4
4
  import { runInitCommand } from "../commands/init.js";
5
5
  import { runHoldingCreateCommand, runHoldingBetaCommand, runHoldingGetCommand, runHoldingHistoricalReturnCommand, runHoldingListCommand, runHoldingRenameCommand, runHoldingSetPositionsCommand, runHoldingSetTargetsCommand, runHoldingVarCommand, runWatchlistAddAssetsCommand, runWatchlistCreateCommand, runWatchlistGetCommand, runWatchlistListCommand, runWatchlistRemoveAssetsCommand, runWatchlistRenameCommand } from "../commands/portfolios.js";
6
+ import { runScreeningRunCommand, runScreeningUniversesCommand } from "../commands/screening.js";
6
7
  import { runSkillsInstallCommand } from "../commands/skills.js";
7
8
  import { runStatusCommand } from "../commands/status.js";
8
9
  import { type TerminalWriter } from "./terminal.js";
@@ -25,6 +26,7 @@ export { runAssetOverviewCommand } from "../commands/assets.js";
25
26
  export { runCapabilitiesCommand, runStatusCommand };
26
27
  export { runInitCommand };
27
28
  export { runMarketAssetsCommand, runMarketPriceCommand };
29
+ export { runScreeningRunCommand, runScreeningUniversesCommand };
28
30
  export { runHoldingBetaCommand, runHoldingCreateCommand, runHoldingGetCommand, runHoldingHistoricalReturnCommand, runHoldingListCommand, runHoldingRenameCommand, runHoldingSetPositionsCommand, runHoldingSetTargetsCommand, runHoldingVarCommand, runWatchlistAddAssetsCommand, runWatchlistCreateCommand, runWatchlistGetCommand, runWatchlistListCommand, runWatchlistRemoveAssetsCommand, runWatchlistRenameCommand, };
29
31
  export { runSkillsInstallCommand };
30
32
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,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,uBAAuB,EACvB,qBAAqB,EACrB,oBAAoB,EACpB,iCAAiC,EACjC,qBAAqB,EACrB,uBAAuB,EACvB,6BAA6B,EAC7B,2BAA2B,EAC3B,oBAAoB,EACpB,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;AAQvE,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,GAAG,CAAC,EAAE,IAAI,CAAC;IACX,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,CA2DzE;AAeD,wBAAsB,GAAG,CACvB,IAAI,WAAe,EACnB,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,IAAI,CAAC,CA8Bf;AAoCD,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAC7B,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,qBAAqB,EACrB,uBAAuB,EACvB,oBAAoB,EACpB,iCAAiC,EACjC,qBAAqB,EACrB,uBAAuB,EACvB,6BAA6B,EAC7B,2BAA2B,EAC3B,oBAAoB,EACpB,4BAA4B,EAC5B,yBAAyB,EACzB,sBAAsB,EACtB,uBAAuB,EACvB,+BAA+B,EAC/B,yBAAyB,GAC1B,CAAC;AACF,OAAO,EAAE,uBAAuB,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,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,uBAAuB,EACvB,qBAAqB,EACrB,oBAAoB,EACpB,iCAAiC,EACjC,qBAAqB,EACrB,uBAAuB,EACvB,6BAA6B,EAC7B,2BAA2B,EAC3B,oBAAoB,EACpB,4BAA4B,EAC5B,yBAAyB,EACzB,sBAAsB,EACtB,uBAAuB,EACvB,+BAA+B,EAC/B,yBAAyB,EAC1B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAGL,sBAAsB,EACtB,4BAA4B,EAC7B,MAAM,0BAA0B,CAAC;AAClC,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;AAQvE,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,GAAG,CAAC,EAAE,IAAI,CAAC;IACX,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,CAiEzE;AAeD,wBAAsB,GAAG,CACvB,IAAI,WAAe,EACnB,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,IAAI,CAAC,CA8Bf;AAoCD,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAC7B,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,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,CAAC;AAChE,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,oBAAoB,EACpB,iCAAiC,EACjC,qBAAqB,EACrB,uBAAuB,EACvB,6BAA6B,EAC7B,2BAA2B,EAC3B,oBAAoB,EACpB,4BAA4B,EAC5B,yBAAyB,EACzB,sBAAsB,EACtB,uBAAuB,EACvB,+BAA+B,EAC/B,yBAAyB,GAC1B,CAAC;AACF,OAAO,EAAE,uBAAuB,EAAE,CAAC"}
package/dist/cli/index.js CHANGED
@@ -6,6 +6,7 @@ import { registerCapabilitiesCommand, runCapabilitiesCommand, } from "../command
6
6
  import { registerMarketCommands, runMarketAssetsCommand, runMarketPriceCommand, } from "../commands/market.js";
7
7
  import { registerInitCommand, runInitCommand, } from "../commands/init.js";
8
8
  import { registerPortfoliosCommands, runHoldingCreateCommand, runHoldingBetaCommand, runHoldingGetCommand, runHoldingHistoricalReturnCommand, runHoldingListCommand, runHoldingRenameCommand, runHoldingSetPositionsCommand, runHoldingSetTargetsCommand, runHoldingVarCommand, runWatchlistAddAssetsCommand, runWatchlistCreateCommand, runWatchlistGetCommand, runWatchlistListCommand, runWatchlistRemoveAssetsCommand, runWatchlistRenameCommand, } from "../commands/portfolios.js";
9
+ import { registerScreeningCommands, runScreeningRunCommand, runScreeningUniversesCommand, } from "../commands/screening.js";
9
10
  import { registerSkillsCommands, runSkillsInstallCommand, } from "../commands/skills.js";
10
11
  import { registerStatusFlag, runStatusCommand, } from "../commands/status.js";
11
12
  import { buildCliErrorPayload, formatCliErrorMessage, normalizeCliError, shouldEmitJsonError, } from "./errors.js";
@@ -42,6 +43,11 @@ export function createCliProgram(options = {}) {
42
43
  fetch: options.fetch,
43
44
  now: options.now,
44
45
  };
46
+ const screeningContext = {
47
+ io: options.io,
48
+ env: options.env,
49
+ fetch: options.fetch,
50
+ };
45
51
  const skillsContext = {
46
52
  io: options.io,
47
53
  env: options.env,
@@ -65,6 +71,7 @@ export function createCliProgram(options = {}) {
65
71
  registerInitCommand(program, initContext);
66
72
  registerMarketCommands(program, marketContext);
67
73
  registerPortfoliosCommands(program, portfoliosContext);
74
+ registerScreeningCommands(program, screeningContext);
68
75
  registerSkillsCommands(program, skillsContext);
69
76
  registerStatusFlag(program, statusContext);
70
77
  return program;
@@ -131,5 +138,6 @@ export { runAssetOverviewCommand } from "../commands/assets.js";
131
138
  export { runCapabilitiesCommand, runStatusCommand };
132
139
  export { runInitCommand };
133
140
  export { runMarketAssetsCommand, runMarketPriceCommand };
141
+ export { runScreeningRunCommand, runScreeningUniversesCommand };
134
142
  export { runHoldingBetaCommand, runHoldingCreateCommand, runHoldingGetCommand, runHoldingHistoricalReturnCommand, runHoldingListCommand, runHoldingRenameCommand, runHoldingSetPositionsCommand, runHoldingSetTargetsCommand, runHoldingVarCommand, runWatchlistAddAssetsCommand, runWatchlistCreateCommand, runWatchlistGetCommand, runWatchlistListCommand, runWatchlistRemoveAssetsCommand, runWatchlistRenameCommand, };
135
143
  export { runSkillsInstallCommand };
@@ -0,0 +1,76 @@
1
+ import { Command } from "commander";
2
+ import type { JsonValue } from "../vendor/core/index.js";
3
+ import { type CliInvokeContext } from "../cli/client.js";
4
+ import { type TerminalWriter } from "../cli/terminal.js";
5
+ export interface ScreeningCommandIO {
6
+ stdout: TerminalWriter;
7
+ }
8
+ export interface ScreeningUniversesCommandOptions {
9
+ json?: boolean;
10
+ }
11
+ export interface ScreeningRunCommandOptions {
12
+ system?: string;
13
+ watchlist?: string;
14
+ holding?: string;
15
+ queryFile?: string;
16
+ limit?: string;
17
+ sort?: string;
18
+ json?: boolean;
19
+ }
20
+ export interface ScreeningUniverseOut {
21
+ [key: string]: JsonValue;
22
+ id: number;
23
+ name: string;
24
+ kind: "SYSTEM" | "WATCHLIST" | "HOLDING";
25
+ slug: string | null;
26
+ symbol_count: number;
27
+ }
28
+ export interface ScreeningUniversesResponse {
29
+ [key: string]: JsonValue;
30
+ ok: boolean;
31
+ system: ScreeningUniverseOut[];
32
+ watchlists: ScreeningUniverseOut[];
33
+ holdings: ScreeningUniverseOut[];
34
+ total: number;
35
+ }
36
+ export interface IndicatorResult {
37
+ [key: string]: JsonValue;
38
+ value: number;
39
+ display_name: string;
40
+ unit: string | null;
41
+ context: {
42
+ [key: string]: JsonValue;
43
+ } | null;
44
+ }
45
+ export interface ScreenerResultItem {
46
+ [key: string]: JsonValue;
47
+ ticker: string;
48
+ price: number;
49
+ indicators: Record<string, IndicatorResult>;
50
+ }
51
+ export interface ScreenerResponse {
52
+ [key: string]: JsonValue;
53
+ count: number;
54
+ results: ScreenerResultItem[];
55
+ }
56
+ export interface ScreeningRunResponse {
57
+ [key: string]: JsonValue;
58
+ ok: boolean;
59
+ summary_markdown: string;
60
+ universe: ScreeningUniverseOut;
61
+ result: ScreenerResponse;
62
+ }
63
+ export interface ScreeningCommandContext extends CliInvokeContext {
64
+ io?: ScreeningCommandIO;
65
+ }
66
+ type JsonRecord = {
67
+ [key: string]: JsonValue;
68
+ };
69
+ export declare function registerScreeningCommands(program: Command, context?: ScreeningCommandContext): void;
70
+ export declare function runScreeningUniversesCommand(options: ScreeningUniversesCommandOptions, context?: ScreeningCommandContext): Promise<void>;
71
+ export declare function runScreeningRunCommand(options: ScreeningRunCommandOptions, context?: ScreeningCommandContext): Promise<void>;
72
+ export declare function buildScreeningRunInput(options: ScreeningRunCommandOptions): Promise<JsonRecord>;
73
+ export declare function formatScreeningUniversesHuman(data: ScreeningUniversesResponse, theme?: import("../cli/terminal.js").TerminalTheme): string;
74
+ export declare function formatScreeningRunHuman(data: ScreeningRunResponse, theme?: import("../cli/terminal.js").TerminalTheme): string;
75
+ export {};
76
+ //# sourceMappingURL=screening.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screening.d.ts","sourceRoot":"","sources":["../../src/commands/screening.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,298 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { screeningSortValues } from "../vendor/core/capabilities/index.js";
3
+ import { invokeCliCapability } from "../cli/client.js";
4
+ import { createCliValidationError } from "../cli/errors.js";
5
+ import { createTerminalTheme } from "../cli/terminal.js";
6
+ export function registerScreeningCommands(program, context = {}) {
7
+ const screeningCommand = program
8
+ .command("screening")
9
+ .description("Executa screening de indicadores em universos salvos");
10
+ screeningCommand
11
+ .command("universes")
12
+ .description("Lista universos salvos disponíveis para screening de indicadores")
13
+ .option("--json", "Exibe saída JSON")
14
+ .action(async (options) => {
15
+ await runScreeningUniversesCommand(options, context);
16
+ });
17
+ screeningCommand
18
+ .command("run")
19
+ .description("Executa screening de indicadores a partir de um ScreenerRequest JSON")
20
+ .option("--system <slug>", "Slug da carteira do sistema")
21
+ .option("--watchlist <id>", "ID da watchlist")
22
+ .option("--holding <id>", "ID da carteira")
23
+ .requiredOption("--query-file <path>", "Caminho para um ScreenerRequest JSON completo, ou - para stdin")
24
+ .option("--limit <limit>", "Sobrescreve o limit de topo do ScreenerRequest")
25
+ .option("--sort <sort>", "Sobrescreve o sort de topo do ScreenerRequest")
26
+ .option("--json", "Exibe saída JSON")
27
+ .action(async (options) => {
28
+ await runScreeningRunCommand(options, context);
29
+ });
30
+ }
31
+ export async function runScreeningUniversesCommand(options, context = {}) {
32
+ const stdout = context.io?.stdout ?? process.stdout;
33
+ const theme = createTerminalTheme(stdout, context.env ?? process.env);
34
+ const response = await invokeCliCapability({
35
+ capability: "screening.universes",
36
+ env: context.env,
37
+ fetch: context.fetch,
38
+ });
39
+ if (options.json) {
40
+ stdout.write(`${JSON.stringify(response.data, null, 2)}\n`);
41
+ return;
42
+ }
43
+ stdout.write(`${formatScreeningUniversesHuman(response.data, theme)}\n`);
44
+ }
45
+ export async function runScreeningRunCommand(options, context = {}) {
46
+ const stdout = context.io?.stdout ?? process.stdout;
47
+ const theme = createTerminalTheme(stdout, context.env ?? process.env);
48
+ const input = await buildScreeningRunInput(options);
49
+ const response = await invokeCliCapability({
50
+ capability: "screening.run",
51
+ input,
52
+ env: context.env,
53
+ fetch: context.fetch,
54
+ });
55
+ if (options.json) {
56
+ stdout.write(`${JSON.stringify(response.data, null, 2)}\n`);
57
+ return;
58
+ }
59
+ stdout.write(`${formatScreeningRunHuman(response.data, theme)}\n`);
60
+ }
61
+ export async function buildScreeningRunInput(options) {
62
+ const selector = parseScreeningSelector(options);
63
+ const queryFile = normalizeRequiredPath(options.queryFile);
64
+ const request = await readScreenerRequest(queryFile);
65
+ if (options.limit !== undefined) {
66
+ request.limit = parseLimitOption(options.limit);
67
+ }
68
+ if (options.sort !== undefined) {
69
+ request.sort = parseSortOption(options.sort);
70
+ }
71
+ return {
72
+ ...selector,
73
+ request,
74
+ };
75
+ }
76
+ export function formatScreeningUniversesHuman(data, theme = createTerminalTheme(process.stdout)) {
77
+ const lines = [
78
+ theme.label("Universos de screening"),
79
+ "",
80
+ `${theme.label("Total:")} ${formatInteger(data.total)}`,
81
+ ];
82
+ appendUniverseGroup(lines, theme, "Carteiras do sistema", data.system);
83
+ appendUniverseGroup(lines, theme, "Watchlists", data.watchlists);
84
+ appendUniverseGroup(lines, theme, "Carteiras", data.holdings);
85
+ return lines.join("\n");
86
+ }
87
+ export function formatScreeningRunHuman(data, theme = createTerminalTheme(process.stdout)) {
88
+ const lines = [
89
+ theme.label("Screening de indicadores"),
90
+ "",
91
+ `${theme.bold(data.universe.name)} ${theme.dim(`- ${formatUniverseKind(data.universe.kind)}`)}`,
92
+ `${theme.label("Seletor:")} ${formatUniverseSelector(data.universe)}`,
93
+ `${theme.label("Ativos encontrados:")} ${formatInteger(data.result.count)}`,
94
+ ];
95
+ if (data.summary_markdown.trim()) {
96
+ lines.push("");
97
+ lines.push(data.summary_markdown);
98
+ }
99
+ if (data.result.results.length === 0) {
100
+ lines.push("");
101
+ lines.push("Nenhum ativo encontrado.");
102
+ return lines.join("\n");
103
+ }
104
+ const indicatorKeys = collectIndicatorKeys(data.result.results);
105
+ const visibleIndicatorKeys = indicatorKeys.slice(0, 4);
106
+ lines.push("");
107
+ lines.push(formatResultTable(data.result.results, visibleIndicatorKeys, theme));
108
+ if (indicatorKeys.length > visibleIndicatorKeys.length) {
109
+ lines.push("");
110
+ lines.push("Use --json para inspecionar todas as colunas de indicadores.");
111
+ }
112
+ return lines.join("\n");
113
+ }
114
+ function parseScreeningSelector(options) {
115
+ const selectorCount = [
116
+ options.system,
117
+ options.watchlist,
118
+ options.holding,
119
+ ].filter(value => value !== undefined).length;
120
+ if (selectorCount !== 1) {
121
+ throw createCliValidationError("Use exatamente um seletor: --system, --watchlist ou --holding.");
122
+ }
123
+ if (options.system !== undefined) {
124
+ const systemSlug = options.system.trim().toLowerCase();
125
+ if (!systemSlug) {
126
+ throw createCliValidationError("O slug da carteira do sistema é obrigatório.");
127
+ }
128
+ return { system_slug: systemSlug };
129
+ }
130
+ if (options.watchlist !== undefined) {
131
+ return {
132
+ watchlist_id: parsePositiveInteger(options.watchlist, "ID da watchlist"),
133
+ };
134
+ }
135
+ return {
136
+ holding_id: parsePositiveInteger(String(options.holding), "ID da carteira"),
137
+ };
138
+ }
139
+ function normalizeRequiredPath(value) {
140
+ const normalized = value?.trim();
141
+ if (!normalized) {
142
+ throw createCliValidationError("Use --query-file com um caminho JSON ou -.");
143
+ }
144
+ return normalized;
145
+ }
146
+ async function readScreenerRequest(path) {
147
+ let text;
148
+ try {
149
+ text = path === "-" ? await readStdinText() : await readFile(path, "utf8");
150
+ }
151
+ catch (error) {
152
+ const message = error instanceof Error ? error.message : String(error);
153
+ throw createCliValidationError(`Não foi possível ler o JSON da consulta: ${message}`);
154
+ }
155
+ let parsed;
156
+ try {
157
+ parsed = JSON.parse(text);
158
+ }
159
+ catch (error) {
160
+ const message = error instanceof Error ? error.message : String(error);
161
+ throw createCliValidationError(`Não foi possível interpretar o JSON da consulta: ${message}`);
162
+ }
163
+ if (!isJsonRecord(parsed)) {
164
+ throw createCliValidationError("O JSON da consulta deve ser um objeto.");
165
+ }
166
+ return parsed;
167
+ }
168
+ async function readStdinText() {
169
+ const chunks = [];
170
+ for await (const chunk of process.stdin) {
171
+ chunks.push(typeof chunk === "string" ? chunk : chunk.toString("utf8"));
172
+ }
173
+ return chunks.join("");
174
+ }
175
+ function parseLimitOption(value) {
176
+ const parsed = parsePositiveInteger(value, "limite");
177
+ if (parsed > 500) {
178
+ throw createCliValidationError("O limite deve ser um inteiro entre 1 e 500.");
179
+ }
180
+ return parsed;
181
+ }
182
+ function parsePositiveInteger(value, fieldName) {
183
+ const normalized = value.trim();
184
+ if (!/^\d+$/.test(normalized)) {
185
+ throw createCliValidationError(`O valor de ${fieldName} deve ser um inteiro positivo.`);
186
+ }
187
+ const parsed = Number(normalized);
188
+ if (!Number.isSafeInteger(parsed) || parsed <= 0) {
189
+ throw createCliValidationError(`O valor de ${fieldName} deve ser um inteiro positivo.`);
190
+ }
191
+ return parsed;
192
+ }
193
+ function parseSortOption(value) {
194
+ const normalized = value.trim().toLowerCase();
195
+ if (!screeningSortValues.includes(normalized)) {
196
+ throw createCliValidationError("A ordenação deve ser uma destas opções: price, ticker.");
197
+ }
198
+ return normalized;
199
+ }
200
+ function appendUniverseGroup(lines, theme, title, universes) {
201
+ lines.push("");
202
+ lines.push(`${theme.label(title)} ${theme.dim(`(${formatInteger(universes.length)})`)}`);
203
+ if (universes.length === 0) {
204
+ lines.push(" nenhum item");
205
+ return;
206
+ }
207
+ for (const universe of universes) {
208
+ lines.push(` ${theme.bold(formatUniverseSelector(universe))} ${theme.dim("-")} ${universe.name}`);
209
+ lines.push(` ${theme.label("Ativos:")} ${formatInteger(universe.symbol_count)}`);
210
+ }
211
+ }
212
+ function formatUniverseSelector(universe) {
213
+ if (universe.kind === "SYSTEM") {
214
+ return `--system ${universe.slug ?? universe.id}`;
215
+ }
216
+ if (universe.kind === "WATCHLIST") {
217
+ return `--watchlist ${universe.id}`;
218
+ }
219
+ return `--holding ${universe.id}`;
220
+ }
221
+ function formatUniverseKind(kind) {
222
+ if (kind === "SYSTEM") {
223
+ return "Carteira do sistema";
224
+ }
225
+ if (kind === "WATCHLIST") {
226
+ return "Watchlist";
227
+ }
228
+ return "Carteira";
229
+ }
230
+ function collectIndicatorKeys(results) {
231
+ const keys = [];
232
+ const seen = new Set();
233
+ for (const result of results) {
234
+ for (const key of Object.keys(result.indicators)) {
235
+ if (seen.has(key)) {
236
+ continue;
237
+ }
238
+ seen.add(key);
239
+ keys.push(key);
240
+ }
241
+ }
242
+ return keys;
243
+ }
244
+ function formatResultTable(results, indicatorKeys, theme) {
245
+ const headers = [
246
+ "Ativo",
247
+ "Preço",
248
+ ...indicatorKeys.map(key => truncate(results[0]?.indicators[key]?.display_name ?? key, 18)),
249
+ ];
250
+ const rows = results.map(result => [
251
+ result.ticker,
252
+ formatNumber(result.price),
253
+ ...indicatorKeys.map(key => formatIndicatorValue(result.indicators[key])),
254
+ ]);
255
+ const widths = headers.map((header, index) => Math.max(header.length, ...rows.map(row => row[index]?.length ?? 0)));
256
+ const lines = [
257
+ headers
258
+ .map((header, index) => header.padEnd(widths[index] ?? 0))
259
+ .join(" "),
260
+ widths.map(width => "-".repeat(width)).join(" "),
261
+ ];
262
+ for (const row of rows) {
263
+ lines.push(row.map((value, index) => value.padEnd(widths[index] ?? 0)).join(" "));
264
+ }
265
+ return lines
266
+ .map((line, index) => (index === 0 ? theme.label(line) : line))
267
+ .join("\n");
268
+ }
269
+ function formatIndicatorValue(indicator) {
270
+ if (!indicator) {
271
+ return "n/d";
272
+ }
273
+ const formatted = formatNumber(indicator.value);
274
+ if (!indicator.unit) {
275
+ return formatted;
276
+ }
277
+ return indicator.unit === "%"
278
+ ? `${formatted}%`
279
+ : `${formatted} ${indicator.unit}`;
280
+ }
281
+ function formatInteger(value) {
282
+ return new Intl.NumberFormat("en-US", {
283
+ maximumFractionDigits: 0,
284
+ }).format(value);
285
+ }
286
+ function formatNumber(value) {
287
+ return new Intl.NumberFormat("en-US", {
288
+ maximumFractionDigits: 4,
289
+ }).format(value);
290
+ }
291
+ function truncate(value, maxLength) {
292
+ return value.length <= maxLength
293
+ ? value
294
+ : `${value.slice(0, Math.max(0, maxLength - 3))}...`;
295
+ }
296
+ function isJsonRecord(value) {
297
+ return typeof value === "object" && value !== null && !Array.isArray(value);
298
+ }
package/dist/index.d.ts CHANGED
@@ -8,6 +8,7 @@ export * from "./commands/capabilities.js";
8
8
  export * from "./commands/init.js";
9
9
  export * from "./commands/market.js";
10
10
  export * from "./commands/portfolios.js";
11
+ export * from "./commands/screening.js";
11
12
  export * from "./commands/skills.js";
12
13
  export * from "./commands/status.js";
13
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC"}
package/dist/index.js CHANGED
@@ -8,5 +8,6 @@ export * from "./commands/capabilities.js";
8
8
  export * from "./commands/init.js";
9
9
  export * from "./commands/market.js";
10
10
  export * from "./commands/portfolios.js";
11
+ export * from "./commands/screening.js";
11
12
  export * from "./commands/skills.js";
12
13
  export * from "./commands/status.js";
@@ -2,6 +2,7 @@ export * from "./types.js";
2
2
  export * from "./shared.js";
3
3
  export * from "./market.js";
4
4
  export * from "./assets.js";
5
+ export * from "./screening.js";
5
6
  export * from "./portfolios.js";
6
7
  export * from "./registry.js";
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/capabilities/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/capabilities/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC"}
@@ -2,5 +2,6 @@ export * from "./types.js";
2
2
  export * from "./shared.js";
3
3
  export * from "./market.js";
4
4
  export * from "./assets.js";
5
+ export * from "./screening.js";
5
6
  export * from "./portfolios.js";
6
7
  export * from "./registry.js";