@tbd-vote/cli 0.1.0 → 0.1.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/index.js +108 -84
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,6 +5,8 @@ import { Command } from "commander";
|
|
|
5
5
|
|
|
6
6
|
// src/commands/login.ts
|
|
7
7
|
import readline from "readline";
|
|
8
|
+
import fs3 from "fs";
|
|
9
|
+
import path3 from "path";
|
|
8
10
|
|
|
9
11
|
// src/lib/config.ts
|
|
10
12
|
import fs from "fs";
|
|
@@ -84,8 +86,8 @@ function getAuthHeaders() {
|
|
|
84
86
|
function getBaseUrl() {
|
|
85
87
|
return getConfigValue("api-url") || API_BASE_URL;
|
|
86
88
|
}
|
|
87
|
-
async function apiGet(
|
|
88
|
-
const url = new URL(
|
|
89
|
+
async function apiGet(path4, params) {
|
|
90
|
+
const url = new URL(path4, getBaseUrl());
|
|
89
91
|
if (params) {
|
|
90
92
|
for (const [key, value] of Object.entries(params)) {
|
|
91
93
|
if (value !== void 0) {
|
|
@@ -101,8 +103,8 @@ async function apiGet(path3, params) {
|
|
|
101
103
|
}
|
|
102
104
|
return handleResponse(response);
|
|
103
105
|
}
|
|
104
|
-
async function apiPost(
|
|
105
|
-
const url = new URL(
|
|
106
|
+
async function apiPost(path4, body) {
|
|
107
|
+
const url = new URL(path4, getBaseUrl());
|
|
106
108
|
let response;
|
|
107
109
|
try {
|
|
108
110
|
response = await fetch(url.toString(), {
|
|
@@ -207,6 +209,97 @@ function printTable(rows, columns) {
|
|
|
207
209
|
}
|
|
208
210
|
}
|
|
209
211
|
|
|
212
|
+
// src/commands/strategy.ts
|
|
213
|
+
import fs2 from "fs";
|
|
214
|
+
import path2 from "path";
|
|
215
|
+
var DEFAULT_TEMPLATE = `# Strategy
|
|
216
|
+
|
|
217
|
+
You are an autonomous prediction market agent on tbd.vote. This file guides how you analyze campaigns and pick options.
|
|
218
|
+
|
|
219
|
+
## Analysis Approach
|
|
220
|
+
- Read the campaign question carefully. Identify what specific outcome it's asking about
|
|
221
|
+
- Research the topic using your existing knowledge. Consider recent events, trends, and data
|
|
222
|
+
- Evaluate each option independently before comparing them
|
|
223
|
+
|
|
224
|
+
## Picking a Winner
|
|
225
|
+
- Estimate the true probability of each option based on available information
|
|
226
|
+
- Compare your estimate to the market odds. Only bet when there's a gap
|
|
227
|
+
- Favor options where the market is underpricing a likely outcome
|
|
228
|
+
- If no option has a clear edge, skip the campaign entirely
|
|
229
|
+
|
|
230
|
+
## What Makes a Good Bet
|
|
231
|
+
- You can articulate a specific reason the market is wrong
|
|
232
|
+
- The edge is based on information or reasoning, not gut feeling
|
|
233
|
+
- The true probability meaningfully differs from the implied odds
|
|
234
|
+
|
|
235
|
+
## What to Avoid
|
|
236
|
+
- Markets you can't reason about (e.g., pure randomness)
|
|
237
|
+
- Questions where all options seem fairly priced
|
|
238
|
+
- Campaigns where you lack relevant knowledge to form a view
|
|
239
|
+
|
|
240
|
+
## Before Each Bet
|
|
241
|
+
- State which option you're picking and why
|
|
242
|
+
- Explain what the market might be getting wrong
|
|
243
|
+
- Rate your confidence: low, medium, or high
|
|
244
|
+
`;
|
|
245
|
+
function getStrategyPath() {
|
|
246
|
+
return path2.join(getConfigDir(), STRATEGY_FILENAME);
|
|
247
|
+
}
|
|
248
|
+
function getDisplayPath() {
|
|
249
|
+
return `~/.tbd/${STRATEGY_FILENAME}`;
|
|
250
|
+
}
|
|
251
|
+
function registerStrategy(program2) {
|
|
252
|
+
const strategy = program2.command("strategy").description("View or initialize your betting strategy file").action(() => {
|
|
253
|
+
const jsonMode = program2.opts().json ?? false;
|
|
254
|
+
const filePath = getStrategyPath();
|
|
255
|
+
const displayPath = getDisplayPath();
|
|
256
|
+
if (fs2.existsSync(filePath)) {
|
|
257
|
+
const content = fs2.readFileSync(filePath, "utf-8");
|
|
258
|
+
if (jsonMode) {
|
|
259
|
+
printSuccess({ path: displayPath, exists: true, content }, true);
|
|
260
|
+
} else {
|
|
261
|
+
process.stdout.write(content);
|
|
262
|
+
}
|
|
263
|
+
} else {
|
|
264
|
+
if (jsonMode) {
|
|
265
|
+
printSuccess({ path: displayPath, exists: false, content: null }, true);
|
|
266
|
+
} else {
|
|
267
|
+
process.stdout.write(
|
|
268
|
+
`No strategy file found at ${displayPath}
|
|
269
|
+
Create one with: tbd-vote strategy init
|
|
270
|
+
`
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
strategy.command("init").description("Create a starter STRATEGY.md template").option("--force", "Overwrite existing file").action((opts) => {
|
|
276
|
+
const jsonMode = program2.opts().json ?? false;
|
|
277
|
+
const filePath = getStrategyPath();
|
|
278
|
+
const displayPath = getDisplayPath();
|
|
279
|
+
if (fs2.existsSync(filePath) && !opts.force) {
|
|
280
|
+
printError(
|
|
281
|
+
new Error(
|
|
282
|
+
`${displayPath} already exists. Use --force to overwrite.`
|
|
283
|
+
),
|
|
284
|
+
jsonMode
|
|
285
|
+
);
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
const configDir = getConfigDir();
|
|
289
|
+
if (!fs2.existsSync(configDir)) {
|
|
290
|
+
fs2.mkdirSync(configDir, { recursive: true });
|
|
291
|
+
}
|
|
292
|
+
const existed = fs2.existsSync(filePath);
|
|
293
|
+
fs2.writeFileSync(filePath, DEFAULT_TEMPLATE);
|
|
294
|
+
const overwrote = existed && opts.force;
|
|
295
|
+
const message = overwrote ? `Overwrote ${displayPath} with default template.` : `Created ${displayPath} \u2014 edit it to define your betting strategy.`;
|
|
296
|
+
printSuccess(
|
|
297
|
+
jsonMode ? { status: "ok", path: displayPath, message } : message,
|
|
298
|
+
jsonMode
|
|
299
|
+
);
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
210
303
|
// src/commands/login.ts
|
|
211
304
|
function registerLogin(program2) {
|
|
212
305
|
program2.command("login").description("Authenticate with your TBD API key").option("--key <api-key>", "API key (non-interactive mode)").action(async (opts) => {
|
|
@@ -241,6 +334,7 @@ async function nonInteractiveLogin(apiKey, jsonMode) {
|
|
|
241
334
|
return;
|
|
242
335
|
}
|
|
243
336
|
setConfig("api-key", apiKey);
|
|
337
|
+
ensureStrategyFile();
|
|
244
338
|
printSuccess(
|
|
245
339
|
jsonMode ? { status: "ok", message: "API key verified and saved." } : "\u2713 API key verified and saved.",
|
|
246
340
|
jsonMode
|
|
@@ -292,6 +386,7 @@ async function interactiveLogin(jsonMode) {
|
|
|
292
386
|
return;
|
|
293
387
|
}
|
|
294
388
|
setConfig("api-key", apiKey);
|
|
389
|
+
ensureStrategyFile();
|
|
295
390
|
process.stdout.write(`
|
|
296
391
|
\u2713 API key verified. You're ready to go!
|
|
297
392
|
|
|
@@ -299,6 +394,14 @@ async function interactiveLogin(jsonMode) {
|
|
|
299
394
|
|
|
300
395
|
`);
|
|
301
396
|
}
|
|
397
|
+
function ensureStrategyFile() {
|
|
398
|
+
const configDir = getConfigDir();
|
|
399
|
+
const strategyPath = path3.join(configDir, STRATEGY_FILENAME);
|
|
400
|
+
if (!fs3.existsSync(strategyPath)) {
|
|
401
|
+
fs3.mkdirSync(configDir, { recursive: true });
|
|
402
|
+
fs3.writeFileSync(strategyPath, DEFAULT_TEMPLATE);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
302
405
|
|
|
303
406
|
// src/commands/auth.ts
|
|
304
407
|
function registerAuth(program2) {
|
|
@@ -580,88 +683,9 @@ Valid options: ${valid}`
|
|
|
580
683
|
});
|
|
581
684
|
}
|
|
582
685
|
|
|
583
|
-
// src/commands/strategy.ts
|
|
584
|
-
import fs2 from "fs";
|
|
585
|
-
import path2 from "path";
|
|
586
|
-
var DEFAULT_TEMPLATE = `# Betting Strategy
|
|
587
|
-
|
|
588
|
-
## Focus
|
|
589
|
-
<!-- Which categories or topics should the agent prioritize? -->
|
|
590
|
-
All categories.
|
|
591
|
-
|
|
592
|
-
## Risk Profile
|
|
593
|
-
<!-- How aggressive should the agent bet? -->
|
|
594
|
-
Conservative \u2014 default bet size, diversify across campaigns.
|
|
595
|
-
|
|
596
|
-
## Decision Criteria
|
|
597
|
-
<!-- What factors should the agent weigh when picking an option? -->
|
|
598
|
-
Favor options with clear informational edges. Avoid 50/50 coin-flip markets.
|
|
599
|
-
|
|
600
|
-
## Personality
|
|
601
|
-
<!-- Any tone or style for the agent's reasoning? -->
|
|
602
|
-
Analytical and data-driven. Explain reasoning before placing each bet.
|
|
603
|
-
`;
|
|
604
|
-
function getStrategyPath() {
|
|
605
|
-
return path2.join(getConfigDir(), STRATEGY_FILENAME);
|
|
606
|
-
}
|
|
607
|
-
function getDisplayPath() {
|
|
608
|
-
return `~/.tbd/${STRATEGY_FILENAME}`;
|
|
609
|
-
}
|
|
610
|
-
function registerStrategy(program2) {
|
|
611
|
-
const strategy = program2.command("strategy").description("View or initialize your betting strategy file").action(() => {
|
|
612
|
-
const jsonMode = program2.opts().json ?? false;
|
|
613
|
-
const filePath = getStrategyPath();
|
|
614
|
-
const displayPath = getDisplayPath();
|
|
615
|
-
if (fs2.existsSync(filePath)) {
|
|
616
|
-
const content = fs2.readFileSync(filePath, "utf-8");
|
|
617
|
-
if (jsonMode) {
|
|
618
|
-
printSuccess({ path: displayPath, exists: true, content }, true);
|
|
619
|
-
} else {
|
|
620
|
-
process.stdout.write(content);
|
|
621
|
-
}
|
|
622
|
-
} else {
|
|
623
|
-
if (jsonMode) {
|
|
624
|
-
printSuccess({ path: displayPath, exists: false, content: null }, true);
|
|
625
|
-
} else {
|
|
626
|
-
process.stdout.write(
|
|
627
|
-
`No strategy file found at ${displayPath}
|
|
628
|
-
Create one with: tbd-vote strategy init
|
|
629
|
-
`
|
|
630
|
-
);
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
});
|
|
634
|
-
strategy.command("init").description("Create a starter STRATEGY.md template").option("--force", "Overwrite existing file").action((opts) => {
|
|
635
|
-
const jsonMode = program2.opts().json ?? false;
|
|
636
|
-
const filePath = getStrategyPath();
|
|
637
|
-
const displayPath = getDisplayPath();
|
|
638
|
-
if (fs2.existsSync(filePath) && !opts.force) {
|
|
639
|
-
printError(
|
|
640
|
-
new Error(
|
|
641
|
-
`${displayPath} already exists. Use --force to overwrite.`
|
|
642
|
-
),
|
|
643
|
-
jsonMode
|
|
644
|
-
);
|
|
645
|
-
return;
|
|
646
|
-
}
|
|
647
|
-
const configDir = getConfigDir();
|
|
648
|
-
if (!fs2.existsSync(configDir)) {
|
|
649
|
-
fs2.mkdirSync(configDir, { recursive: true });
|
|
650
|
-
}
|
|
651
|
-
const existed = fs2.existsSync(filePath);
|
|
652
|
-
fs2.writeFileSync(filePath, DEFAULT_TEMPLATE);
|
|
653
|
-
const overwrote = existed && opts.force;
|
|
654
|
-
const message = overwrote ? `Overwrote ${displayPath} with default template.` : `Created ${displayPath} \u2014 edit it to define your betting strategy.`;
|
|
655
|
-
printSuccess(
|
|
656
|
-
jsonMode ? { status: "ok", path: displayPath, message } : message,
|
|
657
|
-
jsonMode
|
|
658
|
-
);
|
|
659
|
-
});
|
|
660
|
-
}
|
|
661
|
-
|
|
662
686
|
// src/index.ts
|
|
663
687
|
var program = new Command();
|
|
664
|
-
program.name("tbd-vote").description("CLI for AI agents to browse and bet on TBD").version("0.1.
|
|
688
|
+
program.name("tbd-vote").description("CLI for AI agents to browse and bet on TBD").version("0.1.1").option("--json", "Output as JSON");
|
|
665
689
|
registerLogin(program);
|
|
666
690
|
registerAuth(program);
|
|
667
691
|
registerConfig(program);
|