@spfunctions/cli 1.7.19 → 1.7.20
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/dist/101.index.js +1 -0
- package/dist/12.index.js +1 -0
- package/dist/160.index.js +1 -0
- package/dist/174.index.js +1 -0
- package/dist/278.index.js +6 -0
- package/dist/582.index.js +1 -0
- package/dist/641.index.js +324 -0
- package/dist/669.index.js +1 -0
- package/dist/722.index.js +1 -0
- package/dist/788.index.js +1 -0
- package/dist/816.index.js +12 -0
- package/dist/830.index.js +1 -0
- package/dist/921.index.js +1 -0
- package/dist/index.js +1 -833
- package/package.json +5 -2
- package/dist/cache.d.ts +0 -6
- package/dist/cache.js +0 -31
- package/dist/cache.test.d.ts +0 -1
- package/dist/cache.test.js +0 -73
- package/dist/client.d.ts +0 -56
- package/dist/client.js +0 -205
- package/dist/client.test.d.ts +0 -1
- package/dist/client.test.js +0 -89
- package/dist/commands/agent.d.ts +0 -20
- package/dist/commands/agent.js +0 -4119
- package/dist/commands/announcements.d.ts +0 -3
- package/dist/commands/announcements.js +0 -28
- package/dist/commands/augment.d.ts +0 -12
- package/dist/commands/augment.js +0 -56
- package/dist/commands/balance.d.ts +0 -3
- package/dist/commands/balance.js +0 -17
- package/dist/commands/book.d.ts +0 -17
- package/dist/commands/book.js +0 -220
- package/dist/commands/cancel.d.ts +0 -5
- package/dist/commands/cancel.js +0 -41
- package/dist/commands/context.d.ts +0 -6
- package/dist/commands/context.js +0 -208
- package/dist/commands/create.d.ts +0 -7
- package/dist/commands/create.js +0 -42
- package/dist/commands/dashboard.d.ts +0 -14
- package/dist/commands/dashboard.js +0 -215
- package/dist/commands/delta.d.ts +0 -16
- package/dist/commands/delta.js +0 -115
- package/dist/commands/edges.d.ts +0 -26
- package/dist/commands/edges.js +0 -246
- package/dist/commands/evaluate.d.ts +0 -4
- package/dist/commands/evaluate.js +0 -30
- package/dist/commands/explore.d.ts +0 -14
- package/dist/commands/explore.js +0 -116
- package/dist/commands/feed.d.ts +0 -13
- package/dist/commands/feed.js +0 -73
- package/dist/commands/fills.d.ts +0 -4
- package/dist/commands/fills.js +0 -29
- package/dist/commands/forecast.d.ts +0 -4
- package/dist/commands/forecast.js +0 -53
- package/dist/commands/get.d.ts +0 -5
- package/dist/commands/get.js +0 -98
- package/dist/commands/heartbeat.d.ts +0 -20
- package/dist/commands/heartbeat.js +0 -73
- package/dist/commands/history.d.ts +0 -3
- package/dist/commands/history.js +0 -38
- package/dist/commands/liquidity.d.ts +0 -14
- package/dist/commands/liquidity.js +0 -378
- package/dist/commands/list.d.ts +0 -5
- package/dist/commands/list.js +0 -38
- package/dist/commands/login.d.ts +0 -10
- package/dist/commands/login.js +0 -98
- package/dist/commands/markets.d.ts +0 -10
- package/dist/commands/markets.js +0 -39
- package/dist/commands/milestones.d.ts +0 -8
- package/dist/commands/milestones.js +0 -56
- package/dist/commands/orders.d.ts +0 -4
- package/dist/commands/orders.js +0 -28
- package/dist/commands/performance.d.ts +0 -11
- package/dist/commands/performance.js +0 -250
- package/dist/commands/positions.d.ts +0 -19
- package/dist/commands/positions.js +0 -294
- package/dist/commands/prompt.d.ts +0 -13
- package/dist/commands/prompt.js +0 -35
- package/dist/commands/publish.d.ts +0 -15
- package/dist/commands/publish.js +0 -39
- package/dist/commands/query.d.ts +0 -15
- package/dist/commands/query.js +0 -132
- package/dist/commands/rfq.d.ts +0 -5
- package/dist/commands/rfq.js +0 -35
- package/dist/commands/scan.d.ts +0 -11
- package/dist/commands/scan.js +0 -230
- package/dist/commands/schedule.d.ts +0 -3
- package/dist/commands/schedule.js +0 -38
- package/dist/commands/settlements.d.ts +0 -6
- package/dist/commands/settlements.js +0 -50
- package/dist/commands/setup.d.ts +0 -24
- package/dist/commands/setup.js +0 -700
- package/dist/commands/signal.d.ts +0 -6
- package/dist/commands/signal.js +0 -32
- package/dist/commands/strategies.d.ts +0 -11
- package/dist/commands/strategies.js +0 -130
- package/dist/commands/telegram.d.ts +0 -15
- package/dist/commands/telegram.js +0 -125
- package/dist/commands/trade.d.ts +0 -12
- package/dist/commands/trade.js +0 -112
- package/dist/commands/watch.d.ts +0 -19
- package/dist/commands/watch.js +0 -157
- package/dist/commands/whatif.d.ts +0 -17
- package/dist/commands/whatif.js +0 -209
- package/dist/commands/x.d.ts +0 -28
- package/dist/commands/x.js +0 -167
- package/dist/config.d.ts +0 -55
- package/dist/config.js +0 -139
- package/dist/config.test.d.ts +0 -1
- package/dist/config.test.js +0 -138
- package/dist/index.d.ts +0 -20
- package/dist/kalshi.d.ts +0 -144
- package/dist/kalshi.js +0 -498
- package/dist/polymarket.d.ts +0 -237
- package/dist/polymarket.js +0 -353
- package/dist/polymarket.test.d.ts +0 -1
- package/dist/polymarket.test.js +0 -424
- package/dist/share.d.ts +0 -4
- package/dist/share.js +0 -27
- package/dist/skills/loader.d.ts +0 -19
- package/dist/skills/loader.js +0 -86
- package/dist/telegram/agent-bridge.d.ts +0 -15
- package/dist/telegram/agent-bridge.js +0 -573
- package/dist/telegram/bot.d.ts +0 -10
- package/dist/telegram/bot.js +0 -297
- package/dist/telegram/commands.d.ts +0 -11
- package/dist/telegram/commands.js +0 -120
- package/dist/telegram/format.d.ts +0 -11
- package/dist/telegram/format.js +0 -51
- package/dist/telegram/format.test.d.ts +0 -1
- package/dist/telegram/format.test.js +0 -73
- package/dist/telegram/poller.d.ts +0 -6
- package/dist/telegram/poller.js +0 -32
- package/dist/topics.d.ts +0 -17
- package/dist/topics.js +0 -102
- package/dist/topics.test.d.ts +0 -1
- package/dist/topics.test.js +0 -131
- package/dist/tui/border.d.ts +0 -33
- package/dist/tui/border.js +0 -87
- package/dist/tui/chart.d.ts +0 -19
- package/dist/tui/chart.js +0 -117
- package/dist/tui/dashboard.d.ts +0 -9
- package/dist/tui/dashboard.js +0 -814
- package/dist/tui/layout.d.ts +0 -16
- package/dist/tui/layout.js +0 -41
- package/dist/tui/screen.d.ts +0 -33
- package/dist/tui/screen.js +0 -102
- package/dist/tui/state.d.ts +0 -40
- package/dist/tui/state.js +0 -36
- package/dist/tui/widgets/commandbar.d.ts +0 -8
- package/dist/tui/widgets/commandbar.js +0 -82
- package/dist/tui/widgets/detail.d.ts +0 -9
- package/dist/tui/widgets/detail.js +0 -151
- package/dist/tui/widgets/edges.d.ts +0 -4
- package/dist/tui/widgets/edges.js +0 -34
- package/dist/tui/widgets/liquidity.d.ts +0 -9
- package/dist/tui/widgets/liquidity.js +0 -142
- package/dist/tui/widgets/orders.d.ts +0 -4
- package/dist/tui/widgets/orders.js +0 -37
- package/dist/tui/widgets/portfolio.d.ts +0 -4
- package/dist/tui/widgets/portfolio.js +0 -59
- package/dist/tui/widgets/signals.d.ts +0 -4
- package/dist/tui/widgets/signals.js +0 -31
- package/dist/tui/widgets/statusbar.d.ts +0 -8
- package/dist/tui/widgets/statusbar.js +0 -72
- package/dist/tui/widgets/thesis.d.ts +0 -4
- package/dist/tui/widgets/thesis.js +0 -66
- package/dist/tui/widgets/trade.d.ts +0 -9
- package/dist/tui/widgets/trade.js +0 -117
- package/dist/tui/widgets/upcoming.d.ts +0 -4
- package/dist/tui/widgets/upcoming.js +0 -41
- package/dist/tui/widgets/whatif.d.ts +0 -7
- package/dist/tui/widgets/whatif.js +0 -113
- package/dist/types/output.d.ts +0 -412
- package/dist/types/output.js +0 -9
- package/dist/utils.d.ts +0 -52
- package/dist/utils.js +0 -146
- package/dist/utils.test.d.ts +0 -1
- package/dist/utils.test.js +0 -111
package/dist/commands/signal.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.signalCommand = signalCommand;
|
|
4
|
-
const client_js_1 = require("../client.js");
|
|
5
|
-
const utils_js_1 = require("../utils.js");
|
|
6
|
-
async function signalCommand(id, content, opts) {
|
|
7
|
-
const client = new client_js_1.SFClient(opts.apiKey, opts.apiUrl);
|
|
8
|
-
const type = opts.type || 'user_note';
|
|
9
|
-
const result = await client.injectSignal(id, type, content, 'cli');
|
|
10
|
-
if (opts.json) {
|
|
11
|
-
console.log(JSON.stringify({ signalId: result.signalId || null, type, source: 'cli', content }, null, 2));
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
console.log(`${utils_js_1.c.green}✓${utils_js_1.c.reset} Signal injected`);
|
|
15
|
-
console.log(` ${utils_js_1.c.bold}Type:${utils_js_1.c.reset} ${type}`);
|
|
16
|
-
console.log(` ${utils_js_1.c.bold}Source:${utils_js_1.c.reset} cli`);
|
|
17
|
-
console.log(` ${utils_js_1.c.bold}Content:${utils_js_1.c.reset} ${content}`);
|
|
18
|
-
if (result.signalId) {
|
|
19
|
-
console.log(` ${utils_js_1.c.bold}ID:${utils_js_1.c.reset} ${result.signalId}`);
|
|
20
|
-
}
|
|
21
|
-
const now = new Date();
|
|
22
|
-
const minute = now.getMinutes();
|
|
23
|
-
const nextCycleMin = Math.ceil((minute + 1) / 15) * 15;
|
|
24
|
-
const minutesUntil = nextCycleMin - minute;
|
|
25
|
-
const nextRun = new Date(now);
|
|
26
|
-
nextRun.setMinutes(nextCycleMin % 60, 0, 0);
|
|
27
|
-
if (nextCycleMin >= 60)
|
|
28
|
-
nextRun.setHours(nextRun.getHours() + 1);
|
|
29
|
-
const timeStr = nextRun.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
30
|
-
console.log(`\n${utils_js_1.c.dim}Signal queued. Next monitor cycle in ~${minutesUntil}min (${timeStr}).${utils_js_1.c.reset}`);
|
|
31
|
-
console.log(`${utils_js_1.c.dim}Or run ${utils_js_1.c.reset}sf evaluate ${id}${utils_js_1.c.dim} to consume immediately.${utils_js_1.c.reset}`);
|
|
32
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* sf strategies — List strategies across theses
|
|
3
|
-
*
|
|
4
|
-
* Usage:
|
|
5
|
-
* sf strategies — all active strategies across all theses
|
|
6
|
-
* sf strategies f582bf76 — strategies for a specific thesis
|
|
7
|
-
* sf strategies --status executed — filter by status
|
|
8
|
-
* sf strategies --all — all statuses
|
|
9
|
-
*/
|
|
10
|
-
import { Command } from 'commander';
|
|
11
|
-
export declare function registerStrategies(program: Command): void;
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* sf strategies — List strategies across theses
|
|
4
|
-
*
|
|
5
|
-
* Usage:
|
|
6
|
-
* sf strategies — all active strategies across all theses
|
|
7
|
-
* sf strategies f582bf76 — strategies for a specific thesis
|
|
8
|
-
* sf strategies --status executed — filter by status
|
|
9
|
-
* sf strategies --all — all statuses
|
|
10
|
-
*/
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.registerStrategies = registerStrategies;
|
|
13
|
-
const client_js_1 = require("../client.js");
|
|
14
|
-
const STATUS_COLORS = {
|
|
15
|
-
active: '\x1b[32m', // green
|
|
16
|
-
watching: '\x1b[33m', // yellow
|
|
17
|
-
executed: '\x1b[36m', // cyan
|
|
18
|
-
cancelled: '\x1b[90m', // gray
|
|
19
|
-
review: '\x1b[31m', // red
|
|
20
|
-
};
|
|
21
|
-
const RESET = '\x1b[0m';
|
|
22
|
-
const DIM = '\x1b[2m';
|
|
23
|
-
const BOLD = '\x1b[1m';
|
|
24
|
-
function formatStrategy(s, showThesis = false) {
|
|
25
|
-
const statusColor = STATUS_COLORS[s.status] || '';
|
|
26
|
-
const lines = [];
|
|
27
|
-
// Header line
|
|
28
|
-
const thesisPrefix = showThesis ? `${DIM}${s.thesisTitle || s.thesisId?.slice(0, 8)}${RESET} ` : '';
|
|
29
|
-
lines.push(` ${thesisPrefix}${statusColor}[${s.status}]${RESET} ${BOLD}${s.marketId}${RESET} ${s.direction.toUpperCase()} ${DIM}${s.horizon}${RESET} priority ${s.priority || 0}`);
|
|
30
|
-
// Entry conditions
|
|
31
|
-
const entryParts = [];
|
|
32
|
-
if (s.entryBelow != null)
|
|
33
|
-
entryParts.push(`ask ≤ ${s.entryBelow}¢`);
|
|
34
|
-
if (s.entryAbove != null)
|
|
35
|
-
entryParts.push(`ask ≥ ${s.entryAbove}¢`);
|
|
36
|
-
const stopPart = s.stopLoss != null ? `Stop: ${s.stopLoss}¢` : '';
|
|
37
|
-
const tpPart = s.takeProfit != null ? `TP: ${s.takeProfit}¢` : '';
|
|
38
|
-
const maxPart = `Max: ${s.maxQuantity || 500}`;
|
|
39
|
-
const filledPart = `Filled: ${s.executedQuantity || 0}/${s.maxQuantity || 500}`;
|
|
40
|
-
const conditionLine = [
|
|
41
|
-
entryParts.length > 0 ? `Entry: ${entryParts.join(', ')}` : null,
|
|
42
|
-
stopPart || null,
|
|
43
|
-
tpPart || null,
|
|
44
|
-
maxPart,
|
|
45
|
-
filledPart,
|
|
46
|
-
].filter(Boolean).join(' | ');
|
|
47
|
-
lines.push(` ${conditionLine}`);
|
|
48
|
-
// Soft conditions
|
|
49
|
-
if (s.softConditions) {
|
|
50
|
-
lines.push(` ${DIM}Soft: ${s.softConditions}${RESET}`);
|
|
51
|
-
}
|
|
52
|
-
// Review warning
|
|
53
|
-
if (s.status === 'review') {
|
|
54
|
-
lines.push(` \x1b[31m⚠️ Needs review${RESET}`);
|
|
55
|
-
}
|
|
56
|
-
// Rationale (truncated)
|
|
57
|
-
if (s.rationale) {
|
|
58
|
-
const truncated = s.rationale.length > 120 ? s.rationale.slice(0, 117) + '...' : s.rationale;
|
|
59
|
-
lines.push(` ${DIM}${truncated}${RESET}`);
|
|
60
|
-
}
|
|
61
|
-
// Footer
|
|
62
|
-
const createdBy = s.createdBy || 'user';
|
|
63
|
-
const date = s.createdAt ? new Date(s.createdAt).toLocaleDateString('en-US', { month: 'numeric', day: 'numeric', hour: '2-digit', minute: '2-digit' }) : '';
|
|
64
|
-
lines.push(` ${DIM}created by ${createdBy} · ${date}${RESET}`);
|
|
65
|
-
return lines.join('\n');
|
|
66
|
-
}
|
|
67
|
-
function registerStrategies(program) {
|
|
68
|
-
program
|
|
69
|
-
.command('strategies')
|
|
70
|
-
.argument('[thesisId]', 'thesis ID or prefix (omit for all theses)')
|
|
71
|
-
.option('--status <status>', 'filter by status (active|watching|executed|cancelled|review)')
|
|
72
|
-
.option('--all', 'show all statuses (default: active only)')
|
|
73
|
-
.description('List strategies across theses')
|
|
74
|
-
.action(async (thesisId, opts) => {
|
|
75
|
-
try {
|
|
76
|
-
const client = new client_js_1.SFClient();
|
|
77
|
-
if (thesisId) {
|
|
78
|
-
// Strategies for a specific thesis
|
|
79
|
-
const statusParam = opts?.all ? '' : (opts?.status || 'active');
|
|
80
|
-
const url = statusParam
|
|
81
|
-
? `/api/thesis/${thesisId}/strategies?status=${statusParam}`
|
|
82
|
-
: `/api/thesis/${thesisId}/strategies`;
|
|
83
|
-
const data = await client.getStrategies(thesisId, opts?.all ? undefined : (opts?.status || 'active'));
|
|
84
|
-
const strategies = data.strategies || [];
|
|
85
|
-
if (strategies.length === 0) {
|
|
86
|
-
console.log(`\n No strategies found for thesis ${thesisId}`);
|
|
87
|
-
if (!opts?.all && !opts?.status) {
|
|
88
|
-
console.log(` ${DIM}Try --all to see all statuses${RESET}`);
|
|
89
|
-
}
|
|
90
|
-
console.log();
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
console.log(`\n Strategies for ${thesisId}\n`);
|
|
94
|
-
for (const s of strategies) {
|
|
95
|
-
console.log(formatStrategy(s));
|
|
96
|
-
console.log();
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
else {
|
|
100
|
-
// All strategies across all theses
|
|
101
|
-
const { theses } = await client.listTheses();
|
|
102
|
-
let totalStrategies = 0;
|
|
103
|
-
for (const thesis of theses) {
|
|
104
|
-
const statusFilter = opts?.all ? undefined : (opts?.status || 'active');
|
|
105
|
-
const data = await client.getStrategies(thesis.id, statusFilter);
|
|
106
|
-
const strategies = data.strategies || [];
|
|
107
|
-
if (strategies.length === 0)
|
|
108
|
-
continue;
|
|
109
|
-
totalStrategies += strategies.length;
|
|
110
|
-
console.log(`\n ${BOLD}${thesis.title}${RESET} ${DIM}(${thesis.id.slice(0, 8)})${RESET}\n`);
|
|
111
|
-
for (const s of strategies) {
|
|
112
|
-
console.log(formatStrategy(s));
|
|
113
|
-
console.log();
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
if (totalStrategies === 0) {
|
|
117
|
-
console.log(`\n No strategies found`);
|
|
118
|
-
if (!opts?.all && !opts?.status) {
|
|
119
|
-
console.log(` ${DIM}Try --all to see all statuses${RESET}`);
|
|
120
|
-
}
|
|
121
|
-
console.log();
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
catch (err) {
|
|
126
|
-
console.error(`\x1b[31mError:\x1b[0m ${err.message}`);
|
|
127
|
-
process.exit(1);
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* sf telegram — Start Telegram bot
|
|
3
|
-
*
|
|
4
|
-
* Token is saved to ~/.sf/config.json on first use.
|
|
5
|
-
* --daemon: fork to background, write PID to ~/.sf/telegram.pid
|
|
6
|
-
* --stop: kill running daemon
|
|
7
|
-
* --status: check if daemon is running
|
|
8
|
-
*/
|
|
9
|
-
export declare function telegramCommand(opts: {
|
|
10
|
-
token?: string;
|
|
11
|
-
chatId?: string;
|
|
12
|
-
daemon?: boolean;
|
|
13
|
-
stop?: boolean;
|
|
14
|
-
status?: boolean;
|
|
15
|
-
}): Promise<void>;
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* sf telegram — Start Telegram bot
|
|
4
|
-
*
|
|
5
|
-
* Token is saved to ~/.sf/config.json on first use.
|
|
6
|
-
* --daemon: fork to background, write PID to ~/.sf/telegram.pid
|
|
7
|
-
* --stop: kill running daemon
|
|
8
|
-
* --status: check if daemon is running
|
|
9
|
-
*/
|
|
10
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
11
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
12
|
-
};
|
|
13
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.telegramCommand = telegramCommand;
|
|
15
|
-
const child_process_1 = require("child_process");
|
|
16
|
-
const fs_1 = __importDefault(require("fs"));
|
|
17
|
-
const path_1 = __importDefault(require("path"));
|
|
18
|
-
const os_1 = __importDefault(require("os"));
|
|
19
|
-
const config_js_1 = require("../config.js");
|
|
20
|
-
const PID_FILE = path_1.default.join(os_1.default.homedir(), '.sf', 'telegram.pid');
|
|
21
|
-
const LOG_FILE = path_1.default.join(os_1.default.homedir(), '.sf', 'telegram.log');
|
|
22
|
-
function readPid() {
|
|
23
|
-
try {
|
|
24
|
-
const pid = parseInt(fs_1.default.readFileSync(PID_FILE, 'utf-8').trim());
|
|
25
|
-
if (isNaN(pid))
|
|
26
|
-
return null;
|
|
27
|
-
try {
|
|
28
|
-
process.kill(pid, 0);
|
|
29
|
-
return pid;
|
|
30
|
-
}
|
|
31
|
-
catch {
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
catch {
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
/** Resolve token: --token flag > config > env var. Save to config if new. */
|
|
40
|
-
function resolveToken(flagToken) {
|
|
41
|
-
const config = (0, config_js_1.loadConfig)();
|
|
42
|
-
// Flag takes priority
|
|
43
|
-
if (flagToken) {
|
|
44
|
-
// Save to config for future use
|
|
45
|
-
const file = (0, config_js_1.loadFileConfig)();
|
|
46
|
-
if (file.telegramBotToken !== flagToken) {
|
|
47
|
-
(0, config_js_1.saveConfig)({ ...file, telegramBotToken: flagToken });
|
|
48
|
-
}
|
|
49
|
-
return flagToken;
|
|
50
|
-
}
|
|
51
|
-
return config.telegramBotToken || null;
|
|
52
|
-
}
|
|
53
|
-
async function telegramCommand(opts) {
|
|
54
|
-
// ── sf telegram --stop ──
|
|
55
|
-
if (opts.stop) {
|
|
56
|
-
const pid = readPid();
|
|
57
|
-
if (pid) {
|
|
58
|
-
process.kill(pid, 'SIGTERM');
|
|
59
|
-
try {
|
|
60
|
-
fs_1.default.unlinkSync(PID_FILE);
|
|
61
|
-
}
|
|
62
|
-
catch { }
|
|
63
|
-
console.log(` Telegram bot stopped (PID ${pid})`);
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
console.log(' No running Telegram bot found.');
|
|
67
|
-
}
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
// ── sf telegram --status ──
|
|
71
|
-
if (opts.status) {
|
|
72
|
-
const pid = readPid();
|
|
73
|
-
if (pid) {
|
|
74
|
-
console.log(` Telegram bot running (PID ${pid})`);
|
|
75
|
-
console.log(` Log: ${LOG_FILE}`);
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
console.log(' Telegram bot not running.');
|
|
79
|
-
}
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
// Resolve token (saves to config on first use)
|
|
83
|
-
const token = resolveToken(opts.token);
|
|
84
|
-
if (!token) {
|
|
85
|
-
console.log(' No Telegram bot token configured.\n');
|
|
86
|
-
console.log(' Setup:');
|
|
87
|
-
console.log(' 1. Message @BotFather on Telegram → /newbot');
|
|
88
|
-
console.log(' 2. Copy the token');
|
|
89
|
-
console.log(' 3. Run: sf telegram --token YOUR_TOKEN\n');
|
|
90
|
-
console.log(' The token will be saved to ~/.sf/config.json for future use.');
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
// ── sf telegram --daemon ──
|
|
94
|
-
if (opts.daemon) {
|
|
95
|
-
const existing = readPid();
|
|
96
|
-
if (existing) {
|
|
97
|
-
console.log(` Bot already running (PID ${existing}). Use --stop first.`);
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
// Daemon doesn't need --token since it's in config now
|
|
101
|
-
const args = ['telegram'];
|
|
102
|
-
if (opts.chatId)
|
|
103
|
-
args.push('--chat-id', opts.chatId);
|
|
104
|
-
const sfBin = process.argv[1];
|
|
105
|
-
fs_1.default.mkdirSync(path_1.default.dirname(PID_FILE), { recursive: true });
|
|
106
|
-
const logStream = fs_1.default.openSync(LOG_FILE, 'a');
|
|
107
|
-
const child = (0, child_process_1.spawn)(process.execPath, [sfBin, ...args], {
|
|
108
|
-
detached: true,
|
|
109
|
-
stdio: ['ignore', logStream, logStream],
|
|
110
|
-
env: { ...process.env },
|
|
111
|
-
});
|
|
112
|
-
child.unref();
|
|
113
|
-
fs_1.default.writeFileSync(PID_FILE, String(child.pid));
|
|
114
|
-
console.log(` Telegram bot started in background (PID ${child.pid})`);
|
|
115
|
-
console.log(` Log: ${LOG_FILE}`);
|
|
116
|
-
console.log(` Stop: sf telegram --stop`);
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
// ── sf telegram (foreground) ──
|
|
120
|
-
const { startBot } = await import('../telegram/bot.js');
|
|
121
|
-
await startBot({
|
|
122
|
-
token,
|
|
123
|
-
chatId: opts.chatId ? parseInt(opts.chatId) : undefined,
|
|
124
|
-
});
|
|
125
|
-
}
|
package/dist/commands/trade.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export declare function buyCommand(ticker: string, qty: string, opts: {
|
|
2
|
-
price?: string;
|
|
3
|
-
market?: boolean;
|
|
4
|
-
side?: string;
|
|
5
|
-
yesIAmSure?: boolean;
|
|
6
|
-
}): Promise<void>;
|
|
7
|
-
export declare function sellCommand(ticker: string, qty: string, opts: {
|
|
8
|
-
price?: string;
|
|
9
|
-
market?: boolean;
|
|
10
|
-
side?: string;
|
|
11
|
-
yesIAmSure?: boolean;
|
|
12
|
-
}): Promise<void>;
|
package/dist/commands/trade.js
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.buyCommand = buyCommand;
|
|
4
|
-
exports.sellCommand = sellCommand;
|
|
5
|
-
const kalshi_js_1 = require("../kalshi.js");
|
|
6
|
-
const config_js_1 = require("../config.js");
|
|
7
|
-
const utils_js_1 = require("../utils.js");
|
|
8
|
-
const fs_1 = require("fs");
|
|
9
|
-
const path_1 = require("path");
|
|
10
|
-
const os_1 = require("os");
|
|
11
|
-
async function buyCommand(ticker, qty, opts) {
|
|
12
|
-
(0, config_js_1.requireTrading)();
|
|
13
|
-
await executeOrder(ticker, qty, 'buy', opts);
|
|
14
|
-
}
|
|
15
|
-
async function sellCommand(ticker, qty, opts) {
|
|
16
|
-
(0, config_js_1.requireTrading)();
|
|
17
|
-
await executeOrder(ticker, qty, 'sell', opts);
|
|
18
|
-
}
|
|
19
|
-
async function executeOrder(ticker, qty, action, opts) {
|
|
20
|
-
const quantity = parseInt(qty);
|
|
21
|
-
if (isNaN(quantity) || quantity <= 0)
|
|
22
|
-
throw new Error('Quantity must be a positive integer');
|
|
23
|
-
const side = (opts.side || 'yes');
|
|
24
|
-
if (!opts.market && !opts.price) {
|
|
25
|
-
throw new Error('Limit order requires --price <cents>. Example: sf buy TICKER 10 --price 45\nFor market orders use: sf buy TICKER 10 --market --price 99');
|
|
26
|
-
}
|
|
27
|
-
// Kalshi API always requires yes_price — even for "market" orders.
|
|
28
|
-
// For market orders without --price: auto-fetch current market price.
|
|
29
|
-
const orderType = opts.market ? 'market' : 'limit';
|
|
30
|
-
let priceCents = opts.price ? parseInt(opts.price) : undefined;
|
|
31
|
-
if (opts.market && !priceCents) {
|
|
32
|
-
console.log(`${utils_js_1.c.dim}Fetching current market price for ${ticker}...${utils_js_1.c.reset}`);
|
|
33
|
-
const livePrice = await (0, kalshi_js_1.getMarketPrice)(ticker.toUpperCase());
|
|
34
|
-
if (!livePrice) {
|
|
35
|
-
throw new Error(`Could not fetch market price for ${ticker}. Use --price <cents> to set manually.`);
|
|
36
|
-
}
|
|
37
|
-
priceCents = livePrice;
|
|
38
|
-
console.log(`${utils_js_1.c.dim}Using market price: ${livePrice}¢${utils_js_1.c.reset}`);
|
|
39
|
-
}
|
|
40
|
-
if (priceCents !== undefined && (priceCents < 1 || priceCents > 99)) {
|
|
41
|
-
throw new Error('Price must be 1-99 cents.');
|
|
42
|
-
}
|
|
43
|
-
const maxCost = ((priceCents || 99) * quantity / 100).toFixed(2);
|
|
44
|
-
console.log();
|
|
45
|
-
console.log(` ${utils_js_1.c.bold}${utils_js_1.c.cyan}${action.toUpperCase()} Order${utils_js_1.c.reset}`);
|
|
46
|
-
console.log(` ${utils_js_1.c.dim}${'─'.repeat(35)}${utils_js_1.c.reset}`);
|
|
47
|
-
console.log(` Ticker: ${ticker}`);
|
|
48
|
-
console.log(` Side: ${side === 'yes' ? utils_js_1.c.green + 'YES' + utils_js_1.c.reset : utils_js_1.c.red + 'NO' + utils_js_1.c.reset}`);
|
|
49
|
-
console.log(` Quantity: ${quantity}`);
|
|
50
|
-
console.log(` Type: ${orderType}`);
|
|
51
|
-
if (priceCents)
|
|
52
|
-
console.log(` Price: ${priceCents}¢`);
|
|
53
|
-
console.log(` Max cost: $${maxCost}`);
|
|
54
|
-
console.log();
|
|
55
|
-
if (!opts.yesIAmSure) {
|
|
56
|
-
for (let i = 3; i > 0; i--) {
|
|
57
|
-
process.stdout.write(` Executing in ${i}... (Ctrl+C to cancel)\r`);
|
|
58
|
-
await new Promise(r => setTimeout(r, 1000));
|
|
59
|
-
}
|
|
60
|
-
process.stdout.write(' Executing... \n');
|
|
61
|
-
}
|
|
62
|
-
try {
|
|
63
|
-
const result = await (0, kalshi_js_1.createOrder)({
|
|
64
|
-
ticker,
|
|
65
|
-
side,
|
|
66
|
-
action,
|
|
67
|
-
type: orderType,
|
|
68
|
-
count: quantity,
|
|
69
|
-
...(priceCents ? { yes_price: priceCents } : {}),
|
|
70
|
-
});
|
|
71
|
-
const order = result.order || result;
|
|
72
|
-
console.log();
|
|
73
|
-
console.log(` ${utils_js_1.c.green}✓${utils_js_1.c.reset} Order placed: ${order.order_id || 'OK'}`);
|
|
74
|
-
if (order.status)
|
|
75
|
-
console.log(` Status: ${order.status}`);
|
|
76
|
-
if (order.fill_count_fp)
|
|
77
|
-
console.log(` Filled: ${order.fill_count_fp}/${order.initial_count_fp || quantity}`);
|
|
78
|
-
console.log();
|
|
79
|
-
// Auto-log trade to journal
|
|
80
|
-
try {
|
|
81
|
-
const journalDir = (0, path_1.join)((0, os_1.homedir)(), '.sf');
|
|
82
|
-
if (!(0, fs_1.existsSync)(journalDir))
|
|
83
|
-
(0, fs_1.mkdirSync)(journalDir, { recursive: true });
|
|
84
|
-
const entry = JSON.stringify({
|
|
85
|
-
ts: new Date().toISOString(),
|
|
86
|
-
action,
|
|
87
|
-
ticker,
|
|
88
|
-
side,
|
|
89
|
-
quantity,
|
|
90
|
-
price: priceCents || null,
|
|
91
|
-
type: orderType,
|
|
92
|
-
orderId: order.order_id || null,
|
|
93
|
-
status: order.status || null,
|
|
94
|
-
filled: order.fill_count_fp || null,
|
|
95
|
-
}) + '\n';
|
|
96
|
-
(0, fs_1.appendFileSync)((0, path_1.join)(journalDir, 'trade-journal.jsonl'), entry);
|
|
97
|
-
console.log(` ${utils_js_1.c.dim}Trade logged to ~/.sf/trade-journal.jsonl${utils_js_1.c.reset}`);
|
|
98
|
-
}
|
|
99
|
-
catch { /* journal logging is best-effort */ }
|
|
100
|
-
}
|
|
101
|
-
catch (err) {
|
|
102
|
-
const msg = err.message || String(err);
|
|
103
|
-
if (msg.includes('403')) {
|
|
104
|
-
console.error(`\n ${utils_js_1.c.red}✗${utils_js_1.c.reset} 403 Forbidden — your Kalshi key lacks write permission.`);
|
|
105
|
-
console.error(` Get a read+write key at https://kalshi.com/account/api-keys\n`);
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
console.error(`\n ${utils_js_1.c.red}✗${utils_js_1.c.reset} ${msg}\n`);
|
|
109
|
-
}
|
|
110
|
-
process.exit(1);
|
|
111
|
-
}
|
|
112
|
-
}
|
package/dist/commands/watch.d.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* sf watch
|
|
3
|
-
*
|
|
4
|
-
* Push-mode monitoring. Polls GET /api/changes?since= for server-side
|
|
5
|
-
* detected market changes. No client-side diffing — the server handles
|
|
6
|
-
* change detection every 15 minutes via the scan-prices cron.
|
|
7
|
-
*
|
|
8
|
-
* Usage:
|
|
9
|
-
* sf watch "gold" — Watch gold-related changes
|
|
10
|
-
* sf watch "iran oil" — Watch iran/oil changes
|
|
11
|
-
* sf watch — Watch all market changes
|
|
12
|
-
* sf watch --json — JSON change events for piping
|
|
13
|
-
*/
|
|
14
|
-
interface WatchOpts {
|
|
15
|
-
interval?: string;
|
|
16
|
-
json?: boolean;
|
|
17
|
-
}
|
|
18
|
-
export declare function watchCommand(query: string | undefined, opts: WatchOpts): Promise<void>;
|
|
19
|
-
export {};
|
package/dist/commands/watch.js
DELETED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* sf watch
|
|
4
|
-
*
|
|
5
|
-
* Push-mode monitoring. Polls GET /api/changes?since= for server-side
|
|
6
|
-
* detected market changes. No client-side diffing — the server handles
|
|
7
|
-
* change detection every 15 minutes via the scan-prices cron.
|
|
8
|
-
*
|
|
9
|
-
* Usage:
|
|
10
|
-
* sf watch "gold" — Watch gold-related changes
|
|
11
|
-
* sf watch "iran oil" — Watch iran/oil changes
|
|
12
|
-
* sf watch — Watch all market changes
|
|
13
|
-
* sf watch --json — JSON change events for piping
|
|
14
|
-
*/
|
|
15
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
-
exports.watchCommand = watchCommand;
|
|
17
|
-
const utils_js_1 = require("../utils.js");
|
|
18
|
-
const SF_API_URL = process.env.SF_API_URL || 'https://simplefunctions.dev';
|
|
19
|
-
async function watchCommand(query, opts) {
|
|
20
|
-
const intervalSec = parseInt(opts.interval || '60');
|
|
21
|
-
const intervalMs = intervalSec * 1000;
|
|
22
|
-
const isJson = opts.json || false;
|
|
23
|
-
if (!isJson) {
|
|
24
|
-
console.log();
|
|
25
|
-
console.log(` ${utils_js_1.c.bold}sf watch${utils_js_1.c.reset}${query ? ` "${query}"` : ''}`);
|
|
26
|
-
console.log(` ${utils_js_1.c.dim}Polling /api/changes every ${intervalSec}s · Ctrl+C to stop${utils_js_1.c.reset}`);
|
|
27
|
-
console.log();
|
|
28
|
-
}
|
|
29
|
-
let lastSeen = new Date().toISOString();
|
|
30
|
-
// Handle Ctrl+C gracefully
|
|
31
|
-
process.on('SIGINT', () => {
|
|
32
|
-
if (!isJson) {
|
|
33
|
-
console.log(`\n ${utils_js_1.c.dim}Watch stopped.${utils_js_1.c.reset}\n`);
|
|
34
|
-
}
|
|
35
|
-
process.exit(0);
|
|
36
|
-
});
|
|
37
|
-
// First poll: show recent changes from last hour
|
|
38
|
-
try {
|
|
39
|
-
const initialSince = new Date(Date.now() - 60 * 60 * 1000).toISOString();
|
|
40
|
-
const changes = await fetchChanges(initialSince, query);
|
|
41
|
-
if (changes.length > 0) {
|
|
42
|
-
if (!isJson) {
|
|
43
|
-
console.log(` ${utils_js_1.c.dim}${ts()} Recent changes (last hour):${utils_js_1.c.reset}`);
|
|
44
|
-
}
|
|
45
|
-
const deduped = dedupeByTitle(changes);
|
|
46
|
-
for (const change of deduped) {
|
|
47
|
-
if (isJson) {
|
|
48
|
-
console.log(JSON.stringify(change));
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
printChange(change);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
lastSeen = changes[0].detectedAt;
|
|
55
|
-
}
|
|
56
|
-
else if (!isJson) {
|
|
57
|
-
console.log(` ${utils_js_1.c.dim}${ts()} No recent changes. Watching...${utils_js_1.c.reset}`);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
catch (err) {
|
|
61
|
-
if (!isJson) {
|
|
62
|
-
console.error(` ${utils_js_1.c.dim}${ts()} Error: ${err.message}${utils_js_1.c.reset}`);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
// Polling loop
|
|
66
|
-
while (true) {
|
|
67
|
-
await sleep(intervalMs);
|
|
68
|
-
try {
|
|
69
|
-
const changes = await fetchChanges(lastSeen, query);
|
|
70
|
-
const deduped = isJson ? changes : dedupeByTitle(changes);
|
|
71
|
-
for (const change of deduped) {
|
|
72
|
-
if (isJson) {
|
|
73
|
-
console.log(JSON.stringify(change));
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
printChange(change);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
if (changes.length > 0) {
|
|
80
|
-
lastSeen = changes[0].detectedAt;
|
|
81
|
-
}
|
|
82
|
-
else if (!isJson) {
|
|
83
|
-
process.stdout.write(` ${utils_js_1.c.dim}${ts()} · no new changes${utils_js_1.c.reset}\r`);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
catch (err) {
|
|
87
|
-
if (!isJson) {
|
|
88
|
-
console.error(` ${utils_js_1.c.dim}${ts()} Error: ${err.message}${utils_js_1.c.reset}`);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
// Group same-title same-type changes into one line (e.g. 12 FaZe CEO contracts → 1 line)
|
|
94
|
-
function dedupeByTitle(changes) {
|
|
95
|
-
const groups = new Map();
|
|
96
|
-
for (const c of changes) {
|
|
97
|
-
const key = `${c.changeType}:${c.title}`;
|
|
98
|
-
const existing = groups.get(key);
|
|
99
|
-
if (existing) {
|
|
100
|
-
existing.count++;
|
|
101
|
-
}
|
|
102
|
-
else {
|
|
103
|
-
groups.set(key, { count: 1, representative: c });
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
return Array.from(groups.values()).map(({ count, representative }) => {
|
|
107
|
-
if (count > 1) {
|
|
108
|
-
return { ...representative, title: `${representative.title} (${count} contracts)` };
|
|
109
|
-
}
|
|
110
|
-
return representative;
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
async function fetchChanges(since, query) {
|
|
114
|
-
let url = `${SF_API_URL}/api/changes?since=${encodeURIComponent(since)}&limit=50`;
|
|
115
|
-
if (query)
|
|
116
|
-
url += `&q=${encodeURIComponent(query)}`;
|
|
117
|
-
const res = await fetch(url);
|
|
118
|
-
if (!res.ok)
|
|
119
|
-
return [];
|
|
120
|
-
const data = await res.json();
|
|
121
|
-
return data.changes || [];
|
|
122
|
-
}
|
|
123
|
-
function printChange(change) {
|
|
124
|
-
const time = ts();
|
|
125
|
-
const venue = change.venue === 'kalshi' ? `${utils_js_1.c.cyan}K${utils_js_1.c.reset}` :
|
|
126
|
-
change.venue === 'polymarket' ? `\x1b[35mP\x1b[39m` :
|
|
127
|
-
change.venue === 'traditional' ? `${utils_js_1.c.dim}$${utils_js_1.c.reset}` : '·';
|
|
128
|
-
switch (change.changeType) {
|
|
129
|
-
case 'new_contract':
|
|
130
|
-
console.log(` ${time} ${venue} ${utils_js_1.c.green}+ NEW${utils_js_1.c.reset} ${change.afterPrice}¢ ${change.title}`);
|
|
131
|
-
break;
|
|
132
|
-
case 'removed_contract':
|
|
133
|
-
console.log(` ${time} ${venue} ${utils_js_1.c.red}− GONE${utils_js_1.c.reset} ${change.title}`);
|
|
134
|
-
break;
|
|
135
|
-
case 'price_move': {
|
|
136
|
-
if (change.venue === 'traditional') {
|
|
137
|
-
const sign = (change.delta || 0) > 0 ? '+' : '';
|
|
138
|
-
const color = (change.delta || 0) > 0 ? utils_js_1.c.green : utils_js_1.c.red;
|
|
139
|
-
const beforeDollars = ((change.beforePrice || 0) / 100).toFixed(0);
|
|
140
|
-
const afterDollars = ((change.afterPrice || 0) / 100).toFixed(0);
|
|
141
|
-
console.log(` ${time} ${venue} ${color}${sign}${change.delta}¢${utils_js_1.c.reset} $${beforeDollars}→$${afterDollars} ${change.title}`);
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
const sign = (change.delta || 0) > 0 ? '+' : '';
|
|
145
|
-
const color = (change.delta || 0) > 0 ? utils_js_1.c.green : utils_js_1.c.red;
|
|
146
|
-
console.log(` ${time} ${venue} ${color}${sign}${change.delta}¢${utils_js_1.c.reset} ${change.beforePrice}→${change.afterPrice}¢ ${change.title}`);
|
|
147
|
-
}
|
|
148
|
-
break;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
function ts() {
|
|
153
|
-
return new Date().toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' });
|
|
154
|
-
}
|
|
155
|
-
function sleep(ms) {
|
|
156
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
157
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* sf whatif — What-if scenario analysis.
|
|
3
|
-
*
|
|
4
|
-
* Pure computation, zero LLM cost. Answers:
|
|
5
|
-
* "If node X drops to 10%, what happens to my edges and positions?"
|
|
6
|
-
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* sf whatif f582bf76 --set "n1=0.1"
|
|
9
|
-
* sf whatif f582bf76 --set "n1=0.1" --set "n3.1=0.2"
|
|
10
|
-
* sf whatif f582bf76 --set "n1=0.1" --json
|
|
11
|
-
*/
|
|
12
|
-
export declare function whatifCommand(thesisId: string, opts: {
|
|
13
|
-
set?: string[];
|
|
14
|
-
json?: boolean;
|
|
15
|
-
apiKey?: string;
|
|
16
|
-
apiUrl?: string;
|
|
17
|
-
}): Promise<void>;
|