@spfunctions/cli 1.6.1 → 1.7.2
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/client.d.ts +3 -0
- package/dist/client.js +21 -0
- package/dist/commands/agent.js +44 -0
- package/dist/commands/context.d.ts +1 -1
- package/dist/commands/context.js +58 -0
- package/dist/commands/query.js +10 -3
- package/dist/commands/trade.js +24 -0
- package/dist/index.js +5 -5
- package/dist/telegram/agent-bridge.js +20 -0
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -33,3 +33,6 @@ export declare function kalshiFetchEvents(seriesTicker: string): Promise<any[]>;
|
|
|
33
33
|
export declare function kalshiFetchMarket(ticker: string): Promise<any>;
|
|
34
34
|
export declare function kalshiFetchMarketsBySeries(seriesTicker: string): Promise<any[]>;
|
|
35
35
|
export declare function kalshiFetchMarketsByEvent(eventTicker: string): Promise<any[]>;
|
|
36
|
+
export declare function fetchGlobalContext(): Promise<any>;
|
|
37
|
+
export declare function fetchQuery(q: string): Promise<any>;
|
|
38
|
+
export declare function fetchTraditionalMarkets(): Promise<any>;
|
package/dist/client.js
CHANGED
|
@@ -12,6 +12,9 @@ exports.kalshiFetchEvents = kalshiFetchEvents;
|
|
|
12
12
|
exports.kalshiFetchMarket = kalshiFetchMarket;
|
|
13
13
|
exports.kalshiFetchMarketsBySeries = kalshiFetchMarketsBySeries;
|
|
14
14
|
exports.kalshiFetchMarketsByEvent = kalshiFetchMarketsByEvent;
|
|
15
|
+
exports.fetchGlobalContext = fetchGlobalContext;
|
|
16
|
+
exports.fetchQuery = fetchQuery;
|
|
17
|
+
exports.fetchTraditionalMarkets = fetchTraditionalMarkets;
|
|
15
18
|
const DEFAULT_API_URL = 'https://simplefunctions.dev';
|
|
16
19
|
const KALSHI_BASE = 'https://api.elections.kalshi.com/trade-api/v2';
|
|
17
20
|
// ===== SF API Client =====
|
|
@@ -154,3 +157,21 @@ async function kalshiFetchMarketsByEvent(eventTicker) {
|
|
|
154
157
|
});
|
|
155
158
|
return data.markets || [];
|
|
156
159
|
}
|
|
160
|
+
// ===== Public Endpoints (no auth) =====
|
|
161
|
+
const SF_PUBLIC_BASE = 'https://simplefunctions.dev';
|
|
162
|
+
async function fetchGlobalContext() {
|
|
163
|
+
const res = await fetch(`${SF_PUBLIC_BASE}/api/public/context`);
|
|
164
|
+
if (!res.ok)
|
|
165
|
+
throw new Error(`Context API error: ${res.status}`);
|
|
166
|
+
return res.json();
|
|
167
|
+
}
|
|
168
|
+
async function fetchQuery(q) {
|
|
169
|
+
const res = await fetch(`${SF_PUBLIC_BASE}/api/public/query?q=${encodeURIComponent(q)}`);
|
|
170
|
+
if (!res.ok)
|
|
171
|
+
throw new Error(`Query API error: ${res.status}`);
|
|
172
|
+
return res.json();
|
|
173
|
+
}
|
|
174
|
+
async function fetchTraditionalMarkets() {
|
|
175
|
+
const ctx = await fetchGlobalContext();
|
|
176
|
+
return ctx.traditionalMarkets || [];
|
|
177
|
+
}
|
package/dist/commands/agent.js
CHANGED
|
@@ -746,6 +746,30 @@ async function agentCommand(thesisId, opts) {
|
|
|
746
746
|
};
|
|
747
747
|
},
|
|
748
748
|
},
|
|
749
|
+
{
|
|
750
|
+
name: 'global_context',
|
|
751
|
+
label: 'Market Snapshot',
|
|
752
|
+
description: 'Global market snapshot — top movers, expiring contracts, milestones, liquidity, signals. No thesis needed.',
|
|
753
|
+
parameters: emptyParams,
|
|
754
|
+
execute: async () => {
|
|
755
|
+
const { fetchGlobalContext } = await import('../client.js');
|
|
756
|
+
const data = await fetchGlobalContext();
|
|
757
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }], details: {} };
|
|
758
|
+
},
|
|
759
|
+
},
|
|
760
|
+
{
|
|
761
|
+
name: 'query',
|
|
762
|
+
label: 'Query',
|
|
763
|
+
description: 'LLM-enhanced prediction market knowledge search. Ask any question about prediction markets, macro, geopolitics. Returns structured answer with live market prices, thesis data, and key factors.',
|
|
764
|
+
parameters: Type.Object({
|
|
765
|
+
q: Type.String({ description: 'Natural language query (e.g. "iran oil prices", "fed rate cut 2026")' }),
|
|
766
|
+
}),
|
|
767
|
+
execute: async (_toolCallId, params) => {
|
|
768
|
+
const { fetchQuery } = await import('../client.js');
|
|
769
|
+
const data = await fetchQuery(params.q);
|
|
770
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }], details: {} };
|
|
771
|
+
},
|
|
772
|
+
},
|
|
749
773
|
{
|
|
750
774
|
name: 'inject_signal',
|
|
751
775
|
label: 'Inject Signal',
|
|
@@ -2540,6 +2564,26 @@ async function runPlainTextAgent(params) {
|
|
|
2540
2564
|
return { content: [{ type: 'text', text: JSON.stringify(ctx, null, 2) }], details: {} };
|
|
2541
2565
|
},
|
|
2542
2566
|
},
|
|
2567
|
+
{
|
|
2568
|
+
name: 'global_context', label: 'Market Snapshot',
|
|
2569
|
+
description: 'Global market snapshot — top movers, expiring contracts, milestones, liquidity, signals. No thesis needed.',
|
|
2570
|
+
parameters: emptyParams,
|
|
2571
|
+
execute: async () => {
|
|
2572
|
+
const { fetchGlobalContext } = await import('../client.js');
|
|
2573
|
+
const data = await fetchGlobalContext();
|
|
2574
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }], details: {} };
|
|
2575
|
+
},
|
|
2576
|
+
},
|
|
2577
|
+
{
|
|
2578
|
+
name: 'query', label: 'Query',
|
|
2579
|
+
description: 'LLM-enhanced prediction market knowledge search. Returns structured answer with live prices, thesis data, key factors.',
|
|
2580
|
+
parameters: Type.Object({ q: Type.String({ description: 'Natural language query' }) }),
|
|
2581
|
+
execute: async (_id, p) => {
|
|
2582
|
+
const { fetchQuery } = await import('../client.js');
|
|
2583
|
+
const data = await fetchQuery(p.q);
|
|
2584
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }], details: {} };
|
|
2585
|
+
},
|
|
2586
|
+
},
|
|
2543
2587
|
{
|
|
2544
2588
|
name: 'inject_signal', label: 'Inject Signal',
|
|
2545
2589
|
description: 'Inject a signal into the thesis',
|
package/dist/commands/context.js
CHANGED
|
@@ -5,6 +5,64 @@ const client_js_1 = require("../client.js");
|
|
|
5
5
|
const kalshi_js_1 = require("../kalshi.js");
|
|
6
6
|
const utils_js_1 = require("../utils.js");
|
|
7
7
|
async function contextCommand(id, opts) {
|
|
8
|
+
// No thesis ID → global market snapshot
|
|
9
|
+
if (!id) {
|
|
10
|
+
const res = await fetch('https://simplefunctions.dev/api/public/context');
|
|
11
|
+
if (!res.ok) {
|
|
12
|
+
console.error(` Error: ${res.status} ${await res.text()}`);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const data = await res.json();
|
|
16
|
+
if (opts.json) {
|
|
17
|
+
console.log(JSON.stringify(data, null, 2));
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
console.log(`\n${utils_js_1.c.bold}Market Snapshot${utils_js_1.c.reset} ${(0, utils_js_1.shortDate)(data.snapshotAt)}\n`);
|
|
21
|
+
if (data.edges?.length > 0) {
|
|
22
|
+
console.log(`${utils_js_1.c.bold}Thesis Edges${utils_js_1.c.reset}`);
|
|
23
|
+
for (const m of data.edges.slice(0, 10)) {
|
|
24
|
+
const venue = m.venue === 'kalshi' ? `${utils_js_1.c.cyan}K${utils_js_1.c.reset}` : `${utils_js_1.c.magenta}P${utils_js_1.c.reset}`;
|
|
25
|
+
const edgeStr = m.edge > 0 ? `${utils_js_1.c.green}+${m.edge}¢${utils_js_1.c.reset}` : `${utils_js_1.c.red}${m.edge}¢${utils_js_1.c.reset}`;
|
|
26
|
+
console.log(` ${venue} ${String(m.price).padStart(3)}¢ edge ${edgeStr.padStart(14)} ${m.title.slice(0, 50)}`);
|
|
27
|
+
}
|
|
28
|
+
console.log();
|
|
29
|
+
}
|
|
30
|
+
if (data.movers?.length > 0) {
|
|
31
|
+
console.log(`${utils_js_1.c.bold}Movers (24h)${utils_js_1.c.reset}`);
|
|
32
|
+
for (const m of data.movers.slice(0, 8)) {
|
|
33
|
+
const venue = m.venue === 'kalshi' ? `${utils_js_1.c.cyan}K${utils_js_1.c.reset}` : `${utils_js_1.c.magenta}P${utils_js_1.c.reset}`;
|
|
34
|
+
const ch = m.change24h > 0 ? `${utils_js_1.c.green}+${m.change24h}¢${utils_js_1.c.reset}` : `${utils_js_1.c.red}${m.change24h}¢${utils_js_1.c.reset}`;
|
|
35
|
+
console.log(` ${venue} ${String(m.price).padStart(3)}¢ ${ch.padStart(16)} ${m.title.slice(0, 55)}`);
|
|
36
|
+
}
|
|
37
|
+
console.log();
|
|
38
|
+
}
|
|
39
|
+
if (data.milestones?.length > 0) {
|
|
40
|
+
console.log(`${utils_js_1.c.bold}Upcoming (48h)${utils_js_1.c.reset}`);
|
|
41
|
+
for (const m of data.milestones.slice(0, 8)) {
|
|
42
|
+
console.log(` ${utils_js_1.c.dim}${String(m.hoursUntil).padStart(3)}h${utils_js_1.c.reset} ${m.title.slice(0, 55)} ${utils_js_1.c.dim}${m.category}${utils_js_1.c.reset}`);
|
|
43
|
+
}
|
|
44
|
+
console.log();
|
|
45
|
+
}
|
|
46
|
+
if (data.liquid?.length > 0) {
|
|
47
|
+
console.log(`${utils_js_1.c.bold}Liquid${utils_js_1.c.reset}`);
|
|
48
|
+
for (const m of data.liquid.slice(0, 8)) {
|
|
49
|
+
const venue = m.venue === 'kalshi' ? `${utils_js_1.c.cyan}K${utils_js_1.c.reset}` : `${utils_js_1.c.magenta}P${utils_js_1.c.reset}`;
|
|
50
|
+
console.log(` ${venue} ${String(m.price).padStart(3)}¢ spread ${m.spread}¢ ${m.title.slice(0, 55)}`);
|
|
51
|
+
}
|
|
52
|
+
console.log();
|
|
53
|
+
}
|
|
54
|
+
if (data.signals?.length > 0) {
|
|
55
|
+
console.log(`${utils_js_1.c.bold}Recent Signals${utils_js_1.c.reset}`);
|
|
56
|
+
for (const s of data.signals.slice(0, 5)) {
|
|
57
|
+
const d = s.confidenceDelta > 0 ? `${utils_js_1.c.green}▲${s.confidenceDelta}${utils_js_1.c.reset}` : s.confidenceDelta < 0 ? `${utils_js_1.c.red}▼${s.confidenceDelta}${utils_js_1.c.reset}` : `${s.confidenceDelta}`;
|
|
58
|
+
console.log(` ${d} ${s.confidence}% ${s.summary.slice(0, 60)}`);
|
|
59
|
+
console.log(` ${utils_js_1.c.dim}${s.thesisTitle.slice(0, 40)} ${(0, utils_js_1.shortDate)(s.evaluatedAt)}${utils_js_1.c.reset}`);
|
|
60
|
+
}
|
|
61
|
+
console.log();
|
|
62
|
+
}
|
|
63
|
+
console.log(` ${utils_js_1.c.dim}Create a thesis for focused context: sf create "your market view"${utils_js_1.c.reset}\n`);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
8
66
|
const client = new client_js_1.SFClient(opts.apiKey, opts.apiUrl);
|
|
9
67
|
const ctx = await client.getContext(id);
|
|
10
68
|
if (opts.json) {
|
package/dist/commands/query.js
CHANGED
|
@@ -62,11 +62,18 @@ async function queryCommand(q, opts) {
|
|
|
62
62
|
}
|
|
63
63
|
console.log();
|
|
64
64
|
}
|
|
65
|
-
//
|
|
66
|
-
if (data.
|
|
65
|
+
// Theses
|
|
66
|
+
if (data.theses?.length > 0) {
|
|
67
|
+
console.log(` \x1b[1mTheses\x1b[22m`);
|
|
68
|
+
for (const t of data.theses.slice(0, 3)) {
|
|
69
|
+
console.log(` ${t.confidence || '?'}% ${String(t.edges || 0).padStart(2)} edges ${t.title.slice(0, 50)}`);
|
|
70
|
+
}
|
|
71
|
+
console.log();
|
|
72
|
+
}
|
|
73
|
+
else if (data.thesis) {
|
|
74
|
+
// Backward compat
|
|
67
75
|
const t = data.thesis;
|
|
68
76
|
console.log(` \x1b[1mThesis\x1b[22m`);
|
|
69
|
-
console.log(` ${t.title.slice(0, 60)}`);
|
|
70
77
|
console.log(` ${t.confidence}% confidence ${t.edges} edges /thesis/${t.slug}`);
|
|
71
78
|
console.log();
|
|
72
79
|
}
|
package/dist/commands/trade.js
CHANGED
|
@@ -5,6 +5,9 @@ exports.sellCommand = sellCommand;
|
|
|
5
5
|
const kalshi_js_1 = require("../kalshi.js");
|
|
6
6
|
const config_js_1 = require("../config.js");
|
|
7
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");
|
|
8
11
|
async function buyCommand(ticker, qty, opts) {
|
|
9
12
|
(0, config_js_1.requireTrading)();
|
|
10
13
|
await executeOrder(ticker, qty, 'buy', opts);
|
|
@@ -62,6 +65,27 @@ async function executeOrder(ticker, qty, action, opts) {
|
|
|
62
65
|
if (order.fill_count_fp)
|
|
63
66
|
console.log(` Filled: ${order.fill_count_fp}/${order.initial_count_fp || quantity}`);
|
|
64
67
|
console.log();
|
|
68
|
+
// Auto-log trade to journal
|
|
69
|
+
try {
|
|
70
|
+
const journalDir = (0, path_1.join)((0, os_1.homedir)(), '.sf');
|
|
71
|
+
if (!(0, fs_1.existsSync)(journalDir))
|
|
72
|
+
(0, fs_1.mkdirSync)(journalDir, { recursive: true });
|
|
73
|
+
const entry = JSON.stringify({
|
|
74
|
+
ts: new Date().toISOString(),
|
|
75
|
+
action,
|
|
76
|
+
ticker,
|
|
77
|
+
side,
|
|
78
|
+
quantity,
|
|
79
|
+
price: priceCents || null,
|
|
80
|
+
type: orderType,
|
|
81
|
+
orderId: order.order_id || null,
|
|
82
|
+
status: order.status || null,
|
|
83
|
+
filled: order.fill_count_fp || null,
|
|
84
|
+
}) + '\n';
|
|
85
|
+
(0, fs_1.appendFileSync)((0, path_1.join)(journalDir, 'trade-journal.jsonl'), entry);
|
|
86
|
+
console.log(` ${utils_js_1.c.dim}Trade logged to ~/.sf/trade-journal.jsonl${utils_js_1.c.reset}`);
|
|
87
|
+
}
|
|
88
|
+
catch { /* journal logging is best-effort */ }
|
|
65
89
|
}
|
|
66
90
|
catch (err) {
|
|
67
91
|
const msg = err.message || String(err);
|
package/dist/index.js
CHANGED
|
@@ -77,7 +77,7 @@ const GROUPED_HELP = `
|
|
|
77
77
|
\x1b[1mThesis\x1b[22m
|
|
78
78
|
\x1b[36mlist\x1b[39m List all theses
|
|
79
79
|
\x1b[36mget\x1b[39m <id> Full thesis details
|
|
80
|
-
\x1b[36mcontext\x1b[39m
|
|
80
|
+
\x1b[36mcontext\x1b[39m [id] [--json] Market snapshot (no id) or thesis context (with id)
|
|
81
81
|
\x1b[36mcreate\x1b[39m "thesis" Create a new thesis
|
|
82
82
|
\x1b[36msignal\x1b[39m <id> "content" Inject a signal
|
|
83
83
|
\x1b[36mevaluate\x1b[39m <id> Trigger deep evaluation
|
|
@@ -221,7 +221,7 @@ async function interactiveEntry() {
|
|
|
221
221
|
console.log();
|
|
222
222
|
}
|
|
223
223
|
// ── Pre-action guard: check configuration ────────────────────────────────────
|
|
224
|
-
const NO_CONFIG_COMMANDS = new Set(['setup', 'help', 'scan', 'explore', 'query', 'milestones', 'forecast', 'settlements', 'balance', 'orders', 'fills', 'schedule', 'announcements', 'history', 'liquidity', 'book', 'prompt', 'sf']);
|
|
224
|
+
const NO_CONFIG_COMMANDS = new Set(['setup', 'help', 'scan', 'explore', 'query', 'context', 'milestones', 'forecast', 'settlements', 'balance', 'orders', 'fills', 'schedule', 'announcements', 'history', 'liquidity', 'book', 'prompt', 'sf']);
|
|
225
225
|
program.hook('preAction', (thisCommand, actionCommand) => {
|
|
226
226
|
const cmdName = actionCommand.name();
|
|
227
227
|
if (NO_CONFIG_COMMANDS.has(cmdName))
|
|
@@ -279,10 +279,10 @@ program
|
|
|
279
279
|
const g = cmd.optsWithGlobals();
|
|
280
280
|
await run(() => (0, get_js_1.getCommand)(id, { json: opts.json, apiKey: g.apiKey, apiUrl: g.apiUrl }));
|
|
281
281
|
});
|
|
282
|
-
// ── sf context
|
|
282
|
+
// ── sf context [id] ───────────────────────────────────────────────────────────
|
|
283
283
|
program
|
|
284
|
-
.command('context
|
|
285
|
-
.description('
|
|
284
|
+
.command('context [id]')
|
|
285
|
+
.description('Context snapshot. With ID: thesis-specific. Without: global market snapshot (no auth)')
|
|
286
286
|
.option('--json', 'Output raw JSON')
|
|
287
287
|
.action(async (id, opts, cmd) => {
|
|
288
288
|
const g = cmd.optsWithGlobals();
|
|
@@ -38,6 +38,26 @@ async function buildTools(sfClient, thesisId, latestContext) {
|
|
|
38
38
|
return { content: [{ type: 'text', text: JSON.stringify(ctx, null, 2) }], details: {} };
|
|
39
39
|
},
|
|
40
40
|
},
|
|
41
|
+
{
|
|
42
|
+
name: 'global_context', label: 'Snapshot',
|
|
43
|
+
description: 'Global market snapshot — movers, expiring, milestones, liquidity, signals. No thesis needed.',
|
|
44
|
+
parameters: emptyParams,
|
|
45
|
+
execute: async () => {
|
|
46
|
+
const { fetchGlobalContext } = await import('../client.js');
|
|
47
|
+
const data = await fetchGlobalContext();
|
|
48
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }], details: {} };
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'query', label: 'Query',
|
|
53
|
+
description: 'LLM-enhanced prediction market search. Returns answer, live prices, key factors.',
|
|
54
|
+
parameters: Type.Object({ q: Type.String({ description: 'Question' }) }),
|
|
55
|
+
execute: async (_id, p) => {
|
|
56
|
+
const { fetchQuery } = await import('../client.js');
|
|
57
|
+
const data = await fetchQuery(p.q);
|
|
58
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }], details: {} };
|
|
59
|
+
},
|
|
60
|
+
},
|
|
41
61
|
{
|
|
42
62
|
name: 'inject_signal', label: 'Signal',
|
|
43
63
|
description: 'Inject a signal (news, note, observation) into the thesis',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spfunctions/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.2",
|
|
4
4
|
"description": "Prediction market intelligence CLI. Causal thesis model, 24/7 Kalshi/Polymarket scan, live orderbook, edge detection. Interactive agent mode with tool calling.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"sf": "./dist/index.js"
|