@spfunctions/cli 1.7.19 → 1.7.20
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/101.index.js +1 -0
- package/dist/12.index.js +1 -0
- package/dist/160.index.js +1 -0
- package/dist/174.index.js +1 -0
- package/dist/278.index.js +6 -0
- package/dist/582.index.js +1 -0
- package/dist/641.index.js +324 -0
- package/dist/669.index.js +1 -0
- package/dist/722.index.js +1 -0
- package/dist/788.index.js +1 -0
- package/dist/816.index.js +12 -0
- package/dist/830.index.js +1 -0
- package/dist/921.index.js +1 -0
- package/dist/index.js +1 -833
- package/package.json +5 -2
- package/dist/cache.d.ts +0 -6
- package/dist/cache.js +0 -31
- package/dist/cache.test.d.ts +0 -1
- package/dist/cache.test.js +0 -73
- package/dist/client.d.ts +0 -56
- package/dist/client.js +0 -205
- package/dist/client.test.d.ts +0 -1
- package/dist/client.test.js +0 -89
- package/dist/commands/agent.d.ts +0 -20
- package/dist/commands/agent.js +0 -4119
- package/dist/commands/announcements.d.ts +0 -3
- package/dist/commands/announcements.js +0 -28
- package/dist/commands/augment.d.ts +0 -12
- package/dist/commands/augment.js +0 -56
- package/dist/commands/balance.d.ts +0 -3
- package/dist/commands/balance.js +0 -17
- package/dist/commands/book.d.ts +0 -17
- package/dist/commands/book.js +0 -220
- package/dist/commands/cancel.d.ts +0 -5
- package/dist/commands/cancel.js +0 -41
- package/dist/commands/context.d.ts +0 -6
- package/dist/commands/context.js +0 -208
- package/dist/commands/create.d.ts +0 -7
- package/dist/commands/create.js +0 -42
- package/dist/commands/dashboard.d.ts +0 -14
- package/dist/commands/dashboard.js +0 -215
- package/dist/commands/delta.d.ts +0 -16
- package/dist/commands/delta.js +0 -115
- package/dist/commands/edges.d.ts +0 -26
- package/dist/commands/edges.js +0 -246
- package/dist/commands/evaluate.d.ts +0 -4
- package/dist/commands/evaluate.js +0 -30
- package/dist/commands/explore.d.ts +0 -14
- package/dist/commands/explore.js +0 -116
- package/dist/commands/feed.d.ts +0 -13
- package/dist/commands/feed.js +0 -73
- package/dist/commands/fills.d.ts +0 -4
- package/dist/commands/fills.js +0 -29
- package/dist/commands/forecast.d.ts +0 -4
- package/dist/commands/forecast.js +0 -53
- package/dist/commands/get.d.ts +0 -5
- package/dist/commands/get.js +0 -98
- package/dist/commands/heartbeat.d.ts +0 -20
- package/dist/commands/heartbeat.js +0 -73
- package/dist/commands/history.d.ts +0 -3
- package/dist/commands/history.js +0 -38
- package/dist/commands/liquidity.d.ts +0 -14
- package/dist/commands/liquidity.js +0 -378
- package/dist/commands/list.d.ts +0 -5
- package/dist/commands/list.js +0 -38
- package/dist/commands/login.d.ts +0 -10
- package/dist/commands/login.js +0 -98
- package/dist/commands/markets.d.ts +0 -10
- package/dist/commands/markets.js +0 -39
- package/dist/commands/milestones.d.ts +0 -8
- package/dist/commands/milestones.js +0 -56
- package/dist/commands/orders.d.ts +0 -4
- package/dist/commands/orders.js +0 -28
- package/dist/commands/performance.d.ts +0 -11
- package/dist/commands/performance.js +0 -250
- package/dist/commands/positions.d.ts +0 -19
- package/dist/commands/positions.js +0 -294
- package/dist/commands/prompt.d.ts +0 -13
- package/dist/commands/prompt.js +0 -35
- package/dist/commands/publish.d.ts +0 -15
- package/dist/commands/publish.js +0 -39
- package/dist/commands/query.d.ts +0 -15
- package/dist/commands/query.js +0 -132
- package/dist/commands/rfq.d.ts +0 -5
- package/dist/commands/rfq.js +0 -35
- package/dist/commands/scan.d.ts +0 -11
- package/dist/commands/scan.js +0 -230
- package/dist/commands/schedule.d.ts +0 -3
- package/dist/commands/schedule.js +0 -38
- package/dist/commands/settlements.d.ts +0 -6
- package/dist/commands/settlements.js +0 -50
- package/dist/commands/setup.d.ts +0 -24
- package/dist/commands/setup.js +0 -700
- package/dist/commands/signal.d.ts +0 -6
- package/dist/commands/signal.js +0 -32
- package/dist/commands/strategies.d.ts +0 -11
- package/dist/commands/strategies.js +0 -130
- package/dist/commands/telegram.d.ts +0 -15
- package/dist/commands/telegram.js +0 -125
- package/dist/commands/trade.d.ts +0 -12
- package/dist/commands/trade.js +0 -112
- package/dist/commands/watch.d.ts +0 -19
- package/dist/commands/watch.js +0 -157
- package/dist/commands/whatif.d.ts +0 -17
- package/dist/commands/whatif.js +0 -209
- package/dist/commands/x.d.ts +0 -28
- package/dist/commands/x.js +0 -167
- package/dist/config.d.ts +0 -55
- package/dist/config.js +0 -139
- package/dist/config.test.d.ts +0 -1
- package/dist/config.test.js +0 -138
- package/dist/index.d.ts +0 -20
- package/dist/kalshi.d.ts +0 -144
- package/dist/kalshi.js +0 -498
- package/dist/polymarket.d.ts +0 -237
- package/dist/polymarket.js +0 -353
- package/dist/polymarket.test.d.ts +0 -1
- package/dist/polymarket.test.js +0 -424
- package/dist/share.d.ts +0 -4
- package/dist/share.js +0 -27
- package/dist/skills/loader.d.ts +0 -19
- package/dist/skills/loader.js +0 -86
- package/dist/telegram/agent-bridge.d.ts +0 -15
- package/dist/telegram/agent-bridge.js +0 -573
- package/dist/telegram/bot.d.ts +0 -10
- package/dist/telegram/bot.js +0 -297
- package/dist/telegram/commands.d.ts +0 -11
- package/dist/telegram/commands.js +0 -120
- package/dist/telegram/format.d.ts +0 -11
- package/dist/telegram/format.js +0 -51
- package/dist/telegram/format.test.d.ts +0 -1
- package/dist/telegram/format.test.js +0 -73
- package/dist/telegram/poller.d.ts +0 -6
- package/dist/telegram/poller.js +0 -32
- package/dist/topics.d.ts +0 -17
- package/dist/topics.js +0 -102
- package/dist/topics.test.d.ts +0 -1
- package/dist/topics.test.js +0 -131
- package/dist/tui/border.d.ts +0 -33
- package/dist/tui/border.js +0 -87
- package/dist/tui/chart.d.ts +0 -19
- package/dist/tui/chart.js +0 -117
- package/dist/tui/dashboard.d.ts +0 -9
- package/dist/tui/dashboard.js +0 -814
- package/dist/tui/layout.d.ts +0 -16
- package/dist/tui/layout.js +0 -41
- package/dist/tui/screen.d.ts +0 -33
- package/dist/tui/screen.js +0 -102
- package/dist/tui/state.d.ts +0 -40
- package/dist/tui/state.js +0 -36
- package/dist/tui/widgets/commandbar.d.ts +0 -8
- package/dist/tui/widgets/commandbar.js +0 -82
- package/dist/tui/widgets/detail.d.ts +0 -9
- package/dist/tui/widgets/detail.js +0 -151
- package/dist/tui/widgets/edges.d.ts +0 -4
- package/dist/tui/widgets/edges.js +0 -34
- package/dist/tui/widgets/liquidity.d.ts +0 -9
- package/dist/tui/widgets/liquidity.js +0 -142
- package/dist/tui/widgets/orders.d.ts +0 -4
- package/dist/tui/widgets/orders.js +0 -37
- package/dist/tui/widgets/portfolio.d.ts +0 -4
- package/dist/tui/widgets/portfolio.js +0 -59
- package/dist/tui/widgets/signals.d.ts +0 -4
- package/dist/tui/widgets/signals.js +0 -31
- package/dist/tui/widgets/statusbar.d.ts +0 -8
- package/dist/tui/widgets/statusbar.js +0 -72
- package/dist/tui/widgets/thesis.d.ts +0 -4
- package/dist/tui/widgets/thesis.js +0 -66
- package/dist/tui/widgets/trade.d.ts +0 -9
- package/dist/tui/widgets/trade.js +0 -117
- package/dist/tui/widgets/upcoming.d.ts +0 -4
- package/dist/tui/widgets/upcoming.js +0 -41
- package/dist/tui/widgets/whatif.d.ts +0 -7
- package/dist/tui/widgets/whatif.js +0 -113
- package/dist/types/output.d.ts +0 -412
- package/dist/types/output.js +0 -9
- package/dist/utils.d.ts +0 -52
- package/dist/utils.js +0 -146
- package/dist/utils.test.d.ts +0 -1
- package/dist/utils.test.js +0 -111
package/dist/commands/whatif.js
DELETED
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* sf whatif — What-if scenario analysis.
|
|
4
|
-
*
|
|
5
|
-
* Pure computation, zero LLM cost. Answers:
|
|
6
|
-
* "If node X drops to 10%, what happens to my edges and positions?"
|
|
7
|
-
*
|
|
8
|
-
* Usage:
|
|
9
|
-
* sf whatif f582bf76 --set "n1=0.1"
|
|
10
|
-
* sf whatif f582bf76 --set "n1=0.1" --set "n3.1=0.2"
|
|
11
|
-
* sf whatif f582bf76 --set "n1=0.1" --json
|
|
12
|
-
*/
|
|
13
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.whatifCommand = whatifCommand;
|
|
15
|
-
const client_js_1 = require("../client.js");
|
|
16
|
-
const kalshi_js_1 = require("../kalshi.js");
|
|
17
|
-
const utils_js_1 = require("../utils.js");
|
|
18
|
-
// Inline what-if simulation (mirrors server-side logic, zero dependency)
|
|
19
|
-
function simulateWhatIf(ctx, overrides) {
|
|
20
|
-
const allNodes = [];
|
|
21
|
-
function flatten(nodes) {
|
|
22
|
-
for (const n of nodes) {
|
|
23
|
-
allNodes.push(n);
|
|
24
|
-
if (n.children?.length)
|
|
25
|
-
flatten(n.children);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
const rawNodes = ctx.causalTree?.nodes || [];
|
|
29
|
-
flatten(rawNodes);
|
|
30
|
-
// Top-level nodes only (depth=0 or no depth field + no dot in id)
|
|
31
|
-
const treeNodes = rawNodes.filter((n) => n.depth === 0 || (n.depth === undefined && !n.id.includes('.')));
|
|
32
|
-
const overrideMap = new Map(overrides.map(o => [o.nodeId, o.newProbability]));
|
|
33
|
-
const overrideDetails = overrides.map(o => {
|
|
34
|
-
const node = allNodes.find((n) => n.id === o.nodeId);
|
|
35
|
-
return {
|
|
36
|
-
nodeId: o.nodeId,
|
|
37
|
-
oldProb: node?.probability ?? 0,
|
|
38
|
-
newProb: o.newProbability,
|
|
39
|
-
label: node?.label || o.nodeId,
|
|
40
|
-
};
|
|
41
|
-
});
|
|
42
|
-
// Confidence (only top-level nodes)
|
|
43
|
-
const oldConf = treeNodes.reduce((s, n) => s + (n.probability || 0) * (n.importance || 0), 0);
|
|
44
|
-
const newConf = treeNodes.reduce((s, n) => {
|
|
45
|
-
const p = overrideMap.get(n.id) ?? n.probability ?? 0;
|
|
46
|
-
return s + p * (n.importance || 0);
|
|
47
|
-
}, 0);
|
|
48
|
-
// Per-node override ratios — only scale edges directly related to overridden nodes.
|
|
49
|
-
// No global scale: edges unrelated to any override stay unchanged.
|
|
50
|
-
// User must explicitly override each node they think is affected.
|
|
51
|
-
const nodeScales = new Map();
|
|
52
|
-
for (const [nodeId, newProb] of overrideMap.entries()) {
|
|
53
|
-
const node = allNodes.find((n) => n.id === nodeId);
|
|
54
|
-
if (node && node.probability > 0) {
|
|
55
|
-
nodeScales.set(nodeId, Math.max(0, Math.min(2, newProb / node.probability)));
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
// Edges
|
|
59
|
-
const edges = (ctx.edges || []).map((edge) => {
|
|
60
|
-
const relNode = edge.relatedNodeId;
|
|
61
|
-
let scaleFactor = 1; // default: no change
|
|
62
|
-
// Only scale if edge's related node (or its ancestor) was overridden
|
|
63
|
-
if (relNode) {
|
|
64
|
-
const candidates = [relNode, relNode.split('.').slice(0, -1).join('.'), relNode.split('.')[0]].filter(Boolean);
|
|
65
|
-
for (const cid of candidates) {
|
|
66
|
-
if (nodeScales.has(cid)) {
|
|
67
|
-
scaleFactor = nodeScales.get(cid);
|
|
68
|
-
break;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
const mkt = edge.marketPrice || 0;
|
|
73
|
-
const oldTP = edge.thesisPrice || edge.thesisImpliedPrice || mkt;
|
|
74
|
-
const oldEdge = edge.edge || edge.edgeSize || 0;
|
|
75
|
-
const premium = oldTP - mkt;
|
|
76
|
-
const newTP = Math.round((mkt + premium * scaleFactor) * 100) / 100;
|
|
77
|
-
const dir = edge.direction || 'yes';
|
|
78
|
-
const newEdge = Math.round((dir === 'yes' ? newTP - mkt : mkt - newTP) * 100) / 100;
|
|
79
|
-
const delta = Math.round((newEdge - oldEdge) * 100) / 100;
|
|
80
|
-
let signal = 'unchanged';
|
|
81
|
-
if (Math.abs(delta) < 1)
|
|
82
|
-
signal = 'unchanged';
|
|
83
|
-
else if ((oldEdge > 0 && newEdge < 0) || (oldEdge < 0 && newEdge > 0))
|
|
84
|
-
signal = 'reversed';
|
|
85
|
-
else if (Math.abs(newEdge) < 2)
|
|
86
|
-
signal = 'gone';
|
|
87
|
-
else if (Math.abs(newEdge) < Math.abs(oldEdge))
|
|
88
|
-
signal = 'reduced';
|
|
89
|
-
return {
|
|
90
|
-
marketId: edge.marketId,
|
|
91
|
-
market: edge.market || edge.marketTitle || edge.marketId,
|
|
92
|
-
venue: edge.venue,
|
|
93
|
-
direction: dir,
|
|
94
|
-
marketPrice: mkt,
|
|
95
|
-
oldThesisPrice: oldTP,
|
|
96
|
-
newThesisPrice: newTP,
|
|
97
|
-
oldEdge,
|
|
98
|
-
newEdge,
|
|
99
|
-
delta,
|
|
100
|
-
signal,
|
|
101
|
-
relatedNodeId: relNode,
|
|
102
|
-
};
|
|
103
|
-
});
|
|
104
|
-
edges.sort((a, b) => Math.abs(b.delta) - Math.abs(a.delta));
|
|
105
|
-
return {
|
|
106
|
-
overrides: overrideDetails,
|
|
107
|
-
oldConfidence: oldConf,
|
|
108
|
-
newConfidence: newConf,
|
|
109
|
-
confidenceDelta: Math.round((newConf - oldConf) * 100) / 100,
|
|
110
|
-
edges,
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
async function whatifCommand(thesisId, opts) {
|
|
114
|
-
if (!opts.set || opts.set.length === 0) {
|
|
115
|
-
throw new Error('Usage: sf whatif <thesisId> --set "n1=0.1" [--set "n3=0.5"]');
|
|
116
|
-
}
|
|
117
|
-
// Parse overrides
|
|
118
|
-
const overrides = opts.set.map(s => {
|
|
119
|
-
const [nodeId, valStr] = s.split('=');
|
|
120
|
-
if (!nodeId || !valStr)
|
|
121
|
-
throw new Error(`Invalid override: "${s}". Format: nodeId=probability`);
|
|
122
|
-
const prob = parseFloat(valStr);
|
|
123
|
-
if (isNaN(prob) || prob < 0 || prob > 1)
|
|
124
|
-
throw new Error(`Invalid probability: "${valStr}". Must be 0-1.`);
|
|
125
|
-
return { nodeId: nodeId.trim(), newProbability: prob };
|
|
126
|
-
});
|
|
127
|
-
const client = new client_js_1.SFClient(opts.apiKey, opts.apiUrl);
|
|
128
|
-
const ctx = await client.getContext(thesisId);
|
|
129
|
-
const result = simulateWhatIf(ctx, overrides);
|
|
130
|
-
if (opts.json) {
|
|
131
|
-
console.log(JSON.stringify(result, null, 2));
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
// Render
|
|
135
|
-
console.log();
|
|
136
|
-
console.log(`${utils_js_1.c.bold}${utils_js_1.c.cyan}WHAT-IF Scenario${utils_js_1.c.reset}`);
|
|
137
|
-
console.log(`${utils_js_1.c.dim}${'─'.repeat(65)}${utils_js_1.c.reset}`);
|
|
138
|
-
// Overrides
|
|
139
|
-
for (const o of result.overrides) {
|
|
140
|
-
const oldPct = Math.round(o.oldProb * 100);
|
|
141
|
-
const newPct = Math.round(o.newProb * 100);
|
|
142
|
-
const arrow = newPct > oldPct ? utils_js_1.c.green + '↑' + utils_js_1.c.reset : utils_js_1.c.red + '↓' + utils_js_1.c.reset;
|
|
143
|
-
console.log(` ${utils_js_1.c.cyan}${o.nodeId}${utils_js_1.c.reset} ${o.label.slice(0, 40)}`);
|
|
144
|
-
console.log(` ${oldPct}% ${arrow} ${utils_js_1.c.bold}${newPct}%${utils_js_1.c.reset}`);
|
|
145
|
-
}
|
|
146
|
-
// Confidence
|
|
147
|
-
const oldPct = Math.round(result.oldConfidence * 100);
|
|
148
|
-
const newPct = Math.round(result.newConfidence * 100);
|
|
149
|
-
const deltaSign = result.confidenceDelta > 0 ? '+' : '';
|
|
150
|
-
const confColor = result.confidenceDelta >= 0 ? utils_js_1.c.green : utils_js_1.c.red;
|
|
151
|
-
console.log();
|
|
152
|
-
console.log(` Confidence: ${oldPct}% → ${confColor}${utils_js_1.c.bold}${newPct}%${utils_js_1.c.reset} (${confColor}${deltaSign}${Math.round(result.confidenceDelta * 100)}${utils_js_1.c.reset})`);
|
|
153
|
-
console.log();
|
|
154
|
-
// Edges
|
|
155
|
-
const affected = result.edges.filter((e) => e.signal !== 'unchanged');
|
|
156
|
-
if (affected.length === 0) {
|
|
157
|
-
console.log(` ${utils_js_1.c.dim}No edges affected.${utils_js_1.c.reset}`);
|
|
158
|
-
}
|
|
159
|
-
else {
|
|
160
|
-
console.log(` ${utils_js_1.c.bold}Edges Affected${utils_js_1.c.reset}`);
|
|
161
|
-
console.log(` ${'Market'.padEnd(35)} ${'Now'.padEnd(6)} ${'Edge'.padEnd(8)} ${'→'.padEnd(3)} ${'New Edge'.padEnd(8)} Signal`);
|
|
162
|
-
console.log(` ${utils_js_1.c.dim}${'─'.repeat(65)}${utils_js_1.c.reset}`);
|
|
163
|
-
for (const e of affected) {
|
|
164
|
-
const name = (e.market || e.marketId).slice(0, 33).padEnd(35);
|
|
165
|
-
const mkt = `${Math.round(e.marketPrice)}¢`.padEnd(6);
|
|
166
|
-
const oldE = `${e.oldEdge > 0 ? '+' : ''}${Math.round(e.oldEdge)}`.padEnd(8);
|
|
167
|
-
const newE = `${e.newEdge > 0 ? '+' : ''}${Math.round(e.newEdge)}`.padEnd(8);
|
|
168
|
-
let signalStr;
|
|
169
|
-
switch (e.signal) {
|
|
170
|
-
case 'reversed':
|
|
171
|
-
signalStr = `${utils_js_1.c.red}${utils_js_1.c.bold}REVERSED${utils_js_1.c.reset}`;
|
|
172
|
-
break;
|
|
173
|
-
case 'gone':
|
|
174
|
-
signalStr = `${utils_js_1.c.red}GONE${utils_js_1.c.reset}`;
|
|
175
|
-
break;
|
|
176
|
-
case 'reduced':
|
|
177
|
-
signalStr = `${utils_js_1.c.dim}reduced${utils_js_1.c.reset}`;
|
|
178
|
-
break;
|
|
179
|
-
default: signalStr = `${utils_js_1.c.dim}-${utils_js_1.c.reset}`;
|
|
180
|
-
}
|
|
181
|
-
console.log(` ${utils_js_1.c.dim}${name}${utils_js_1.c.reset} ${mkt} ${oldE} → ${newE} ${signalStr}`);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
// Position risk (if positions available)
|
|
185
|
-
try {
|
|
186
|
-
const positions = await (0, kalshi_js_1.getPositions)();
|
|
187
|
-
if (positions && positions.length > 0) {
|
|
188
|
-
const edgeMap = new Map(result.edges.map((e) => [e.marketId, e]));
|
|
189
|
-
const atRisk = positions.filter((p) => {
|
|
190
|
-
const e = edgeMap.get(p.ticker);
|
|
191
|
-
return e && (e.signal === 'reversed' || e.signal === 'gone');
|
|
192
|
-
});
|
|
193
|
-
if (atRisk.length > 0) {
|
|
194
|
-
console.log();
|
|
195
|
-
console.log(` ${utils_js_1.c.red}${utils_js_1.c.bold}⚠ Positions at Risk${utils_js_1.c.reset}`);
|
|
196
|
-
for (const p of atRisk) {
|
|
197
|
-
const e = edgeMap.get(p.ticker);
|
|
198
|
-
const livePrice = await (0, kalshi_js_1.getMarketPrice)(p.ticker);
|
|
199
|
-
const currentPnl = livePrice !== null
|
|
200
|
-
? ((livePrice - p.average_price_paid) * p.quantity / 100).toFixed(2)
|
|
201
|
-
: '?';
|
|
202
|
-
console.log(` ${utils_js_1.c.red}${p.ticker}${utils_js_1.c.reset} ${p.quantity} ${p.side} P&L $${currentPnl} edge ${e.oldEdge > 0 ? '+' : ''}${Math.round(e.oldEdge)} → ${utils_js_1.c.red}${e.newEdge > 0 ? '+' : ''}${Math.round(e.newEdge)}${utils_js_1.c.reset}`);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
catch { /* positions not available, skip */ }
|
|
208
|
-
console.log();
|
|
209
|
-
}
|
package/dist/commands/x.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* sf x "query" — Search X discussions
|
|
3
|
-
* sf x-volume "query" — Discussion volume trend
|
|
4
|
-
* sf x-news "query" — X news stories
|
|
5
|
-
* sf x-account @user — Track account posts
|
|
6
|
-
*
|
|
7
|
-
* All use authenticated /api/x/* endpoints via SFClient.
|
|
8
|
-
*/
|
|
9
|
-
export declare function xSearchCommand(query: string, opts?: {
|
|
10
|
-
json?: boolean;
|
|
11
|
-
raw?: boolean;
|
|
12
|
-
hours?: string;
|
|
13
|
-
limit?: string;
|
|
14
|
-
}): Promise<void>;
|
|
15
|
-
export declare function xVolumeCommand(query: string, opts?: {
|
|
16
|
-
json?: boolean;
|
|
17
|
-
hours?: string;
|
|
18
|
-
granularity?: string;
|
|
19
|
-
}): Promise<void>;
|
|
20
|
-
export declare function xNewsCommand(query: string, opts?: {
|
|
21
|
-
json?: boolean;
|
|
22
|
-
limit?: string;
|
|
23
|
-
}): Promise<void>;
|
|
24
|
-
export declare function xAccountCommand(username: string, opts?: {
|
|
25
|
-
json?: boolean;
|
|
26
|
-
hours?: string;
|
|
27
|
-
limit?: string;
|
|
28
|
-
}): Promise<void>;
|
package/dist/commands/x.js
DELETED
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* sf x "query" — Search X discussions
|
|
4
|
-
* sf x-volume "query" — Discussion volume trend
|
|
5
|
-
* sf x-news "query" — X news stories
|
|
6
|
-
* sf x-account @user — Track account posts
|
|
7
|
-
*
|
|
8
|
-
* All use authenticated /api/x/* endpoints via SFClient.
|
|
9
|
-
*/
|
|
10
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
exports.xSearchCommand = xSearchCommand;
|
|
12
|
-
exports.xVolumeCommand = xVolumeCommand;
|
|
13
|
-
exports.xNewsCommand = xNewsCommand;
|
|
14
|
-
exports.xAccountCommand = xAccountCommand;
|
|
15
|
-
const BASE_URL = process.env.SF_API_URL || 'https://simplefunctions.dev';
|
|
16
|
-
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
17
|
-
function getApiKey() {
|
|
18
|
-
const key = process.env.SF_API_KEY || '';
|
|
19
|
-
if (!key) {
|
|
20
|
-
console.error(' API key required. Run: sf setup');
|
|
21
|
-
process.exit(1);
|
|
22
|
-
}
|
|
23
|
-
return key;
|
|
24
|
-
}
|
|
25
|
-
async function apiFetch(path) {
|
|
26
|
-
const res = await fetch(`${BASE_URL}${path}`, {
|
|
27
|
-
headers: { 'Authorization': `Bearer ${getApiKey()}` },
|
|
28
|
-
});
|
|
29
|
-
if (!res.ok) {
|
|
30
|
-
const text = await res.text();
|
|
31
|
-
throw new Error(`${res.status}: ${text}`);
|
|
32
|
-
}
|
|
33
|
-
return res.json();
|
|
34
|
-
}
|
|
35
|
-
// ── sf x "query" ─────────────────────────────────────────────────────────────
|
|
36
|
-
async function xSearchCommand(query, opts) {
|
|
37
|
-
const mode = opts?.raw ? 'raw' : 'summary';
|
|
38
|
-
const hours = opts?.hours || '24';
|
|
39
|
-
const limit = opts?.limit || '20';
|
|
40
|
-
const data = await apiFetch(`/api/x/search?q=${encodeURIComponent(query)}&mode=${mode}&hours=${hours}&limit=${limit}`);
|
|
41
|
-
if (opts?.json) {
|
|
42
|
-
console.log(JSON.stringify(data, null, 2));
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
// Summary
|
|
46
|
-
if (data.summary) {
|
|
47
|
-
console.log(`\n \x1b[1m\x1b[36mX: ${query}\x1b[0m\n`);
|
|
48
|
-
console.log(` ${data.summary}\n`);
|
|
49
|
-
if (data.sentiment) {
|
|
50
|
-
const colors = { bullish: '\x1b[32m', bearish: '\x1b[31m', mixed: '\x1b[33m', neutral: '\x1b[2m' };
|
|
51
|
-
console.log(` Sentiment: ${colors[data.sentiment] || ''}${data.sentiment}\x1b[0m`);
|
|
52
|
-
}
|
|
53
|
-
if (data.keyThemes?.length) {
|
|
54
|
-
console.log(` Themes: ${data.keyThemes.join(', ')}`);
|
|
55
|
-
}
|
|
56
|
-
console.log();
|
|
57
|
-
}
|
|
58
|
-
// Posts
|
|
59
|
-
const posts = data.posts || [];
|
|
60
|
-
if (posts.length > 0) {
|
|
61
|
-
console.log(` \x1b[1mTop posts\x1b[22m (${posts.length})\n`);
|
|
62
|
-
for (const p of posts.slice(0, 10)) {
|
|
63
|
-
const likes = p.metrics?.likes || 0;
|
|
64
|
-
const rt = p.metrics?.retweets || 0;
|
|
65
|
-
const followers = p.authorFollowers ? ` (${formatNum(p.authorFollowers)})` : '';
|
|
66
|
-
console.log(` \x1b[36m@${p.authorUsername}\x1b[0m${followers}`);
|
|
67
|
-
console.log(` ${p.text.slice(0, 140)}${p.text.length > 140 ? '...' : ''}`);
|
|
68
|
-
console.log(` \x1b[2m♥ ${likes} ↻ ${rt}\x1b[0m\n`);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
// Volume
|
|
72
|
-
if (data.volume) {
|
|
73
|
-
const v = data.volume;
|
|
74
|
-
const vel = v.velocityChange > 1
|
|
75
|
-
? `\x1b[32m+${Math.round((v.velocityChange - 1) * 100)}%\x1b[0m`
|
|
76
|
-
: `\x1b[31m${Math.round((v.velocityChange - 1) * 100)}%\x1b[0m`;
|
|
77
|
-
console.log(` \x1b[2mVolume: ${formatNum(v.totalCount)} posts (${hours}h) | Velocity: ${vel} | Peak: ${v.peak?.count}\x1b[0m\n`);
|
|
78
|
-
}
|
|
79
|
-
// News
|
|
80
|
-
const news = data.news || [];
|
|
81
|
-
if (news.length > 0) {
|
|
82
|
-
console.log(` \x1b[1mX News\x1b[22m (${news.length})\n`);
|
|
83
|
-
for (const n of news.slice(0, 5)) {
|
|
84
|
-
const tickers = n.tickers?.length ? ` \x1b[33m${n.tickers.join(' ')}\x1b[0m` : '';
|
|
85
|
-
console.log(` ${n.title}${tickers}`);
|
|
86
|
-
console.log(` \x1b[2m${n.summary.slice(0, 120)}...\x1b[0m\n`);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
// ── sf x-volume "query" ──────────────────────────────────────────────────────
|
|
91
|
-
async function xVolumeCommand(query, opts) {
|
|
92
|
-
const hours = opts?.hours || '72';
|
|
93
|
-
const granularity = opts?.granularity || 'hour';
|
|
94
|
-
const data = await apiFetch(`/api/x/volume?q=${encodeURIComponent(query)}&hours=${hours}&granularity=${granularity}`);
|
|
95
|
-
if (opts?.json) {
|
|
96
|
-
console.log(JSON.stringify(data, null, 2));
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
console.log(`\n \x1b[1m\x1b[36mX Volume: ${query}\x1b[0m\n`);
|
|
100
|
-
console.log(` Total: ${formatNum(data.totalCount)} posts (${hours}h)`);
|
|
101
|
-
const vel = data.velocityChange > 1
|
|
102
|
-
? `\x1b[32m+${Math.round((data.velocityChange - 1) * 100)}%\x1b[0m`
|
|
103
|
-
: `\x1b[31m${Math.round((data.velocityChange - 1) * 100)}%\x1b[0m`;
|
|
104
|
-
console.log(` Velocity: ${vel}`);
|
|
105
|
-
console.log(` Peak: ${data.peak?.count} at ${data.peak?.time?.slice(11, 16) || '?'}\n`);
|
|
106
|
-
// Histogram
|
|
107
|
-
const ts = data.timeseries || [];
|
|
108
|
-
if (ts.length > 0) {
|
|
109
|
-
const maxCount = Math.max(...ts.map((b) => b.count));
|
|
110
|
-
const barWidth = 40;
|
|
111
|
-
for (const b of ts.slice(-24)) {
|
|
112
|
-
const t = (b.time || '').slice(11, 16) || '?';
|
|
113
|
-
const w = maxCount > 0 ? Math.round((b.count / maxCount) * barWidth) : 0;
|
|
114
|
-
const bar = '▓'.repeat(w);
|
|
115
|
-
const count = String(b.count).padStart(6);
|
|
116
|
-
console.log(` ${t} ${count} ${bar}`);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
console.log();
|
|
120
|
-
}
|
|
121
|
-
// ── sf x-news "query" ────────────────────────────────────────────────────────
|
|
122
|
-
async function xNewsCommand(query, opts) {
|
|
123
|
-
const limit = opts?.limit || '10';
|
|
124
|
-
const data = await apiFetch(`/api/x/news?q=${encodeURIComponent(query)}&limit=${limit}`);
|
|
125
|
-
if (opts?.json) {
|
|
126
|
-
console.log(JSON.stringify(data, null, 2));
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
const stories = data.stories || [];
|
|
130
|
-
console.log(`\n \x1b[1m\x1b[36mX News: ${query}\x1b[0m (${stories.length} stories)\n`);
|
|
131
|
-
for (const s of stories) {
|
|
132
|
-
const tickers = s.tickers?.length ? ` \x1b[33m${s.tickers.join(' ')}\x1b[0m` : '';
|
|
133
|
-
const cats = s.categories?.length ? `\x1b[2m[${s.categories.join(', ')}]\x1b[0m` : '';
|
|
134
|
-
console.log(` \x1b[1m${s.title}\x1b[22m${tickers} ${cats}`);
|
|
135
|
-
console.log(` ${s.summary.slice(0, 200)}${s.summary.length > 200 ? '...' : ''}`);
|
|
136
|
-
console.log();
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
// ── sf x-account @username ───────────────────────────────────────────────────
|
|
140
|
-
async function xAccountCommand(username, opts) {
|
|
141
|
-
// Strip @ if present
|
|
142
|
-
const user = username.replace(/^@/, '');
|
|
143
|
-
const hours = opts?.hours || '24';
|
|
144
|
-
const limit = opts?.limit || '20';
|
|
145
|
-
const data = await apiFetch(`/api/x/account?username=${user}&hours=${hours}&limit=${limit}`);
|
|
146
|
-
if (opts?.json) {
|
|
147
|
-
console.log(JSON.stringify(data, null, 2));
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
const posts = data.posts || [];
|
|
151
|
-
console.log(`\n \x1b[1m\x1b[36m@${user}\x1b[0m (${posts.length} posts, last ${hours}h)\n`);
|
|
152
|
-
for (const p of posts) {
|
|
153
|
-
const likes = p.metrics?.likes || 0;
|
|
154
|
-
const rt = p.metrics?.retweets || 0;
|
|
155
|
-
const time = p.createdAt?.slice(11, 16) || '';
|
|
156
|
-
console.log(` \x1b[2m${time}\x1b[0m ${p.text.slice(0, 140)}${p.text.length > 140 ? '...' : ''}`);
|
|
157
|
-
console.log(` \x1b[2m♥ ${likes} ↻ ${rt}\x1b[0m\n`);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
// ── Util ─────────────────────────────────────────────────────────────────────
|
|
161
|
-
function formatNum(n) {
|
|
162
|
-
if (n >= 1_000_000)
|
|
163
|
-
return `${(n / 1_000_000).toFixed(1)}M`;
|
|
164
|
-
if (n >= 1_000)
|
|
165
|
-
return `${(n / 1_000).toFixed(1)}K`;
|
|
166
|
-
return String(n);
|
|
167
|
-
}
|
package/dist/config.d.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CLI Configuration — ~/.sf/config.json
|
|
3
|
-
*
|
|
4
|
-
* Priority: env vars > config file > defaults
|
|
5
|
-
*
|
|
6
|
-
* After `sf setup`, all keys are stored in config.json.
|
|
7
|
-
* `applyConfig()` sets process.env from config so all existing code
|
|
8
|
-
* (client.ts, kalshi.ts, agent.ts) keeps working without changes.
|
|
9
|
-
*/
|
|
10
|
-
export interface SFConfig {
|
|
11
|
-
apiKey?: string;
|
|
12
|
-
apiUrl?: string;
|
|
13
|
-
openrouterKey?: string;
|
|
14
|
-
kalshiKeyId?: string;
|
|
15
|
-
kalshiPrivateKeyPath?: string;
|
|
16
|
-
polymarketWalletAddress?: string;
|
|
17
|
-
polymarketPrivateKeyPath?: string;
|
|
18
|
-
tavilyKey?: string;
|
|
19
|
-
model?: string;
|
|
20
|
-
tradingEnabled?: boolean;
|
|
21
|
-
telegramBotToken?: string;
|
|
22
|
-
configuredAt?: string;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Load config from file. Does NOT apply env overrides — use resolveConfig() for that.
|
|
26
|
-
*/
|
|
27
|
-
export declare function loadFileConfig(): SFConfig;
|
|
28
|
-
/**
|
|
29
|
-
* Resolve final config: env vars > config file > defaults.
|
|
30
|
-
*/
|
|
31
|
-
export declare function loadConfig(): SFConfig;
|
|
32
|
-
/**
|
|
33
|
-
* Save config to ~/.sf/config.json.
|
|
34
|
-
*/
|
|
35
|
-
export declare function saveConfig(config: SFConfig): void;
|
|
36
|
-
/**
|
|
37
|
-
* Delete config file (for --reset).
|
|
38
|
-
*/
|
|
39
|
-
export declare function resetConfig(): void;
|
|
40
|
-
/**
|
|
41
|
-
* Apply config to process.env.
|
|
42
|
-
*
|
|
43
|
-
* Call this ONCE at CLI startup, before any command runs.
|
|
44
|
-
* This means client.ts, kalshi.ts, agent.ts etc. keep reading process.env
|
|
45
|
-
* and just work — no code changes needed in those files.
|
|
46
|
-
*
|
|
47
|
-
* Env vars already set by the user take priority (we only fill gaps).
|
|
48
|
-
*/
|
|
49
|
-
export declare function applyConfig(): void;
|
|
50
|
-
/**
|
|
51
|
-
* Check if SF API key is configured (from any source).
|
|
52
|
-
*/
|
|
53
|
-
export declare function isConfigured(): boolean;
|
|
54
|
-
export declare function requireTrading(): void;
|
|
55
|
-
export declare function getConfigPath(): string;
|
package/dist/config.js
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* CLI Configuration — ~/.sf/config.json
|
|
4
|
-
*
|
|
5
|
-
* Priority: env vars > config file > defaults
|
|
6
|
-
*
|
|
7
|
-
* After `sf setup`, all keys are stored in config.json.
|
|
8
|
-
* `applyConfig()` sets process.env from config so all existing code
|
|
9
|
-
* (client.ts, kalshi.ts, agent.ts) keeps working without changes.
|
|
10
|
-
*/
|
|
11
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
-
};
|
|
14
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.loadFileConfig = loadFileConfig;
|
|
16
|
-
exports.loadConfig = loadConfig;
|
|
17
|
-
exports.saveConfig = saveConfig;
|
|
18
|
-
exports.resetConfig = resetConfig;
|
|
19
|
-
exports.applyConfig = applyConfig;
|
|
20
|
-
exports.isConfigured = isConfigured;
|
|
21
|
-
exports.requireTrading = requireTrading;
|
|
22
|
-
exports.getConfigPath = getConfigPath;
|
|
23
|
-
const fs_1 = __importDefault(require("fs"));
|
|
24
|
-
const path_1 = __importDefault(require("path"));
|
|
25
|
-
const os_1 = __importDefault(require("os"));
|
|
26
|
-
const CONFIG_DIR = path_1.default.join(os_1.default.homedir(), '.sf');
|
|
27
|
-
const CONFIG_PATH = path_1.default.join(CONFIG_DIR, 'config.json');
|
|
28
|
-
const DEFAULT_API_URL = 'https://simplefunctions.dev';
|
|
29
|
-
const DEFAULT_MODEL = 'anthropic/claude-sonnet-4.6';
|
|
30
|
-
/**
|
|
31
|
-
* Load config from file. Does NOT apply env overrides — use resolveConfig() for that.
|
|
32
|
-
*/
|
|
33
|
-
function loadFileConfig() {
|
|
34
|
-
try {
|
|
35
|
-
if (fs_1.default.existsSync(CONFIG_PATH)) {
|
|
36
|
-
return JSON.parse(fs_1.default.readFileSync(CONFIG_PATH, 'utf-8'));
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
catch { /* corrupt file, ignore */ }
|
|
40
|
-
return {};
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Resolve final config: env vars > config file > defaults.
|
|
44
|
-
*/
|
|
45
|
-
function loadConfig() {
|
|
46
|
-
const file = loadFileConfig();
|
|
47
|
-
return {
|
|
48
|
-
apiKey: process.env.SF_API_KEY || file.apiKey,
|
|
49
|
-
apiUrl: process.env.SF_API_URL || file.apiUrl || DEFAULT_API_URL,
|
|
50
|
-
openrouterKey: process.env.OPENROUTER_API_KEY || file.openrouterKey,
|
|
51
|
-
kalshiKeyId: process.env.KALSHI_API_KEY_ID || file.kalshiKeyId,
|
|
52
|
-
kalshiPrivateKeyPath: process.env.KALSHI_PRIVATE_KEY_PATH || file.kalshiPrivateKeyPath,
|
|
53
|
-
polymarketWalletAddress: process.env.POLYMARKET_WALLET_ADDRESS || file.polymarketWalletAddress,
|
|
54
|
-
polymarketPrivateKeyPath: process.env.POLYMARKET_PRIVATE_KEY_PATH || file.polymarketPrivateKeyPath,
|
|
55
|
-
tavilyKey: process.env.TAVILY_API_KEY || file.tavilyKey,
|
|
56
|
-
model: process.env.SF_MODEL || file.model || DEFAULT_MODEL,
|
|
57
|
-
tradingEnabled: file.tradingEnabled || false,
|
|
58
|
-
telegramBotToken: process.env.TELEGRAM_BOT_TOKEN || file.telegramBotToken,
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Save config to ~/.sf/config.json.
|
|
63
|
-
*/
|
|
64
|
-
function saveConfig(config) {
|
|
65
|
-
fs_1.default.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
66
|
-
fs_1.default.writeFileSync(CONFIG_PATH, JSON.stringify({ ...config, configuredAt: new Date().toISOString() }, null, 2));
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Delete config file (for --reset).
|
|
70
|
-
*/
|
|
71
|
-
function resetConfig() {
|
|
72
|
-
try {
|
|
73
|
-
if (fs_1.default.existsSync(CONFIG_PATH)) {
|
|
74
|
-
fs_1.default.unlinkSync(CONFIG_PATH);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
catch { /* ignore */ }
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Apply config to process.env.
|
|
81
|
-
*
|
|
82
|
-
* Call this ONCE at CLI startup, before any command runs.
|
|
83
|
-
* This means client.ts, kalshi.ts, agent.ts etc. keep reading process.env
|
|
84
|
-
* and just work — no code changes needed in those files.
|
|
85
|
-
*
|
|
86
|
-
* Env vars already set by the user take priority (we only fill gaps).
|
|
87
|
-
*/
|
|
88
|
-
function applyConfig() {
|
|
89
|
-
const file = loadFileConfig();
|
|
90
|
-
// Only set process.env if not already set (env vars > config file)
|
|
91
|
-
if (!process.env.SF_API_KEY && file.apiKey) {
|
|
92
|
-
process.env.SF_API_KEY = file.apiKey;
|
|
93
|
-
}
|
|
94
|
-
if (!process.env.SF_API_URL && file.apiUrl) {
|
|
95
|
-
process.env.SF_API_URL = file.apiUrl;
|
|
96
|
-
}
|
|
97
|
-
if (!process.env.OPENROUTER_API_KEY && file.openrouterKey) {
|
|
98
|
-
process.env.OPENROUTER_API_KEY = file.openrouterKey;
|
|
99
|
-
}
|
|
100
|
-
if (!process.env.KALSHI_API_KEY_ID && file.kalshiKeyId) {
|
|
101
|
-
process.env.KALSHI_API_KEY_ID = file.kalshiKeyId;
|
|
102
|
-
}
|
|
103
|
-
if (!process.env.KALSHI_PRIVATE_KEY_PATH && file.kalshiPrivateKeyPath) {
|
|
104
|
-
process.env.KALSHI_PRIVATE_KEY_PATH = file.kalshiPrivateKeyPath;
|
|
105
|
-
}
|
|
106
|
-
if (!process.env.POLYMARKET_WALLET_ADDRESS && file.polymarketWalletAddress) {
|
|
107
|
-
process.env.POLYMARKET_WALLET_ADDRESS = file.polymarketWalletAddress;
|
|
108
|
-
}
|
|
109
|
-
if (!process.env.POLYMARKET_PRIVATE_KEY_PATH && file.polymarketPrivateKeyPath) {
|
|
110
|
-
process.env.POLYMARKET_PRIVATE_KEY_PATH = file.polymarketPrivateKeyPath;
|
|
111
|
-
}
|
|
112
|
-
if (!process.env.TAVILY_API_KEY && file.tavilyKey) {
|
|
113
|
-
process.env.TAVILY_API_KEY = file.tavilyKey;
|
|
114
|
-
}
|
|
115
|
-
if (!process.env.SF_MODEL && file.model) {
|
|
116
|
-
process.env.SF_MODEL = file.model;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Check if SF API key is configured (from any source).
|
|
121
|
-
*/
|
|
122
|
-
function isConfigured() {
|
|
123
|
-
const config = loadConfig();
|
|
124
|
-
return !!config.apiKey;
|
|
125
|
-
}
|
|
126
|
-
function requireTrading() {
|
|
127
|
-
const config = loadConfig();
|
|
128
|
-
if (!config.tradingEnabled) {
|
|
129
|
-
console.error('\n Trading is disabled. Run: sf setup --enable-trading\n');
|
|
130
|
-
process.exit(1);
|
|
131
|
-
}
|
|
132
|
-
if (!config.kalshiKeyId && !process.env.KALSHI_API_KEY_ID) {
|
|
133
|
-
console.error('\n Kalshi API key not configured. Run: sf setup --kalshi\n');
|
|
134
|
-
process.exit(1);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
function getConfigPath() {
|
|
138
|
-
return CONFIG_PATH;
|
|
139
|
-
}
|
package/dist/config.test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|