@spfunctions/cli 1.6.1 → 1.7.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/dist/client.d.ts CHANGED
@@ -33,3 +33,5 @@ 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>;
package/dist/client.js CHANGED
@@ -12,6 +12,8 @@ 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;
15
17
  const DEFAULT_API_URL = 'https://simplefunctions.dev';
16
18
  const KALSHI_BASE = 'https://api.elections.kalshi.com/trade-api/v2';
17
19
  // ===== SF API Client =====
@@ -154,3 +156,17 @@ async function kalshiFetchMarketsByEvent(eventTicker) {
154
156
  });
155
157
  return data.markets || [];
156
158
  }
159
+ // ===== Public Endpoints (no auth) =====
160
+ const SF_PUBLIC_BASE = 'https://simplefunctions.dev';
161
+ async function fetchGlobalContext() {
162
+ const res = await fetch(`${SF_PUBLIC_BASE}/api/public/context`);
163
+ if (!res.ok)
164
+ throw new Error(`Context API error: ${res.status}`);
165
+ return res.json();
166
+ }
167
+ async function fetchQuery(q) {
168
+ const res = await fetch(`${SF_PUBLIC_BASE}/api/public/query?q=${encodeURIComponent(q)}`);
169
+ if (!res.ok)
170
+ throw new Error(`Query API error: ${res.status}`);
171
+ return res.json();
172
+ }
@@ -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',
@@ -1,4 +1,4 @@
1
- export declare function contextCommand(id: string, opts: {
1
+ export declare function contextCommand(id: string | undefined, opts: {
2
2
  json?: boolean;
3
3
  apiKey?: string;
4
4
  apiUrl?: string;
@@ -5,6 +5,63 @@ 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.movers?.length > 0) {
22
+ console.log(`${utils_js_1.c.bold}Movers (24h)${utils_js_1.c.reset}`);
23
+ for (const m of data.movers.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 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}`;
26
+ console.log(` ${venue} ${String(m.price).padStart(3)}¢ ${ch.padStart(16)} ${m.title.slice(0, 55)}`);
27
+ }
28
+ console.log();
29
+ }
30
+ if (data.milestones?.length > 0) {
31
+ console.log(`${utils_js_1.c.bold}Upcoming (48h)${utils_js_1.c.reset}`);
32
+ for (const m of data.milestones.slice(0, 8)) {
33
+ 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}`);
34
+ }
35
+ console.log();
36
+ }
37
+ if (data.expiring?.length > 0) {
38
+ console.log(`${utils_js_1.c.bold}Expiring (7d)${utils_js_1.c.reset}`);
39
+ for (const m of data.expiring.slice(0, 8)) {
40
+ 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}`;
41
+ console.log(` ${venue} ${String(m.price).padStart(3)}¢ ${utils_js_1.c.dim}${String(m.hoursUntil).padStart(3)}h${utils_js_1.c.reset} ${m.title.slice(0, 55)}`);
42
+ }
43
+ console.log();
44
+ }
45
+ if (data.liquid?.length > 0) {
46
+ console.log(`${utils_js_1.c.bold}Liquid${utils_js_1.c.reset}`);
47
+ for (const m of data.liquid.slice(0, 8)) {
48
+ 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}`;
49
+ console.log(` ${venue} ${String(m.price).padStart(3)}¢ spread ${m.spread}¢ ${m.title.slice(0, 55)}`);
50
+ }
51
+ console.log();
52
+ }
53
+ if (data.signals?.length > 0) {
54
+ console.log(`${utils_js_1.c.bold}Recent Signals${utils_js_1.c.reset}`);
55
+ for (const s of data.signals.slice(0, 5)) {
56
+ 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}`;
57
+ console.log(` ${d} ${s.confidence}% ${s.summary.slice(0, 60)}`);
58
+ console.log(` ${utils_js_1.c.dim}${s.thesisTitle.slice(0, 40)} ${(0, utils_js_1.shortDate)(s.evaluatedAt)}${utils_js_1.c.reset}`);
59
+ }
60
+ console.log();
61
+ }
62
+ console.log(` ${utils_js_1.c.dim}Create a thesis for focused context: sf create "your market view"${utils_js_1.c.reset}\n`);
63
+ return;
64
+ }
8
65
  const client = new client_js_1.SFClient(opts.apiKey, opts.apiUrl);
9
66
  const ctx = await client.getContext(id);
10
67
  if (opts.json) {
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 <id> [--json] Thesis snapshot \x1b[2m(primary for agents)\x1b[22m
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 <id> ───────────────────────────────────────────────────────────
282
+ // ── sf context [id] ───────────────────────────────────────────────────────────
283
283
  program
284
- .command('context <id>')
285
- .description('Get thesis context snapshot (primary command for agents)')
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.6.1",
3
+ "version": "1.7.1",
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"