@spfunctions/cli 1.1.4 → 1.1.5
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 +2 -0
- package/dist/client.js +6 -0
- package/dist/commands/agent.js +23 -0
- package/dist/commands/explore.d.ts +13 -0
- package/dist/commands/explore.js +110 -0
- package/dist/commands/publish.d.ts +15 -0
- package/dist/commands/publish.js +20 -0
- package/dist/index.js +29 -1
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -18,6 +18,8 @@ export declare class SFClient {
|
|
|
18
18
|
injectSignal(id: string, type: string, content: string, source?: string): Promise<any>;
|
|
19
19
|
evaluate(id: string): Promise<any>;
|
|
20
20
|
updateThesis(id: string, data: Record<string, unknown>): Promise<any>;
|
|
21
|
+
publish(id: string, slug: string, description?: string): Promise<any>;
|
|
22
|
+
unpublish(id: string): Promise<any>;
|
|
21
23
|
}
|
|
22
24
|
export declare function kalshiFetchAllSeries(): Promise<any[]>;
|
|
23
25
|
export declare function kalshiFetchEvents(seriesTicker: string): Promise<any[]>;
|
package/dist/client.js
CHANGED
|
@@ -65,6 +65,12 @@ class SFClient {
|
|
|
65
65
|
async updateThesis(id, data) {
|
|
66
66
|
return this.request('PATCH', `/api/thesis/${id}`, data);
|
|
67
67
|
}
|
|
68
|
+
async publish(id, slug, description) {
|
|
69
|
+
return this.request('POST', `/api/thesis/${id}/publish`, { slug, description });
|
|
70
|
+
}
|
|
71
|
+
async unpublish(id) {
|
|
72
|
+
return this.request('DELETE', `/api/thesis/${id}/publish`);
|
|
73
|
+
}
|
|
68
74
|
}
|
|
69
75
|
exports.SFClient = SFClient;
|
|
70
76
|
// ===== Kalshi Public API (no auth) =====
|
package/dist/commands/agent.js
CHANGED
|
@@ -613,6 +613,29 @@ async function agentCommand(thesisId, opts) {
|
|
|
613
613
|
};
|
|
614
614
|
},
|
|
615
615
|
},
|
|
616
|
+
{
|
|
617
|
+
name: 'explore_public',
|
|
618
|
+
label: 'Explore Public Theses',
|
|
619
|
+
description: 'Browse public theses from other users. No auth required. Pass a slug to get details, or omit to list all.',
|
|
620
|
+
parameters: Type.Object({
|
|
621
|
+
slug: Type.Optional(Type.String({ description: 'Specific thesis slug, or empty to list all' })),
|
|
622
|
+
}),
|
|
623
|
+
execute: async (_toolCallId, params) => {
|
|
624
|
+
const base = 'https://simplefunctions.dev';
|
|
625
|
+
if (params.slug) {
|
|
626
|
+
const res = await fetch(`${base}/api/public/thesis/${params.slug}`);
|
|
627
|
+
if (!res.ok)
|
|
628
|
+
return { content: [{ type: 'text', text: `Not found: ${params.slug}` }], details: {} };
|
|
629
|
+
const data = await res.json();
|
|
630
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }], details: {} };
|
|
631
|
+
}
|
|
632
|
+
const res = await fetch(`${base}/api/public/theses`);
|
|
633
|
+
if (!res.ok)
|
|
634
|
+
return { content: [{ type: 'text', text: 'Failed to fetch public theses' }], details: {} };
|
|
635
|
+
const data = await res.json();
|
|
636
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }], details: {} };
|
|
637
|
+
},
|
|
638
|
+
},
|
|
616
639
|
];
|
|
617
640
|
// ── System prompt builder ──────────────────────────────────────────────────
|
|
618
641
|
function buildSystemPrompt(ctx) {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sf explore [slug]
|
|
3
|
+
*
|
|
4
|
+
* Browse public theses. No authentication required.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* sf explore — List all public theses
|
|
8
|
+
* sf explore us-iran-war — View a specific public thesis
|
|
9
|
+
* sf explore us-iran-war --json — JSON output (for agents)
|
|
10
|
+
*/
|
|
11
|
+
export declare function exploreCommand(slug?: string, opts?: {
|
|
12
|
+
json?: boolean;
|
|
13
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* sf explore [slug]
|
|
4
|
+
*
|
|
5
|
+
* Browse public theses. No authentication required.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* sf explore — List all public theses
|
|
9
|
+
* sf explore us-iran-war — View a specific public thesis
|
|
10
|
+
* sf explore us-iran-war --json — JSON output (for agents)
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.exploreCommand = exploreCommand;
|
|
14
|
+
const BASE_URL = 'https://simplefunctions.dev';
|
|
15
|
+
async function exploreCommand(slug, opts) {
|
|
16
|
+
if (!slug) {
|
|
17
|
+
// List all public theses
|
|
18
|
+
const res = await fetch(`${BASE_URL}/api/public/theses`);
|
|
19
|
+
if (!res.ok) {
|
|
20
|
+
console.error(` Error: ${res.status} ${await res.text()}`);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const { theses } = await res.json();
|
|
24
|
+
if (opts?.json) {
|
|
25
|
+
console.log(JSON.stringify(theses, null, 2));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
console.log('\n Public Theses\n');
|
|
29
|
+
if (theses.length === 0) {
|
|
30
|
+
console.log(' No public theses yet.\n');
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
for (const t of theses) {
|
|
34
|
+
const conf = t.confidence != null ? Math.round(t.confidence * 100) : '?';
|
|
35
|
+
const ret = t.impliedReturn != null ? `${t.impliedReturn > 0 ? '+' : ''}${t.impliedReturn}%` : '';
|
|
36
|
+
console.log(` ${(t.slug || '').padEnd(35)} ${String(conf).padStart(3)}% ${ret.padStart(8)} ${(t.status || '').padEnd(8)} ${(t.title || '').slice(0, 45)}`);
|
|
37
|
+
}
|
|
38
|
+
console.log(`\n ${theses.length} public theses. Use: sf explore <slug>\n`);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
// View a specific public thesis
|
|
42
|
+
const res = await fetch(`${BASE_URL}/api/public/thesis/${slug}`);
|
|
43
|
+
if (!res.ok) {
|
|
44
|
+
if (res.status === 404) {
|
|
45
|
+
console.error(` Not found: ${slug}`);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
console.error(` Error: ${res.status} ${await res.text()}`);
|
|
49
|
+
}
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const data = await res.json();
|
|
53
|
+
if (opts?.json) {
|
|
54
|
+
console.log(JSON.stringify(data, null, 2));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
// Formatted output
|
|
58
|
+
const t = data.thesis;
|
|
59
|
+
const ir = data.impliedReturns;
|
|
60
|
+
console.log(`\n ${t.title}`);
|
|
61
|
+
console.log(` ${t.slug} | ${t.confidence != null ? Math.round(t.confidence * 100) : '?'}% | ${t.status} | published ${t.publishedAt?.slice(0, 10) || '?'}`);
|
|
62
|
+
if (t.description)
|
|
63
|
+
console.log(` ${t.description}`);
|
|
64
|
+
console.log('');
|
|
65
|
+
// Causal tree
|
|
66
|
+
if (data.causalTree?.nodes?.length) {
|
|
67
|
+
console.log(' Causal Tree');
|
|
68
|
+
for (const n of data.causalTree.nodes) {
|
|
69
|
+
const bar = '█'.repeat(Math.round((n.probability || 0) * 10)) + '░'.repeat(10 - Math.round((n.probability || 0) * 10));
|
|
70
|
+
console.log(` ${n.id} ${(n.label || '').slice(0, 35).padEnd(35)} ${Math.round((n.probability || 0) * 100)}% ${bar}`);
|
|
71
|
+
if (n.children) {
|
|
72
|
+
for (const c of n.children) {
|
|
73
|
+
const cbar = '█'.repeat(Math.round((c.probability || 0) * 10)) + '░'.repeat(10 - Math.round((c.probability || 0) * 10));
|
|
74
|
+
console.log(` ${c.id} ${(c.label || '').slice(0, 33).padEnd(33)} ${Math.round((c.probability || 0) * 100)}% ${cbar}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
console.log('');
|
|
79
|
+
}
|
|
80
|
+
// Implied returns
|
|
81
|
+
if (ir && ir.edges?.length > 0) {
|
|
82
|
+
console.log(` Implied Returns (equal-weight, since ${ir.trackedSince?.slice(0, 10) || '?'})`);
|
|
83
|
+
console.log(` Avg: ${ir.avgReturnPct > 0 ? '+' : ''}${ir.avgReturnPct}% | Win rate: ${ir.winRate}% (${ir.winners}W ${ir.losers}L)`);
|
|
84
|
+
console.log('');
|
|
85
|
+
for (const e of ir.edges.slice(0, 10)) {
|
|
86
|
+
const ret = e.returnPct > 0 ? `+${e.returnPct}%` : `${e.returnPct}%`;
|
|
87
|
+
console.log(` ${(e.market || '').slice(0, 35).padEnd(35)} ${e.entryPrice}¢ → ${e.currentPrice}¢ ${ret}`);
|
|
88
|
+
}
|
|
89
|
+
console.log('');
|
|
90
|
+
}
|
|
91
|
+
// Recent evaluations
|
|
92
|
+
if (data.confidenceHistory?.length > 0) {
|
|
93
|
+
console.log(' Recent Evaluations');
|
|
94
|
+
for (const h of data.confidenceHistory.slice(-5)) {
|
|
95
|
+
const d = h.delta > 0 ? `+${Math.round(h.delta * 100)}` : `${Math.round(h.delta * 100)}`;
|
|
96
|
+
console.log(` ${(h.evaluatedAt || '').slice(0, 16)} ${Math.round(h.confidence * 100)}% (${d}) ${(h.summary || '').slice(0, 60)}`);
|
|
97
|
+
}
|
|
98
|
+
console.log('');
|
|
99
|
+
}
|
|
100
|
+
// Top edges
|
|
101
|
+
if (data.edges?.length > 0) {
|
|
102
|
+
console.log(' Top Edges');
|
|
103
|
+
const sorted = [...data.edges].sort((a, b) => Math.abs(b.edge) - Math.abs(a.edge)).slice(0, 10);
|
|
104
|
+
for (const e of sorted) {
|
|
105
|
+
const liq = e.orderbook?.liquidityScore || '?';
|
|
106
|
+
console.log(` ${(e.market || '').slice(0, 35).padEnd(35)} ${e.marketPrice}¢ → ${e.thesisPrice}¢ edge ${e.edge > 0 ? '+' : ''}${e.edge} ${liq}`);
|
|
107
|
+
}
|
|
108
|
+
console.log('');
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sf publish / sf unpublish
|
|
3
|
+
*
|
|
4
|
+
* Publish a thesis for public viewing or remove it from public.
|
|
5
|
+
*/
|
|
6
|
+
export declare function publishCommand(thesisId: string, opts: {
|
|
7
|
+
slug: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
apiKey?: string;
|
|
10
|
+
apiUrl?: string;
|
|
11
|
+
}): Promise<void>;
|
|
12
|
+
export declare function unpublishCommand(thesisId: string, opts: {
|
|
13
|
+
apiKey?: string;
|
|
14
|
+
apiUrl?: string;
|
|
15
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* sf publish / sf unpublish
|
|
4
|
+
*
|
|
5
|
+
* Publish a thesis for public viewing or remove it from public.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.publishCommand = publishCommand;
|
|
9
|
+
exports.unpublishCommand = unpublishCommand;
|
|
10
|
+
const client_js_1 = require("../client.js");
|
|
11
|
+
async function publishCommand(thesisId, opts) {
|
|
12
|
+
const client = new client_js_1.SFClient(opts.apiKey, opts.apiUrl);
|
|
13
|
+
await client.publish(thesisId, opts.slug, opts.description);
|
|
14
|
+
console.log(`\n ✓ Published: https://simplefunctions.dev/thesis/${opts.slug}\n`);
|
|
15
|
+
}
|
|
16
|
+
async function unpublishCommand(thesisId, opts) {
|
|
17
|
+
const client = new client_js_1.SFClient(opts.apiKey, opts.apiUrl);
|
|
18
|
+
await client.unpublish(thesisId);
|
|
19
|
+
console.log(`\n ✓ Unpublished thesis ${thesisId}\n`);
|
|
20
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -32,6 +32,8 @@ const positions_js_1 = require("./commands/positions.js");
|
|
|
32
32
|
const edges_js_1 = require("./commands/edges.js");
|
|
33
33
|
const agent_js_1 = require("./commands/agent.js");
|
|
34
34
|
const setup_js_1 = require("./commands/setup.js");
|
|
35
|
+
const publish_js_1 = require("./commands/publish.js");
|
|
36
|
+
const explore_js_1 = require("./commands/explore.js");
|
|
35
37
|
const utils_js_1 = require("./utils.js");
|
|
36
38
|
// ── Apply ~/.sf/config.json to process.env BEFORE any command ────────────────
|
|
37
39
|
// This means client.ts, kalshi.ts, agent.ts keep reading process.env and just work.
|
|
@@ -44,7 +46,7 @@ program
|
|
|
44
46
|
.option('--api-key <key>', 'API key (or set SF_API_KEY env var)')
|
|
45
47
|
.option('--api-url <url>', 'API base URL (or set SF_API_URL env var)');
|
|
46
48
|
// ── Pre-action guard: check configuration ────────────────────────────────────
|
|
47
|
-
const NO_CONFIG_COMMANDS = new Set(['setup', 'help', 'scan']);
|
|
49
|
+
const NO_CONFIG_COMMANDS = new Set(['setup', 'help', 'scan', 'explore']);
|
|
48
50
|
program.hook('preAction', (thisCommand) => {
|
|
49
51
|
const cmdName = thisCommand.name();
|
|
50
52
|
if (NO_CONFIG_COMMANDS.has(cmdName))
|
|
@@ -185,6 +187,32 @@ program
|
|
|
185
187
|
const g = cmd.optsWithGlobals();
|
|
186
188
|
await run(() => (0, agent_js_1.agentCommand)(thesisId, { model: opts.model, modelKey: opts.modelKey, newSession: opts.new }));
|
|
187
189
|
});
|
|
190
|
+
// ── sf publish <thesisId> ─────────────────────────────────────────────────────
|
|
191
|
+
program
|
|
192
|
+
.command('publish <thesisId>')
|
|
193
|
+
.description('Publish a thesis for public viewing')
|
|
194
|
+
.requiredOption('--slug <slug>', 'URL slug (lowercase, hyphens, 3-60 chars)')
|
|
195
|
+
.option('--description <desc>', 'Short description')
|
|
196
|
+
.action(async (thesisId, opts, cmd) => {
|
|
197
|
+
const g = cmd.optsWithGlobals();
|
|
198
|
+
await run(() => (0, publish_js_1.publishCommand)(thesisId, { slug: opts.slug, description: opts.description, apiKey: g.apiKey, apiUrl: g.apiUrl }));
|
|
199
|
+
});
|
|
200
|
+
// ── sf unpublish <thesisId> ───────────────────────────────────────────────────
|
|
201
|
+
program
|
|
202
|
+
.command('unpublish <thesisId>')
|
|
203
|
+
.description('Remove a thesis from public viewing')
|
|
204
|
+
.action(async (thesisId, _opts, cmd) => {
|
|
205
|
+
const g = cmd.optsWithGlobals();
|
|
206
|
+
await run(() => (0, publish_js_1.unpublishCommand)(thesisId, { apiKey: g.apiKey, apiUrl: g.apiUrl }));
|
|
207
|
+
});
|
|
208
|
+
// ── sf explore [slug] ─────────────────────────────────────────────────────────
|
|
209
|
+
program
|
|
210
|
+
.command('explore [slug]')
|
|
211
|
+
.description('Browse public theses (no auth required)')
|
|
212
|
+
.option('--json', 'JSON output')
|
|
213
|
+
.action(async (slug, opts) => {
|
|
214
|
+
await run(() => (0, explore_js_1.exploreCommand)(slug, { json: opts.json }));
|
|
215
|
+
});
|
|
188
216
|
// ── Error wrapper ─────────────────────────────────────────────────────────────
|
|
189
217
|
async function run(fn) {
|
|
190
218
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spfunctions/cli",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.5",
|
|
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"
|