@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 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) =====
@@ -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.4",
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"