@spfunctions/cli 1.1.3 → 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) =====
@@ -520,7 +520,7 @@ async function agentCommand(thesisId, opts) {
520
520
  const series = await (0, client_js_1.kalshiFetchAllSeries)();
521
521
  const keywords = params.query.toLowerCase().split(/\s+/);
522
522
  const matched = series
523
- .filter((s) => keywords.some((kw) => (s.title || '').toLowerCase().includes(kw) ||
523
+ .filter((s) => keywords.every((kw) => (s.title || '').toLowerCase().includes(kw) ||
524
524
  (s.ticker || '').toLowerCase().includes(kw)))
525
525
  .slice(0, 15);
526
526
  result = matched;
@@ -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,21 @@
1
+ /**
2
+ * sf edges — Top edges across all active theses
3
+ *
4
+ * The most important output of the entire system: "what to trade now."
5
+ *
6
+ * Flow:
7
+ * 1. GET /api/thesis → all active theses
8
+ * 2. For each: GET /api/thesis/:id/context → edges with orderbook
9
+ * 3. Optional: getPositions() → Kalshi positions with live prices
10
+ * 4. Merge edges, dedupe by marketId (keep highest edge, note source thesis)
11
+ * 5. Sort by executableEdge descending
12
+ * 6. Display table with position overlay + summary
13
+ */
14
+ interface EdgesOpts {
15
+ json?: boolean;
16
+ limit?: string;
17
+ apiKey?: string;
18
+ apiUrl?: string;
19
+ }
20
+ export declare function edgesCommand(opts: EdgesOpts): Promise<void>;
21
+ export {};
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+ /**
3
+ * sf edges — Top edges across all active theses
4
+ *
5
+ * The most important output of the entire system: "what to trade now."
6
+ *
7
+ * Flow:
8
+ * 1. GET /api/thesis → all active theses
9
+ * 2. For each: GET /api/thesis/:id/context → edges with orderbook
10
+ * 3. Optional: getPositions() → Kalshi positions with live prices
11
+ * 4. Merge edges, dedupe by marketId (keep highest edge, note source thesis)
12
+ * 5. Sort by executableEdge descending
13
+ * 6. Display table with position overlay + summary
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.edgesCommand = edgesCommand;
17
+ const client_js_1 = require("../client.js");
18
+ const kalshi_js_1 = require("../kalshi.js");
19
+ const utils_js_1 = require("../utils.js");
20
+ async function edgesCommand(opts) {
21
+ const client = new client_js_1.SFClient(opts.apiKey, opts.apiUrl);
22
+ const limit = parseInt(opts.limit || '20');
23
+ // ── Step 1: Fetch all active theses ────────────────────────────────────────
24
+ console.log(`${utils_js_1.c.dim}Fetching theses...${utils_js_1.c.reset}`);
25
+ const data = await client.listTheses();
26
+ const rawTheses = data.theses || data;
27
+ const theses = (Array.isArray(rawTheses) ? rawTheses : []).filter((t) => t.status === 'active');
28
+ if (theses.length === 0) {
29
+ console.log(`${utils_js_1.c.yellow}No active theses found.${utils_js_1.c.reset} Create one: sf create "your thesis"`);
30
+ return;
31
+ }
32
+ // ── Step 2: Fetch context for each thesis (parallel) ───────────────────────
33
+ console.log(`${utils_js_1.c.dim}Fetching edges from ${theses.length} theses...${utils_js_1.c.reset}`);
34
+ const allEdges = [];
35
+ const contextPromises = theses.map(async (t) => {
36
+ try {
37
+ const ctx = await client.getContext(t.id);
38
+ return { thesisId: t.id, edges: ctx.edges || [] };
39
+ }
40
+ catch {
41
+ return { thesisId: t.id, edges: [] };
42
+ }
43
+ });
44
+ const results = await Promise.all(contextPromises);
45
+ for (const { thesisId, edges } of results) {
46
+ for (const e of edges) {
47
+ allEdges.push({
48
+ marketId: e.marketId || '',
49
+ market: e.market || e.marketTitle || e.marketId || '',
50
+ venue: e.venue || 'kalshi',
51
+ direction: e.direction || 'yes',
52
+ marketPrice: typeof e.marketPrice === 'number' ? e.marketPrice : 0,
53
+ thesisPrice: typeof e.thesisPrice === 'number' ? e.thesisPrice : 0,
54
+ edge: typeof e.edge === 'number' ? e.edge : 0,
55
+ executableEdge: typeof e.executableEdge === 'number' ? e.executableEdge : null,
56
+ spread: e.orderbook?.spread ?? null,
57
+ liquidityScore: e.orderbook?.liquidityScore ?? null,
58
+ thesisId,
59
+ position: null,
60
+ });
61
+ }
62
+ }
63
+ if (allEdges.length === 0) {
64
+ console.log(`${utils_js_1.c.yellow}No edges found across ${theses.length} theses.${utils_js_1.c.reset}`);
65
+ return;
66
+ }
67
+ // ── Step 3: Dedupe by marketId — keep highest absolute edge ────────────────
68
+ const deduped = new Map();
69
+ for (const edge of allEdges) {
70
+ const key = edge.marketId;
71
+ if (!key)
72
+ continue;
73
+ const existing = deduped.get(key);
74
+ if (!existing || Math.abs(edge.edge) > Math.abs(existing.edge)) {
75
+ deduped.set(key, edge);
76
+ }
77
+ }
78
+ let merged = Array.from(deduped.values());
79
+ // ── Step 4: Fetch positions (optional) ─────────────────────────────────────
80
+ let positions = null;
81
+ if ((0, kalshi_js_1.isKalshiConfigured)()) {
82
+ console.log(`${utils_js_1.c.dim}Fetching Kalshi positions...${utils_js_1.c.reset}`);
83
+ positions = await (0, kalshi_js_1.getPositions)();
84
+ if (positions) {
85
+ // Enrich with live prices
86
+ for (const pos of positions) {
87
+ const livePrice = await (0, kalshi_js_1.getMarketPrice)(pos.ticker);
88
+ if (livePrice !== null) {
89
+ pos.current_value = livePrice;
90
+ pos.unrealized_pnl = Math.round((livePrice - pos.average_price_paid) * pos.quantity);
91
+ }
92
+ }
93
+ // Match positions to edges
94
+ for (const edge of merged) {
95
+ const pos = positions.find(p => p.ticker === edge.marketId ||
96
+ (edge.marketId && p.ticker?.includes(edge.marketId)));
97
+ if (pos) {
98
+ edge.position = {
99
+ side: pos.side || 'yes',
100
+ quantity: pos.quantity,
101
+ avgPrice: pos.average_price_paid,
102
+ currentValue: pos.current_value,
103
+ pnl: pos.unrealized_pnl || 0,
104
+ totalCost: pos.total_cost || Math.round(pos.average_price_paid * pos.quantity),
105
+ };
106
+ }
107
+ }
108
+ }
109
+ }
110
+ // ── Step 5: Sort by executableEdge (or edge) descending ────────────────────
111
+ merged.sort((a, b) => {
112
+ const aVal = a.executableEdge !== null ? a.executableEdge : a.edge;
113
+ const bVal = b.executableEdge !== null ? b.executableEdge : b.edge;
114
+ return Math.abs(bVal) - Math.abs(aVal);
115
+ });
116
+ // Apply limit
117
+ const display = merged.slice(0, limit);
118
+ // ── Step 6: JSON output ────────────────────────────────────────────────────
119
+ if (opts.json) {
120
+ console.log(JSON.stringify({
121
+ totalEdges: merged.length,
122
+ displayed: display.length,
123
+ thesesScanned: theses.length,
124
+ edges: display,
125
+ }, null, 2));
126
+ return;
127
+ }
128
+ // ── Step 6: Pretty output ──────────────────────────────────────────────────
129
+ console.log();
130
+ (0, utils_js_1.header)(`Top Edges Across ${theses.length} Theses`);
131
+ console.log();
132
+ // Header row
133
+ const hdr = [
134
+ (0, utils_js_1.pad)('Market', 32),
135
+ (0, utils_js_1.rpad)('Mkt', 5),
136
+ (0, utils_js_1.rpad)('Thesis', 7),
137
+ (0, utils_js_1.rpad)('Edge', 6),
138
+ (0, utils_js_1.rpad)('Exec', 6),
139
+ (0, utils_js_1.rpad)('Sprd', 5),
140
+ (0, utils_js_1.pad)('Liq', 5),
141
+ (0, utils_js_1.pad)('Thesis', 10),
142
+ (0, utils_js_1.pad)('Position', 20),
143
+ ].join(' ');
144
+ console.log(`${utils_js_1.c.dim}${hdr}${utils_js_1.c.reset}`);
145
+ (0, utils_js_1.hr)(100);
146
+ for (const edge of display) {
147
+ const name = (0, utils_js_1.trunc)(edge.market, 31);
148
+ const mktStr = `${edge.marketPrice}¢`;
149
+ const thesisStr = `${edge.thesisPrice}¢`;
150
+ const edgeStr = edge.edge > 0 ? `+${edge.edge}` : `${edge.edge}`;
151
+ const execStr = edge.executableEdge !== null ? (edge.executableEdge > 0 ? `+${edge.executableEdge}` : `${edge.executableEdge}`) : '—';
152
+ const spreadStr = edge.spread !== null ? `${edge.spread}¢` : '—';
153
+ const liqStr = edge.liquidityScore || '—';
154
+ const thesisIdStr = (0, utils_js_1.shortId)(edge.thesisId);
155
+ // Color the edge values
156
+ const edgeColor = edge.edge > 0 ? utils_js_1.c.green : edge.edge < 0 ? utils_js_1.c.red : utils_js_1.c.dim;
157
+ const execColor = edge.executableEdge !== null ? (edge.executableEdge > 0 ? utils_js_1.c.green : utils_js_1.c.red) : utils_js_1.c.dim;
158
+ const liqColor = liqStr === 'high' ? utils_js_1.c.green : liqStr === 'medium' ? utils_js_1.c.yellow : utils_js_1.c.dim;
159
+ // Position string
160
+ let posStr = `${utils_js_1.c.dim}—${utils_js_1.c.reset}`;
161
+ if (edge.position) {
162
+ const p = edge.position;
163
+ const pnlStr = p.pnl >= 0 ? `${utils_js_1.c.green}+$${(p.pnl / 100).toFixed(0)}${utils_js_1.c.reset}` : `${utils_js_1.c.red}-$${(Math.abs(p.pnl) / 100).toFixed(0)}${utils_js_1.c.reset}`;
164
+ posStr = `${utils_js_1.c.green}${p.quantity}@${p.avgPrice}¢${utils_js_1.c.reset} ${pnlStr}`;
165
+ }
166
+ const row = [
167
+ edge.position ? `${utils_js_1.c.green}${(0, utils_js_1.pad)(name, 32)}${utils_js_1.c.reset}` : (0, utils_js_1.pad)(name, 32),
168
+ (0, utils_js_1.rpad)(mktStr, 5),
169
+ (0, utils_js_1.rpad)(thesisStr, 7),
170
+ `${edgeColor}${(0, utils_js_1.rpad)(edgeStr, 6)}${utils_js_1.c.reset}`,
171
+ `${execColor}${(0, utils_js_1.rpad)(execStr, 6)}${utils_js_1.c.reset}`,
172
+ (0, utils_js_1.rpad)(spreadStr, 5),
173
+ `${liqColor}${(0, utils_js_1.pad)(liqStr, 5)}${utils_js_1.c.reset}`,
174
+ `${utils_js_1.c.dim}${(0, utils_js_1.pad)(thesisIdStr, 10)}${utils_js_1.c.reset}`,
175
+ posStr,
176
+ ].join(' ');
177
+ console.log(row);
178
+ }
179
+ // ── Summary ────────────────────────────────────────────────────────────────
180
+ (0, utils_js_1.hr)(100);
181
+ // Positioned summary
182
+ const positioned = display.filter(e => e.position);
183
+ if (positioned.length > 0) {
184
+ let totalCost = 0;
185
+ let totalPnl = 0;
186
+ for (const e of positioned) {
187
+ totalCost += e.position.totalCost;
188
+ totalPnl += e.position.pnl;
189
+ }
190
+ const costStr = `$${(totalCost / 100).toFixed(0)}`;
191
+ const pnlColor = totalPnl >= 0 ? utils_js_1.c.green : utils_js_1.c.red;
192
+ const pnlSign = totalPnl >= 0 ? '+' : '-';
193
+ const pnlStr = `${pnlColor}${pnlSign}$${(Math.abs(totalPnl) / 100).toFixed(0)}${utils_js_1.c.reset}`;
194
+ console.log(`${utils_js_1.c.bold}Total positioned:${utils_js_1.c.reset} ${costStr} cost | P&L: ${pnlStr}`);
195
+ }
196
+ // Top unpositioned
197
+ const unpositioned = display.filter(e => !e.position && e.edge > 0);
198
+ if (unpositioned.length > 0) {
199
+ const top = unpositioned[0];
200
+ const execLabel = top.executableEdge !== null ? `exec +${top.executableEdge}` : `edge +${top.edge}`;
201
+ const liq = top.liquidityScore ? `, ${top.liquidityScore} liq` : '';
202
+ console.log(`${utils_js_1.c.bold}Top unpositioned:${utils_js_1.c.reset} ${(0, utils_js_1.trunc)(top.market, 30)} @ ${top.marketPrice}¢ (${execLabel}${liq})`);
203
+ }
204
+ console.log();
205
+ }
@@ -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
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * sf setup — Interactive configuration wizard
3
+ *
4
+ * Walks user through:
5
+ * 1. SF API key (required)
6
+ * 2. OpenRouter API key (optional, for agent)
7
+ * 3. Kalshi exchange credentials (optional, for positions)
8
+ * 4. Tavily API key (optional, for web search)
9
+ * 5. First thesis creation (if none exist)
10
+ *
11
+ * Each key is validated in real-time.
12
+ * Config is saved to ~/.sf/config.json.
13
+ */
14
+ interface SetupOpts {
15
+ check?: boolean;
16
+ reset?: boolean;
17
+ key?: string;
18
+ }
19
+ export declare function setupCommand(opts: SetupOpts): Promise<void>;
20
+ export {};