@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.
- package/README.md +272 -0
- package/bin/quantbrasil.js +4 -0
- package/dist/cli/auth.d.ts +20 -0
- package/dist/cli/auth.d.ts.map +1 -0
- package/dist/cli/auth.js +76 -0
- package/dist/cli/client.d.ts +17 -0
- package/dist/cli/client.d.ts.map +1 -0
- package/dist/cli/client.js +112 -0
- package/dist/cli/config.d.ts +33 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +148 -0
- package/dist/cli/errors.d.ts +40 -0
- package/dist/cli/errors.d.ts.map +1 -0
- package/dist/cli/errors.js +122 -0
- package/dist/cli/index.d.ts +30 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +112 -0
- package/dist/cli/prompt.d.ts +2 -0
- package/dist/cli/prompt.d.ts.map +1 -0
- package/dist/cli/prompt.js +40 -0
- package/dist/cli/skills.d.ts +26 -0
- package/dist/cli/skills.d.ts.map +1 -0
- package/dist/cli/skills.js +94 -0
- package/dist/cli/terminal.d.ts +18 -0
- package/dist/cli/terminal.d.ts.map +1 -0
- package/dist/cli/terminal.js +43 -0
- package/dist/commands/analytics.d.ts +131 -0
- package/dist/commands/analytics.d.ts.map +1 -0
- package/dist/commands/analytics.js +291 -0
- package/dist/commands/assets.d.ts +69 -0
- package/dist/commands/assets.d.ts.map +1 -0
- package/dist/commands/assets.js +350 -0
- package/dist/commands/auth.d.ts +17 -0
- package/dist/commands/auth.d.ts.map +1 -0
- package/dist/commands/auth.js +48 -0
- package/dist/commands/capabilities.d.ts +25 -0
- package/dist/commands/capabilities.d.ts.map +1 -0
- package/dist/commands/capabilities.js +61 -0
- package/dist/commands/init.d.ts +17 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +89 -0
- package/dist/commands/market.d.ts +45 -0
- package/dist/commands/market.d.ts.map +1 -0
- package/dist/commands/market.js +162 -0
- package/dist/commands/portfolios.d.ts +60 -0
- package/dist/commands/portfolios.d.ts.map +1 -0
- package/dist/commands/portfolios.js +298 -0
- package/dist/commands/skills.d.ts +17 -0
- package/dist/commands/skills.d.ts.map +1 -0
- package/dist/commands/skills.js +38 -0
- package/dist/commands/status.d.ts +15 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +52 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/vendor/core/capabilities/analytics.d.ts +187 -0
- package/dist/vendor/core/capabilities/analytics.d.ts.map +1 -0
- package/dist/vendor/core/capabilities/analytics.js +214 -0
- package/dist/vendor/core/capabilities/assets.d.ts +48 -0
- package/dist/vendor/core/capabilities/assets.d.ts.map +1 -0
- package/dist/vendor/core/capabilities/assets.js +66 -0
- package/dist/vendor/core/capabilities/index.d.ts +8 -0
- package/dist/vendor/core/capabilities/index.d.ts.map +1 -0
- package/dist/vendor/core/capabilities/index.js +7 -0
- package/dist/vendor/core/capabilities/market.d.ts +90 -0
- package/dist/vendor/core/capabilities/market.d.ts.map +1 -0
- package/dist/vendor/core/capabilities/market.js +114 -0
- package/dist/vendor/core/capabilities/portfolios.d.ts +224 -0
- package/dist/vendor/core/capabilities/portfolios.d.ts.map +1 -0
- package/dist/vendor/core/capabilities/portfolios.js +244 -0
- package/dist/vendor/core/capabilities/registry.d.ts +1083 -0
- package/dist/vendor/core/capabilities/registry.d.ts.map +1 -0
- package/dist/vendor/core/capabilities/registry.js +14 -0
- package/dist/vendor/core/capabilities/shared.d.ts +3 -0
- package/dist/vendor/core/capabilities/shared.d.ts.map +1 -0
- package/dist/vendor/core/capabilities/shared.js +2 -0
- package/dist/vendor/core/capabilities/types.d.ts +75 -0
- package/dist/vendor/core/capabilities/types.d.ts.map +1 -0
- package/dist/vendor/core/capabilities/types.js +1 -0
- package/dist/vendor/core/errors.d.ts +22 -0
- package/dist/vendor/core/errors.d.ts.map +1 -0
- package/dist/vendor/core/errors.js +42 -0
- package/dist/vendor/core/http/client.d.ts +45 -0
- package/dist/vendor/core/http/client.d.ts.map +1 -0
- package/dist/vendor/core/http/client.js +170 -0
- package/dist/vendor/core/http/index.d.ts +2 -0
- package/dist/vendor/core/http/index.d.ts.map +1 -0
- package/dist/vendor/core/http/index.js +1 -0
- package/dist/vendor/core/index.d.ts +5 -0
- package/dist/vendor/core/index.d.ts.map +1 -0
- package/dist/vendor/core/index.js +4 -0
- package/dist/vendor/core/invoke.d.ts +17 -0
- package/dist/vendor/core/invoke.d.ts.map +1 -0
- package/dist/vendor/core/invoke.js +70 -0
- package/package.json +57 -0
- package/skills/quantbrasil/SKILL.md +29 -0
- package/skills/quantbrasil/references/cli.md +77 -0
- package/skills/quantbrasil/references/costs.md +30 -0
- package/skills/quantbrasil/references/errors.md +128 -0
- package/skills/quantbrasil/references/unsupported.md +20 -0
- package/skills/quantbrasil/references/workflows.md +99 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { monitoredAssetTypes } from "../vendor/core/capabilities/index.js";
|
|
2
|
+
import { invokeCliCapability } from "../cli/client.js";
|
|
3
|
+
import { createCliValidationError } from "../cli/errors.js";
|
|
4
|
+
import { createTerminalTheme } from "../cli/terminal.js";
|
|
5
|
+
export function registerMarketCommands(program, context = {}) {
|
|
6
|
+
const marketCommand = program
|
|
7
|
+
.command("market")
|
|
8
|
+
.description("Read market data operations");
|
|
9
|
+
marketCommand
|
|
10
|
+
.command("assets")
|
|
11
|
+
.description("List the monitored QuantBrasil asset universe")
|
|
12
|
+
.option("--type <type>", `Filter by exact asset type (${monitoredAssetTypes.join(", ")})`)
|
|
13
|
+
.option("--json", "Show JSON output")
|
|
14
|
+
.action(async (options) => {
|
|
15
|
+
await runMarketAssetsCommand(options, context);
|
|
16
|
+
});
|
|
17
|
+
marketCommand
|
|
18
|
+
.command("price")
|
|
19
|
+
.description("Get the latest or historical price for one ticker")
|
|
20
|
+
.argument("<ticker>", "Ticker symbol, for example PETR4")
|
|
21
|
+
.option("--date <date>", "Reference date in ISO format (YYYY-MM-DD)")
|
|
22
|
+
.option("--timeframe <timeframe>", "Timeframe identifier", "D1")
|
|
23
|
+
.option("--json", "Show JSON output")
|
|
24
|
+
.action(async (ticker, options) => {
|
|
25
|
+
await runMarketPriceCommand(ticker, options, context);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
export async function runMarketAssetsCommand(options, context = {}) {
|
|
29
|
+
const stdout = context.io?.stdout ?? process.stdout;
|
|
30
|
+
const theme = createTerminalTheme(stdout, context.env ?? process.env);
|
|
31
|
+
const assetType = normalizeMarketAssetType(options.type);
|
|
32
|
+
const response = await invokeCliCapability({
|
|
33
|
+
capability: "market.assets",
|
|
34
|
+
input: assetType ? { type: assetType } : {},
|
|
35
|
+
env: context.env,
|
|
36
|
+
fetch: context.fetch,
|
|
37
|
+
});
|
|
38
|
+
if (options.json) {
|
|
39
|
+
stdout.write(`${JSON.stringify(response.data, null, 2)}\n`);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
stdout.write(`${formatMarketAssetsHuman(response.data, theme)}\n`);
|
|
43
|
+
}
|
|
44
|
+
export async function runMarketPriceCommand(ticker, options, context = {}) {
|
|
45
|
+
const stdout = context.io?.stdout ?? process.stdout;
|
|
46
|
+
const theme = createTerminalTheme(stdout, context.env ?? process.env);
|
|
47
|
+
const response = await invokeCliCapability({
|
|
48
|
+
capability: "market.price",
|
|
49
|
+
input: buildMarketPriceInput(ticker, options),
|
|
50
|
+
env: context.env,
|
|
51
|
+
fetch: context.fetch,
|
|
52
|
+
});
|
|
53
|
+
if (options.json) {
|
|
54
|
+
stdout.write(`${JSON.stringify(response.data, null, 2)}\n`);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
stdout.write(`${formatMarketPriceHuman(response.data, theme)}\n`);
|
|
58
|
+
}
|
|
59
|
+
function normalizeMarketAssetType(rawType) {
|
|
60
|
+
if (!rawType) {
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
const normalized = rawType.trim();
|
|
64
|
+
if (!normalized) {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
if (!monitoredAssetTypes.includes(normalized)) {
|
|
68
|
+
throw createCliValidationError(`Invalid asset type. Use one of: ${monitoredAssetTypes.join(", ")}.`);
|
|
69
|
+
}
|
|
70
|
+
return normalized;
|
|
71
|
+
}
|
|
72
|
+
function buildMarketPriceInput(ticker, options) {
|
|
73
|
+
const payload = {
|
|
74
|
+
ticker,
|
|
75
|
+
timeframe: options.timeframe ?? "D1",
|
|
76
|
+
};
|
|
77
|
+
if (options.date) {
|
|
78
|
+
payload.date = options.date;
|
|
79
|
+
}
|
|
80
|
+
return payload;
|
|
81
|
+
}
|
|
82
|
+
export function formatMarketAssetsHuman(data, theme = createTerminalTheme(process.stdout)) {
|
|
83
|
+
const lines = [
|
|
84
|
+
theme.label("Available market assets"),
|
|
85
|
+
"",
|
|
86
|
+
`${theme.label("Total:")} ${formatInteger(data.total)}`,
|
|
87
|
+
];
|
|
88
|
+
for (const [group, symbols] of Object.entries(data.groups)) {
|
|
89
|
+
lines.push("");
|
|
90
|
+
lines.push(`${theme.label(group)} ${theme.dim(`(${formatInteger(symbols.length)})`)}`);
|
|
91
|
+
lines.push(...wrapSymbols(symbols));
|
|
92
|
+
}
|
|
93
|
+
return lines.join("\n");
|
|
94
|
+
}
|
|
95
|
+
export function formatMarketPriceHuman(data, theme = createTerminalTheme(process.stdout)) {
|
|
96
|
+
const identity = data.name && data.name.trim()
|
|
97
|
+
? `${theme.bold(data.ticker)} ${theme.dim(`· ${data.name}`)}`
|
|
98
|
+
: theme.bold(data.ticker);
|
|
99
|
+
const lines = [theme.label("Market price"), "", identity];
|
|
100
|
+
if (data.type) {
|
|
101
|
+
lines.push(`${theme.label("Type:")} ${data.type}`);
|
|
102
|
+
}
|
|
103
|
+
lines.push(`${theme.label("Timeframe:")} ${data.timeframe}`);
|
|
104
|
+
lines.push(`${theme.label("Price date:")} ${data.price_date}`);
|
|
105
|
+
lines.push("");
|
|
106
|
+
lines.push(`${theme.label("Close:")} ${formatNumber(data.close)}`);
|
|
107
|
+
lines.push(`${theme.label("Open:")} ${formatNumber(data.open)}`);
|
|
108
|
+
lines.push(`${theme.label("High:")} ${formatNumber(data.high)}`);
|
|
109
|
+
lines.push(`${theme.label("Low:")} ${formatNumber(data.low)}`);
|
|
110
|
+
if (data.volume !== null) {
|
|
111
|
+
lines.push(`${theme.label("Volume:")} ${formatNumber(data.volume)}`);
|
|
112
|
+
}
|
|
113
|
+
if (data.prev_close !== null) {
|
|
114
|
+
lines.push(`${theme.label("Previous close:")} ${formatNumber(data.prev_close)}`);
|
|
115
|
+
}
|
|
116
|
+
if (data.change_pct !== null) {
|
|
117
|
+
lines.push(`${theme.label("Change:")} ${formatChangePct(data.change_pct, theme)}`);
|
|
118
|
+
}
|
|
119
|
+
return lines.join("\n");
|
|
120
|
+
}
|
|
121
|
+
function formatNumber(value) {
|
|
122
|
+
return new Intl.NumberFormat("en-US", {
|
|
123
|
+
maximumFractionDigits: 4,
|
|
124
|
+
}).format(value);
|
|
125
|
+
}
|
|
126
|
+
function formatInteger(value) {
|
|
127
|
+
return new Intl.NumberFormat("en-US", {
|
|
128
|
+
maximumFractionDigits: 0,
|
|
129
|
+
}).format(value);
|
|
130
|
+
}
|
|
131
|
+
function formatChangePct(value, theme) {
|
|
132
|
+
const formatted = `${new Intl.NumberFormat("en-US", {
|
|
133
|
+
maximumFractionDigits: 2,
|
|
134
|
+
minimumFractionDigits: 2,
|
|
135
|
+
}).format(value)}%`;
|
|
136
|
+
if (value > 0) {
|
|
137
|
+
return theme.success(formatted);
|
|
138
|
+
}
|
|
139
|
+
if (value < 0) {
|
|
140
|
+
return theme.danger(formatted);
|
|
141
|
+
}
|
|
142
|
+
return formatted;
|
|
143
|
+
}
|
|
144
|
+
function wrapSymbols(symbols) {
|
|
145
|
+
const lines = [];
|
|
146
|
+
let current = " ";
|
|
147
|
+
for (const symbol of symbols) {
|
|
148
|
+
const next = current.trim() === ""
|
|
149
|
+
? ` ${symbol}`
|
|
150
|
+
: `${current}${current === " " ? "" : ", "}${symbol}`;
|
|
151
|
+
if (next.length > 88 && current !== " ") {
|
|
152
|
+
lines.push(current);
|
|
153
|
+
current = ` ${symbol}`;
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
current = next;
|
|
157
|
+
}
|
|
158
|
+
if (current.trim()) {
|
|
159
|
+
lines.push(current);
|
|
160
|
+
}
|
|
161
|
+
return lines;
|
|
162
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
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 PortfoliosCommandIO {
|
|
6
|
+
stdout: TerminalWriter;
|
|
7
|
+
}
|
|
8
|
+
export interface PortfolioListCommandOptions {
|
|
9
|
+
json?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface PortfolioGetCommandOptions {
|
|
12
|
+
json?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface PortfolioMutationCommandOptions {
|
|
15
|
+
json?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface PortfolioOut {
|
|
18
|
+
[key: string]: JsonValue;
|
|
19
|
+
id: number;
|
|
20
|
+
name: string;
|
|
21
|
+
symbols: string[];
|
|
22
|
+
weights: Record<string, number> | null;
|
|
23
|
+
}
|
|
24
|
+
export interface PortfolioListResponse {
|
|
25
|
+
[key: string]: JsonValue;
|
|
26
|
+
ok: boolean;
|
|
27
|
+
portfolios: PortfolioOut[];
|
|
28
|
+
total: number;
|
|
29
|
+
}
|
|
30
|
+
export interface PortfolioGetResponse {
|
|
31
|
+
[key: string]: JsonValue;
|
|
32
|
+
ok: boolean;
|
|
33
|
+
portfolio: PortfolioOut;
|
|
34
|
+
}
|
|
35
|
+
export interface PortfolioCreateResponse {
|
|
36
|
+
[key: string]: JsonValue;
|
|
37
|
+
ok: boolean;
|
|
38
|
+
summary_markdown: string;
|
|
39
|
+
portfolio: PortfolioOut;
|
|
40
|
+
}
|
|
41
|
+
export interface PortfolioMutationResponse {
|
|
42
|
+
[key: string]: JsonValue;
|
|
43
|
+
ok: boolean;
|
|
44
|
+
summary_markdown: string;
|
|
45
|
+
portfolio: PortfolioOut;
|
|
46
|
+
}
|
|
47
|
+
export interface PortfoliosCommandContext extends CliInvokeContext {
|
|
48
|
+
io?: PortfoliosCommandIO;
|
|
49
|
+
}
|
|
50
|
+
export declare function registerPortfoliosCommands(program: Command, context?: PortfoliosCommandContext): void;
|
|
51
|
+
export declare function runPortfolioListCommand(options: PortfolioListCommandOptions, context?: PortfoliosCommandContext): Promise<void>;
|
|
52
|
+
export declare function runPortfolioGetCommand(portfolioId: number, options: PortfolioGetCommandOptions, context?: PortfoliosCommandContext): Promise<void>;
|
|
53
|
+
export declare function runPortfolioCreateCommand(name: string, options: PortfolioMutationCommandOptions, context?: PortfoliosCommandContext): Promise<void>;
|
|
54
|
+
export declare function runPortfolioRenameCommand(portfolioId: number, name: string, options: PortfolioMutationCommandOptions, context?: PortfoliosCommandContext): Promise<void>;
|
|
55
|
+
export declare function runPortfolioAddAssetsCommand(portfolioId: number, symbols: string[], options: PortfolioMutationCommandOptions, context?: PortfoliosCommandContext): Promise<void>;
|
|
56
|
+
export declare function runPortfolioRemoveAssetsCommand(portfolioId: number, symbols: string[], options: PortfolioMutationCommandOptions, context?: PortfoliosCommandContext): Promise<void>;
|
|
57
|
+
export declare function formatPortfolioListHuman(data: PortfolioListResponse, theme?: import("../cli/terminal.js").TerminalTheme): string;
|
|
58
|
+
export declare function formatPortfolioGetHuman(data: PortfolioGetResponse, theme?: import("../cli/terminal.js").TerminalTheme): string;
|
|
59
|
+
export declare function formatPortfolioMutationHuman(data: PortfolioCreateResponse | PortfolioMutationResponse, theme?: import("../cli/terminal.js").TerminalTheme): string;
|
|
60
|
+
//# sourceMappingURL=portfolios.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"portfolios.d.ts","sourceRoot":"","sources":["../../src/commands/portfolios.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import { invokeCliCapability } from "../cli/client.js";
|
|
2
|
+
import { createCliMutationFailedError, createCliValidationError, } from "../cli/errors.js";
|
|
3
|
+
import { createTerminalTheme } from "../cli/terminal.js";
|
|
4
|
+
export function registerPortfoliosCommands(program, context = {}) {
|
|
5
|
+
const portfoliosCommand = program
|
|
6
|
+
.command("portfolios")
|
|
7
|
+
.description("Manage saved portfolios");
|
|
8
|
+
portfoliosCommand
|
|
9
|
+
.command("list")
|
|
10
|
+
.description("List saved portfolios for authenticated user")
|
|
11
|
+
.option("--json", "Show JSON output")
|
|
12
|
+
.action(async (options) => {
|
|
13
|
+
await runPortfolioListCommand(options, context);
|
|
14
|
+
});
|
|
15
|
+
portfoliosCommand
|
|
16
|
+
.command("get")
|
|
17
|
+
.description("Get one saved portfolio by id")
|
|
18
|
+
.argument("<portfolio-id>", "Saved portfolio id", parsePortfolioIdArgument)
|
|
19
|
+
.option("--json", "Show JSON output")
|
|
20
|
+
.action(async (portfolioId, options) => {
|
|
21
|
+
await runPortfolioGetCommand(portfolioId, options, context);
|
|
22
|
+
});
|
|
23
|
+
portfoliosCommand
|
|
24
|
+
.command("create")
|
|
25
|
+
.description("Create a new portfolio")
|
|
26
|
+
.argument("<name>", "Portfolio name")
|
|
27
|
+
.option("--json", "Show JSON output")
|
|
28
|
+
.action(async (name, options) => {
|
|
29
|
+
await runPortfolioCreateCommand(name, options, context);
|
|
30
|
+
});
|
|
31
|
+
portfoliosCommand
|
|
32
|
+
.command("rename")
|
|
33
|
+
.description("Rename an existing portfolio")
|
|
34
|
+
.argument("<portfolio-id>", "Saved portfolio id", parsePortfolioIdArgument)
|
|
35
|
+
.argument("<name>", "New portfolio name")
|
|
36
|
+
.option("--json", "Show JSON output")
|
|
37
|
+
.action(async (portfolioId, name, options) => {
|
|
38
|
+
await runPortfolioRenameCommand(portfolioId, name, options, context);
|
|
39
|
+
});
|
|
40
|
+
portfoliosCommand
|
|
41
|
+
.command("add-assets")
|
|
42
|
+
.description("Add one or more monitored tickers to a portfolio")
|
|
43
|
+
.argument("<portfolio-id>", "Saved portfolio id", parsePortfolioIdArgument)
|
|
44
|
+
.argument("<ticker...>", "One or more tickers to add")
|
|
45
|
+
.option("--json", "Show JSON output")
|
|
46
|
+
.action(async (portfolioId, symbols, options) => {
|
|
47
|
+
await runPortfolioAddAssetsCommand(portfolioId, symbols, options, context);
|
|
48
|
+
});
|
|
49
|
+
portfoliosCommand
|
|
50
|
+
.command("remove-assets")
|
|
51
|
+
.description("Remove one or more monitored tickers from a portfolio")
|
|
52
|
+
.argument("<portfolio-id>", "Saved portfolio id", parsePortfolioIdArgument)
|
|
53
|
+
.argument("<ticker...>", "One or more tickers to remove")
|
|
54
|
+
.option("--json", "Show JSON output")
|
|
55
|
+
.action(async (portfolioId, symbols, options) => {
|
|
56
|
+
await runPortfolioRemoveAssetsCommand(portfolioId, symbols, options, context);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
export async function runPortfolioListCommand(options, context = {}) {
|
|
60
|
+
const stdout = context.io?.stdout ?? process.stdout;
|
|
61
|
+
const theme = createTerminalTheme(stdout, context.env ?? process.env);
|
|
62
|
+
const response = await invokeCliCapability({
|
|
63
|
+
capability: "portfolios.list",
|
|
64
|
+
env: context.env,
|
|
65
|
+
fetch: context.fetch,
|
|
66
|
+
});
|
|
67
|
+
if (options.json) {
|
|
68
|
+
stdout.write(`${JSON.stringify(response.data, null, 2)}\n`);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
stdout.write(`${formatPortfolioListHuman(response.data, theme)}\n`);
|
|
72
|
+
}
|
|
73
|
+
export async function runPortfolioGetCommand(portfolioId, options, context = {}) {
|
|
74
|
+
const stdout = context.io?.stdout ?? process.stdout;
|
|
75
|
+
const theme = createTerminalTheme(stdout, context.env ?? process.env);
|
|
76
|
+
const response = await invokeCliCapability({
|
|
77
|
+
capability: "portfolios.get",
|
|
78
|
+
input: {
|
|
79
|
+
portfolio_id: portfolioId,
|
|
80
|
+
},
|
|
81
|
+
env: context.env,
|
|
82
|
+
fetch: context.fetch,
|
|
83
|
+
});
|
|
84
|
+
if (options.json) {
|
|
85
|
+
stdout.write(`${JSON.stringify(response.data, null, 2)}\n`);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
stdout.write(`${formatPortfolioGetHuman(response.data, theme)}\n`);
|
|
89
|
+
}
|
|
90
|
+
export async function runPortfolioCreateCommand(name, options, context = {}) {
|
|
91
|
+
const stdout = context.io?.stdout ?? process.stdout;
|
|
92
|
+
const theme = createTerminalTheme(stdout, context.env ?? process.env);
|
|
93
|
+
const response = await invokeCliCapability({
|
|
94
|
+
capability: "portfolios.create",
|
|
95
|
+
input: {
|
|
96
|
+
name: parsePortfolioNameArgument(name),
|
|
97
|
+
},
|
|
98
|
+
env: context.env,
|
|
99
|
+
fetch: context.fetch,
|
|
100
|
+
});
|
|
101
|
+
writeMutationResponse(response.data, options.json, stdout, theme);
|
|
102
|
+
}
|
|
103
|
+
export async function runPortfolioRenameCommand(portfolioId, name, options, context = {}) {
|
|
104
|
+
const stdout = context.io?.stdout ?? process.stdout;
|
|
105
|
+
const theme = createTerminalTheme(stdout, context.env ?? process.env);
|
|
106
|
+
const response = await invokeCliCapability({
|
|
107
|
+
capability: "portfolios.rename",
|
|
108
|
+
input: {
|
|
109
|
+
portfolio_id: portfolioId,
|
|
110
|
+
name: parsePortfolioNameArgument(name),
|
|
111
|
+
},
|
|
112
|
+
env: context.env,
|
|
113
|
+
fetch: context.fetch,
|
|
114
|
+
});
|
|
115
|
+
writeMutationResponse(response.data, options.json, stdout, theme);
|
|
116
|
+
}
|
|
117
|
+
export async function runPortfolioAddAssetsCommand(portfolioId, symbols, options, context = {}) {
|
|
118
|
+
const stdout = context.io?.stdout ?? process.stdout;
|
|
119
|
+
const theme = createTerminalTheme(stdout, context.env ?? process.env);
|
|
120
|
+
const response = await invokeCliCapability({
|
|
121
|
+
capability: "portfolios.add-assets",
|
|
122
|
+
input: {
|
|
123
|
+
portfolio_id: portfolioId,
|
|
124
|
+
symbols: parseSymbolArguments(symbols),
|
|
125
|
+
},
|
|
126
|
+
env: context.env,
|
|
127
|
+
fetch: context.fetch,
|
|
128
|
+
});
|
|
129
|
+
writeMutationResponse(response.data, options.json, stdout, theme);
|
|
130
|
+
}
|
|
131
|
+
export async function runPortfolioRemoveAssetsCommand(portfolioId, symbols, options, context = {}) {
|
|
132
|
+
const stdout = context.io?.stdout ?? process.stdout;
|
|
133
|
+
const theme = createTerminalTheme(stdout, context.env ?? process.env);
|
|
134
|
+
const response = await invokeCliCapability({
|
|
135
|
+
capability: "portfolios.remove-assets",
|
|
136
|
+
input: {
|
|
137
|
+
portfolio_id: portfolioId,
|
|
138
|
+
symbols: parseSymbolArguments(symbols),
|
|
139
|
+
},
|
|
140
|
+
env: context.env,
|
|
141
|
+
fetch: context.fetch,
|
|
142
|
+
});
|
|
143
|
+
writeMutationResponse(response.data, options.json, stdout, theme);
|
|
144
|
+
}
|
|
145
|
+
export function formatPortfolioListHuman(data, theme = createTerminalTheme(process.stdout)) {
|
|
146
|
+
const lines = [
|
|
147
|
+
theme.label("Portfolios"),
|
|
148
|
+
"",
|
|
149
|
+
`${theme.label("Total:")} ${formatInteger(data.total)}`,
|
|
150
|
+
];
|
|
151
|
+
if (data.portfolios.length === 0) {
|
|
152
|
+
lines.push("");
|
|
153
|
+
lines.push("No saved portfolios.");
|
|
154
|
+
return lines.join("\n");
|
|
155
|
+
}
|
|
156
|
+
for (const portfolio of data.portfolios) {
|
|
157
|
+
lines.push("");
|
|
158
|
+
lines.push(`${theme.bold(String(portfolio.id))} ${theme.dim("·")} ${portfolio.name}`);
|
|
159
|
+
lines.push(` ${theme.label("Symbols:")} ${formatSymbolSummary(portfolio.symbols)}`);
|
|
160
|
+
if (portfolio.weights) {
|
|
161
|
+
lines.push(` ${theme.label("Weights:")} ${formatWeightsInline(portfolio)}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return lines.join("\n");
|
|
165
|
+
}
|
|
166
|
+
export function formatPortfolioGetHuman(data, theme = createTerminalTheme(process.stdout)) {
|
|
167
|
+
const { portfolio } = data;
|
|
168
|
+
const lines = [
|
|
169
|
+
theme.label("Portfolio"),
|
|
170
|
+
"",
|
|
171
|
+
`${theme.bold(String(portfolio.id))} ${theme.dim("·")} ${portfolio.name}`,
|
|
172
|
+
`${theme.label("Assets:")} ${formatInteger(portfolio.symbols.length)}`,
|
|
173
|
+
];
|
|
174
|
+
if (portfolio.symbols.length === 0) {
|
|
175
|
+
lines.push("");
|
|
176
|
+
lines.push("No assets in this portfolio.");
|
|
177
|
+
return lines.join("\n");
|
|
178
|
+
}
|
|
179
|
+
lines.push("");
|
|
180
|
+
lines.push(theme.label("Holdings"));
|
|
181
|
+
if (portfolio.weights) {
|
|
182
|
+
for (const symbol of portfolio.symbols) {
|
|
183
|
+
const weight = portfolio.weights[symbol];
|
|
184
|
+
const suffix = weight === undefined ? "n/a" : `${formatNumber(weight)}%`;
|
|
185
|
+
lines.push(` - ${symbol}: ${suffix}`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
for (const symbol of portfolio.symbols) {
|
|
190
|
+
lines.push(` - ${symbol}`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return lines.join("\n");
|
|
194
|
+
}
|
|
195
|
+
export function formatPortfolioMutationHuman(data, theme = createTerminalTheme(process.stdout)) {
|
|
196
|
+
const lines = [
|
|
197
|
+
data.ok
|
|
198
|
+
? theme.success(theme.bold("Portfolio"))
|
|
199
|
+
: theme.danger(theme.bold("Portfolio mutation failed")),
|
|
200
|
+
"",
|
|
201
|
+
data.summary_markdown,
|
|
202
|
+
"",
|
|
203
|
+
`${theme.bold(String(data.portfolio.id))} ${theme.dim("·")} ${data.portfolio.name || "Portfolio"}`,
|
|
204
|
+
`${theme.label("Assets:")} ${formatInteger(data.portfolio.symbols.length)}`,
|
|
205
|
+
];
|
|
206
|
+
if (data.portfolio.symbols.length > 0) {
|
|
207
|
+
lines.push("");
|
|
208
|
+
lines.push(theme.label("Holdings"));
|
|
209
|
+
for (const symbol of data.portfolio.symbols) {
|
|
210
|
+
lines.push(` - ${symbol}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return lines.join("\n");
|
|
214
|
+
}
|
|
215
|
+
function parsePortfolioIdArgument(value) {
|
|
216
|
+
const normalized = value.trim();
|
|
217
|
+
if (!/^\d+$/.test(normalized)) {
|
|
218
|
+
throw createCliValidationError("Portfolio id must be a positive integer.");
|
|
219
|
+
}
|
|
220
|
+
const portfolioId = Number(normalized);
|
|
221
|
+
if (!Number.isSafeInteger(portfolioId) || portfolioId <= 0) {
|
|
222
|
+
throw createCliValidationError("Portfolio id must be a positive integer.");
|
|
223
|
+
}
|
|
224
|
+
return portfolioId;
|
|
225
|
+
}
|
|
226
|
+
function parsePortfolioNameArgument(value) {
|
|
227
|
+
const normalized = value.trim();
|
|
228
|
+
if (!normalized) {
|
|
229
|
+
throw createCliValidationError("Portfolio name cannot be empty.");
|
|
230
|
+
}
|
|
231
|
+
if (normalized.length > 100) {
|
|
232
|
+
throw createCliValidationError("Portfolio name cannot exceed 100 characters.");
|
|
233
|
+
}
|
|
234
|
+
return normalized;
|
|
235
|
+
}
|
|
236
|
+
function parseSymbolArguments(values) {
|
|
237
|
+
const symbols = values.map(symbol => symbol.trim().toUpperCase());
|
|
238
|
+
if (symbols.length === 0 || symbols.some(symbol => symbol.length === 0)) {
|
|
239
|
+
throw createCliValidationError("At least one ticker is required.");
|
|
240
|
+
}
|
|
241
|
+
return dedupeSymbols(symbols);
|
|
242
|
+
}
|
|
243
|
+
function dedupeSymbols(symbols) {
|
|
244
|
+
const seen = new Set();
|
|
245
|
+
const deduped = [];
|
|
246
|
+
for (const symbol of symbols) {
|
|
247
|
+
if (seen.has(symbol)) {
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
seen.add(symbol);
|
|
251
|
+
deduped.push(symbol);
|
|
252
|
+
}
|
|
253
|
+
return deduped;
|
|
254
|
+
}
|
|
255
|
+
function writeMutationResponse(data, json, stdout, theme) {
|
|
256
|
+
if (!data.ok) {
|
|
257
|
+
if (!json) {
|
|
258
|
+
stdout.write(`${formatPortfolioMutationHuman(data, theme)}\n`);
|
|
259
|
+
}
|
|
260
|
+
throw createCliMutationFailedError(data.summary_markdown);
|
|
261
|
+
}
|
|
262
|
+
if (json) {
|
|
263
|
+
stdout.write(`${JSON.stringify(data, null, 2)}\n`);
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
stdout.write(`${formatPortfolioMutationHuman(data, theme)}\n`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
function formatSymbolSummary(symbols) {
|
|
270
|
+
if (symbols.length === 0) {
|
|
271
|
+
return "none";
|
|
272
|
+
}
|
|
273
|
+
return `${symbols.join(", ")} ${createCountSuffix(symbols.length)}`;
|
|
274
|
+
}
|
|
275
|
+
function formatWeightsInline(portfolio) {
|
|
276
|
+
if (!portfolio.weights) {
|
|
277
|
+
return "not set";
|
|
278
|
+
}
|
|
279
|
+
return portfolio.symbols
|
|
280
|
+
.map(symbol => {
|
|
281
|
+
const weight = portfolio.weights?.[symbol];
|
|
282
|
+
return `${symbol}=${weight === undefined ? "n/a" : `${formatNumber(weight)}%`}`;
|
|
283
|
+
})
|
|
284
|
+
.join(", ");
|
|
285
|
+
}
|
|
286
|
+
function createCountSuffix(count) {
|
|
287
|
+
return count === 1 ? "(1 asset)" : `(${count} assets)`;
|
|
288
|
+
}
|
|
289
|
+
function formatInteger(value) {
|
|
290
|
+
return new Intl.NumberFormat("en-US", {
|
|
291
|
+
maximumFractionDigits: 0,
|
|
292
|
+
}).format(value);
|
|
293
|
+
}
|
|
294
|
+
function formatNumber(value) {
|
|
295
|
+
return new Intl.NumberFormat("en-US", {
|
|
296
|
+
maximumFractionDigits: 4,
|
|
297
|
+
}).format(value);
|
|
298
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { type SkillInstallResult } from "../cli/skills.js";
|
|
3
|
+
import { type TerminalWriter } from "../cli/terminal.js";
|
|
4
|
+
export interface SkillsCommandIO {
|
|
5
|
+
stdout: TerminalWriter;
|
|
6
|
+
}
|
|
7
|
+
export interface SkillsCommandContext {
|
|
8
|
+
io?: SkillsCommandIO;
|
|
9
|
+
env?: NodeJS.ProcessEnv;
|
|
10
|
+
}
|
|
11
|
+
export interface SkillsInstallCommandOptions {
|
|
12
|
+
all?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function registerSkillsCommands(program: Command, context?: SkillsCommandContext): void;
|
|
15
|
+
export declare function runSkillsInstallCommand(options: SkillsInstallCommandOptions, context?: SkillsCommandContext): Promise<void>;
|
|
16
|
+
export declare function formatSkillsInstallResult(result: SkillInstallResult, theme?: import("../cli/terminal.js").TerminalTheme): string;
|
|
17
|
+
//# sourceMappingURL=skills.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/commands/skills.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAuB,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAE9E,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,CAAC,EAAE,eAAe,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAED,MAAM,WAAW,2BAA2B;IAC1C,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,oBAAyB,GACjC,IAAI,CAcN;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,2BAA2B,EACpC,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,IAAI,CAAC,CAcf;AAED,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,kBAAkB,EAC1B,KAAK,6CAAsC,GAC1C,MAAM,CAoBR"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { installBundledSkillEverywhere, } from "../cli/skills.js";
|
|
2
|
+
import { createCliValidationError } from "../cli/errors.js";
|
|
3
|
+
import { createTerminalTheme } from "../cli/terminal.js";
|
|
4
|
+
export function registerSkillsCommands(program, context = {}) {
|
|
5
|
+
const skillsCommand = program
|
|
6
|
+
.command("skills")
|
|
7
|
+
.description("Manage bundled public skills");
|
|
8
|
+
skillsCommand
|
|
9
|
+
.command("install")
|
|
10
|
+
.description("Install bundled QuantBrasil skills into detected agent clients")
|
|
11
|
+
.option("--all", "Install all bundled public QuantBrasil skills")
|
|
12
|
+
.action(async (options) => {
|
|
13
|
+
await runSkillsInstallCommand(options, context);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
export async function runSkillsInstallCommand(options, context = {}) {
|
|
17
|
+
if (!options.all) {
|
|
18
|
+
throw createCliValidationError("Use --all to install the bundled QuantBrasil skill into detected agent clients.");
|
|
19
|
+
}
|
|
20
|
+
const stdout = context.io?.stdout ?? process.stdout;
|
|
21
|
+
const theme = createTerminalTheme(stdout, context.env ?? process.env);
|
|
22
|
+
const result = await installBundledSkillEverywhere(context.env ?? process.env);
|
|
23
|
+
stdout.write(`${formatSkillsInstallResult(result, theme)}\n`);
|
|
24
|
+
}
|
|
25
|
+
export function formatSkillsInstallResult(result, theme = createTerminalTheme(process.stdout)) {
|
|
26
|
+
const lines = [theme.label("Installed QuantBrasil skill"), ""];
|
|
27
|
+
for (const target of result.installed) {
|
|
28
|
+
lines.push(`${theme.success(target.label)} ${theme.dim(`→ ${target.installDir}`)}`);
|
|
29
|
+
}
|
|
30
|
+
if (result.skipped.length > 0) {
|
|
31
|
+
lines.push("");
|
|
32
|
+
lines.push(theme.label("Skipped"));
|
|
33
|
+
for (const target of result.skipped) {
|
|
34
|
+
lines.push(`${theme.dim(`${target.label} not detected at ${target.rootDir}`)}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return lines.join("\n");
|
|
38
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { type TerminalWriter } from "../cli/terminal.js";
|
|
3
|
+
export interface StatusCommandIO {
|
|
4
|
+
stdout: TerminalWriter;
|
|
5
|
+
}
|
|
6
|
+
export interface StatusCommandContext {
|
|
7
|
+
io?: StatusCommandIO;
|
|
8
|
+
env?: NodeJS.ProcessEnv;
|
|
9
|
+
}
|
|
10
|
+
export interface StatusFlagOptions {
|
|
11
|
+
status?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare function registerStatusFlag(program: Command, context?: StatusCommandContext): void;
|
|
14
|
+
export declare function runStatusCommand(context?: StatusCommandContext): Promise<void>;
|
|
15
|
+
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAuB,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAE9E,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,CAAC,EAAE,eAAe,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,oBAAyB,GACjC,IAAI,CAUN;AAED,wBAAsB,gBAAgB,CACpC,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,IAAI,CAAC,CAwBf"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { resolveCliStatusSnapshot } from "../cli/config.js";
|
|
2
|
+
import { createTerminalTheme } from "../cli/terminal.js";
|
|
3
|
+
export function registerStatusFlag(program, context = {}) {
|
|
4
|
+
program.option("--status", "Show CLI status");
|
|
5
|
+
program.action(async (options) => {
|
|
6
|
+
if (!options.status) {
|
|
7
|
+
program.outputHelp();
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
await runStatusCommand(context);
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
export async function runStatusCommand(context = {}) {
|
|
14
|
+
const stdout = getStdout(context);
|
|
15
|
+
const theme = createTerminalTheme(stdout, context.env ?? process.env);
|
|
16
|
+
const snapshot = await resolveCliStatusSnapshot(context.env ?? process.env);
|
|
17
|
+
const lines = [
|
|
18
|
+
theme.label("QuantBrasil CLI Status"),
|
|
19
|
+
"",
|
|
20
|
+
`${theme.label("CLI:")} ${formatCliState(snapshot.isReady, theme)}`,
|
|
21
|
+
`${theme.label("Backend:")} ${snapshot.backendUrl} ${theme.dim(formatBackendSource(snapshot.backendSource))}`,
|
|
22
|
+
`${theme.label("Authentication:")} ${formatAuthSource(snapshot.authSource, theme)}`,
|
|
23
|
+
`${theme.label("Local config:")} ${theme.dim(snapshot.configPath)}`,
|
|
24
|
+
`${theme.label("Local file present:")} ${snapshot.storedApiKey ? theme.success("yes") : theme.dim("no")}`,
|
|
25
|
+
`${theme.label("Ready for authenticated commands:")} ${snapshot.isReady ? theme.success("yes") : theme.warning("no")}`,
|
|
26
|
+
];
|
|
27
|
+
if (!snapshot.isReady) {
|
|
28
|
+
lines.push(theme.dim("Use quantbrasil auth login --api-key <key> or set QUANTBRASIL_API_KEY."));
|
|
29
|
+
}
|
|
30
|
+
stdout.write(`${lines.join("\n")}\n`);
|
|
31
|
+
}
|
|
32
|
+
function formatAuthSource(source, theme) {
|
|
33
|
+
switch (source) {
|
|
34
|
+
case "env":
|
|
35
|
+
return theme.info("configured via QUANTBRASIL_API_KEY");
|
|
36
|
+
case "config":
|
|
37
|
+
return theme.info("configured via local file");
|
|
38
|
+
case "none":
|
|
39
|
+
return theme.warning("not configured");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function formatBackendSource(source) {
|
|
43
|
+
return source === "override" ? "(QB_BACKEND_URL)" : "(default)";
|
|
44
|
+
}
|
|
45
|
+
function formatCliState(isReady, theme) {
|
|
46
|
+
return isReady
|
|
47
|
+
? theme.success(theme.bold("ready"))
|
|
48
|
+
: theme.warning("authentication required");
|
|
49
|
+
}
|
|
50
|
+
function getStdout(context) {
|
|
51
|
+
return context.io?.stdout ?? process.stdout;
|
|
52
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export * from "./cli/auth.js";
|
|
2
|
+
export * from "./cli/client.js";
|
|
3
|
+
export * from "./cli/errors.js";
|
|
4
|
+
export * from "./cli/index.js";
|
|
5
|
+
export * from "./commands/analytics.js";
|
|
6
|
+
export * from "./commands/assets.js";
|
|
7
|
+
export * from "./commands/auth.js";
|
|
8
|
+
export * from "./commands/capabilities.js";
|
|
9
|
+
export * from "./commands/init.js";
|
|
10
|
+
export * from "./commands/market.js";
|
|
11
|
+
export * from "./commands/portfolios.js";
|
|
12
|
+
export * from "./commands/skills.js";
|
|
13
|
+
export * from "./commands/status.js";
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|