@trading-boy/cli 2.1.0 → 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 +660 -98
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/package.json +4 -4
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 = {
|
package/dist/cli.bundle.js
CHANGED
|
@@ -19,11 +19,20 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
19
19
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
20
20
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
21
21
|
});
|
|
22
|
-
var __esm = (fn, res) => function __init() {
|
|
23
|
-
|
|
22
|
+
var __esm = (fn, res, err) => function __init() {
|
|
23
|
+
if (err) throw err[0];
|
|
24
|
+
try {
|
|
25
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
26
|
+
} catch (e) {
|
|
27
|
+
throw err = [e], e;
|
|
28
|
+
}
|
|
24
29
|
};
|
|
25
30
|
var __commonJS = (cb, mod) => function __require2() {
|
|
26
|
-
|
|
31
|
+
try {
|
|
32
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
33
|
+
} catch (e) {
|
|
34
|
+
throw mod = 0, e;
|
|
35
|
+
}
|
|
27
36
|
};
|
|
28
37
|
var __export = (target, all) => {
|
|
29
38
|
for (var name in all)
|
|
@@ -6979,13 +6988,16 @@ var init_credentials = __esm({
|
|
|
6979
6988
|
// dist/api-client.js
|
|
6980
6989
|
var api_client_exports = {};
|
|
6981
6990
|
__export(api_client_exports, {
|
|
6991
|
+
ApiCredentialConflictError: () => ApiCredentialConflictError,
|
|
6992
|
+
ApiCredentialMissingError: () => ApiCredentialMissingError,
|
|
6982
6993
|
ApiError: () => ApiError,
|
|
6983
6994
|
apiRequest: () => apiRequest,
|
|
6984
6995
|
getApiBase: () => getApiBase,
|
|
6985
6996
|
isDevMode: () => isDevMode,
|
|
6986
6997
|
isRemoteMode: () => isRemoteMode,
|
|
6987
6998
|
redactApiKey: () => redactApiKey,
|
|
6988
|
-
resolveApiKey: () => resolveApiKey
|
|
6999
|
+
resolveApiKey: () => resolveApiKey,
|
|
7000
|
+
resolveApiKeyWithSource: () => resolveApiKeyWithSource
|
|
6989
7001
|
});
|
|
6990
7002
|
function isDevMode() {
|
|
6991
7003
|
if (process.env.NODE_ENV !== "development")
|
|
@@ -7000,22 +7012,50 @@ function isDevMode() {
|
|
|
7000
7012
|
return false;
|
|
7001
7013
|
}
|
|
7002
7014
|
}
|
|
7003
|
-
|
|
7004
|
-
const
|
|
7015
|
+
function normalizeCandidateKey(value) {
|
|
7016
|
+
const trimmed = value?.trim();
|
|
7017
|
+
return trimmed ? trimmed : null;
|
|
7018
|
+
}
|
|
7019
|
+
function assertNoCredentialConflicts(candidates) {
|
|
7020
|
+
if (candidates.length <= 1)
|
|
7021
|
+
return;
|
|
7022
|
+
const first = candidates[0].apiKey;
|
|
7023
|
+
const conflictingSources = candidates.filter((candidate) => candidate.apiKey !== first).map((candidate) => candidate.source);
|
|
7024
|
+
if (conflictingSources.length === 0)
|
|
7025
|
+
return;
|
|
7026
|
+
throw new ApiCredentialConflictError([
|
|
7027
|
+
candidates[0].source,
|
|
7028
|
+
...conflictingSources
|
|
7029
|
+
]);
|
|
7030
|
+
}
|
|
7031
|
+
async function resolveApiKeyWithSource(flagKey) {
|
|
7032
|
+
const candidates = [];
|
|
7033
|
+
const envKey = normalizeCandidateKey(process.env.TRADING_BOY_API_KEY);
|
|
7005
7034
|
if (envKey) {
|
|
7006
|
-
|
|
7007
|
-
return envKey;
|
|
7035
|
+
candidates.push({ apiKey: envKey, source: "TRADING_BOY_API_KEY env var" });
|
|
7008
7036
|
}
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7037
|
+
const normalizedFlagKey = normalizeCandidateKey(flagKey);
|
|
7038
|
+
if (normalizedFlagKey) {
|
|
7039
|
+
candidates.push({ apiKey: normalizedFlagKey, source: "--api-key flag" });
|
|
7012
7040
|
}
|
|
7013
7041
|
const stored = await loadCredentials();
|
|
7014
7042
|
if (stored?.apiKey) {
|
|
7015
|
-
|
|
7016
|
-
|
|
7043
|
+
candidates.push({
|
|
7044
|
+
apiKey: stored.apiKey,
|
|
7045
|
+
source: "stored credentials",
|
|
7046
|
+
storedCredentials: stored
|
|
7047
|
+
});
|
|
7048
|
+
}
|
|
7049
|
+
assertNoCredentialConflicts(candidates);
|
|
7050
|
+
const resolved = candidates[0];
|
|
7051
|
+
if (!resolved) {
|
|
7052
|
+
throw new ApiCredentialMissingError();
|
|
7017
7053
|
}
|
|
7018
|
-
|
|
7054
|
+
logger2.debug({ source: resolved.source }, "Using API key");
|
|
7055
|
+
return resolved;
|
|
7056
|
+
}
|
|
7057
|
+
async function resolveApiKey(flagKey) {
|
|
7058
|
+
return (await resolveApiKeyWithSource(flagKey)).apiKey;
|
|
7019
7059
|
}
|
|
7020
7060
|
function enforceHttps(url) {
|
|
7021
7061
|
try {
|
|
@@ -7036,7 +7076,7 @@ function getApiBase() {
|
|
|
7036
7076
|
}
|
|
7037
7077
|
async function apiRequest(path3, options = {}) {
|
|
7038
7078
|
const dev = isDevMode();
|
|
7039
|
-
const apiKey = dev ? void 0 :
|
|
7079
|
+
const apiKey = dev ? void 0 : await resolveApiKey(options.apiKey);
|
|
7040
7080
|
const apiBase = getApiBase();
|
|
7041
7081
|
const url = `${apiBase}${path3}`;
|
|
7042
7082
|
const headers = {
|
|
@@ -7109,14 +7149,14 @@ async function isRemoteMode() {
|
|
|
7109
7149
|
const stored = await loadCredentials();
|
|
7110
7150
|
return !!stored?.apiKey;
|
|
7111
7151
|
}
|
|
7112
|
-
var logger2, DEFAULT_API_BASE, ApiError;
|
|
7152
|
+
var logger2, DEFAULT_API_BASE, ApiError, ApiCredentialMissingError, ApiCredentialConflictError;
|
|
7113
7153
|
var init_api_client = __esm({
|
|
7114
7154
|
"dist/api-client.js"() {
|
|
7115
7155
|
"use strict";
|
|
7116
7156
|
init_logger();
|
|
7117
7157
|
init_credentials();
|
|
7118
7158
|
logger2 = createLogger2("cli-api-client");
|
|
7119
|
-
DEFAULT_API_BASE = "https://api.
|
|
7159
|
+
DEFAULT_API_BASE = "https://api.tradingboy.ai";
|
|
7120
7160
|
ApiError = class extends Error {
|
|
7121
7161
|
status;
|
|
7122
7162
|
body;
|
|
@@ -7127,6 +7167,20 @@ var init_api_client = __esm({
|
|
|
7127
7167
|
this.name = "ApiError";
|
|
7128
7168
|
}
|
|
7129
7169
|
};
|
|
7170
|
+
ApiCredentialMissingError = class extends Error {
|
|
7171
|
+
constructor() {
|
|
7172
|
+
super("Not authenticated. Run `trading-boy login` to set up your API key.");
|
|
7173
|
+
this.name = "ApiCredentialMissingError";
|
|
7174
|
+
}
|
|
7175
|
+
};
|
|
7176
|
+
ApiCredentialConflictError = class extends Error {
|
|
7177
|
+
sources;
|
|
7178
|
+
constructor(sources) {
|
|
7179
|
+
super(`Conflicting API credentials found in ${sources.join(", ")}. Unset one credential source or make them match before running this command.`);
|
|
7180
|
+
this.sources = sources;
|
|
7181
|
+
this.name = "ApiCredentialConflictError";
|
|
7182
|
+
}
|
|
7183
|
+
};
|
|
7130
7184
|
}
|
|
7131
7185
|
});
|
|
7132
7186
|
|
|
@@ -21425,6 +21479,39 @@ function createLogger(_name) {
|
|
|
21425
21479
|
}
|
|
21426
21480
|
|
|
21427
21481
|
// src/public-core-shim.ts
|
|
21482
|
+
var LLM_REASONING_EFFORTS = ["minimal", "low", "medium", "high", "xhigh"];
|
|
21483
|
+
var EXIT_REASONER_MODES = ["off", "observe", "notify", "protect", "manage", "full"];
|
|
21484
|
+
var EXIT_STYLES = ["scalp", "swing", "runner", "defensive", "manual"];
|
|
21485
|
+
var EXIT_TIMEFRAMES = ["scalp", "swing", "runner"];
|
|
21486
|
+
var CUSTOMER_API_KEY_V0_PATTERN = /^(tb_(?:live|test|free)_)([a-f0-9]{32})$/;
|
|
21487
|
+
var CUSTOMER_API_KEY_V1_PATTERN = /^(tb_(live|test)_v1_)([A-Za-z0-9_-]{16})\.([A-Za-z0-9_-]{32})$/;
|
|
21488
|
+
function legacyEnvironmentFromPrefix(prefix) {
|
|
21489
|
+
return prefix === "tb_live_" ? "live" : "test";
|
|
21490
|
+
}
|
|
21491
|
+
function parseCustomerApiKey(apiKey) {
|
|
21492
|
+
if (apiKey.trim() !== apiKey) return null;
|
|
21493
|
+
const v1 = apiKey.match(CUSTOMER_API_KEY_V1_PATTERN);
|
|
21494
|
+
if (v1) {
|
|
21495
|
+
const environment = v1[2];
|
|
21496
|
+
const keyId = v1[3];
|
|
21497
|
+
const secret = v1[4];
|
|
21498
|
+
return {
|
|
21499
|
+
version: 1,
|
|
21500
|
+
environment,
|
|
21501
|
+
keyId,
|
|
21502
|
+
secret,
|
|
21503
|
+
keyPrefix: `${v1[1]}${keyId}`,
|
|
21504
|
+
last4: secret.slice(-4)
|
|
21505
|
+
};
|
|
21506
|
+
}
|
|
21507
|
+
const legacy = apiKey.match(CUSTOMER_API_KEY_V0_PATTERN);
|
|
21508
|
+
if (!legacy) return null;
|
|
21509
|
+
return {
|
|
21510
|
+
version: 0,
|
|
21511
|
+
environment: legacyEnvironmentFromPrefix(legacy[1]),
|
|
21512
|
+
keyPrefix: legacy[1] + legacy[2].substring(0, 8)
|
|
21513
|
+
};
|
|
21514
|
+
}
|
|
21428
21515
|
function normalizeWatchlistSymbol(value) {
|
|
21429
21516
|
const trimmed = value.trim();
|
|
21430
21517
|
if (trimmed.length === 0) return trimmed;
|
|
@@ -22208,8 +22295,8 @@ function formatPnl(pnl) {
|
|
|
22208
22295
|
if (pnl === null) {
|
|
22209
22296
|
return source_default.dim("-");
|
|
22210
22297
|
}
|
|
22211
|
-
const sign = pnl >= 0 ? "+" : "";
|
|
22212
|
-
const str = `${sign}$${pnl.toFixed(2)}`;
|
|
22298
|
+
const sign = pnl >= 0 ? "+" : "-";
|
|
22299
|
+
const str = `${sign}$${Math.abs(pnl).toFixed(2)}`;
|
|
22213
22300
|
return pnl > 0 ? source_default.green(str) : pnl < 0 ? source_default.red(str) : source_default.dim(str);
|
|
22214
22301
|
}
|
|
22215
22302
|
function formatPercent(pct) {
|
|
@@ -24480,6 +24567,9 @@ init_logger();
|
|
|
24480
24567
|
init_api_client();
|
|
24481
24568
|
init_utils();
|
|
24482
24569
|
var logger14 = createLogger2("cli-public-config");
|
|
24570
|
+
function formatModelReasoning(model, reasoningEffort) {
|
|
24571
|
+
return reasoningEffort ? `${model} (${reasoningEffort})` : model;
|
|
24572
|
+
}
|
|
24483
24573
|
function printLlmConfig(result) {
|
|
24484
24574
|
console.log("");
|
|
24485
24575
|
console.log(source_default.bold.cyan(" LLM Configuration"));
|
|
@@ -24488,21 +24578,21 @@ function printLlmConfig(result) {
|
|
|
24488
24578
|
if (result.effectiveProvider && (result.effectiveProvider !== result.provider || result.effectiveModel !== result.model)) {
|
|
24489
24579
|
console.log(` ${source_default.gray("Effective:")} ${result.effectiveProvider} / ${result.effectiveModel ?? result.model}`);
|
|
24490
24580
|
}
|
|
24491
|
-
console.log(` ${source_default.gray("Model:")} ${result.model}`);
|
|
24492
|
-
if (result.scanProvider || result.scanModel) {
|
|
24493
|
-
console.log(` ${source_default.gray("Scan:")} ${result.scanProvider ?? result.provider} / ${result.scanModel ?? result.model}`);
|
|
24581
|
+
console.log(` ${source_default.gray("Model:")} ${formatModelReasoning(result.model, result.reasoningEffort)}`);
|
|
24582
|
+
if (result.scanProvider || result.scanModel || result.scanReasoningEffort) {
|
|
24583
|
+
console.log(` ${source_default.gray("Scan:")} ${result.scanProvider ?? result.provider} / ${formatModelReasoning(result.scanModel ?? result.model, result.scanReasoningEffort ?? result.reasoningEffort)}`);
|
|
24494
24584
|
}
|
|
24495
|
-
if (result.analyzeProvider || result.analyzeModel) {
|
|
24496
|
-
console.log(` ${source_default.gray("Analyze:")} ${result.analyzeProvider ?? result.provider} / ${result.analyzeModel ?? result.model}`);
|
|
24585
|
+
if (result.analyzeProvider || result.analyzeModel || result.analyzeReasoningEffort) {
|
|
24586
|
+
console.log(` ${source_default.gray("Analyze:")} ${result.analyzeProvider ?? result.provider} / ${formatModelReasoning(result.analyzeModel ?? result.model, result.analyzeReasoningEffort ?? result.reasoningEffort)}`);
|
|
24497
24587
|
}
|
|
24498
|
-
if (result.decideProvider || result.decideModel) {
|
|
24499
|
-
console.log(` ${source_default.gray("Decide:")} ${result.decideProvider ?? result.provider} / ${result.decideModel ?? result.model}`);
|
|
24588
|
+
if (result.decideProvider || result.decideModel || result.decideReasoningEffort) {
|
|
24589
|
+
console.log(` ${source_default.gray("Decide:")} ${result.decideProvider ?? result.provider} / ${formatModelReasoning(result.decideModel ?? result.model, result.decideReasoningEffort ?? result.reasoningEffort)}`);
|
|
24500
24590
|
}
|
|
24501
|
-
if (result.exitHeartbeatModel) {
|
|
24502
|
-
console.log(` ${source_default.gray("Exit HB:")} ${result.exitHeartbeatModel}`);
|
|
24591
|
+
if (result.exitHeartbeatModel || result.exitHeartbeatReasoningEffort) {
|
|
24592
|
+
console.log(` ${source_default.gray("Exit HB:")} ${formatModelReasoning(result.exitHeartbeatModel ?? result.model, result.exitHeartbeatReasoningEffort ?? result.reasoningEffort)}`);
|
|
24503
24593
|
}
|
|
24504
|
-
if (result.exitEventModel) {
|
|
24505
|
-
console.log(` ${source_default.gray("Exit Event:")} ${result.exitEventModel}`);
|
|
24594
|
+
if (result.exitEventModel || result.exitEventReasoningEffort) {
|
|
24595
|
+
console.log(` ${source_default.gray("Exit Event:")} ${formatModelReasoning(result.exitEventModel ?? result.model, result.exitEventReasoningEffort ?? result.reasoningEffort)}`);
|
|
24506
24596
|
}
|
|
24507
24597
|
if (result.baseUrl) {
|
|
24508
24598
|
console.log(` ${source_default.gray("Base URL:")} ${result.baseUrl}`);
|
|
@@ -24566,7 +24656,44 @@ function registerConfigCommand(program2) {
|
|
|
24566
24656
|
}
|
|
24567
24657
|
printLlmConfig(llmConfig);
|
|
24568
24658
|
});
|
|
24569
|
-
configCmd.command("set-llm-key <apiKey>").description("Store your LLM provider API key for agents, thesis extraction, and coaching (BYOK)").addOption(new Option("-p, --provider <provider>", "LLM provider (auto-detected from key prefix if omitted)").choices([
|
|
24659
|
+
configCmd.command("set-llm-key <apiKey>").description("Store your LLM provider API key for agents, thesis extraction, and coaching (BYOK)").addOption(new Option("-p, --provider <provider>", "LLM provider (auto-detected from key prefix if omitted)").choices([
|
|
24660
|
+
"anthropic",
|
|
24661
|
+
"openai",
|
|
24662
|
+
"openrouter",
|
|
24663
|
+
"ollama",
|
|
24664
|
+
"gemini",
|
|
24665
|
+
"groq",
|
|
24666
|
+
"deepseek",
|
|
24667
|
+
"codex",
|
|
24668
|
+
"custom"
|
|
24669
|
+
])).option("-m, --model <model>", "Model name (default for all phases)").option("--base-url <url>", "Custom base URL (for openrouter/ollama/custom providers)").option("--scan-model <model>", "Model for market scanning").option("--analyze-model <model>", "Model for deep analysis").option("--decide-model <model>", "Model for trade decisions").addOption(new Option("--scan-provider <provider>", "Provider for scan phase").choices([
|
|
24670
|
+
"anthropic",
|
|
24671
|
+
"openai",
|
|
24672
|
+
"openrouter",
|
|
24673
|
+
"ollama",
|
|
24674
|
+
"gemini",
|
|
24675
|
+
"groq",
|
|
24676
|
+
"deepseek",
|
|
24677
|
+
"custom"
|
|
24678
|
+
])).option("--scan-key <key>", "LLM provider API key for the scan phase").addOption(new Option("--analyze-provider <provider>", "Provider for analyze phase").choices([
|
|
24679
|
+
"anthropic",
|
|
24680
|
+
"openai",
|
|
24681
|
+
"openrouter",
|
|
24682
|
+
"ollama",
|
|
24683
|
+
"gemini",
|
|
24684
|
+
"groq",
|
|
24685
|
+
"deepseek",
|
|
24686
|
+
"custom"
|
|
24687
|
+
])).option("--analyze-key <key>", "LLM provider API key for the analyze phase").addOption(new Option("--decide-provider <provider>", "Provider for decide phase").choices([
|
|
24688
|
+
"anthropic",
|
|
24689
|
+
"openai",
|
|
24690
|
+
"openrouter",
|
|
24691
|
+
"ollama",
|
|
24692
|
+
"gemini",
|
|
24693
|
+
"groq",
|
|
24694
|
+
"deepseek",
|
|
24695
|
+
"custom"
|
|
24696
|
+
])).option("--decide-key <key>", "LLM provider API key for the decide phase").action(async (apiKey, opts) => {
|
|
24570
24697
|
if (!await ensureRemote())
|
|
24571
24698
|
return;
|
|
24572
24699
|
try {
|
|
@@ -24615,12 +24742,14 @@ function registerConfigCommand(program2) {
|
|
|
24615
24742
|
process.exitCode = error2 instanceof ApiError ? 2 : 1;
|
|
24616
24743
|
}
|
|
24617
24744
|
});
|
|
24618
|
-
configCmd.command("set-models").description("Update per-stage model assignments (works with BYOK or a ChatGPT connection)").option("-m, --model <model>", "Default model for all phases").
|
|
24745
|
+
configCmd.command("set-models").description("Update per-stage model assignments (works with BYOK or a ChatGPT connection)").option("-m, --model <model>", "Default model for all phases").addOption(new Option("--reasoning-effort <effort>", "Default reasoning effort").choices([
|
|
24746
|
+
...LLM_REASONING_EFFORTS
|
|
24747
|
+
])).option("--scan-model <model>", "Model for market scanning").addOption(new Option("--scan-reasoning-effort <effort>", "Reasoning effort for market scanning").choices([...LLM_REASONING_EFFORTS])).option("--analyze-model <model>", "Model for deep analysis").addOption(new Option("--analyze-reasoning-effort <effort>", "Reasoning effort for deep analysis").choices([...LLM_REASONING_EFFORTS])).option("--decide-model <model>", "Model for trade decisions").addOption(new Option("--decide-reasoning-effort <effort>", "Reasoning effort for trade decisions").choices([...LLM_REASONING_EFFORTS])).option("--exit-heartbeat-model <model>", "Model for exit heartbeat checks").addOption(new Option("--exit-heartbeat-reasoning-effort <effort>", "Reasoning effort for exit heartbeat checks").choices([...LLM_REASONING_EFFORTS])).option("--exit-event-model <model>", "Model for exit event-driven analysis").addOption(new Option("--exit-event-reasoning-effort <effort>", "Reasoning effort for exit event-driven analysis").choices([...LLM_REASONING_EFFORTS])).action(async (opts) => {
|
|
24619
24748
|
if (!await ensureRemote())
|
|
24620
24749
|
return;
|
|
24621
|
-
if (!opts.model && !opts.scanModel && !opts.analyzeModel && !opts.decideModel && !opts.exitHeartbeatModel && !opts.exitEventModel) {
|
|
24622
|
-
console.error(source_default.red(" Error: At least one model flag is required."));
|
|
24623
|
-
console.log(source_default.dim(" Example: trading-boy config set-models --
|
|
24750
|
+
if (!opts.model && !opts.reasoningEffort && !opts.scanModel && !opts.scanReasoningEffort && !opts.analyzeModel && !opts.analyzeReasoningEffort && !opts.decideModel && !opts.decideReasoningEffort && !opts.exitHeartbeatModel && !opts.exitHeartbeatReasoningEffort && !opts.exitEventModel && !opts.exitEventReasoningEffort) {
|
|
24751
|
+
console.error(source_default.red(" Error: At least one model or reasoning flag is required."));
|
|
24752
|
+
console.log(source_default.dim(" Example: trading-boy config set-models --model gpt-5.5 --reasoning-effort low"));
|
|
24624
24753
|
process.exitCode = 1;
|
|
24625
24754
|
return;
|
|
24626
24755
|
}
|
|
@@ -24629,27 +24758,33 @@ function registerConfigCommand(program2) {
|
|
|
24629
24758
|
method: "PATCH",
|
|
24630
24759
|
body: {
|
|
24631
24760
|
...opts.model ? { model: opts.model } : {},
|
|
24761
|
+
...opts.reasoningEffort ? { reasoningEffort: opts.reasoningEffort } : {},
|
|
24632
24762
|
...opts.scanModel ? { scanModel: opts.scanModel } : {},
|
|
24763
|
+
...opts.scanReasoningEffort ? { scanReasoningEffort: opts.scanReasoningEffort } : {},
|
|
24633
24764
|
...opts.analyzeModel ? { analyzeModel: opts.analyzeModel } : {},
|
|
24765
|
+
...opts.analyzeReasoningEffort ? { analyzeReasoningEffort: opts.analyzeReasoningEffort } : {},
|
|
24634
24766
|
...opts.decideModel ? { decideModel: opts.decideModel } : {},
|
|
24767
|
+
...opts.decideReasoningEffort ? { decideReasoningEffort: opts.decideReasoningEffort } : {},
|
|
24635
24768
|
...opts.exitHeartbeatModel ? { exitHeartbeatModel: opts.exitHeartbeatModel } : {},
|
|
24636
|
-
...opts.
|
|
24769
|
+
...opts.exitHeartbeatReasoningEffort ? { exitHeartbeatReasoningEffort: opts.exitHeartbeatReasoningEffort } : {},
|
|
24770
|
+
...opts.exitEventModel ? { exitEventModel: opts.exitEventModel } : {},
|
|
24771
|
+
...opts.exitEventReasoningEffort ? { exitEventReasoningEffort: opts.exitEventReasoningEffort } : {}
|
|
24637
24772
|
}
|
|
24638
24773
|
});
|
|
24639
24774
|
console.log("");
|
|
24640
|
-
console.log(source_default.green(" Stage
|
|
24775
|
+
console.log(source_default.green(" Stage LLM settings updated"));
|
|
24641
24776
|
console.log(source_default.gray(" " + "\u2500".repeat(40)));
|
|
24642
|
-
console.log(` ${source_default.gray("Default:")} ${result.model}`);
|
|
24643
|
-
if (result.scanModel)
|
|
24644
|
-
console.log(` ${source_default.gray("Scan:")} ${result.scanModel}`);
|
|
24645
|
-
if (result.analyzeModel)
|
|
24646
|
-
console.log(` ${source_default.gray("Analyze:")} ${result.analyzeModel}`);
|
|
24647
|
-
if (result.decideModel)
|
|
24648
|
-
console.log(` ${source_default.gray("Decide:")} ${result.decideModel}`);
|
|
24649
|
-
if (result.exitHeartbeatModel)
|
|
24650
|
-
console.log(` ${source_default.gray("Exit heartbeat:")} ${result.exitHeartbeatModel}`);
|
|
24651
|
-
if (result.exitEventModel)
|
|
24652
|
-
console.log(` ${source_default.gray("Exit event:")} ${result.exitEventModel}`);
|
|
24777
|
+
console.log(` ${source_default.gray("Default:")} ${formatModelReasoning(result.model, result.reasoningEffort)}`);
|
|
24778
|
+
if (result.scanModel || result.scanReasoningEffort)
|
|
24779
|
+
console.log(` ${source_default.gray("Scan:")} ${formatModelReasoning(result.scanModel ?? result.model, result.scanReasoningEffort ?? result.reasoningEffort)}`);
|
|
24780
|
+
if (result.analyzeModel || result.analyzeReasoningEffort)
|
|
24781
|
+
console.log(` ${source_default.gray("Analyze:")} ${formatModelReasoning(result.analyzeModel ?? result.model, result.analyzeReasoningEffort ?? result.reasoningEffort)}`);
|
|
24782
|
+
if (result.decideModel || result.decideReasoningEffort)
|
|
24783
|
+
console.log(` ${source_default.gray("Decide:")} ${formatModelReasoning(result.decideModel ?? result.model, result.decideReasoningEffort ?? result.reasoningEffort)}`);
|
|
24784
|
+
if (result.exitHeartbeatModel || result.exitHeartbeatReasoningEffort)
|
|
24785
|
+
console.log(` ${source_default.gray("Exit heartbeat:")} ${formatModelReasoning(result.exitHeartbeatModel ?? result.model, result.exitHeartbeatReasoningEffort ?? result.reasoningEffort)}`);
|
|
24786
|
+
if (result.exitEventModel || result.exitEventReasoningEffort)
|
|
24787
|
+
console.log(` ${source_default.gray("Exit event:")} ${formatModelReasoning(result.exitEventModel ?? result.model, result.exitEventReasoningEffort ?? result.reasoningEffort)}`);
|
|
24653
24788
|
console.log("");
|
|
24654
24789
|
console.log(source_default.dim(" Agents will use these models on their next tick."));
|
|
24655
24790
|
console.log("");
|
|
@@ -24712,9 +24847,9 @@ init_source();
|
|
|
24712
24847
|
init_credentials();
|
|
24713
24848
|
init_api_client();
|
|
24714
24849
|
var logger15 = createLogger("cli-login");
|
|
24715
|
-
var
|
|
24850
|
+
var API_KEY_FORMAT_HELP = "Expected: tb_live_v1_<keyId>.<secret>, tb_test_v1_<keyId>.<secret>, or legacy tb_live_<32hex>/tb_test_<32hex>/tb_free_<32hex>";
|
|
24716
24851
|
function validateApiKeyFormat(key) {
|
|
24717
|
-
return
|
|
24852
|
+
return parseCustomerApiKey(key) !== null;
|
|
24718
24853
|
}
|
|
24719
24854
|
async function verifyApiKey(apiKey) {
|
|
24720
24855
|
const apiBase = getApiBase();
|
|
@@ -24776,14 +24911,14 @@ function registerLoginCommand(program2) {
|
|
|
24776
24911
|
if (!input)
|
|
24777
24912
|
return "Trading Boy API key is required";
|
|
24778
24913
|
if (!validateApiKeyFormat(input)) {
|
|
24779
|
-
return
|
|
24914
|
+
return `Invalid Trading Boy API key format. ${API_KEY_FORMAT_HELP}`;
|
|
24780
24915
|
}
|
|
24781
24916
|
return true;
|
|
24782
24917
|
}
|
|
24783
24918
|
});
|
|
24784
24919
|
}
|
|
24785
24920
|
if (!validateApiKeyFormat(apiKey)) {
|
|
24786
|
-
console.error(source_default.red(
|
|
24921
|
+
console.error(source_default.red(` Invalid Trading Boy API key format. ${API_KEY_FORMAT_HELP}`));
|
|
24787
24922
|
process.exitCode = 1;
|
|
24788
24923
|
return;
|
|
24789
24924
|
}
|
|
@@ -24915,34 +25050,31 @@ init_credentials();
|
|
|
24915
25050
|
init_api_client();
|
|
24916
25051
|
var logger17 = createLogger("cli-whoami");
|
|
24917
25052
|
async function executeWhoami() {
|
|
24918
|
-
|
|
24919
|
-
|
|
24920
|
-
|
|
24921
|
-
|
|
24922
|
-
|
|
24923
|
-
|
|
24924
|
-
}
|
|
24925
|
-
|
|
24926
|
-
const creds = await loadCredentials();
|
|
24927
|
-
if (!creds) {
|
|
24928
|
-
return { authenticated: false };
|
|
25053
|
+
let resolved;
|
|
25054
|
+
try {
|
|
25055
|
+
resolved = await resolveApiKeyWithSource();
|
|
25056
|
+
} catch (error2) {
|
|
25057
|
+
if (error2 instanceof ApiCredentialMissingError) {
|
|
25058
|
+
return { authenticated: false };
|
|
25059
|
+
}
|
|
25060
|
+
throw error2;
|
|
24929
25061
|
}
|
|
25062
|
+
const creds = resolved.source === "stored credentials" ? resolved.storedCredentials ?? await loadCredentials() : null;
|
|
24930
25063
|
const result = {
|
|
24931
25064
|
authenticated: true,
|
|
24932
|
-
email: creds
|
|
24933
|
-
plan: creds
|
|
24934
|
-
keyId: creds
|
|
24935
|
-
redactedKey: redactApiKey(
|
|
24936
|
-
storageMethod: creds.
|
|
24937
|
-
storedAt: creds
|
|
25065
|
+
email: creds?.email,
|
|
25066
|
+
plan: creds?.plan,
|
|
25067
|
+
keyId: creds?.keyId,
|
|
25068
|
+
redactedKey: redactApiKey(resolved.apiKey),
|
|
25069
|
+
storageMethod: resolved.source === "stored credentials" ? creds?.storageMethod : resolved.source,
|
|
25070
|
+
storedAt: creds?.storedAt
|
|
24938
25071
|
};
|
|
24939
25072
|
try {
|
|
24940
|
-
const apiKey = await resolveApiKey();
|
|
24941
25073
|
const response = await fetch(`${getApiBase()}/api/v1/auth/verify`, {
|
|
24942
25074
|
method: "POST",
|
|
24943
25075
|
headers: {
|
|
24944
25076
|
"Content-Type": "application/json",
|
|
24945
|
-
"Authorization": `Bearer ${apiKey}`
|
|
25077
|
+
"Authorization": `Bearer ${resolved.apiKey}`
|
|
24946
25078
|
},
|
|
24947
25079
|
body: "{}"
|
|
24948
25080
|
});
|
|
@@ -25011,16 +25143,9 @@ function registerWhoamiCommand(program2) {
|
|
|
25011
25143
|
try {
|
|
25012
25144
|
const result = await executeWhoami();
|
|
25013
25145
|
if (options.showKey && result.authenticated) {
|
|
25014
|
-
const
|
|
25015
|
-
|
|
25016
|
-
|
|
25017
|
-
return;
|
|
25018
|
-
}
|
|
25019
|
-
const creds = await loadCredentials();
|
|
25020
|
-
if (creds) {
|
|
25021
|
-
console.log(creds.apiKey);
|
|
25022
|
-
return;
|
|
25023
|
-
}
|
|
25146
|
+
const resolved = await resolveApiKeyWithSource();
|
|
25147
|
+
console.log(resolved.apiKey);
|
|
25148
|
+
return;
|
|
25024
25149
|
}
|
|
25025
25150
|
if (options.format === "json") {
|
|
25026
25151
|
console.log(JSON.stringify({ ...result, apiUrl: getApiBase() }, null, 2));
|
|
@@ -25735,7 +25860,7 @@ function printExploreQuickReference() {
|
|
|
25735
25860
|
console.log(` ${source_default.white("trading-boy stats")} ${source_default.dim("Track performance")}`);
|
|
25736
25861
|
console.log("");
|
|
25737
25862
|
console.log(source_default.dim(" Build an agent later: trading-boy onboarding"));
|
|
25738
|
-
console.log(source_default.dim(" Full docs: https://api.
|
|
25863
|
+
console.log(source_default.dim(" Full docs: https://api.tradingboy.ai/docs"));
|
|
25739
25864
|
console.log("");
|
|
25740
25865
|
}
|
|
25741
25866
|
function printAgentRuntimeOverview() {
|
|
@@ -25779,7 +25904,7 @@ function printAgentQuickReference(traderRegistered) {
|
|
|
25779
25904
|
console.log(` ${source_default.white("trading-boy behavioral profile --trader <trader-id>")} ${source_default.dim("Behavioral analysis")}`);
|
|
25780
25905
|
}
|
|
25781
25906
|
console.log("");
|
|
25782
|
-
console.log(source_default.dim(" Full docs: https://api.
|
|
25907
|
+
console.log(source_default.dim(" Full docs: https://api.tradingboy.ai/docs"));
|
|
25783
25908
|
console.log("");
|
|
25784
25909
|
}
|
|
25785
25910
|
async function resolveTraderId(nameOrId) {
|
|
@@ -26208,7 +26333,7 @@ async function pollForApiKey(token, onTick) {
|
|
|
26208
26333
|
if (result.status === "expired" || result.status === "not_found") {
|
|
26209
26334
|
return {
|
|
26210
26335
|
success: false,
|
|
26211
|
-
error: "Provisioning token expired.
|
|
26336
|
+
error: "Provisioning token expired or was not found. Run `trading-boy forgot-key -e <email>` to request a one-time HTTPS recovery link. Full API keys are never emailed."
|
|
26212
26337
|
};
|
|
26213
26338
|
}
|
|
26214
26339
|
if (result.status === "already_retrieved") {
|
|
@@ -26225,7 +26350,7 @@ async function pollForApiKey(token, onTick) {
|
|
|
26225
26350
|
}
|
|
26226
26351
|
return {
|
|
26227
26352
|
success: false,
|
|
26228
|
-
error: "Timed out waiting for payment confirmation.
|
|
26353
|
+
error: "Timed out waiting for payment confirmation. Check your payment status, rerun `trading-boy subscribe`, or use `trading-boy forgot-key -e <email>` after activation. Full API keys are never emailed."
|
|
26229
26354
|
};
|
|
26230
26355
|
}
|
|
26231
26356
|
async function saveApiKey(apiKey, metadata) {
|
|
@@ -26537,7 +26662,7 @@ function sleep2(ms) {
|
|
|
26537
26662
|
var ALLOWED_CHECKOUT_DOMAINS = /* @__PURE__ */ new Set([
|
|
26538
26663
|
"checkout.stripe.com",
|
|
26539
26664
|
"billing.stripe.com",
|
|
26540
|
-
"api.
|
|
26665
|
+
"api.tradingboy.ai"
|
|
26541
26666
|
]);
|
|
26542
26667
|
function validateBrowserUrl(url) {
|
|
26543
26668
|
const parsed = new URL(url);
|
|
@@ -26693,7 +26818,7 @@ function formatElapsed2(ms) {
|
|
|
26693
26818
|
return `${seconds}s`;
|
|
26694
26819
|
}
|
|
26695
26820
|
function registerForgotKeyCommand(program2) {
|
|
26696
|
-
program2.command("forgot-key").description("Recover your API key
|
|
26821
|
+
program2.command("forgot-key").description("Recover your API key with a one-time HTTPS claim link").requiredOption("-e, --email <email>", "Your account email address").action(async (options) => {
|
|
26697
26822
|
const { email } = options;
|
|
26698
26823
|
if (!isValidEmail2(email)) {
|
|
26699
26824
|
console.error(source_default.red(" Invalid email address."));
|
|
@@ -26708,6 +26833,7 @@ function registerForgotKeyCommand(program2) {
|
|
|
26708
26833
|
const recovery = await requestKeyRecovery(email);
|
|
26709
26834
|
console.log(source_default.white(" Recovery email sent! Check your inbox."));
|
|
26710
26835
|
console.log(source_default.dim(" Click the link in the email to provision a new key."));
|
|
26836
|
+
console.log(source_default.dim(" Full API keys are never emailed."));
|
|
26711
26837
|
console.log("");
|
|
26712
26838
|
let pollResult;
|
|
26713
26839
|
try {
|
|
@@ -26842,9 +26968,9 @@ function formatAttributionOutput(data) {
|
|
|
26842
26968
|
}
|
|
26843
26969
|
lines.push(source_default.bold(" Summary"));
|
|
26844
26970
|
lines.push(` ${source_default.gray("Total PnL:")} ${colorPnl(s.totalPnlUsd ?? 0)}`);
|
|
26845
|
-
lines.push(` ${source_default.gray("Signal Alpha:")} ${
|
|
26846
|
-
lines.push(` ${source_default.gray("Execution Cost:")} ${
|
|
26847
|
-
lines.push(` ${source_default.gray("Timing Variance:")} ${
|
|
26971
|
+
lines.push(` ${source_default.gray("Signal Alpha:")} ${formatPctPoints(s.avgSignalAlphaPct ?? 0)}`);
|
|
26972
|
+
lines.push(` ${source_default.gray("Execution Cost:")} ${formatPctPoints(s.avgExecutionCostPct ?? 0)}`);
|
|
26973
|
+
lines.push(` ${source_default.gray("Timing Variance:")} ${formatPctPoints(s.avgTimingVariancePct ?? 0)}`);
|
|
26848
26974
|
lines.push(` ${source_default.gray("Trade Count:")} ${s.trades ?? 0}`);
|
|
26849
26975
|
const setupEntries = Object.entries(data.analysis.bySetupType ?? {});
|
|
26850
26976
|
if (setupEntries.length > 0) {
|
|
@@ -26853,7 +26979,7 @@ function formatAttributionOutput(data) {
|
|
|
26853
26979
|
lines.push(` ${source_default.gray("Setup".padEnd(20))}${"Signal%".padStart(10)}${"Exec%".padStart(10)}${"Timing%".padStart(10)}${"N".padStart(5)}`);
|
|
26854
26980
|
lines.push(source_default.gray(" " + "\u2500".repeat(55)));
|
|
26855
26981
|
for (const [setup, v] of setupEntries) {
|
|
26856
|
-
lines.push(` ${setup.padEnd(20)}${
|
|
26982
|
+
lines.push(` ${setup.padEnd(20)}${formatPctPoints(v.avgSignalAlphaPct).padStart(10)}${formatPctPoints(v.avgExecutionCostPct).padStart(10)}${formatPctPoints(v.avgTimingVariancePct).padStart(10)}${String(v.trades).padStart(5)}`);
|
|
26857
26983
|
}
|
|
26858
26984
|
}
|
|
26859
26985
|
if (data.analysis.attributions.length > 0) {
|
|
@@ -26888,13 +27014,17 @@ function colorPnl(usd) {
|
|
|
26888
27014
|
}
|
|
26889
27015
|
function formatUsd4(val) {
|
|
26890
27016
|
const v = val ?? 0;
|
|
26891
|
-
const sign = v >= 0 ? "+" : "";
|
|
26892
|
-
return `${sign}$${v.toFixed(2)}`;
|
|
27017
|
+
const sign = v >= 0 ? "+" : "-";
|
|
27018
|
+
return `${sign}$${Math.abs(v).toFixed(2)}`;
|
|
26893
27019
|
}
|
|
26894
27020
|
function formatPct2(val) {
|
|
26895
27021
|
const v = val ?? 0;
|
|
26896
27022
|
return `${v >= 0 ? "+" : ""}${(v * 100).toFixed(1)}%`;
|
|
26897
27023
|
}
|
|
27024
|
+
function formatPctPoints(val) {
|
|
27025
|
+
const v = val ?? 0;
|
|
27026
|
+
return `${v >= 0 ? "+" : ""}${v.toFixed(1)}%`;
|
|
27027
|
+
}
|
|
26898
27028
|
function registerEdgeCommand(program2) {
|
|
26899
27029
|
program2.command("edge <traderId>").description("Analyze trade quality \u2014 edge ratio and PnL attribution").option("--attribution", "Show PnL attribution breakdown instead of edge ratio").option("--token <symbol>", "Filter by token symbol").option("--limit <n>", "Number of trades to analyze (1-500)", "100").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (traderId, options) => {
|
|
26900
27030
|
try {
|
|
@@ -28247,6 +28377,8 @@ var AUTONOMY_HELP_UPDATE = "Autonomy mode. Choose Fully auto (FULLY_AUTONOMOUS),
|
|
|
28247
28377
|
var MIN_CONFIDENCE_HELP = "Minimum confidence threshold (0-1, so 0.70 = 70%)";
|
|
28248
28378
|
var EXIT_REASONER_HELP = "Enable LLM-powered exit reasoning for open positions (hold, exit, tighten stop, or extend take profit)";
|
|
28249
28379
|
var DISABLE_EXIT_REASONER_HELP = "Disable LLM-powered exit reasoning for open positions";
|
|
28380
|
+
var EXIT_REASONER_MODE_HELP = "Exit reasoner authority mode for open positions";
|
|
28381
|
+
var URGENT_EVENT_EXIT_MODE_HELP = "Urgent event exit review mode; cannot exceed the normal exit reasoner mode";
|
|
28250
28382
|
var SHARED_SCAN_CACHE_INTERNAL_HELP = "Internal/load-test only: bypass shared scan cache for this agent";
|
|
28251
28383
|
var ENABLE_SHARED_SCAN_CACHE_HELP = "Internal/load-test only: re-enable shared scan cache for this agent";
|
|
28252
28384
|
function formatShortDate5(isoString) {
|
|
@@ -28311,7 +28443,7 @@ function parseHumanInterval2(value) {
|
|
|
28311
28443
|
var MIN_SCAN_INTERVAL_MS2 = 6e4;
|
|
28312
28444
|
function registerAgentCommand(program2) {
|
|
28313
28445
|
const agent = program2.command("agent").description("Manage autonomous trading agents");
|
|
28314
|
-
agent.command("create").description("Create a new agent").option("--trader-id <traderId>", "Trader ID").option("--strategy-id <strategyId>", "Strategy ID (optional \u2014 auto-creates if omitted)").option("--name <name>", "Agent name").option("--autonomy <level>", AUTONOMY_HELP_CREATE, "FULLY_AUTONOMOUS").option("--scan-interval <ms>", "Scan interval in raw milliseconds (min 60000; e.g. 300000 = 5m)", "300000").option("--scan-interval-human <duration>", "Scan interval in human-readable format (e.g. 1m, 5m, 15m, 30m, 1h). Overrides --scan-interval").option("--watchlist <symbols>", "Comma-separated token symbols").option("--max-daily-trades <n>", "Max daily trades", "10").option("--max-daily-loss <usd>", "Max daily loss in USD", "500").option("--max-position-size <pct>", "Max position size as decimal (0.10 = 10%)", "0.10").option("--min-confidence <n>", MIN_CONFIDENCE_HELP, "0.60").option("--scan-model <model>", "LLM model for market scanning").option("--analyze-model <model>", "LLM model for deep analysis").option("--decide-model <model>", "LLM model for trade decisions").option("--disable-shared-scan-cache", SHARED_SCAN_CACHE_INTERNAL_HELP).addOption(new Option("--asset-class <class>", "Asset class for this agent").choices(["crypto", "commodities", "mixed"]).default("crypto")).option("--soul-override <text>", "Custom soul/personality for this agent").option("--purpose-override <text>", "Custom purpose/mission for this agent").option("--soul-file <path>", "Load soul from a file").option("--purpose-file <path>", "Load purpose from a file").option("--exit-reasoner", EXIT_REASONER_HELP).addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (options) => {
|
|
28446
|
+
agent.command("create").description("Create a new agent").option("--trader-id <traderId>", "Trader ID").option("--strategy-id <strategyId>", "Strategy ID (optional \u2014 auto-creates if omitted)").option("--name <name>", "Agent name").option("--autonomy <level>", AUTONOMY_HELP_CREATE, "FULLY_AUTONOMOUS").option("--scan-interval <ms>", "Scan interval in raw milliseconds (min 60000; e.g. 300000 = 5m)", "300000").option("--scan-interval-human <duration>", "Scan interval in human-readable format (e.g. 1m, 5m, 15m, 30m, 1h). Overrides --scan-interval").option("--watchlist <symbols>", "Comma-separated token symbols").option("--max-daily-trades <n>", "Max daily trades", "10").option("--max-daily-loss <usd>", "Max daily loss in USD", "500").option("--max-position-size <pct>", "Max position size as decimal (0.10 = 10%)", "0.10").option("--min-confidence <n>", MIN_CONFIDENCE_HELP, "0.60").option("--scan-model <model>", "LLM model for market scanning").option("--analyze-model <model>", "LLM model for deep analysis").option("--decide-model <model>", "LLM model for trade decisions").option("--disable-shared-scan-cache", SHARED_SCAN_CACHE_INTERNAL_HELP).addOption(new Option("--asset-class <class>", "Asset class for this agent").choices(["crypto", "commodities", "mixed"]).default("crypto")).option("--soul-override <text>", "Custom soul/personality for this agent").option("--purpose-override <text>", "Custom purpose/mission for this agent").option("--soul-file <path>", "Load soul from a file").option("--purpose-file <path>", "Load purpose from a file").option("--exit-reasoner", EXIT_REASONER_HELP).addOption(new Option("--exit-reasoner-mode <mode>", EXIT_REASONER_MODE_HELP).choices([...EXIT_REASONER_MODES])).addOption(new Option("--urgent-event-exit-mode <mode>", URGENT_EVENT_EXIT_MODE_HELP).choices([...EXIT_REASONER_MODES])).addOption(new Option("--exit-style <style>", "Exit management preset").choices([...EXIT_STYLES])).addOption(new Option("--exit-timeframe <timeframe>", "Strategy exit timing preset").choices([...EXIT_TIMEFRAMES])).addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (options) => {
|
|
28315
28447
|
if (!await ensureRemote())
|
|
28316
28448
|
return;
|
|
28317
28449
|
if (!options.traderId) {
|
|
@@ -28367,6 +28499,14 @@ function registerAgentCommand(program2) {
|
|
|
28367
28499
|
body.assetClass = options.assetClass;
|
|
28368
28500
|
if (options.exitReasoner)
|
|
28369
28501
|
body.exitReasonerEnabled = true;
|
|
28502
|
+
if (options.exitReasonerMode)
|
|
28503
|
+
body.exitReasonerMode = options.exitReasonerMode;
|
|
28504
|
+
if (options.urgentEventExitMode)
|
|
28505
|
+
body.urgentEventExitReviewMode = options.urgentEventExitMode;
|
|
28506
|
+
if (options.exitStyle)
|
|
28507
|
+
body.exitStyle = options.exitStyle;
|
|
28508
|
+
if (options.exitTimeframe)
|
|
28509
|
+
body.exitTimingPolicy = { timeframe: options.exitTimeframe };
|
|
28370
28510
|
if (options.soulFile) {
|
|
28371
28511
|
const path3 = resolve(options.soulFile);
|
|
28372
28512
|
if (!existsSync2(path3)) {
|
|
@@ -28404,7 +28544,8 @@ function registerAgentCommand(program2) {
|
|
|
28404
28544
|
console.log(` ${source_default.gray("Trader:")} ${result.traderId}`);
|
|
28405
28545
|
console.log(` ${source_default.gray("Strategy:")} ${result.strategyId}${result.autoStrategyCreated ? source_default.dim(" (auto-created)") : ""}`);
|
|
28406
28546
|
console.log(` ${source_default.gray("Autonomy:")} ${formatAutonomy(result.autonomyLevel)}`);
|
|
28407
|
-
console.log(` ${source_default.gray("Exit reasoner:")} ${result.exitReasonerEnabled ? source_default.green("enabled") : source_default.dim("disabled")}`);
|
|
28547
|
+
console.log(` ${source_default.gray("Exit reasoner:")} ${result.exitReasonerEnabled ? source_default.green("enabled") : source_default.dim("disabled")} (${result.exitReasonerMode ?? "off"})`);
|
|
28548
|
+
console.log(` ${source_default.gray("Exit preset:")} ${result.exitStyle ?? "balanced"} / ${result.exitTimingPolicy?.timeframe ?? "swing"}`);
|
|
28408
28549
|
console.log(` ${source_default.gray("Interval:")} ${formatInterval2(result.scanIntervalMs)}`);
|
|
28409
28550
|
console.log(` ${source_default.gray("Next scan:")} ${formatShortDate5(result.nextScanAt)}`);
|
|
28410
28551
|
console.log("");
|
|
@@ -28474,7 +28615,8 @@ function registerAgentCommand(program2) {
|
|
|
28474
28615
|
if (a.decideModel)
|
|
28475
28616
|
console.log(` ${source_default.gray("Decide model:")} ${a.decideModel}`);
|
|
28476
28617
|
console.log(` ${source_default.gray("Shared scan cache:")} ${a.disableSharedScanCache ? source_default.yellow("bypassed") : source_default.dim("enabled")}`);
|
|
28477
|
-
console.log(` ${source_default.gray("Exit reasoner:")} ${a.exitReasonerEnabled ? source_default.green("enabled") : source_default.dim("disabled")}`);
|
|
28618
|
+
console.log(` ${source_default.gray("Exit reasoner:")} ${a.exitReasonerEnabled ? source_default.green("enabled") : source_default.dim("disabled")} (${a.exitReasonerMode ?? "off"})`);
|
|
28619
|
+
console.log(` ${source_default.gray("Exit preset:")} ${a.exitStyle ?? "balanced"} / ${a.exitTimingPolicy?.timeframe ?? "swing"}`);
|
|
28478
28620
|
console.log(` ${source_default.gray("Scan interval:")} ${formatInterval2(a.scanIntervalMs)}`);
|
|
28479
28621
|
console.log(` ${source_default.gray("Max daily trades:")} ${a.maxDailyTrades}`);
|
|
28480
28622
|
console.log(` ${source_default.gray("Max daily loss:")} $${a.maxDailyLossUsd}`);
|
|
@@ -28598,7 +28740,7 @@ function registerAgentCommand(program2) {
|
|
|
28598
28740
|
handleApiError(error2, "Position exit failed", logger30);
|
|
28599
28741
|
}
|
|
28600
28742
|
});
|
|
28601
|
-
agent.command("update <agentId>").description("Update agent config").option("--name <name>", "Agent name").option("--autonomy <level>", AUTONOMY_HELP_UPDATE).option("--scan-interval <ms>", "Scan interval in raw milliseconds (e.g. 300000 = 5m)").option("--scan-interval-human <duration>", "Scan interval in human-readable format (e.g. 1m, 5m, 15m, 30m, 1h). Overrides --scan-interval").option("--watchlist <symbols>", "Comma-separated token symbols").option("--max-daily-trades <n>", "Max daily trades").option("--max-daily-loss <usd>", "Max daily loss in USD").option("--max-position-size <pct>", "Max position size as decimal").option("--min-confidence <n>", MIN_CONFIDENCE_HELP).option("--scan-model <model>", "LLM model for market scanning").option("--analyze-model <model>", "LLM model for deep analysis").option("--decide-model <model>", "LLM model for trade decisions").option("--disable-shared-scan-cache", SHARED_SCAN_CACHE_INTERNAL_HELP).option("--enable-shared-scan-cache", ENABLE_SHARED_SCAN_CACHE_HELP).addOption(new Option("--asset-class <class>", "Asset class for this agent").choices(["crypto", "commodities", "mixed"])).option("--soul-override <text>", "Custom soul/personality for this agent").option("--purpose-override <text>", "Custom purpose/mission for this agent").option("--soul-file <path>", "Load soul from a file").option("--purpose-file <path>", "Load purpose from a file").option("--exit-reasoner", EXIT_REASONER_HELP).option("--disable-exit-reasoner", DISABLE_EXIT_REASONER_HELP).addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (agentId, options) => {
|
|
28743
|
+
agent.command("update <agentId>").description("Update agent config").option("--name <name>", "Agent name").option("--autonomy <level>", AUTONOMY_HELP_UPDATE).option("--scan-interval <ms>", "Scan interval in raw milliseconds (e.g. 300000 = 5m)").option("--scan-interval-human <duration>", "Scan interval in human-readable format (e.g. 1m, 5m, 15m, 30m, 1h). Overrides --scan-interval").option("--watchlist <symbols>", "Comma-separated token symbols").option("--max-daily-trades <n>", "Max daily trades").option("--max-daily-loss <usd>", "Max daily loss in USD").option("--max-position-size <pct>", "Max position size as decimal").option("--min-confidence <n>", MIN_CONFIDENCE_HELP).option("--scan-model <model>", "LLM model for market scanning").option("--analyze-model <model>", "LLM model for deep analysis").option("--decide-model <model>", "LLM model for trade decisions").option("--disable-shared-scan-cache", SHARED_SCAN_CACHE_INTERNAL_HELP).option("--enable-shared-scan-cache", ENABLE_SHARED_SCAN_CACHE_HELP).addOption(new Option("--asset-class <class>", "Asset class for this agent").choices(["crypto", "commodities", "mixed"])).option("--soul-override <text>", "Custom soul/personality for this agent").option("--purpose-override <text>", "Custom purpose/mission for this agent").option("--soul-file <path>", "Load soul from a file").option("--purpose-file <path>", "Load purpose from a file").option("--exit-reasoner", EXIT_REASONER_HELP).option("--disable-exit-reasoner", DISABLE_EXIT_REASONER_HELP).addOption(new Option("--exit-reasoner-mode <mode>", EXIT_REASONER_MODE_HELP).choices([...EXIT_REASONER_MODES])).addOption(new Option("--urgent-event-exit-mode <mode>", URGENT_EVENT_EXIT_MODE_HELP).choices([...EXIT_REASONER_MODES])).addOption(new Option("--exit-style <style>", "Exit management preset").choices([...EXIT_STYLES])).addOption(new Option("--exit-timeframe <timeframe>", "Strategy exit timing preset").choices([...EXIT_TIMEFRAMES])).addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (agentId, options) => {
|
|
28602
28744
|
if (!await ensureRemote())
|
|
28603
28745
|
return;
|
|
28604
28746
|
const body = {};
|
|
@@ -28656,6 +28798,14 @@ function registerAgentCommand(program2) {
|
|
|
28656
28798
|
body.exitReasonerEnabled = true;
|
|
28657
28799
|
if (options.disableExitReasoner)
|
|
28658
28800
|
body.exitReasonerEnabled = false;
|
|
28801
|
+
if (options.exitReasonerMode)
|
|
28802
|
+
body.exitReasonerMode = options.exitReasonerMode;
|
|
28803
|
+
if (options.urgentEventExitMode)
|
|
28804
|
+
body.urgentEventExitReviewMode = options.urgentEventExitMode;
|
|
28805
|
+
if (options.exitStyle)
|
|
28806
|
+
body.exitStyle = options.exitStyle;
|
|
28807
|
+
if (options.exitTimeframe)
|
|
28808
|
+
body.exitTimingPolicy = { timeframe: options.exitTimeframe };
|
|
28659
28809
|
if (options.assetClass)
|
|
28660
28810
|
body.assetClass = options.assetClass;
|
|
28661
28811
|
if (options.soulFile) {
|
|
@@ -28701,6 +28851,417 @@ function registerAgentCommand(program2) {
|
|
|
28701
28851
|
});
|
|
28702
28852
|
}
|
|
28703
28853
|
|
|
28854
|
+
// dist/commands/prediction-market-paper.js
|
|
28855
|
+
init_source();
|
|
28856
|
+
init_api_client();
|
|
28857
|
+
init_utils();
|
|
28858
|
+
var PREDICTION_MARKET_PAPER_RESULTS_CLI_FLAG = "PREDICTION_MARKET_PAPER_RESULTS_CLI_ENABLED";
|
|
28859
|
+
var DEFAULT_PAPER_POSITION_LIMIT = 50;
|
|
28860
|
+
var MAX_PAPER_POSITION_LIMIT = 100;
|
|
28861
|
+
var MAX_PAPER_POSITION_OFFSET = 1e4;
|
|
28862
|
+
var SAFE_IDENTIFIER_PATTERN = /^[A-Za-z0-9_.:@-]+$/;
|
|
28863
|
+
var PAPER_POSITION_STATUSES = [
|
|
28864
|
+
"OPEN",
|
|
28865
|
+
"CLOSING",
|
|
28866
|
+
"CLOSED",
|
|
28867
|
+
"EXPIRED",
|
|
28868
|
+
"RESOLVED_WON",
|
|
28869
|
+
"RESOLVED_LOST",
|
|
28870
|
+
"INVALID",
|
|
28871
|
+
"CANCELED",
|
|
28872
|
+
"SETTLED"
|
|
28873
|
+
];
|
|
28874
|
+
function isPredictionMarketPaperCliEnabled(env2 = process.env) {
|
|
28875
|
+
return env2[PREDICTION_MARKET_PAPER_RESULTS_CLI_FLAG] === "true";
|
|
28876
|
+
}
|
|
28877
|
+
function printDisabled(format2) {
|
|
28878
|
+
const payload = {
|
|
28879
|
+
disabled: true,
|
|
28880
|
+
featureFlag: PREDICTION_MARKET_PAPER_RESULTS_CLI_FLAG,
|
|
28881
|
+
mode: "paper",
|
|
28882
|
+
label: "Paper / Simulated",
|
|
28883
|
+
noVenueOrderPlaced: true,
|
|
28884
|
+
message: "Prediction-market paper result inspection is disabled."
|
|
28885
|
+
};
|
|
28886
|
+
if (format2 === "json") {
|
|
28887
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
28888
|
+
return;
|
|
28889
|
+
}
|
|
28890
|
+
console.log(source_default.yellow("Prediction-market paper result inspection is disabled."));
|
|
28891
|
+
console.log(source_default.dim("Paper / Simulated. No venue order placed. Read-only inspection is unavailable in this CLI environment."));
|
|
28892
|
+
}
|
|
28893
|
+
function validateIdentifier(label, value) {
|
|
28894
|
+
if (!value)
|
|
28895
|
+
return null;
|
|
28896
|
+
if (value.length > 300)
|
|
28897
|
+
return `${label} must be 300 characters or fewer.`;
|
|
28898
|
+
if (!SAFE_IDENTIFIER_PATTERN.test(value)) {
|
|
28899
|
+
return `${label} may contain only letters, numbers, underscore, dot, colon, at, or dash.`;
|
|
28900
|
+
}
|
|
28901
|
+
return null;
|
|
28902
|
+
}
|
|
28903
|
+
function parseTimestamp(label, value) {
|
|
28904
|
+
if (!value)
|
|
28905
|
+
return { value: null, error: null };
|
|
28906
|
+
const parsed = new Date(value);
|
|
28907
|
+
if (Number.isNaN(parsed.getTime())) {
|
|
28908
|
+
return { value: null, error: `${label} must be a valid timestamp.` };
|
|
28909
|
+
}
|
|
28910
|
+
return { value: parsed.toISOString(), error: null };
|
|
28911
|
+
}
|
|
28912
|
+
function parseIntegerOption(label, value, fallback, min, max) {
|
|
28913
|
+
if (value == null)
|
|
28914
|
+
return { value: fallback, error: null };
|
|
28915
|
+
const parsed = Number(value);
|
|
28916
|
+
if (!Number.isInteger(parsed)) {
|
|
28917
|
+
return { value: fallback, error: `${label} must be an integer.` };
|
|
28918
|
+
}
|
|
28919
|
+
if (parsed < min || parsed > max) {
|
|
28920
|
+
return { value: fallback, error: `${label} must be between ${min} and ${max}.` };
|
|
28921
|
+
}
|
|
28922
|
+
return { value: parsed, error: null };
|
|
28923
|
+
}
|
|
28924
|
+
function validateWindow(from, to) {
|
|
28925
|
+
if (!from || !to)
|
|
28926
|
+
return null;
|
|
28927
|
+
return new Date(from) < new Date(to) ? null : "--from must be before --to.";
|
|
28928
|
+
}
|
|
28929
|
+
function printValidationError(message) {
|
|
28930
|
+
console.error(source_default.red(`Error: ${message}`));
|
|
28931
|
+
process.exitCode = 1;
|
|
28932
|
+
}
|
|
28933
|
+
function buildQuery(options, includePagination) {
|
|
28934
|
+
for (const [label, value] of [
|
|
28935
|
+
["--agent", options.agent],
|
|
28936
|
+
["--venue", options.venue],
|
|
28937
|
+
["--market-id", options.marketId],
|
|
28938
|
+
["--instrument-key", options.instrumentKey]
|
|
28939
|
+
]) {
|
|
28940
|
+
const error2 = validateIdentifier(label, value);
|
|
28941
|
+
if (error2) {
|
|
28942
|
+
printValidationError(error2);
|
|
28943
|
+
return null;
|
|
28944
|
+
}
|
|
28945
|
+
}
|
|
28946
|
+
const from = parseTimestamp("--from", options.from);
|
|
28947
|
+
if (from.error) {
|
|
28948
|
+
printValidationError(from.error);
|
|
28949
|
+
return null;
|
|
28950
|
+
}
|
|
28951
|
+
const to = parseTimestamp("--to", options.to);
|
|
28952
|
+
if (to.error) {
|
|
28953
|
+
printValidationError(to.error);
|
|
28954
|
+
return null;
|
|
28955
|
+
}
|
|
28956
|
+
const windowError = validateWindow(from.value, to.value);
|
|
28957
|
+
if (windowError) {
|
|
28958
|
+
printValidationError(windowError);
|
|
28959
|
+
return null;
|
|
28960
|
+
}
|
|
28961
|
+
const params = new URLSearchParams();
|
|
28962
|
+
if (options.agent)
|
|
28963
|
+
params.set("agentId", options.agent);
|
|
28964
|
+
if ("status" in options && options.status)
|
|
28965
|
+
params.set("status", options.status);
|
|
28966
|
+
if (options.venue)
|
|
28967
|
+
params.set("venue", options.venue);
|
|
28968
|
+
if (options.marketId)
|
|
28969
|
+
params.set("marketId", options.marketId);
|
|
28970
|
+
if (options.instrumentKey)
|
|
28971
|
+
params.set("instrumentKey", options.instrumentKey);
|
|
28972
|
+
if (from.value)
|
|
28973
|
+
params.set("from", from.value);
|
|
28974
|
+
if (to.value)
|
|
28975
|
+
params.set("to", to.value);
|
|
28976
|
+
if (includePagination) {
|
|
28977
|
+
const queryOptions = options;
|
|
28978
|
+
const limit = parseIntegerOption("--limit", queryOptions.limit, DEFAULT_PAPER_POSITION_LIMIT, 1, MAX_PAPER_POSITION_LIMIT);
|
|
28979
|
+
if (limit.error) {
|
|
28980
|
+
printValidationError(limit.error);
|
|
28981
|
+
return null;
|
|
28982
|
+
}
|
|
28983
|
+
const offset = parseIntegerOption("--offset", queryOptions.offset, 0, 0, MAX_PAPER_POSITION_OFFSET);
|
|
28984
|
+
if (offset.error) {
|
|
28985
|
+
printValidationError(offset.error);
|
|
28986
|
+
return null;
|
|
28987
|
+
}
|
|
28988
|
+
params.set("limit", String(limit.value));
|
|
28989
|
+
params.set("offset", String(offset.value));
|
|
28990
|
+
}
|
|
28991
|
+
return params;
|
|
28992
|
+
}
|
|
28993
|
+
function withQuery(path3, params) {
|
|
28994
|
+
const query = params.toString();
|
|
28995
|
+
return query ? `${path3}?${query}` : path3;
|
|
28996
|
+
}
|
|
28997
|
+
function formatUsd6(value) {
|
|
28998
|
+
if (value == null || !Number.isFinite(value))
|
|
28999
|
+
return source_default.dim("-");
|
|
29000
|
+
return `$${value.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
|
|
29001
|
+
}
|
|
29002
|
+
function formatSignedUsd(value) {
|
|
29003
|
+
if (value == null || !Number.isFinite(value))
|
|
29004
|
+
return source_default.dim("-");
|
|
29005
|
+
const formatted = formatUsd6(Math.abs(value));
|
|
29006
|
+
if (value > 0)
|
|
29007
|
+
return source_default.green(`+${formatted}`);
|
|
29008
|
+
if (value < 0)
|
|
29009
|
+
return source_default.red(`-${formatted}`);
|
|
29010
|
+
return formatted;
|
|
29011
|
+
}
|
|
29012
|
+
function formatProbability(value) {
|
|
29013
|
+
if (value == null || !Number.isFinite(value))
|
|
29014
|
+
return source_default.dim("-");
|
|
29015
|
+
return `${(value * 100).toFixed(1)}%`;
|
|
29016
|
+
}
|
|
29017
|
+
function formatQuantity(value) {
|
|
29018
|
+
if (value == null || !Number.isFinite(value))
|
|
29019
|
+
return source_default.dim("-");
|
|
29020
|
+
return value.toLocaleString("en-US", { maximumFractionDigits: 4 });
|
|
29021
|
+
}
|
|
29022
|
+
function formatTimestamp(value) {
|
|
29023
|
+
if (!value)
|
|
29024
|
+
return source_default.dim("-");
|
|
29025
|
+
try {
|
|
29026
|
+
return new Date(value).toISOString().slice(0, 19).replace("T", " ");
|
|
29027
|
+
} catch {
|
|
29028
|
+
return value;
|
|
29029
|
+
}
|
|
29030
|
+
}
|
|
29031
|
+
function latestLifecycleTime(position) {
|
|
29032
|
+
return position.closedAt ?? position.settledAt ?? position.resolvedAt ?? position.lastMonitoredAt ?? position.latestSnapshotAt ?? null;
|
|
29033
|
+
}
|
|
29034
|
+
function formatPaperSummary(summary) {
|
|
29035
|
+
const lines = [];
|
|
29036
|
+
lines.push("");
|
|
29037
|
+
lines.push(source_default.bold.cyan(" Prediction Market Paper Results"));
|
|
29038
|
+
lines.push(source_default.gray(" Paper / Simulated"));
|
|
29039
|
+
lines.push(source_default.gray(" No venue order placed"));
|
|
29040
|
+
lines.push(source_default.gray(" Read-only inspection"));
|
|
29041
|
+
lines.push(source_default.gray(" " + "-".repeat(52)));
|
|
29042
|
+
lines.push(` ${source_default.gray("Open positions:")} ${summary.openPositions}`);
|
|
29043
|
+
lines.push(` ${source_default.gray("Closed positions:")} ${summary.closedPositions}`);
|
|
29044
|
+
lines.push(` ${source_default.gray("Resolved won:")} ${summary.resolvedWon}`);
|
|
29045
|
+
lines.push(` ${source_default.gray("Resolved lost:")} ${summary.resolvedLost}`);
|
|
29046
|
+
lines.push(` ${source_default.gray("Invalid / canceled:")} ${summary.invalidOrCanceled}`);
|
|
29047
|
+
lines.push(` ${source_default.gray("Total notional:")} ${formatUsd6(summary.totalNotionalUsd)}`);
|
|
29048
|
+
lines.push(` ${source_default.gray("Realized PnL:")} ${formatSignedUsd(summary.realizedPnlUsd)}`);
|
|
29049
|
+
lines.push(` ${source_default.gray("Unrealized PnL:")} ${formatSignedUsd(summary.unrealizedPnlUsd)}`);
|
|
29050
|
+
lines.push(` ${source_default.gray("Last updated:")} ${formatTimestamp(summary.lastUpdatedAt)}`);
|
|
29051
|
+
lines.push("");
|
|
29052
|
+
return lines.join("\n");
|
|
29053
|
+
}
|
|
29054
|
+
function formatPaperPositions(positions) {
|
|
29055
|
+
const lines = [];
|
|
29056
|
+
lines.push("");
|
|
29057
|
+
lines.push(source_default.bold.cyan(" Prediction Market Paper Positions"));
|
|
29058
|
+
lines.push(source_default.gray(" Paper / Simulated"));
|
|
29059
|
+
lines.push(source_default.gray(" No venue order placed"));
|
|
29060
|
+
lines.push(source_default.gray(" Read-only inspection"));
|
|
29061
|
+
lines.push(source_default.gray(" " + "-".repeat(132)));
|
|
29062
|
+
if (positions.length === 0) {
|
|
29063
|
+
lines.push(` ${source_default.dim("No paper prediction-market positions found.")}`);
|
|
29064
|
+
lines.push(` ${source_default.dim("Paper PM results appear only after paper runtime and paper writes are enabled.")}`);
|
|
29065
|
+
lines.push("");
|
|
29066
|
+
return lines.join("\n");
|
|
29067
|
+
}
|
|
29068
|
+
lines.push(` ${source_default.gray("Position".padEnd(14))}${source_default.gray("Agent".padEnd(14))}${source_default.gray("Venue".padEnd(12))}${source_default.gray("Outcome".padEnd(10))}${source_default.gray("Side".padEnd(10))}${source_default.gray("Qty".padStart(10))}${source_default.gray("Entry".padStart(10))}${source_default.gray("Mark".padStart(10))}${source_default.gray("Notional".padStart(12))}${source_default.gray("Realized".padStart(12))}${source_default.gray("Unrealized".padStart(12))}${source_default.gray("Status".padStart(14))}`);
|
|
29069
|
+
lines.push(source_default.gray(" " + "-".repeat(132)));
|
|
29070
|
+
for (const position of positions) {
|
|
29071
|
+
lines.push(` ${truncate(position.positionId, 13).padEnd(14)}${truncate(position.agentId ?? "-", 13).padEnd(14)}${truncate(position.venue ?? "-", 11).padEnd(12)}${truncate(position.outcomeSide ?? "-", 9).padEnd(10)}${truncate(position.positionSide, 9).padEnd(10)}${formatQuantity(position.quantity).padStart(10)}${formatProbability(position.averageEntryPrice).padStart(10)}${formatProbability(position.markPrice).padStart(10)}${formatUsd6(position.notionalUsd).padStart(12)}${formatSignedUsd(position.realizedPnlUsd).padStart(12)}${formatSignedUsd(position.unrealizedPnlUsd).padStart(12)}${truncate(position.status, 13).padStart(14)}`);
|
|
29072
|
+
lines.push(` ${source_default.dim("Market:")} ${truncate(position.marketQuestion ?? position.marketId ?? position.instrumentKey, 92)} ${source_default.dim("Opened:")} ${formatTimestamp(position.openedAt)} ${source_default.dim("Latest:")} ${formatTimestamp(latestLifecycleTime(position))} ` + source_default.dim("paper / no venue order placed"));
|
|
29073
|
+
}
|
|
29074
|
+
lines.push("");
|
|
29075
|
+
return lines.join("\n");
|
|
29076
|
+
}
|
|
29077
|
+
function formatPaperPositionDetail(position) {
|
|
29078
|
+
const lines = [];
|
|
29079
|
+
lines.push("");
|
|
29080
|
+
lines.push(source_default.bold.cyan(` Prediction Market Paper Position - ${position.positionId}`));
|
|
29081
|
+
lines.push(source_default.gray(" Paper / Simulated"));
|
|
29082
|
+
lines.push(source_default.gray(" No venue order placed"));
|
|
29083
|
+
lines.push(source_default.gray(" Read-only inspection"));
|
|
29084
|
+
lines.push(source_default.gray(" " + "-".repeat(68)));
|
|
29085
|
+
lines.push(` ${source_default.gray("Agent:")} ${position.agentId ?? "-"}`);
|
|
29086
|
+
lines.push(` ${source_default.gray("Trader:")} ${position.traderId ?? "-"}`);
|
|
29087
|
+
lines.push(` ${source_default.gray("Instrument key:")} ${position.instrumentKey}`);
|
|
29088
|
+
lines.push(` ${source_default.gray("Instrument type:")} ${position.instrumentType}`);
|
|
29089
|
+
lines.push(` ${source_default.gray("Venue:")} ${position.venue ?? "-"}`);
|
|
29090
|
+
lines.push(` ${source_default.gray("Market ID:")} ${position.marketId ?? "-"}`);
|
|
29091
|
+
lines.push(` ${source_default.gray("Market question:")} ${position.marketQuestion ?? "-"}`);
|
|
29092
|
+
lines.push(` ${source_default.gray("Outcome side:")} ${position.outcomeSide ?? "-"}`);
|
|
29093
|
+
lines.push(` ${source_default.gray("Position side:")} ${position.positionSide}`);
|
|
29094
|
+
lines.push(` ${source_default.gray("Quantity:")} ${formatQuantity(position.quantity)}`);
|
|
29095
|
+
lines.push(` ${source_default.gray("Average entry:")} ${formatProbability(position.averageEntryPrice)}`);
|
|
29096
|
+
lines.push(` ${source_default.gray("Mark:")} ${formatProbability(position.markPrice)}`);
|
|
29097
|
+
lines.push(` ${source_default.gray("Notional USD:")} ${formatUsd6(position.notionalUsd)}`);
|
|
29098
|
+
lines.push(` ${source_default.gray("Realized PnL:")} ${formatSignedUsd(position.realizedPnlUsd)}`);
|
|
29099
|
+
lines.push(` ${source_default.gray("Unrealized PnL:")} ${formatSignedUsd(position.unrealizedPnlUsd)}`);
|
|
29100
|
+
lines.push(` ${source_default.gray("Status:")} ${position.status}`);
|
|
29101
|
+
lines.push(` ${source_default.gray("Opened:")} ${formatTimestamp(position.openedAt)}`);
|
|
29102
|
+
lines.push(` ${source_default.gray("Closed:")} ${formatTimestamp(position.closedAt)}`);
|
|
29103
|
+
lines.push(` ${source_default.gray("Expiry:")} ${formatTimestamp(position.expiryAt)}`);
|
|
29104
|
+
lines.push(` ${source_default.gray("Resolved:")} ${formatTimestamp(position.resolvedAt)}`);
|
|
29105
|
+
lines.push(` ${source_default.gray("Settled:")} ${formatTimestamp(position.settledAt)}`);
|
|
29106
|
+
lines.push(` ${source_default.gray("Settlement ID:")} ${position.settlementId ?? "-"}`);
|
|
29107
|
+
lines.push(` ${source_default.gray("Execution mode:")} ${position.executionMode}`);
|
|
29108
|
+
lines.push(` ${source_default.gray("Source:")} ${position.source}`);
|
|
29109
|
+
lines.push(` ${source_default.gray("No venue order:")} ${String(position.noVenueOrderPlaced)}`);
|
|
29110
|
+
lines.push("");
|
|
29111
|
+
return lines.join("\n");
|
|
29112
|
+
}
|
|
29113
|
+
async function readSummary(options) {
|
|
29114
|
+
const query = buildQuery(options, false);
|
|
29115
|
+
if (!query)
|
|
29116
|
+
return null;
|
|
29117
|
+
const path3 = withQuery("/api/v1/prediction-market-paper/summary", query);
|
|
29118
|
+
return apiRequest(path3);
|
|
29119
|
+
}
|
|
29120
|
+
async function readPositions(options) {
|
|
29121
|
+
const query = buildQuery(options, true);
|
|
29122
|
+
if (!query)
|
|
29123
|
+
return null;
|
|
29124
|
+
const path3 = withQuery("/api/v1/prediction-market-paper/positions", query);
|
|
29125
|
+
return apiRequest(path3);
|
|
29126
|
+
}
|
|
29127
|
+
async function readAgentSummary(agentId, options) {
|
|
29128
|
+
const idError = validateIdentifier("agentId", agentId);
|
|
29129
|
+
if (idError) {
|
|
29130
|
+
printValidationError(idError);
|
|
29131
|
+
return null;
|
|
29132
|
+
}
|
|
29133
|
+
const query = buildQuery({ ...options, agent: void 0 }, false);
|
|
29134
|
+
if (!query)
|
|
29135
|
+
return null;
|
|
29136
|
+
const path3 = withQuery(`/api/v1/agents/${encodeURIComponent(agentId)}/prediction-market-paper/summary`, query);
|
|
29137
|
+
return apiRequest(path3);
|
|
29138
|
+
}
|
|
29139
|
+
async function readAgentPositions(agentId, options) {
|
|
29140
|
+
const idError = validateIdentifier("agentId", agentId);
|
|
29141
|
+
if (idError) {
|
|
29142
|
+
printValidationError(idError);
|
|
29143
|
+
return null;
|
|
29144
|
+
}
|
|
29145
|
+
const query = buildQuery({ ...options, agent: void 0 }, true);
|
|
29146
|
+
if (!query)
|
|
29147
|
+
return null;
|
|
29148
|
+
const path3 = withQuery(`/api/v1/agents/${encodeURIComponent(agentId)}/prediction-market-paper/positions`, query);
|
|
29149
|
+
return apiRequest(path3);
|
|
29150
|
+
}
|
|
29151
|
+
async function readPosition(positionId) {
|
|
29152
|
+
const idError = validateIdentifier("positionId", positionId);
|
|
29153
|
+
if (idError) {
|
|
29154
|
+
printValidationError(idError);
|
|
29155
|
+
return null;
|
|
29156
|
+
}
|
|
29157
|
+
return apiRequest(`/api/v1/prediction-market-paper/positions/${encodeURIComponent(positionId)}`);
|
|
29158
|
+
}
|
|
29159
|
+
function isBackendDisabled(error2) {
|
|
29160
|
+
if (!(error2 instanceof ApiError))
|
|
29161
|
+
return false;
|
|
29162
|
+
const body = error2.body;
|
|
29163
|
+
return error2.status === 404 && (error2.message.toLowerCase().includes("paper result reads are disabled") || typeof body === "object" && body !== null && body.code === "PREDICTION_MARKET_PAPER_RESULTS_READ_DISABLED");
|
|
29164
|
+
}
|
|
29165
|
+
function handlePaperError(error2, format2) {
|
|
29166
|
+
if (isBackendDisabled(error2)) {
|
|
29167
|
+
const payload = {
|
|
29168
|
+
disabled: true,
|
|
29169
|
+
mode: "paper",
|
|
29170
|
+
label: "Paper / Simulated",
|
|
29171
|
+
noVenueOrderPlaced: true,
|
|
29172
|
+
message: "Prediction-market paper result reads are disabled by the API."
|
|
29173
|
+
};
|
|
29174
|
+
if (format2 === "json") {
|
|
29175
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
29176
|
+
} else {
|
|
29177
|
+
console.log(source_default.yellow("Prediction-market paper result reads are disabled by the API."));
|
|
29178
|
+
console.log(source_default.dim("Paper / Simulated. No venue order placed. Read-only inspection only."));
|
|
29179
|
+
}
|
|
29180
|
+
return;
|
|
29181
|
+
}
|
|
29182
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
29183
|
+
console.error(source_default.red(`Error: ${message}`));
|
|
29184
|
+
process.exitCode = error2 instanceof ApiError ? 2 : 1;
|
|
29185
|
+
}
|
|
29186
|
+
async function runReadAction(format2, action) {
|
|
29187
|
+
if (!isPredictionMarketPaperCliEnabled()) {
|
|
29188
|
+
printDisabled(format2);
|
|
29189
|
+
return;
|
|
29190
|
+
}
|
|
29191
|
+
if (!await ensureRemote())
|
|
29192
|
+
return;
|
|
29193
|
+
try {
|
|
29194
|
+
await action();
|
|
29195
|
+
} catch (error2) {
|
|
29196
|
+
handlePaperError(error2, format2);
|
|
29197
|
+
}
|
|
29198
|
+
}
|
|
29199
|
+
function registerPredictionMarketPaperCommand(program2) {
|
|
29200
|
+
const command = program2.command("prediction-market-paper").alias("pm-paper").description("Inspect paper prediction-market positions and results");
|
|
29201
|
+
const addSummaryFilters = (cmd) => cmd.option("--agent <agentId>", "Optional agent ID filter").option("--venue <venue>", "Venue filter").option("--market-id <marketId>", "Prediction-market ID filter").option("--instrument-key <instrumentKey>", "Instrument key filter").option("--from <timestamp>", "Opened-at window start").option("--to <timestamp>", "Opened-at window end").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text"));
|
|
29202
|
+
const addPositionFilters = (cmd) => addSummaryFilters(cmd).addOption(new Option("--status <status>", "Position status filter").choices([...PAPER_POSITION_STATUSES])).option("--limit <n>", `Maximum rows, 1-${MAX_PAPER_POSITION_LIMIT}`, String(DEFAULT_PAPER_POSITION_LIMIT)).option("--offset <n>", `Rows to skip, 0-${MAX_PAPER_POSITION_OFFSET}`, "0");
|
|
29203
|
+
addSummaryFilters(command.command("summary").description("Show read-only paper prediction-market result summary")).action(async (options) => {
|
|
29204
|
+
await runReadAction(options.format, async () => {
|
|
29205
|
+
const data = await readSummary(options);
|
|
29206
|
+
if (!data)
|
|
29207
|
+
return;
|
|
29208
|
+
if (options.format === "json") {
|
|
29209
|
+
console.log(JSON.stringify(data, null, 2));
|
|
29210
|
+
} else {
|
|
29211
|
+
console.log(formatPaperSummary(data.summary));
|
|
29212
|
+
}
|
|
29213
|
+
});
|
|
29214
|
+
});
|
|
29215
|
+
addPositionFilters(command.command("positions").description("List read-only paper prediction-market positions")).action(async (options) => {
|
|
29216
|
+
await runReadAction(options.format, async () => {
|
|
29217
|
+
const data = await readPositions(options);
|
|
29218
|
+
if (!data)
|
|
29219
|
+
return;
|
|
29220
|
+
if (options.format === "json") {
|
|
29221
|
+
console.log(JSON.stringify(data, null, 2));
|
|
29222
|
+
} else {
|
|
29223
|
+
console.log(formatPaperPositions(data.positions));
|
|
29224
|
+
}
|
|
29225
|
+
});
|
|
29226
|
+
});
|
|
29227
|
+
command.command("position").description("Show one read-only paper prediction-market position").argument("<positionId>", "Paper prediction-market position ID").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (positionId, options) => {
|
|
29228
|
+
await runReadAction(options.format, async () => {
|
|
29229
|
+
const data = await readPosition(positionId);
|
|
29230
|
+
if (!data)
|
|
29231
|
+
return;
|
|
29232
|
+
if (options.format === "json") {
|
|
29233
|
+
console.log(JSON.stringify(data, null, 2));
|
|
29234
|
+
} else {
|
|
29235
|
+
console.log(formatPaperPositionDetail(data.position));
|
|
29236
|
+
}
|
|
29237
|
+
});
|
|
29238
|
+
});
|
|
29239
|
+
addSummaryFilters(command.command("agent-summary").description("Show read-only paper prediction-market result summary for one agent").argument("<agentId>", "Agent ID")).action(async (agentId, options) => {
|
|
29240
|
+
await runReadAction(options.format, async () => {
|
|
29241
|
+
const data = await readAgentSummary(agentId, options);
|
|
29242
|
+
if (!data)
|
|
29243
|
+
return;
|
|
29244
|
+
if (options.format === "json") {
|
|
29245
|
+
console.log(JSON.stringify(data, null, 2));
|
|
29246
|
+
} else {
|
|
29247
|
+
console.log(formatPaperSummary(data.summary));
|
|
29248
|
+
}
|
|
29249
|
+
});
|
|
29250
|
+
});
|
|
29251
|
+
addPositionFilters(command.command("agent-positions").description("List read-only paper prediction-market positions for one agent").argument("<agentId>", "Agent ID")).action(async (agentId, options) => {
|
|
29252
|
+
await runReadAction(options.format, async () => {
|
|
29253
|
+
const data = await readAgentPositions(agentId, options);
|
|
29254
|
+
if (!data)
|
|
29255
|
+
return;
|
|
29256
|
+
if (options.format === "json") {
|
|
29257
|
+
console.log(JSON.stringify(data, null, 2));
|
|
29258
|
+
} else {
|
|
29259
|
+
console.log(formatPaperPositions(data.positions));
|
|
29260
|
+
}
|
|
29261
|
+
});
|
|
29262
|
+
});
|
|
29263
|
+
}
|
|
29264
|
+
|
|
28704
29265
|
// dist/cli.js
|
|
28705
29266
|
import { readFileSync as readFileSync5 } from "node:fs";
|
|
28706
29267
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
@@ -28752,6 +29313,7 @@ function createCli() {
|
|
|
28752
29313
|
registerSuggestionsCommand(program2);
|
|
28753
29314
|
registerCronCommand(program2);
|
|
28754
29315
|
registerAgentCommand(program2);
|
|
29316
|
+
registerPredictionMarketPaperCommand(program2);
|
|
28755
29317
|
registerConfigCommand(program2);
|
|
28756
29318
|
const GROUPS = {
|
|
28757
29319
|
"Core": ["context", "query", "watch"],
|
|
@@ -28760,7 +29322,7 @@ function createCli() {
|
|
|
28760
29322
|
"Edge & Safety": ["edge", "edge-guard", "coaching", "thesis"],
|
|
28761
29323
|
"Strategy & Benchmarking": ["strategy", "replay", "benchmark", "suggestions"],
|
|
28762
29324
|
"Scheduling": ["cron"],
|
|
28763
|
-
"Agents": ["agent"],
|
|
29325
|
+
"Agents": ["agent", "prediction-market-paper"],
|
|
28764
29326
|
"Account": ["login", "logout", "whoami", "billing", "subscribe", "rotate-key", "forgot-key", "connect-chatgpt", "config"]
|
|
28765
29327
|
};
|
|
28766
29328
|
program2.addHelpText("before", "");
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { formatConnectionError } from './utils.js';
|
|
2
2
|
export { storeCredentials, loadCredentials, clearCredentials, redactApiKey, getCredentialsFilePath } from './credentials.js';
|
|
3
3
|
export type { StoredCredentials } from './credentials.js';
|
|
4
|
-
export { apiRequest, resolveApiKey, getApiBase, ApiError } from './api-client.js';
|
|
4
|
+
export { apiRequest, resolveApiKey, resolveApiKeyWithSource, getApiBase, ApiError, ApiCredentialConflictError, ApiCredentialMissingError, } from './api-client.js';
|
|
5
|
+
export type { ApiKeySourceName, ResolvedApiKey } from './api-client.js';
|
|
5
6
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { formatConnectionError } from './utils.js';
|
|
2
2
|
export { storeCredentials, loadCredentials, clearCredentials, redactApiKey, getCredentialsFilePath } from './credentials.js';
|
|
3
|
-
export { apiRequest, resolveApiKey, getApiBase, ApiError } from './api-client.js';
|
|
3
|
+
export { apiRequest, resolveApiKey, resolveApiKeyWithSource, getApiBase, ApiError, ApiCredentialConflictError, ApiCredentialMissingError, } from './api-client.js';
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trading-boy/cli",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "Trading Boy CLI — remote trading intelligence for traders and AI agents.",
|
|
5
|
-
"homepage": "https://
|
|
5
|
+
"homepage": "https://tradingboy.ai",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
|
-
"url": "https://github.com/0xLLM73/Trading-Boy"
|
|
8
|
+
"url": "git+https://github.com/0xLLM73/Trading-Boy.git"
|
|
9
9
|
},
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"keywords": [
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@trading-boy/core": "workspace:*",
|
|
72
|
-
"esbuild": "~0.
|
|
72
|
+
"esbuild": "~0.28.1",
|
|
73
73
|
"typescript": "^5.7.0"
|
|
74
74
|
}
|
|
75
75
|
}
|