@trading-boy/cli 2.0.1 → 2.1.1
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 +2 -2
- package/dist/api-client.d.ts +15 -1
- package/dist/api-client.js +57 -14
- package/dist/cli.bundle.js +764 -104
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/package.json +15 -14
- package/LICENSE +0 -22
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Remote trading intelligence for traders and AI agents. Real-time market data, on-chain analytics, DeFi risk scoring, and adaptive learning outcomes — all from the command line.
|
|
4
4
|
|
|
5
|
-
**Website:** [
|
|
5
|
+
**Website:** [tradingboy.ai](https://tradingboy.ai) | **Docs:** [tradingboy.ai/docs](https://tradingboy.ai/docs)
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -118,7 +118,7 @@ All plans include every feature. Limits apply to traded tokens and logged trades
|
|
|
118
118
|
Trading Boy exposes an MCP server for AI agent integration and a REST API for programmatic access.
|
|
119
119
|
|
|
120
120
|
```bash
|
|
121
|
-
# REST API is hosted at https://api.
|
|
121
|
+
# REST API is hosted at https://api.tradingboy.ai
|
|
122
122
|
# MCP server: npx @trading-boy/mcp-server
|
|
123
123
|
# CLI onboarding and first-agent setup: see docs/getting-started.md
|
|
124
124
|
```
|
package/dist/api-client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { redactApiKey } from './credentials.js';
|
|
1
|
+
import { redactApiKey, type StoredCredentials } from './credentials.js';
|
|
2
2
|
export interface ApiResponse<T> {
|
|
3
3
|
data: T;
|
|
4
4
|
status: number;
|
|
@@ -8,11 +8,25 @@ export declare class ApiError extends Error {
|
|
|
8
8
|
readonly body?: unknown | undefined;
|
|
9
9
|
constructor(message: string, status: number, body?: unknown | undefined);
|
|
10
10
|
}
|
|
11
|
+
export declare class ApiCredentialMissingError extends Error {
|
|
12
|
+
constructor();
|
|
13
|
+
}
|
|
14
|
+
export declare class ApiCredentialConflictError extends Error {
|
|
15
|
+
readonly sources: string[];
|
|
16
|
+
constructor(sources: string[]);
|
|
17
|
+
}
|
|
11
18
|
/**
|
|
12
19
|
* Dev mode: TRADING_BOY_API_URL points to localhost AND NODE_ENV=development.
|
|
13
20
|
* In dev mode, auth is optional for a local API server.
|
|
14
21
|
*/
|
|
15
22
|
export declare function isDevMode(): boolean;
|
|
23
|
+
export type ApiKeySourceName = 'TRADING_BOY_API_KEY env var' | '--api-key flag' | 'stored credentials';
|
|
24
|
+
export interface ResolvedApiKey {
|
|
25
|
+
apiKey: string;
|
|
26
|
+
source: ApiKeySourceName;
|
|
27
|
+
storedCredentials?: StoredCredentials;
|
|
28
|
+
}
|
|
29
|
+
export declare function resolveApiKeyWithSource(flagKey?: string): Promise<ResolvedApiKey>;
|
|
16
30
|
export declare function resolveApiKey(flagKey?: string): Promise<string>;
|
|
17
31
|
export declare function getApiBase(): string;
|
|
18
32
|
export declare function apiRequest<T>(path: string, options?: {
|
package/dist/api-client.js
CHANGED
|
@@ -2,7 +2,7 @@ import { createLogger } from './logger.js';
|
|
|
2
2
|
import { loadCredentials, redactApiKey } from './credentials.js';
|
|
3
3
|
const logger = createLogger('cli-api-client');
|
|
4
4
|
// ─── Constants ───
|
|
5
|
-
const DEFAULT_API_BASE = 'https://api.
|
|
5
|
+
const DEFAULT_API_BASE = 'https://api.tradingboy.ai';
|
|
6
6
|
export class ApiError extends Error {
|
|
7
7
|
status;
|
|
8
8
|
body;
|
|
@@ -13,6 +13,21 @@ export class ApiError extends Error {
|
|
|
13
13
|
this.name = 'ApiError';
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
+
export class ApiCredentialMissingError extends Error {
|
|
17
|
+
constructor() {
|
|
18
|
+
super('Not authenticated. Run `trading-boy login` to set up your API key.');
|
|
19
|
+
this.name = 'ApiCredentialMissingError';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export class ApiCredentialConflictError extends Error {
|
|
23
|
+
sources;
|
|
24
|
+
constructor(sources) {
|
|
25
|
+
super(`Conflicting API credentials found in ${sources.join(', ')}. ` +
|
|
26
|
+
'Unset one credential source or make them match before running this command.');
|
|
27
|
+
this.sources = sources;
|
|
28
|
+
this.name = 'ApiCredentialConflictError';
|
|
29
|
+
}
|
|
30
|
+
}
|
|
16
31
|
// ─── Dev Mode Detection ───
|
|
17
32
|
/**
|
|
18
33
|
* Dev mode: TRADING_BOY_API_URL points to localhost AND NODE_ENV=development.
|
|
@@ -32,24 +47,52 @@ export function isDevMode() {
|
|
|
32
47
|
return false;
|
|
33
48
|
}
|
|
34
49
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
50
|
+
function normalizeCandidateKey(value) {
|
|
51
|
+
const trimmed = value?.trim();
|
|
52
|
+
return trimmed ? trimmed : null;
|
|
53
|
+
}
|
|
54
|
+
function assertNoCredentialConflicts(candidates) {
|
|
55
|
+
if (candidates.length <= 1)
|
|
56
|
+
return;
|
|
57
|
+
const first = candidates[0].apiKey;
|
|
58
|
+
const conflictingSources = candidates
|
|
59
|
+
.filter((candidate) => candidate.apiKey !== first)
|
|
60
|
+
.map((candidate) => candidate.source);
|
|
61
|
+
if (conflictingSources.length === 0)
|
|
62
|
+
return;
|
|
63
|
+
throw new ApiCredentialConflictError([
|
|
64
|
+
candidates[0].source,
|
|
65
|
+
...conflictingSources,
|
|
66
|
+
]);
|
|
67
|
+
}
|
|
68
|
+
export async function resolveApiKeyWithSource(flagKey) {
|
|
69
|
+
const candidates = [];
|
|
70
|
+
const envKey = normalizeCandidateKey(process.env.TRADING_BOY_API_KEY);
|
|
39
71
|
if (envKey) {
|
|
40
|
-
|
|
41
|
-
return envKey;
|
|
72
|
+
candidates.push({ apiKey: envKey, source: 'TRADING_BOY_API_KEY env var' });
|
|
42
73
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
74
|
+
const normalizedFlagKey = normalizeCandidateKey(flagKey);
|
|
75
|
+
if (normalizedFlagKey) {
|
|
76
|
+
candidates.push({ apiKey: normalizedFlagKey, source: '--api-key flag' });
|
|
46
77
|
}
|
|
47
78
|
const stored = await loadCredentials();
|
|
48
79
|
if (stored?.apiKey) {
|
|
49
|
-
|
|
50
|
-
|
|
80
|
+
candidates.push({
|
|
81
|
+
apiKey: stored.apiKey,
|
|
82
|
+
source: 'stored credentials',
|
|
83
|
+
storedCredentials: stored,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
assertNoCredentialConflicts(candidates);
|
|
87
|
+
const resolved = candidates[0];
|
|
88
|
+
if (!resolved) {
|
|
89
|
+
throw new ApiCredentialMissingError();
|
|
51
90
|
}
|
|
52
|
-
|
|
91
|
+
logger.debug({ source: resolved.source }, 'Using API key');
|
|
92
|
+
return resolved;
|
|
93
|
+
}
|
|
94
|
+
export async function resolveApiKey(flagKey) {
|
|
95
|
+
return (await resolveApiKeyWithSource(flagKey)).apiKey;
|
|
53
96
|
}
|
|
54
97
|
// ─── HTTPS Enforcement ───
|
|
55
98
|
function enforceHttps(url) {
|
|
@@ -77,7 +120,7 @@ export function getApiBase() {
|
|
|
77
120
|
// ─── API Request ───
|
|
78
121
|
export async function apiRequest(path, options = {}) {
|
|
79
122
|
const dev = isDevMode();
|
|
80
|
-
const apiKey = dev ? undefined : (options.apiKey
|
|
123
|
+
const apiKey = dev ? undefined : await resolveApiKey(options.apiKey);
|
|
81
124
|
const apiBase = getApiBase();
|
|
82
125
|
const url = `${apiBase}${path}`;
|
|
83
126
|
const headers = {
|