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

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
@@ -31,6 +31,7 @@ that file only exists inside this package.
31
31
  node ./bin/quantbrasil.js auth login --api-key qb_live_<id>.<secret>
32
32
  node ./bin/quantbrasil.js whoami
33
33
  node ./bin/quantbrasil.js skills install --all
34
+ node ./bin/quantbrasil.js update
34
35
  node ./bin/quantbrasil.js --status
35
36
  node ./bin/quantbrasil.js auth logout
36
37
  ```
@@ -73,6 +74,7 @@ quantbrasil holdings historical-return 182 --period 1y
73
74
  quantbrasil holdings beta 182 --years 3
74
75
  quantbrasil holdings var 182 --years 1 --confidence 95
75
76
  quantbrasil screening universes
77
+ quantbrasil screening indicators
76
78
  quantbrasil screening run --system acoes-mais-liquidas --query-file ./screening.json
77
79
  quantbrasil screening run --watchlist 93 --query-file ./screening.json --limit 25
78
80
  cat ./screening.json | quantbrasil screening run --holding 182 --query-file -
@@ -144,8 +146,14 @@ quantbrasil init
144
146
  quantbrasil --status
145
147
  quantbrasil auth login --api-key qb_live_<id>.<secret>
146
148
  quantbrasil skills install --all
149
+ quantbrasil update
147
150
  ```
148
151
 
152
+ `quantbrasil update` checks the current global package against
153
+ `@quantbrasil/cli@beta`, checks whether the bundled skill is missing or stale,
154
+ shows the planned actions, and asks for confirmation before updating. Use
155
+ `quantbrasil update --yes` only in noninteractive automation.
156
+
149
157
  ## Publishing
150
158
 
151
159
  Publish from `monorepo/packages/cli`. The package build vendors the private
@@ -3,9 +3,10 @@ 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
+ import { runScreeningIndicatorsCommand, runScreeningRunCommand, runScreeningUniversesCommand } from "../commands/screening.js";
7
7
  import { runSkillsInstallCommand } from "../commands/skills.js";
8
8
  import { runStatusCommand } from "../commands/status.js";
9
+ import { runUpdateCommand, type UpdateCommandRunner } from "../commands/update.js";
9
10
  import { type TerminalWriter } from "./terminal.js";
10
11
  export interface CliProgramOptions {
11
12
  io?: CapabilitiesCommandIO;
@@ -15,6 +16,8 @@ export interface CliProgramOptions {
15
16
  now?: Date;
16
17
  stderr?: TerminalWriter;
17
18
  suppressCommanderErrors?: boolean;
19
+ updateCommandRunner?: UpdateCommandRunner;
20
+ currentVersion?: string;
18
21
  }
19
22
  export interface CliRunOptions extends CliProgramOptions {
20
23
  stderr?: TerminalWriter;
@@ -26,7 +29,8 @@ export { runAssetOverviewCommand } from "../commands/assets.js";
26
29
  export { runCapabilitiesCommand, runStatusCommand };
27
30
  export { runInitCommand };
28
31
  export { runMarketAssetsCommand, runMarketPriceCommand };
29
- export { runScreeningRunCommand, runScreeningUniversesCommand };
32
+ export { runScreeningIndicatorsCommand, runScreeningRunCommand, runScreeningUniversesCommand, };
30
33
  export { runHoldingBetaCommand, runHoldingCreateCommand, runHoldingGetCommand, runHoldingHistoricalReturnCommand, runHoldingListCommand, runHoldingRenameCommand, runHoldingSetPositionsCommand, runHoldingSetTargetsCommand, runHoldingVarCommand, runWatchlistAddAssetsCommand, runWatchlistCreateCommand, runWatchlistGetCommand, runWatchlistListCommand, runWatchlistRemoveAssetsCommand, runWatchlistRenameCommand, };
31
34
  export { runSkillsInstallCommand };
35
+ export { runUpdateCommand };
32
36
  //# 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,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"}
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,6BAA6B,EAC7B,sBAAsB,EACtB,4BAA4B,EAC7B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAGL,uBAAuB,EACxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAGL,gBAAgB,EACjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAEL,gBAAgB,EAEhB,KAAK,mBAAmB,EACzB,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;IAClC,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;IAC1C,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,aAAc,SAAQ,iBAAiB;IACtD,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB;AAED,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CA0EzE;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,6BAA6B,EAC7B,sBAAsB,EACtB,4BAA4B,GAC7B,CAAC;AACF,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;AACnC,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
package/dist/cli/index.js CHANGED
@@ -6,9 +6,10 @@ 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
+ import { registerScreeningCommands, runScreeningIndicatorsCommand, runScreeningRunCommand, runScreeningUniversesCommand, } from "../commands/screening.js";
10
10
  import { registerSkillsCommands, runSkillsInstallCommand, } from "../commands/skills.js";
11
11
  import { registerStatusFlag, runStatusCommand, } from "../commands/status.js";
12
+ import { registerUpdateCommand, runUpdateCommand, } from "../commands/update.js";
12
13
  import { buildCliErrorPayload, formatCliErrorMessage, normalizeCliError, shouldEmitJsonError, } from "./errors.js";
13
14
  import { styleErrorMessage } from "./terminal.js";
14
15
  const requirePackage = createRequire(import.meta.url);
@@ -56,10 +57,18 @@ export function createCliProgram(options = {}) {
56
57
  io: options.io,
57
58
  env: options.env,
58
59
  };
60
+ const updateContext = {
61
+ io: options.io,
62
+ env: options.env,
63
+ prompt: options.prompt,
64
+ commandRunner: options.updateCommandRunner,
65
+ currentVersion: options.currentVersion ?? CLI_VERSION,
66
+ };
59
67
  program
60
68
  .name("quantbrasil")
61
- .description("Public QuantBrasil CLI for deterministic operations")
69
+ .description("CLI pública do QuantBrasil para operações determinísticas")
62
70
  .version(CLI_VERSION)
71
+ .helpOption("-h, --help", "Exibe ajuda do comando")
63
72
  .exitOverride()
64
73
  .showHelpAfterError()
65
74
  .showSuggestionAfterError();
@@ -73,6 +82,7 @@ export function createCliProgram(options = {}) {
73
82
  registerPortfoliosCommands(program, portfoliosContext);
74
83
  registerScreeningCommands(program, screeningContext);
75
84
  registerSkillsCommands(program, skillsContext);
85
+ registerUpdateCommand(program, updateContext);
76
86
  registerStatusFlag(program, statusContext);
77
87
  return program;
78
88
  }
@@ -138,6 +148,7 @@ export { runAssetOverviewCommand } from "../commands/assets.js";
138
148
  export { runCapabilitiesCommand, runStatusCommand };
139
149
  export { runInitCommand };
140
150
  export { runMarketAssetsCommand, runMarketPriceCommand };
141
- export { runScreeningRunCommand, runScreeningUniversesCommand };
151
+ export { runScreeningIndicatorsCommand, runScreeningRunCommand, runScreeningUniversesCommand, };
142
152
  export { runHoldingBetaCommand, runHoldingCreateCommand, runHoldingGetCommand, runHoldingHistoricalReturnCommand, runHoldingListCommand, runHoldingRenameCommand, runHoldingSetPositionsCommand, runHoldingSetTargetsCommand, runHoldingVarCommand, runWatchlistAddAssetsCommand, runWatchlistCreateCommand, runWatchlistGetCommand, runWatchlistListCommand, runWatchlistRemoveAssetsCommand, runWatchlistRenameCommand, };
143
153
  export { runSkillsInstallCommand };
154
+ export { runUpdateCommand };
@@ -1,2 +1,3 @@
1
1
  export declare function promptForSecret(promptLabel: string): Promise<string>;
2
+ export declare function promptForConfirmation(promptLabel: string): Promise<boolean>;
2
3
  //# sourceMappingURL=prompt.d.ts.map
@@ -1 +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"}
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;AAED,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,OAAO,CAAC,CAmBlB"}
@@ -38,3 +38,20 @@ export async function promptForSecret(promptLabel) {
38
38
  readline.close();
39
39
  }
40
40
  }
41
+ export async function promptForConfirmation(promptLabel) {
42
+ if (!input.isTTY || !output.isTTY) {
43
+ throw createCliConfigError("Confirmação interativa requer um TTY. Use --yes para aplicar a atualização.");
44
+ }
45
+ const readline = createInterface({
46
+ input,
47
+ output,
48
+ terminal: true,
49
+ });
50
+ try {
51
+ const answer = await readline.question(promptLabel);
52
+ return ["s", "sim", "y", "yes"].includes(answer.trim().toLowerCase());
53
+ }
54
+ finally {
55
+ readline.close();
56
+ }
57
+ }
@@ -20,7 +20,16 @@ export interface SkillInstallResult {
20
20
  installed: InstalledSkillTarget[];
21
21
  skipped: SkippedSkillTarget[];
22
22
  }
23
+ export type SkillInstallStatus = "current" | "missing" | "stale" | "skipped";
24
+ export interface SkillInstallTargetStatus extends SkillInstallTarget {
25
+ status: SkillInstallStatus;
26
+ }
27
+ export interface SkillInstallState {
28
+ targets: SkillInstallTargetStatus[];
29
+ needsInstall: boolean;
30
+ }
23
31
  export declare function installBundledSkillEverywhere(env?: NodeJS.ProcessEnv): Promise<SkillInstallResult>;
32
+ export declare function getBundledSkillInstallState(env?: NodeJS.ProcessEnv): Promise<SkillInstallState>;
24
33
  export declare function resolveSkillInstallTargets(env?: NodeJS.ProcessEnv): SkillInstallTarget[];
25
34
  export declare function resolveBundledSkillSourcePath(): string;
26
35
  //# sourceMappingURL=skills.d.ts.map
@@ -1 +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"}
1
+ {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/cli/skills.ts"],"names":[],"mappings":"AAOA,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;AAED,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;AAE7E,MAAM,WAAW,wBAAyB,SAAQ,kBAAkB;IAClE,MAAM,EAAE,kBAAkB,CAAC;CAC5B;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,wBAAwB,EAAE,CAAC;IACpC,YAAY,EAAE,OAAO,CAAC;CACvB;AAcD,wBAAsB,6BAA6B,CACjD,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAAC,kBAAkB,CAAC,CAmD7B;AAED,wBAAsB,2BAA2B,CAC/C,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAAC,iBAAiB,CAAC,CA0C5B;AAED,wBAAgB,0BAA0B,CACxC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,kBAAkB,EAAE,CAetB;AAED,wBAAgB,6BAA6B,IAAI,MAAM,CAEtD"}
@@ -1,4 +1,5 @@
1
- import { access, cp, mkdir, rm } from "node:fs/promises";
1
+ import { createHash } from "node:crypto";
2
+ import { access, cp, mkdir, readdir, readFile, rm } from "node:fs/promises";
2
3
  import { homedir } from "node:os";
3
4
  import { dirname, join } from "node:path";
4
5
  import { fileURLToPath } from "node:url";
@@ -45,13 +46,46 @@ export async function installBundledSkillEverywhere(env = process.env) {
45
46
  }
46
47
  if (installed.length === 0) {
47
48
  const checkedRoots = targets.map(target => target.rootDir).join(", ");
48
- throw createCliConfigError(`No supported agent clients detected. Checked: ${checkedRoots}.`);
49
+ throw createCliConfigError(`Nenhum cliente de agente compatível detectado. Verificados: ${checkedRoots}.`);
49
50
  }
50
51
  return {
51
52
  installed,
52
53
  skipped,
53
54
  };
54
55
  }
56
+ export async function getBundledSkillInstallState(env = process.env) {
57
+ const bundledSkillPath = resolveBundledSkillSourcePath();
58
+ await assertBundledSkillExists(bundledSkillPath);
59
+ const bundledHash = await hashDirectory(bundledSkillPath);
60
+ const targets = [];
61
+ for (const target of resolveSkillInstallTargets(env)) {
62
+ if (target.id !== AGENT_SKILLS_CONVENTION_ID &&
63
+ !(await pathExists(target.rootDir))) {
64
+ targets.push({
65
+ ...target,
66
+ status: "skipped",
67
+ });
68
+ continue;
69
+ }
70
+ if (!(await pathExists(join(target.installDir, "SKILL.md")))) {
71
+ targets.push({
72
+ ...target,
73
+ status: "missing",
74
+ });
75
+ continue;
76
+ }
77
+ targets.push({
78
+ ...target,
79
+ status: (await hashDirectory(target.installDir)) === bundledHash
80
+ ? "current"
81
+ : "stale",
82
+ });
83
+ }
84
+ return {
85
+ targets,
86
+ needsInstall: targets.some(target => target.status === "missing" || target.status === "stale"),
87
+ };
88
+ }
55
89
  export function resolveSkillInstallTargets(env = process.env) {
56
90
  const home = resolveCliHomeDirectory(env);
57
91
  return SUPPORTED_SKILL_CLIENTS.map(client => {
@@ -74,12 +108,42 @@ async function assertBundledSkillExists(skillPath) {
74
108
  if (await pathExists(skillEntryPath)) {
75
109
  return;
76
110
  }
77
- throw createCliConfigError(`Bundled QuantBrasil skill not found at ${skillEntryPath}. Reinstall the CLI package.`);
111
+ throw createCliConfigError(`Skill QuantBrasil empacotada não encontrada em ${skillEntryPath}. Reinstale o pacote da CLI.`);
112
+ }
113
+ async function hashDirectory(directory) {
114
+ const hash = createHash("sha256");
115
+ const files = await collectDirectoryFiles(directory);
116
+ for (const file of files) {
117
+ hash.update(file.relativePath);
118
+ hash.update("\0");
119
+ hash.update(await readFile(file.fullPath));
120
+ hash.update("\0");
121
+ }
122
+ return hash.digest("hex");
123
+ }
124
+ async function collectDirectoryFiles(current, relativePrefix = "") {
125
+ const entries = await readdir(current, { withFileTypes: true });
126
+ const sortedEntries = entries.sort((left, right) => left.name.localeCompare(right.name));
127
+ const files = [];
128
+ for (const entry of sortedEntries) {
129
+ const fullPath = join(current, entry.name);
130
+ const relativePath = relativePrefix
131
+ ? `${relativePrefix}/${entry.name}`
132
+ : entry.name;
133
+ if (entry.isDirectory()) {
134
+ files.push(...(await collectDirectoryFiles(fullPath, relativePath)));
135
+ continue;
136
+ }
137
+ if (entry.isFile()) {
138
+ files.push({ fullPath, relativePath });
139
+ }
140
+ }
141
+ return files;
78
142
  }
79
143
  function resolveCliHomeDirectory(env) {
80
144
  const home = env.HOME?.trim() || homedir();
81
145
  if (!home) {
82
- throw createCliConfigError("Could not resolve the HOME directory for skill install.");
146
+ throw createCliConfigError("Não foi possível resolver o diretório HOME para instalar a skill.");
83
147
  }
84
148
  return home;
85
149
  }
@@ -8,6 +8,9 @@ export interface ScreeningCommandIO {
8
8
  export interface ScreeningUniversesCommandOptions {
9
9
  json?: boolean;
10
10
  }
11
+ export interface ScreeningIndicatorsCommandOptions {
12
+ json?: boolean;
13
+ }
11
14
  export interface ScreeningRunCommandOptions {
12
15
  system?: string;
13
16
  watchlist?: string;
@@ -33,6 +36,45 @@ export interface ScreeningUniversesResponse {
33
36
  holdings: ScreeningUniverseOut[];
34
37
  total: number;
35
38
  }
39
+ export type ScreeningIndicatorScalar = string | number | boolean;
40
+ export interface ScreeningIndicatorParamOut {
41
+ [key: string]: JsonValue;
42
+ name: string;
43
+ type: "integer" | "number" | "enum" | "string" | "boolean";
44
+ required: boolean;
45
+ default: ScreeningIndicatorScalar | null;
46
+ description: string;
47
+ enum_values: string[] | null;
48
+ examples: ScreeningIndicatorScalar[];
49
+ }
50
+ export interface ScreeningIndicatorRef {
51
+ [key: string]: JsonValue;
52
+ name: string;
53
+ timeframe: string;
54
+ offset: number;
55
+ params: Record<string, JsonValue>;
56
+ }
57
+ export interface ScreeningIndicatorExampleOut {
58
+ [key: string]: JsonValue;
59
+ label: string;
60
+ description: string;
61
+ indicator: ScreeningIndicatorRef;
62
+ }
63
+ export interface ScreeningIndicatorOut {
64
+ [key: string]: JsonValue;
65
+ name: string;
66
+ display_name: string;
67
+ description: string;
68
+ timeframes: string[];
69
+ params: ScreeningIndicatorParamOut[];
70
+ examples: ScreeningIndicatorExampleOut[];
71
+ }
72
+ export interface ScreeningIndicatorsResponse {
73
+ [key: string]: JsonValue;
74
+ ok: boolean;
75
+ indicators: ScreeningIndicatorOut[];
76
+ operators: string[];
77
+ }
36
78
  export interface IndicatorResult {
37
79
  [key: string]: JsonValue;
38
80
  value: number;
@@ -68,9 +110,11 @@ type JsonRecord = {
68
110
  };
69
111
  export declare function registerScreeningCommands(program: Command, context?: ScreeningCommandContext): void;
70
112
  export declare function runScreeningUniversesCommand(options: ScreeningUniversesCommandOptions, context?: ScreeningCommandContext): Promise<void>;
113
+ export declare function runScreeningIndicatorsCommand(options: ScreeningIndicatorsCommandOptions, context?: ScreeningCommandContext): Promise<void>;
71
114
  export declare function runScreeningRunCommand(options: ScreeningRunCommandOptions, context?: ScreeningCommandContext): Promise<void>;
72
115
  export declare function buildScreeningRunInput(options: ScreeningRunCommandOptions): Promise<JsonRecord>;
73
116
  export declare function formatScreeningUniversesHuman(data: ScreeningUniversesResponse, theme?: import("../cli/terminal.js").TerminalTheme): string;
117
+ export declare function formatScreeningIndicatorsHuman(data: ScreeningIndicatorsResponse, theme?: import("../cli/terminal.js").TerminalTheme): string;
74
118
  export declare function formatScreeningRunHuman(data: ScreeningRunResponse, theme?: import("../cli/terminal.js").TerminalTheme): string;
75
119
  export {};
76
120
  //# sourceMappingURL=screening.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"screening.d.ts","sourceRoot":"","sources":["../../src/commands/screening.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"screening.d.ts","sourceRoot":"","sources":["../../src/commands/screening.ts"],"names":[],"mappings":"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"}
@@ -14,6 +14,13 @@ export function registerScreeningCommands(program, context = {}) {
14
14
  .action(async (options) => {
15
15
  await runScreeningUniversesCommand(options, context);
16
16
  });
17
+ screeningCommand
18
+ .command("indicators")
19
+ .description("Lista indicadores disponíveis para screening")
20
+ .option("--json", "Exibe saída JSON")
21
+ .action(async (options) => {
22
+ await runScreeningIndicatorsCommand(options, context);
23
+ });
17
24
  screeningCommand
18
25
  .command("run")
19
26
  .description("Executa screening de indicadores a partir de um ScreenerRequest JSON")
@@ -42,6 +49,20 @@ export async function runScreeningUniversesCommand(options, context = {}) {
42
49
  }
43
50
  stdout.write(`${formatScreeningUniversesHuman(response.data, theme)}\n`);
44
51
  }
52
+ export async function runScreeningIndicatorsCommand(options, context = {}) {
53
+ const stdout = context.io?.stdout ?? process.stdout;
54
+ const theme = createTerminalTheme(stdout, context.env ?? process.env);
55
+ const response = await invokeCliCapability({
56
+ capability: "screening.indicators",
57
+ env: context.env,
58
+ fetch: context.fetch,
59
+ });
60
+ if (options.json) {
61
+ stdout.write(`${JSON.stringify(response.data, null, 2)}\n`);
62
+ return;
63
+ }
64
+ stdout.write(`${formatScreeningIndicatorsHuman(response.data, theme)}\n`);
65
+ }
45
66
  export async function runScreeningRunCommand(options, context = {}) {
46
67
  const stdout = context.io?.stdout ?? process.stdout;
47
68
  const theme = createTerminalTheme(stdout, context.env ?? process.env);
@@ -84,6 +105,32 @@ export function formatScreeningUniversesHuman(data, theme = createTerminalTheme(
84
105
  appendUniverseGroup(lines, theme, "Carteiras", data.holdings);
85
106
  return lines.join("\n");
86
107
  }
108
+ export function formatScreeningIndicatorsHuman(data, theme = createTerminalTheme(process.stdout)) {
109
+ const lines = [
110
+ theme.label("Indicadores de screening"),
111
+ "",
112
+ `${theme.label("Total:")} ${formatInteger(data.indicators.length)}`,
113
+ `${theme.label("Operadores:")} ${data.operators.join(", ")}`,
114
+ ];
115
+ for (const indicator of data.indicators) {
116
+ lines.push("");
117
+ lines.push(`${theme.bold(indicator.name)} ${theme.dim("-")} ${indicator.display_name}`);
118
+ lines.push(` ${indicator.description}`);
119
+ lines.push(` ${theme.label("Timeframes:")} ${indicator.timeframes.join(", ")}`);
120
+ if (indicator.params.length > 0) {
121
+ lines.push(` ${theme.label("Parâmetros:")}`);
122
+ for (const param of indicator.params) {
123
+ lines.push(` ${formatIndicatorParam(param)}`);
124
+ }
125
+ }
126
+ if (indicator.examples.length > 0) {
127
+ lines.push(` ${theme.label("Exemplos:")} ${indicator.examples
128
+ .map(example => example.label)
129
+ .join(", ")}`);
130
+ }
131
+ }
132
+ return lines.join("\n");
133
+ }
87
134
  export function formatScreeningRunHuman(data, theme = createTerminalTheme(process.stdout)) {
88
135
  const lines = [
89
136
  theme.label("Screening de indicadores"),
@@ -227,6 +274,22 @@ function formatUniverseKind(kind) {
227
274
  }
228
275
  return "Carteira";
229
276
  }
277
+ function formatIndicatorParam(param) {
278
+ const details = [param.type];
279
+ if (param.required) {
280
+ details.push("obrigatório");
281
+ }
282
+ if (param.default !== null) {
283
+ details.push(`padrão ${formatScalar(param.default)}`);
284
+ }
285
+ if (param.enum_values !== null && param.enum_values.length > 0) {
286
+ details.push(`opções ${param.enum_values.join("|")}`);
287
+ }
288
+ return `${param.name}: ${details.join(", ")} - ${param.description}`;
289
+ }
290
+ function formatScalar(value) {
291
+ return typeof value === "string" ? JSON.stringify(value) : String(value);
292
+ }
230
293
  function collectIndicatorKeys(results) {
231
294
  const keys = [];
232
295
  const seen = new Set();
@@ -4,18 +4,18 @@ import { createTerminalTheme } from "../cli/terminal.js";
4
4
  export function registerSkillsCommands(program, context = {}) {
5
5
  const skillsCommand = program
6
6
  .command("skills")
7
- .description("Manage bundled public skills");
7
+ .description("Gerencia skills públicas empacotadas");
8
8
  skillsCommand
9
9
  .command("install")
10
- .description("Install bundled QuantBrasil skills into detected agent clients")
11
- .option("--all", "Install all bundled public QuantBrasil skills")
10
+ .description("Instala a skill pública do QuantBrasil nos clientes de agente detectados")
11
+ .option("--all", "Instala todas as skills públicas empacotadas")
12
12
  .action(async (options) => {
13
13
  await runSkillsInstallCommand(options, context);
14
14
  });
15
15
  }
16
16
  export async function runSkillsInstallCommand(options, context = {}) {
17
17
  if (!options.all) {
18
- throw createCliValidationError("Use --all to install the bundled QuantBrasil skill into detected agent clients.");
18
+ throw createCliValidationError("Use --all para instalar a skill QuantBrasil nos clientes de agente detectados.");
19
19
  }
20
20
  const stdout = context.io?.stdout ?? process.stdout;
21
21
  const theme = createTerminalTheme(stdout, context.env ?? process.env);
@@ -23,15 +23,15 @@ export async function runSkillsInstallCommand(options, context = {}) {
23
23
  stdout.write(`${formatSkillsInstallResult(result, theme)}\n`);
24
24
  }
25
25
  export function formatSkillsInstallResult(result, theme = createTerminalTheme(process.stdout)) {
26
- const lines = [theme.label("Installed QuantBrasil skill"), ""];
26
+ const lines = [theme.label("Skill QuantBrasil instalada"), ""];
27
27
  for (const target of result.installed) {
28
28
  lines.push(`${theme.success(target.label)} ${theme.dim(`→ ${target.installDir}`)}`);
29
29
  }
30
30
  if (result.skipped.length > 0) {
31
31
  lines.push("");
32
- lines.push(theme.label("Skipped"));
32
+ lines.push(theme.label("Ignorados"));
33
33
  for (const target of result.skipped) {
34
- lines.push(`${theme.dim(`${target.label} not detected at ${target.rootDir}`)}`);
34
+ lines.push(`${theme.dim(`${target.label} não detectado em ${target.rootDir}`)}`);
35
35
  }
36
36
  }
37
37
  return lines.join("\n");
@@ -0,0 +1,23 @@
1
+ import { Command } from "commander";
2
+ import { type TerminalWriter } from "../cli/terminal.js";
3
+ export interface UpdateCommandIO {
4
+ stdout: TerminalWriter;
5
+ }
6
+ export interface UpdateCommandOptions {
7
+ yes?: boolean;
8
+ }
9
+ export interface UpdateCommandResult {
10
+ stdout: string;
11
+ stderr: string;
12
+ }
13
+ export type UpdateCommandRunner = (command: string, args: readonly string[], env: NodeJS.ProcessEnv) => Promise<UpdateCommandResult>;
14
+ export interface UpdateCommandContext {
15
+ io?: UpdateCommandIO;
16
+ env?: NodeJS.ProcessEnv;
17
+ prompt?: (promptLabel: string) => Promise<string>;
18
+ commandRunner?: UpdateCommandRunner;
19
+ currentVersion?: string;
20
+ }
21
+ export declare function registerUpdateCommand(program: Command, context?: UpdateCommandContext): void;
22
+ export declare function runUpdateCommand(options: UpdateCommandOptions, context?: UpdateCommandContext): Promise<void>;
23
+ //# sourceMappingURL=update.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,OAAO,EAAuB,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAG9E,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,mBAAmB,GAAG,CAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,mBAAmB,CAAC,CAAC;AAElC,MAAM,WAAW,oBAAoB;IACnC,EAAE,CAAC,EAAE,eAAe,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAClD,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAID,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,oBAAyB,GACjC,IAAI,CAQN;AAED,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,oBAAoB,EAC7B,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,IAAI,CAAC,CA2Cf"}
@@ -0,0 +1,209 @@
1
+ import { spawn } from "node:child_process";
2
+ import { createCliConfigError } from "../cli/errors.js";
3
+ import { promptForConfirmation } from "../cli/prompt.js";
4
+ import { getBundledSkillInstallState, installBundledSkillEverywhere, } from "../cli/skills.js";
5
+ import { createTerminalTheme } from "../cli/terminal.js";
6
+ import { formatSkillsInstallResult } from "./skills.js";
7
+ const CLI_PACKAGE_SPEC = "@quantbrasil/cli@beta";
8
+ export function registerUpdateCommand(program, context = {}) {
9
+ program
10
+ .command("update")
11
+ .description("Atualiza o pacote global e a skill pública do QuantBrasil")
12
+ .option("--yes", "Atualiza sem confirmação interativa")
13
+ .action(async (options) => {
14
+ await runUpdateCommand(options, context);
15
+ });
16
+ }
17
+ export async function runUpdateCommand(options, context = {}) {
18
+ const env = context.env ?? process.env;
19
+ const stdout = context.io?.stdout ?? process.stdout;
20
+ const theme = createTerminalTheme(stdout, env);
21
+ const runner = context.commandRunner ?? runExternalCommand;
22
+ const currentVersion = context.currentVersion ?? "0.0.0";
23
+ const latestVersion = await getLatestBetaVersion(runner, env);
24
+ const cliNeedsUpdate = compareVersions(currentVersion, latestVersion) < 0;
25
+ const skillState = await getBundledSkillInstallState(env);
26
+ const skillNeedsUpdate = skillState.needsInstall;
27
+ if (!cliNeedsUpdate && !skillNeedsUpdate) {
28
+ stdout.write(`${theme.success("QuantBrasil CLI já está atualizado.")}\n`);
29
+ return;
30
+ }
31
+ stdout.write(`${formatUpdatePlan({
32
+ currentVersion,
33
+ latestVersion,
34
+ cliNeedsUpdate,
35
+ skillState,
36
+ }, theme)}\n`);
37
+ if (!(await shouldContinue(options, context))) {
38
+ stdout.write(`${theme.warning("Atualização cancelada.")}\n`);
39
+ return;
40
+ }
41
+ if (cliNeedsUpdate) {
42
+ await runner("npm", ["install", "-g", CLI_PACKAGE_SPEC], env);
43
+ await runner("quantbrasil", ["skills", "install", "--all"], env);
44
+ stdout.write(`${theme.success("Atualização concluída.")}\n`);
45
+ return;
46
+ }
47
+ const skillInstallResult = await installBundledSkillEverywhere(env);
48
+ stdout.write(`${formatSkillsInstallResult(skillInstallResult, theme)}\n`);
49
+ stdout.write(`${theme.success("Atualização concluída.")}\n`);
50
+ }
51
+ function formatUpdatePlan(data, theme) {
52
+ const lines = [
53
+ theme.label("Atualização do QuantBrasil CLI"),
54
+ "",
55
+ `${theme.label("Versão instalada:")} ${data.currentVersion}`,
56
+ `${theme.label("Versão beta publicada:")} ${data.latestVersion}`,
57
+ ];
58
+ const skillTargets = data.skillState.targets.filter(target => target.status === "missing" || target.status === "stale");
59
+ if (skillTargets.length > 0) {
60
+ lines.push(`${theme.label("Skills:")} ${skillTargets.length} alvo(s) precisam ser atualizados`);
61
+ for (const target of skillTargets) {
62
+ lines.push(` ${target.label}: ${formatSkillStatus(target.status)} ${theme.dim(`(${target.installDir})`)}`);
63
+ }
64
+ }
65
+ else {
66
+ lines.push(`${theme.label("Skills:")} já estão atualizadas`);
67
+ }
68
+ lines.push("");
69
+ lines.push(theme.label("Ações"));
70
+ if (data.cliNeedsUpdate) {
71
+ lines.push(` npm install -g ${CLI_PACKAGE_SPEC}`);
72
+ lines.push(" quantbrasil skills install --all");
73
+ }
74
+ else if (skillTargets.length > 0) {
75
+ lines.push(" quantbrasil skills install --all");
76
+ }
77
+ return lines.join("\n");
78
+ }
79
+ async function shouldContinue(options, context) {
80
+ if (options.yes) {
81
+ return true;
82
+ }
83
+ if (context.prompt) {
84
+ return parseConfirmationAnswer(await context.prompt("Atualizar agora? [s/N] "));
85
+ }
86
+ return promptForConfirmation("Atualizar agora? [s/N] ");
87
+ }
88
+ function formatSkillStatus(status) {
89
+ if (status === "missing") {
90
+ return "não instalada";
91
+ }
92
+ if (status === "stale") {
93
+ return "desatualizada";
94
+ }
95
+ return status;
96
+ }
97
+ function parseConfirmationAnswer(answer) {
98
+ return ["s", "sim", "y", "yes"].includes(answer.trim().toLowerCase());
99
+ }
100
+ async function getLatestBetaVersion(runner, env) {
101
+ const result = await runner("npm", ["view", CLI_PACKAGE_SPEC, "version"], env);
102
+ const version = result.stdout.trim();
103
+ if (!version) {
104
+ throw createCliConfigError(`Não foi possível resolver a versão publicada de ${CLI_PACKAGE_SPEC}.`);
105
+ }
106
+ return version;
107
+ }
108
+ function compareVersions(left, right) {
109
+ const parsedLeft = parseVersion(left);
110
+ const parsedRight = parseVersion(right);
111
+ for (let index = 0; index < 3; index += 1) {
112
+ const diff = (parsedLeft.main[index] ?? 0) - (parsedRight.main[index] ?? 0);
113
+ if (diff !== 0) {
114
+ return diff;
115
+ }
116
+ }
117
+ if (parsedLeft.prerelease.length === 0 &&
118
+ parsedRight.prerelease.length === 0) {
119
+ return 0;
120
+ }
121
+ if (parsedLeft.prerelease.length === 0) {
122
+ return 1;
123
+ }
124
+ if (parsedRight.prerelease.length === 0) {
125
+ return -1;
126
+ }
127
+ const length = Math.max(parsedLeft.prerelease.length, parsedRight.prerelease.length);
128
+ for (let index = 0; index < length; index += 1) {
129
+ const leftPart = parsedLeft.prerelease[index];
130
+ const rightPart = parsedRight.prerelease[index];
131
+ if (leftPart === undefined) {
132
+ return -1;
133
+ }
134
+ if (rightPart === undefined) {
135
+ return 1;
136
+ }
137
+ const diff = comparePrereleasePart(leftPart, rightPart);
138
+ if (diff !== 0) {
139
+ return diff;
140
+ }
141
+ }
142
+ return 0;
143
+ }
144
+ function parseVersion(version) {
145
+ const [mainVersion = "0.0.0", prerelease = ""] = version
146
+ .trim()
147
+ .replace(/^v/, "")
148
+ .split("-");
149
+ const mainParts = mainVersion.split(".").map(part => Number(part));
150
+ const main = [
151
+ normalizeVersionPart(mainParts[0]),
152
+ normalizeVersionPart(mainParts[1]),
153
+ normalizeVersionPart(mainParts[2]),
154
+ ];
155
+ return {
156
+ main,
157
+ prerelease: prerelease ? prerelease.split(".") : [],
158
+ };
159
+ }
160
+ function normalizeVersionPart(part) {
161
+ return Number.isFinite(part) ? Number(part) : 0;
162
+ }
163
+ function comparePrereleasePart(left, right) {
164
+ const leftNumber = Number(left);
165
+ const rightNumber = Number(right);
166
+ const leftIsNumeric = /^\d+$/.test(left);
167
+ const rightIsNumeric = /^\d+$/.test(right);
168
+ if (leftIsNumeric && rightIsNumeric) {
169
+ return leftNumber - rightNumber;
170
+ }
171
+ if (leftIsNumeric) {
172
+ return -1;
173
+ }
174
+ if (rightIsNumeric) {
175
+ return 1;
176
+ }
177
+ return left.localeCompare(right);
178
+ }
179
+ function runExternalCommand(command, args, env) {
180
+ return new Promise((resolve, reject) => {
181
+ const child = spawn(command, args, {
182
+ env,
183
+ stdio: ["ignore", "pipe", "pipe"],
184
+ });
185
+ let stdout = "";
186
+ let stderr = "";
187
+ child.stdout.on("data", chunk => {
188
+ stdout += chunk;
189
+ });
190
+ child.stderr.on("data", chunk => {
191
+ stderr += chunk;
192
+ });
193
+ child.on("error", error => {
194
+ reject(createCliConfigError(`Não foi possível executar ${command}: ${error.message}`));
195
+ });
196
+ child.on("close", code => {
197
+ if (code === 0) {
198
+ resolve({ stdout, stderr });
199
+ return;
200
+ }
201
+ reject(createCliConfigError([
202
+ `${command} ${args.join(" ")} falhou com exit ${code}.`,
203
+ stderr.trim() || stdout.trim(),
204
+ ]
205
+ .filter(Boolean)
206
+ .join("\n")));
207
+ });
208
+ });
209
+ }
package/dist/index.d.ts CHANGED
@@ -11,4 +11,5 @@ export * from "./commands/portfolios.js";
11
11
  export * from "./commands/screening.js";
12
12
  export * from "./commands/skills.js";
13
13
  export * from "./commands/status.js";
14
+ export * from "./commands/update.js";
14
15
  //# 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,yBAAyB,CAAC;AACxC,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;AACrC,cAAc,sBAAsB,CAAC"}
package/dist/index.js CHANGED
@@ -11,3 +11,4 @@ export * from "./commands/portfolios.js";
11
11
  export * from "./commands/screening.js";
12
12
  export * from "./commands/skills.js";
13
13
  export * from "./commands/status.js";
14
+ export * from "./commands/update.js";
@@ -165,6 +165,33 @@ export declare const capabilityRegistry: readonly [{
165
165
  readonly title: "Listar universos de screening";
166
166
  };
167
167
  readonly outputModes: readonly ["json", "human"];
168
+ }, {
169
+ readonly id: "screening.indicators";
170
+ readonly kind: "read";
171
+ readonly visibility: readonly ["cli", "opencode"];
172
+ readonly description: "Lista indicadores, parâmetros e operadores disponíveis para screening.";
173
+ readonly http: {
174
+ readonly method: "GET";
175
+ readonly path: "/api/desk/tools/screening/indicators";
176
+ readonly inputMode: "none";
177
+ readonly schemas: {
178
+ readonly request: null;
179
+ readonly response: "ScreeningIndicatorsResponse";
180
+ };
181
+ };
182
+ readonly cli: {
183
+ readonly group: "screening";
184
+ readonly command: "indicators";
185
+ readonly summary: "Lista indicadores, parâmetros e exemplos disponíveis para screening.";
186
+ readonly positional: readonly [];
187
+ readonly options: readonly [];
188
+ readonly examples: readonly ["quantbrasil screening indicators", "quantbrasil screening indicators --json"];
189
+ };
190
+ readonly tool: {
191
+ readonly name: "qb_screening_indicators";
192
+ readonly title: "Listar indicadores de screening";
193
+ };
194
+ readonly outputModes: readonly ["json", "human"];
168
195
  }, {
169
196
  readonly id: "screening.run";
170
197
  readonly kind: "read";
@@ -1032,6 +1059,33 @@ export declare function getCapabilityById(id: CapabilityId): {
1032
1059
  readonly title: "Listar universos de screening";
1033
1060
  };
1034
1061
  readonly outputModes: readonly ["json", "human"];
1062
+ } | {
1063
+ readonly id: "screening.indicators";
1064
+ readonly kind: "read";
1065
+ readonly visibility: readonly ["cli", "opencode"];
1066
+ readonly description: "Lista indicadores, parâmetros e operadores disponíveis para screening.";
1067
+ readonly http: {
1068
+ readonly method: "GET";
1069
+ readonly path: "/api/desk/tools/screening/indicators";
1070
+ readonly inputMode: "none";
1071
+ readonly schemas: {
1072
+ readonly request: null;
1073
+ readonly response: "ScreeningIndicatorsResponse";
1074
+ };
1075
+ };
1076
+ readonly cli: {
1077
+ readonly group: "screening";
1078
+ readonly command: "indicators";
1079
+ readonly summary: "Lista indicadores, parâmetros e exemplos disponíveis para screening.";
1080
+ readonly positional: readonly [];
1081
+ readonly options: readonly [];
1082
+ readonly examples: readonly ["quantbrasil screening indicators", "quantbrasil screening indicators --json"];
1083
+ };
1084
+ readonly tool: {
1085
+ readonly name: "qb_screening_indicators";
1086
+ readonly title: "Listar indicadores de screening";
1087
+ };
1088
+ readonly outputModes: readonly ["json", "human"];
1035
1089
  } | {
1036
1090
  readonly id: "screening.run";
1037
1091
  readonly kind: "read";
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/capabilities/registry.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAKrB,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC;AAErE,eAAO,MAAM,sBAAsB,EAE9B,MAAM,CAAC,YAAY,EAAE,CAAC,OAAO,kBAAkB,EAAE,MAAM,CAAC,CAAC,CAAC;AAE/D,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAEjD"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/capabilities/registry.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAKrB,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC;AAErE,eAAO,MAAM,sBAAsB,EAE9B,MAAM,CAAC,YAAY,EAAE,CAAC,OAAO,kBAAkB,EAAE,MAAM,CAAC,CAAC,CAAC;AAE/D,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAEjD"}
@@ -26,6 +26,33 @@ export declare const screeningCapabilities: readonly [{
26
26
  readonly title: "Listar universos de screening";
27
27
  };
28
28
  readonly outputModes: readonly ["json", "human"];
29
+ }, {
30
+ readonly id: "screening.indicators";
31
+ readonly kind: "read";
32
+ readonly visibility: readonly ["cli", "opencode"];
33
+ readonly description: "Lista indicadores, parâmetros e operadores disponíveis para screening.";
34
+ readonly http: {
35
+ readonly method: "GET";
36
+ readonly path: "/api/desk/tools/screening/indicators";
37
+ readonly inputMode: "none";
38
+ readonly schemas: {
39
+ readonly request: null;
40
+ readonly response: "ScreeningIndicatorsResponse";
41
+ };
42
+ };
43
+ readonly cli: {
44
+ readonly group: "screening";
45
+ readonly command: "indicators";
46
+ readonly summary: "Lista indicadores, parâmetros e exemplos disponíveis para screening.";
47
+ readonly positional: readonly [];
48
+ readonly options: readonly [];
49
+ readonly examples: readonly ["quantbrasil screening indicators", "quantbrasil screening indicators --json"];
50
+ };
51
+ readonly tool: {
52
+ readonly name: "qb_screening_indicators";
53
+ readonly title: "Listar indicadores de screening";
54
+ };
55
+ readonly outputModes: readonly ["json", "human"];
29
56
  }, {
30
57
  readonly id: "screening.run";
31
58
  readonly kind: "read";
@@ -1 +1 @@
1
- {"version":3,"file":"screening.d.ts","sourceRoot":"","sources":["../../src/capabilities/screening.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,mBAAmB,8BAA+B,CAAC;AAEhE,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgIkB,CAAC"}
1
+ {"version":3,"file":"screening.d.ts","sourceRoot":"","sources":["../../src/capabilities/screening.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,mBAAmB,8BAA+B,CAAC;AAEhE,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiKkB,CAAC"}
@@ -30,6 +30,37 @@ export const screeningCapabilities = [
30
30
  },
31
31
  outputModes: standardOutputModes,
32
32
  },
33
+ {
34
+ id: "screening.indicators",
35
+ kind: "read",
36
+ visibility: publicRuntimeVisibility,
37
+ description: "Lista indicadores, parâmetros e operadores disponíveis para screening.",
38
+ http: {
39
+ method: "GET",
40
+ path: "/api/desk/tools/screening/indicators",
41
+ inputMode: "none",
42
+ schemas: {
43
+ request: null,
44
+ response: "ScreeningIndicatorsResponse",
45
+ },
46
+ },
47
+ cli: {
48
+ group: "screening",
49
+ command: "indicators",
50
+ summary: "Lista indicadores, parâmetros e exemplos disponíveis para screening.",
51
+ positional: [],
52
+ options: [],
53
+ examples: [
54
+ "quantbrasil screening indicators",
55
+ "quantbrasil screening indicators --json",
56
+ ],
57
+ },
58
+ tool: {
59
+ name: "qb_screening_indicators",
60
+ title: "Listar indicadores de screening",
61
+ },
62
+ outputModes: standardOutputModes,
63
+ },
33
64
  {
34
65
  id: "screening.run",
35
66
  kind: "read",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quantbrasil/cli",
3
- "version": "0.1.0-beta.7",
3
+ "version": "0.1.0-beta.8",
4
4
  "type": "module",
5
5
  "description": "Public QuantBrasil CLI for deterministic operations",
6
6
  "repository": {
@@ -41,8 +41,8 @@
41
41
  "typescript": "^5.3.3",
42
42
  "vitest": "^3.2.4",
43
43
  "@repo/core": "0.0.0",
44
- "@repo/eslint-config": "0.0.0",
45
- "@repo/typescript-config": "0.0.0"
44
+ "@repo/typescript-config": "0.0.0",
45
+ "@repo/eslint-config": "0.0.0"
46
46
  },
47
47
  "scripts": {
48
48
  "build": "pnpm --filter @repo/core build && pnpm run clean && tsc && node scripts/vendor-core.mjs",
@@ -13,6 +13,7 @@ Use this skill when the user asks for market or investing data/actions that Quan
13
13
  - Most end-user QuantBrasil requests are expected in pt-BR; Portuguese prompts about ativos, carteiras, cotações, screening, retorno, beta, VaR, watchlists, or Ibovespa should trigger this skill when they map to the supported CLI surface.
14
14
  - For QuantBrasil-supported market, asset, screening, watchlist, holding, or holding metric data, use the CLI before generic web or finance search.
15
15
  - When the request mentions portfolios, carteiras, watchlists, holdings, target weights, positions, historical return, beta, VaR, screening universes, or saved compositions, load [`references/portfolios.md`](./references/portfolios.md) before choosing commands.
16
+ - When the request mentions IFR/RSI filters, sobrevendido, sobrecomprado, indicator screening, technical screening rules, or screening indicators, load [`references/screening.md`](./references/screening.md) before building the request JSON.
16
17
  - Use `quantbrasil` when available on PATH.
17
18
  - If `quantbrasil` is not found, report that the CLI binary is not on PATH and ask the user to install it or fix PATH.
18
19
  - Check readiness first: `quantbrasil --status`
@@ -24,7 +25,7 @@ Use this skill when the user asks for market or investing data/actions that Quan
24
25
  - richer asset analysis: `quantbrasil assets overview <ticker> --sections ...`
25
26
  - watchlist details and changes: `quantbrasil watchlists ...`
26
27
  - holding details and historical return: `quantbrasil holdings ...`
27
- - indicator screening over saved universes: `quantbrasil screening ...`
28
+ - indicator screening over saved universes: `quantbrasil screening universes|indicators|run ...`
28
29
  - holding metrics: `quantbrasil holdings historical-return|beta|var ...`
29
30
  - Use `--json` when output will be parsed by agent or script
30
31
  - Use generic web or finance search only if the CLI is unavailable, the requested data is outside the QuantBrasil-supported surface, or the user explicitly asks for an external source.
@@ -35,6 +36,7 @@ Use this skill when the user asks for market or investing data/actions that Quan
35
36
  - Load [`references/workflows.md`](./references/workflows.md) when the user describes an investing task but does not name an exact command, or when a task spans discovery plus a follow-up action.
36
37
  - Load [`references/cli.md`](./references/cli.md) when you need exact command syntax, flags, examples, or supported `--sections` values.
37
38
  - Load [`references/portfolios.md`](./references/portfolios.md) when the request mentions portfolios, carteiras, watchlists, holdings, target weights, positions, historical return, beta, VaR, screening universes, or saved compositions.
39
+ - Load [`references/screening.md`](./references/screening.md) when the user asks for IFR/RSI filters, sobrevendido/sobrecomprado assets, indicator screening, technical filter JSON, screening indicators, or examples of `ScreenerRequest`.
38
40
  - Load [`references/costs.md`](./references/costs.md) before chaining heavy reads, choosing between overview/screening/holding metrics, or answering cost-sensitive agent workflow questions.
39
41
  - Load [`references/errors.md`](./references/errors.md) when a CLI command fails, auth/config is unclear, or the user asks how to fix a QuantBrasil CLI error.
40
42
  - Load [`references/unsupported.md`](./references/unsupported.md) when the user asks for deletion, file export, ad-hoc ticker-list screening, unsupported commands, or a capability that may not be public yet.
@@ -82,6 +82,7 @@ Use `--json` on any holding metric command when machine parsing needed.
82
82
 
83
83
  ```bash
84
84
  quantbrasil screening universes
85
+ quantbrasil screening indicators
85
86
  quantbrasil screening run --system acoes-mais-liquidas --query-file ./screening.json
86
87
  quantbrasil screening run --watchlist 93 --query-file ./screening.json --limit 25
87
88
  quantbrasil screening run --holding 182 --query-file ./screening.json --sort ticker
@@ -96,6 +97,10 @@ Rules:
96
97
  - `--query-file` must contain the full backend `ScreenerRequest` JSON shape
97
98
  - `--query-file -` reads the same JSON shape from stdin
98
99
  - `--limit` and `--sort` override only top-level fields from the query JSON
100
+ - use `screening indicators` to discover supported indicator names, params, examples, timeframes, and operators
101
+
102
+ Load [`screening.md`](./screening.md) for detailed screening examples, including
103
+ IFR14, IFR2, and logical `AND` JSON payloads.
99
104
 
100
105
  Example query JSON:
101
106
 
@@ -14,6 +14,7 @@ Current guidance uses backend qualitative classes only:
14
14
  - `market price` is narrow read path
15
15
  - `assets overview` is richer and should use minimal `--sections`
16
16
  - `screening universes` is a discovery path for saved screening universes
17
+ - `screening indicators` is a discovery path for supported screening JSON
17
18
  - `screening run` is a heavy read and should be targeted to one selected universe
18
19
  - holding metrics (`historical-return`, `beta`, `var`) are heaviest current public reads
19
20
 
@@ -22,6 +23,7 @@ Current guidance uses backend qualitative classes only:
22
23
  - prefer narrow command that answers question
23
24
  - prefer `market price` over `assets overview` for quote-only requests
24
25
  - run `screening universes` before `screening run` when the universe selector is not known
26
+ - run `screening indicators` before `screening run` when the indicator JSON is not known
25
27
  - prefer one holding metric call targeted to actual question
26
28
  - do not chain multiple heavy holding metric or screening calls unless user asked for them
27
29
  - use `--json` only when structured output needed
@@ -44,6 +44,11 @@
44
44
  "should_trigger": true,
45
45
  "expected_behavior": "Use screening universes and present system portfolios, watchlists, and holdings."
46
46
  },
47
+ {
48
+ "query": "Quais indicadores posso usar no screening?",
49
+ "should_trigger": true,
50
+ "expected_behavior": "Use screening indicators and present supported indicator names, params, examples, timeframes, and operators."
51
+ },
47
52
  {
48
53
  "query": "Rode um screening de IFR na carteira do sistema Ações Mais Líquidas.",
49
54
  "should_trigger": true,
@@ -0,0 +1,212 @@
1
+ # Screening
2
+
3
+ Use screening for indicator filters over saved QuantBrasil universes.
4
+
5
+ ## Discovery
6
+
7
+ ```bash
8
+ quantbrasil screening universes
9
+ quantbrasil screening indicators
10
+ ```
11
+
12
+ Use `screening universes` to pick the asset set. The CLI supports only saved,
13
+ portfolio-backed universes:
14
+
15
+ - system portfolios via `--system <slug>`
16
+ - watchlists via `--watchlist <id>`
17
+ - holdings via `--holding <id>`
18
+
19
+ Do not invent ad-hoc ticker-list screening. If the user gives loose tickers,
20
+ explain that this CLI slice only screens saved universes.
21
+
22
+ Use `screening indicators` before building JSON when the indicator name,
23
+ parameters, timeframes, or comparison operators are unclear.
24
+
25
+ ## Common Portuguese mappings
26
+
27
+ - `IFR`, `IFR14`, `IFR(14)` -> `RSI` with `params.period = 14`
28
+ - `IFR2`, `IFR(2)` -> `RSI` with `params.period = 2`
29
+ - `sobrevendido` usually means low RSI, commonly `< 30` or a threshold supplied by the user
30
+ - `sobrecomprado` usually means high RSI, commonly `> 70` or a threshold supplied by the user
31
+ - `Ações Mais Líquidas` -> system universe slug `acoes-mais-liquidas` when present in `screening universes`
32
+
33
+ ## Operators
34
+
35
+ - `lt` means less than
36
+ - `lte` means less than or equal to
37
+ - `gt` means greater than
38
+ - `gte` means greater than or equal to
39
+ - `eq` means equal to
40
+ - `neq` means not equal to
41
+
42
+ ## IFR14 abaixo de 25
43
+
44
+ ```json
45
+ {
46
+ "query": {
47
+ "comparison": {
48
+ "left": {
49
+ "indicator": {
50
+ "name": "RSI",
51
+ "timeframe": "D1",
52
+ "offset": 0,
53
+ "params": {
54
+ "period": 14
55
+ }
56
+ }
57
+ },
58
+ "operator": "lt",
59
+ "right": {
60
+ "constant": {
61
+ "value": 25
62
+ }
63
+ }
64
+ }
65
+ },
66
+ "limit": 500,
67
+ "sort": "ticker"
68
+ }
69
+ ```
70
+
71
+ Run it:
72
+
73
+ ```bash
74
+ quantbrasil screening run --system acoes-mais-liquidas --query-file ./screening-ifr14-lt-25.json
75
+ ```
76
+
77
+ For agent/script parsing:
78
+
79
+ ```bash
80
+ quantbrasil screening run --system acoes-mais-liquidas --query-file ./screening-ifr14-lt-25.json --json
81
+ ```
82
+
83
+ ## IFR14 acima de 70
84
+
85
+ ```json
86
+ {
87
+ "query": {
88
+ "comparison": {
89
+ "left": {
90
+ "indicator": {
91
+ "name": "RSI",
92
+ "timeframe": "D1",
93
+ "offset": 0,
94
+ "params": {
95
+ "period": 14
96
+ }
97
+ }
98
+ },
99
+ "operator": "gt",
100
+ "right": {
101
+ "constant": {
102
+ "value": 70
103
+ }
104
+ }
105
+ }
106
+ },
107
+ "limit": 500,
108
+ "sort": "ticker"
109
+ }
110
+ ```
111
+
112
+ ## IFR2 abaixo de 10
113
+
114
+ ```json
115
+ {
116
+ "query": {
117
+ "comparison": {
118
+ "left": {
119
+ "indicator": {
120
+ "name": "RSI",
121
+ "timeframe": "D1",
122
+ "offset": 0,
123
+ "params": {
124
+ "period": 2
125
+ }
126
+ }
127
+ },
128
+ "operator": "lt",
129
+ "right": {
130
+ "constant": {
131
+ "value": 10
132
+ }
133
+ }
134
+ }
135
+ },
136
+ "limit": 500,
137
+ "sort": "ticker"
138
+ }
139
+ ```
140
+
141
+ ## Exemplo com AND lógico
142
+
143
+ Este exemplo filtra ativos com fechamento acima da média móvel de 20 períodos e
144
+ IFR14 abaixo de 30.
145
+
146
+ ```json
147
+ {
148
+ "query": {
149
+ "logical": {
150
+ "op": "AND",
151
+ "expressions": [
152
+ {
153
+ "comparison": {
154
+ "left": {
155
+ "indicator": {
156
+ "name": "OHLC",
157
+ "timeframe": "D1",
158
+ "offset": 0,
159
+ "params": {
160
+ "price_type": "close"
161
+ }
162
+ }
163
+ },
164
+ "operator": "gt",
165
+ "right": {
166
+ "indicator": {
167
+ "name": "RollingWindow",
168
+ "timeframe": "D1",
169
+ "offset": 0,
170
+ "params": {
171
+ "window": 20,
172
+ "method": "mean"
173
+ }
174
+ }
175
+ }
176
+ }
177
+ },
178
+ {
179
+ "comparison": {
180
+ "left": {
181
+ "indicator": {
182
+ "name": "RSI",
183
+ "timeframe": "D1",
184
+ "offset": 0,
185
+ "params": {
186
+ "period": 14
187
+ }
188
+ }
189
+ },
190
+ "operator": "lt",
191
+ "right": {
192
+ "constant": {
193
+ "value": 30
194
+ }
195
+ }
196
+ }
197
+ }
198
+ ]
199
+ }
200
+ },
201
+ "limit": 100,
202
+ "sort": "ticker"
203
+ }
204
+ ```
205
+
206
+ ## Stdin
207
+
208
+ Use stdin when creating the JSON dynamically:
209
+
210
+ ```bash
211
+ cat ./screening-ifr14-lt-25.json | quantbrasil screening run --system acoes-mais-liquidas --query-file -
212
+ ```
@@ -8,7 +8,7 @@
8
8
  - watchlist details or changes → `watchlists ...`
9
9
  - holding details or changes → `holdings ...`
10
10
  - holding return, beta, risk, VaR, or comparison → `holdings historical-return|beta|var`
11
- - indicator screening over saved asset sets → `screening universes`, then `screening run`
11
+ - indicator screening over saved asset sets → `screening universes`, `screening indicators` when needed, then `screening run`
12
12
 
13
13
  ## Find supported ticker, then get price
14
14
 
@@ -79,11 +79,13 @@ quantbrasil holdings var 93 --years 1 --confidence 95
79
79
  ## Run indicator screening
80
80
 
81
81
  1. Discover available universes.
82
- 2. Pick exactly one system portfolio, watchlist, or holding.
83
- 3. Run screening with a full `ScreenerRequest` JSON file.
82
+ 2. Discover available indicators when the filter JSON is not already known.
83
+ 3. Pick exactly one system portfolio, watchlist, or holding.
84
+ 4. Run screening with a full `ScreenerRequest` JSON file.
84
85
 
85
86
  ```bash
86
87
  quantbrasil screening universes
88
+ quantbrasil screening indicators
87
89
  quantbrasil screening run --system acoes-mais-liquidas --query-file ./screening.json
88
90
  quantbrasil screening run --watchlist 93 --query-file ./screening.json --limit 25
89
91
  quantbrasil screening run --holding 182 --query-file ./screening.json --sort ticker
@@ -94,6 +96,7 @@ Rules:
94
96
  - screening universes are portfolio-backed only: system portfolios, watchlists, or holdings
95
97
  - a holding used as a screening universe contributes only its asset set
96
98
  - do not invent ad-hoc ticker-list screening commands
99
+ - load `references/screening.md` for IFR/RSI examples and full JSON payloads
97
100
  - use `--json` when the result will be parsed by an agent or script
98
101
 
99
102
  ## Analyze a theoretical composition