@t2000/cli 0.19.2 → 0.20.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/README.md +22 -37
- package/dist/{chunk-YPWSCLE3.js → chunk-45YCL2KY.js} +3 -16
- package/dist/{dist-NNID5OEY.js → dist-UJGH2XLF.js} +6823 -1504
- package/dist/dist-UJGH2XLF.js.map +1 -0
- package/dist/index.js +119 -411
- package/dist/index.js.map +1 -1
- package/package.json +4 -6
- package/dist/chunk-5TJJMPLT.js +0 -5337
- package/dist/chunk-5TJJMPLT.js.map +0 -1
- package/dist/chunk-7KJXKMEM.js +0 -2055
- package/dist/chunk-7KJXKMEM.js.map +0 -1
- package/dist/dist-NNID5OEY.js.map +0 -1
- package/dist/dist-PJEEL7WQ.js +0 -27152
- package/dist/dist-PJEEL7WQ.js.map +0 -1
- package/dist/fileFromPath-TJOXOKGY.js +0 -131
- package/dist/fileFromPath-TJOXOKGY.js.map +0 -1
- /package/dist/{chunk-YPWSCLE3.js.map → chunk-45YCL2KY.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire as __createRequire } from 'module'; import { fileURLToPath as __fileURLToPath } from 'url'; import { dirname as __pathDirname } from 'path'; const require = __createRequire(import.meta.url); const __filename = __fileURLToPath(import.meta.url); const __dirname = __pathDirname(__filename);
|
|
3
|
-
import "./chunk-
|
|
3
|
+
import "./chunk-45YCL2KY.js";
|
|
4
4
|
|
|
5
5
|
// src/program.ts
|
|
6
6
|
import { Command } from "commander";
|
|
@@ -142,45 +142,65 @@ async function resolvePin(opts) {
|
|
|
142
142
|
|
|
143
143
|
// src/commands/init.ts
|
|
144
144
|
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
145
|
-
import {
|
|
145
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
146
|
+
import { join, dirname } from "path";
|
|
146
147
|
import { homedir as homedir2, platform } from "os";
|
|
147
|
-
import { exec } from "child_process";
|
|
148
|
-
var LLM_KEY_URLS = {
|
|
149
|
-
anthropic: "https://console.anthropic.com/settings/keys",
|
|
150
|
-
openai: "https://platform.openai.com/api-keys"
|
|
151
|
-
};
|
|
152
|
-
function openBrowser(url) {
|
|
153
|
-
const cmd = platform() === "darwin" ? "open" : platform() === "win32" ? "start" : "xdg-open";
|
|
154
|
-
exec(`${cmd} "${url}"`, () => {
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
148
|
var CONFIG_DIR = join(homedir2(), ".t2000");
|
|
158
149
|
var CONFIG_PATH = join(CONFIG_DIR, "config.json");
|
|
159
|
-
function
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
150
|
+
function getMcpPlatforms() {
|
|
151
|
+
const home = homedir2();
|
|
152
|
+
const isMac = platform() === "darwin";
|
|
153
|
+
return [
|
|
154
|
+
{
|
|
155
|
+
name: "Claude Desktop",
|
|
156
|
+
path: isMac ? join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json") : join(home, "AppData", "Roaming", "Claude", "claude_desktop_config.json")
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
name: "Cursor",
|
|
160
|
+
path: join(home, ".cursor", "mcp.json")
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
name: "Windsurf",
|
|
164
|
+
path: join(home, ".codeium", "windsurf", "mcp_config.json")
|
|
165
|
+
}
|
|
166
|
+
];
|
|
165
167
|
}
|
|
166
|
-
function
|
|
167
|
-
|
|
168
|
-
|
|
168
|
+
async function installMcpForPlatforms(platforms) {
|
|
169
|
+
const mcpConfig = { command: "t2000", args: ["mcp"] };
|
|
170
|
+
for (const p of platforms) {
|
|
171
|
+
let config = {};
|
|
172
|
+
try {
|
|
173
|
+
config = JSON.parse(await readFile2(p.path, "utf-8"));
|
|
174
|
+
} catch {
|
|
175
|
+
}
|
|
176
|
+
const servers = config.mcpServers ?? {};
|
|
177
|
+
if (servers["t2000"]) {
|
|
178
|
+
printInfo(`${p.name} already configured`);
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
config.mcpServers = { ...servers, t2000: mcpConfig };
|
|
182
|
+
const dir = dirname(p.path);
|
|
183
|
+
if (!existsSync(dir)) await mkdir2(dir, { recursive: true });
|
|
184
|
+
await writeFile2(p.path, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
185
|
+
printSuccess(`${p.name} configured`);
|
|
186
|
+
}
|
|
169
187
|
}
|
|
170
188
|
function registerInit(program2) {
|
|
171
|
-
program2.command("init").description("Create a new agent bank account \u2014 guided setup with
|
|
189
|
+
program2.command("init").description("Create a new agent bank account \u2014 guided setup with MCP + safeguards").option("--key <path>", "Key file path").option("--no-sponsor", "Skip gas sponsorship").action(async (opts) => {
|
|
172
190
|
try {
|
|
173
|
-
const {
|
|
191
|
+
const { checkbox, input, password: password3 } = await import("@inquirer/prompts");
|
|
174
192
|
console.log("");
|
|
175
193
|
console.log(` \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510`);
|
|
176
194
|
console.log(` \u2502 ${pc2.bold("Welcome to t2000")} \u2502`);
|
|
177
|
-
console.log(` \u2502
|
|
195
|
+
console.log(` \u2502 A bank account for AI agents \u2502`);
|
|
178
196
|
console.log(` \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518`);
|
|
179
197
|
console.log("");
|
|
180
198
|
const hasWallet = await walletExists(opts.key);
|
|
181
199
|
let address = "";
|
|
182
|
-
const
|
|
183
|
-
|
|
200
|
+
const isReturning = hasWallet;
|
|
201
|
+
const totalSteps = isReturning ? 2 : 3;
|
|
202
|
+
let step = 1;
|
|
203
|
+
if (isReturning) {
|
|
184
204
|
printSuccess("Existing wallet detected");
|
|
185
205
|
const pin = await password3({ message: "Enter your PIN:" });
|
|
186
206
|
if (!pin || pin.length < 4) throw new Error("PIN must be at least 4 characters");
|
|
@@ -189,7 +209,7 @@ function registerInit(program2) {
|
|
|
189
209
|
await saveSession(pin);
|
|
190
210
|
printSuccess(`Wallet unlocked (${address.slice(0, 6)}...${address.slice(-4)})`);
|
|
191
211
|
} else {
|
|
192
|
-
console.log(` ${pc2.bold(
|
|
212
|
+
console.log(` ${pc2.bold(`Step ${step} of ${totalSteps}`)} \u2014 Create wallet`);
|
|
193
213
|
printBlank();
|
|
194
214
|
const pin = await password3({ message: `Create PIN (min 4 chars):` });
|
|
195
215
|
if (!pin || pin.length < 4) throw new Error("PIN must be at least 4 characters");
|
|
@@ -197,7 +217,7 @@ function registerInit(program2) {
|
|
|
197
217
|
if (pin !== pinConfirm) throw new Error("PINs do not match");
|
|
198
218
|
printBlank();
|
|
199
219
|
printInfo("Creating agent wallet...");
|
|
200
|
-
const {
|
|
220
|
+
const { address: addr, sponsored } = await T2000.init({ pin, keyPath: opts.key, sponsored: opts.sponsor });
|
|
201
221
|
address = addr;
|
|
202
222
|
await saveSession(pin);
|
|
203
223
|
printSuccess("Keypair generated");
|
|
@@ -212,82 +232,31 @@ function registerInit(program2) {
|
|
|
212
232
|
printLine(` \u{1F389} ${pc2.green("Bank account created")}`);
|
|
213
233
|
printLine(` Address: ${pc2.yellow(address.slice(0, 6) + "..." + address.slice(-4))}`);
|
|
214
234
|
printBlank();
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
console.log(` ${pc2.bold(`Step ${
|
|
218
|
-
printBlank();
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
235
|
+
step++;
|
|
236
|
+
}
|
|
237
|
+
console.log(` ${pc2.bold(`Step ${step} of ${totalSteps}`)} \u2014 Connect AI platforms`);
|
|
238
|
+
printBlank();
|
|
239
|
+
const allPlatforms = getMcpPlatforms();
|
|
240
|
+
const selectedNames = await checkbox({
|
|
241
|
+
message: "Which AI platforms do you use? (space to select)",
|
|
242
|
+
choices: allPlatforms.map((p) => ({
|
|
243
|
+
name: p.name,
|
|
244
|
+
value: p.name,
|
|
245
|
+
checked: p.name !== "Windsurf"
|
|
246
|
+
}))
|
|
226
247
|
});
|
|
227
|
-
|
|
228
|
-
const providerName = llmProvider === "anthropic" ? "Anthropic" : "OpenAI";
|
|
229
|
-
const keyUrl = LLM_KEY_URLS[llmProvider];
|
|
230
|
-
printBlank();
|
|
231
|
-
printInfo(`Opening ${providerName} API keys page in your browser...`);
|
|
232
|
-
openBrowser(keyUrl);
|
|
233
|
-
printLine(` ${pc2.dim(keyUrl)}`);
|
|
234
|
-
printBlank();
|
|
235
|
-
const apiKey = await password3({
|
|
236
|
-
message: `Paste your ${providerName} API key:`
|
|
237
|
-
});
|
|
238
|
-
if (!apiKey) throw new Error("API key is required");
|
|
239
|
-
const config = loadConfig();
|
|
240
|
-
config.llm = { provider: llmProvider, apiKey };
|
|
241
|
-
saveConfig(config);
|
|
242
|
-
const modelName = llmProvider === "anthropic" ? "claude-sonnet-4-20250514" : "gpt-4o";
|
|
243
|
-
printSuccess(`${providerName} connected \u2014 model: ${modelName}`);
|
|
244
|
-
} else {
|
|
245
|
-
printSuccess("Skipped \u2014 use CLI commands directly");
|
|
246
|
-
}
|
|
247
|
-
printBlank();
|
|
248
|
-
const telegramStepNum = skipWallet ? 2 : 4;
|
|
249
|
-
console.log(` ${pc2.bold(`Step ${telegramStepNum} of ${skipWallet ? 3 : 5}`)} \u2014 Connect Telegram ${pc2.dim("(optional)")}`);
|
|
248
|
+
const selectedPlatforms = allPlatforms.filter((p) => selectedNames.includes(p.name));
|
|
250
249
|
printBlank();
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
default: true
|
|
254
|
-
});
|
|
255
|
-
if (wantsTelegram) {
|
|
256
|
-
printBlank();
|
|
257
|
-
printInfo("Opening BotFather in Telegram...");
|
|
258
|
-
openBrowser("https://t.me/BotFather");
|
|
259
|
-
printBlank();
|
|
260
|
-
printLine(`1. Send ${pc2.cyan("/newbot")} to BotFather`);
|
|
261
|
-
printLine(`2. Pick a name (e.g. "My t2000 Agent")`);
|
|
262
|
-
printLine(`3. Copy the bot token`);
|
|
263
|
-
printBlank();
|
|
264
|
-
const botToken = await input({ message: "Paste the bot token:" });
|
|
265
|
-
if (!botToken) throw new Error("Bot token is required");
|
|
250
|
+
if (selectedPlatforms.length > 0) {
|
|
251
|
+
printInfo("Adding t2000 to your AI platforms...");
|
|
266
252
|
printBlank();
|
|
267
|
-
|
|
268
|
-
openBrowser("https://t.me/userinfobot");
|
|
269
|
-
printBlank();
|
|
270
|
-
printLine(`Send any message to ${pc2.cyan("@userinfobot")} \u2014 it will reply with your ID.`);
|
|
271
|
-
printBlank();
|
|
272
|
-
const userId = await input({ message: "Paste your Telegram user ID:" });
|
|
273
|
-
const config = loadConfig();
|
|
274
|
-
config.channels = {
|
|
275
|
-
...config.channels ?? {},
|
|
276
|
-
telegram: {
|
|
277
|
-
enabled: true,
|
|
278
|
-
botToken,
|
|
279
|
-
allowedUsers: userId ? [userId] : []
|
|
280
|
-
},
|
|
281
|
-
webchat: { enabled: true, port: 2e3 }
|
|
282
|
-
};
|
|
283
|
-
saveConfig(config);
|
|
284
|
-
printSuccess("Telegram connected");
|
|
253
|
+
await installMcpForPlatforms(selectedPlatforms);
|
|
285
254
|
} else {
|
|
286
|
-
|
|
255
|
+
printInfo("Skipped \u2014 you can add MCP later with: t2000 mcp install");
|
|
287
256
|
}
|
|
288
257
|
printBlank();
|
|
289
|
-
|
|
290
|
-
console.log(` ${pc2.bold(`Step ${
|
|
258
|
+
step++;
|
|
259
|
+
console.log(` ${pc2.bold(`Step ${step} of ${totalSteps}`)} \u2014 Set safeguards`);
|
|
291
260
|
printBlank();
|
|
292
261
|
const maxPerTx = await input({
|
|
293
262
|
message: "Max per transaction ($):",
|
|
@@ -303,18 +272,21 @@ function registerInit(program2) {
|
|
|
303
272
|
enforcer.set("maxDailySend", Number(maxDaily));
|
|
304
273
|
printSuccess("Safeguards configured");
|
|
305
274
|
printBlank();
|
|
275
|
+
const platformList = selectedPlatforms.map((p) => p.name).join(" / ");
|
|
306
276
|
console.log(` \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510`);
|
|
307
277
|
console.log(` \u2502 ${pc2.green("\u2713 You're all set")} \u2502`);
|
|
308
278
|
console.log(` \u2502 \u2502`);
|
|
309
|
-
if (
|
|
310
|
-
console.log(` \u2502
|
|
311
|
-
console.log(` \u2502 ${
|
|
279
|
+
if (selectedPlatforms.length > 0) {
|
|
280
|
+
console.log(` \u2502 ${pc2.bold("Next steps:")} \u2502`);
|
|
281
|
+
console.log(` \u2502 1. Restart ${platformList.length > 20 ? "your AI platform" : platformList}${" ".repeat(Math.max(0, 23 - Math.min(platformList.length, 20)))}\u2502`);
|
|
282
|
+
console.log(` \u2502 2. Ask: ${pc2.cyan(`"What's my t2000 balance?"`)} \u2502`);
|
|
283
|
+
console.log(` \u2502 \u2502`);
|
|
284
|
+
} else {
|
|
285
|
+
console.log(` \u2502 Use the CLI directly: \u2502`);
|
|
286
|
+
console.log(` \u2502 ${pc2.cyan("t2000 balance")} \u2502`);
|
|
287
|
+
console.log(` \u2502 ${pc2.cyan("t2000 invest buy 100 SUI")} \u2502`);
|
|
312
288
|
console.log(` \u2502 \u2502`);
|
|
313
289
|
}
|
|
314
|
-
console.log(` \u2502 Or use the CLI directly: \u2502`);
|
|
315
|
-
console.log(` \u2502 ${pc2.cyan("t2000 balance")} \u2502`);
|
|
316
|
-
console.log(` \u2502 ${pc2.cyan("t2000 invest buy 100 SUI")} \u2502`);
|
|
317
|
-
console.log(` \u2502 \u2502`);
|
|
318
290
|
console.log(` \u2502 Deposit USDC to get started: \u2502`);
|
|
319
291
|
console.log(` \u2502 ${pc2.yellow(address)} \u2502`);
|
|
320
292
|
console.log(` \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518`);
|
|
@@ -551,7 +523,7 @@ function registerHistory(program2) {
|
|
|
551
523
|
}
|
|
552
524
|
|
|
553
525
|
// src/commands/exportKey.ts
|
|
554
|
-
import { readFile as
|
|
526
|
+
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
|
|
555
527
|
import { resolve as resolve2 } from "path";
|
|
556
528
|
import { homedir as homedir3 } from "os";
|
|
557
529
|
import { T2000 as T20007 } from "@t2000/sdk";
|
|
@@ -560,15 +532,15 @@ var MAX_ATTEMPTS = 5;
|
|
|
560
532
|
var LOCKOUT_MS = 5 * 60 * 1e3;
|
|
561
533
|
async function getLockState() {
|
|
562
534
|
try {
|
|
563
|
-
const data = JSON.parse(await
|
|
535
|
+
const data = JSON.parse(await readFile3(LOCKFILE, "utf-8"));
|
|
564
536
|
return data;
|
|
565
537
|
} catch {
|
|
566
538
|
return { attempts: 0, lockedUntil: 0 };
|
|
567
539
|
}
|
|
568
540
|
}
|
|
569
541
|
async function setLockState(state) {
|
|
570
|
-
await
|
|
571
|
-
await
|
|
542
|
+
await mkdir3(resolve2(homedir3(), ".t2000"), { recursive: true });
|
|
543
|
+
await writeFile3(LOCKFILE, JSON.stringify(state), { mode: 384 });
|
|
572
544
|
}
|
|
573
545
|
function registerExport(program2) {
|
|
574
546
|
program2.command("export").description("Export private key (raw Ed25519 hex)").option("--key <path>", "Key file path").option("--yes", "Skip confirmation").action(async (opts) => {
|
|
@@ -1040,14 +1012,14 @@ function setNestedValue(obj, path, value) {
|
|
|
1040
1012
|
}
|
|
1041
1013
|
current[parts[parts.length - 1]] = value;
|
|
1042
1014
|
}
|
|
1043
|
-
function
|
|
1015
|
+
function loadConfig() {
|
|
1044
1016
|
try {
|
|
1045
1017
|
return JSON.parse(readFileSync2(CONFIG_PATH2, "utf-8"));
|
|
1046
1018
|
} catch {
|
|
1047
1019
|
return {};
|
|
1048
1020
|
}
|
|
1049
1021
|
}
|
|
1050
|
-
function
|
|
1022
|
+
function saveConfig(config) {
|
|
1051
1023
|
if (!existsSync2(CONFIG_DIR2)) {
|
|
1052
1024
|
mkdirSync2(CONFIG_DIR2, { recursive: true });
|
|
1053
1025
|
}
|
|
@@ -1084,7 +1056,7 @@ function registerConfig(program2) {
|
|
|
1084
1056
|
});
|
|
1085
1057
|
configCmd.command("get").argument("[key]", "Config key to get, supports dot notation (e.g. llm.provider)").action((key) => {
|
|
1086
1058
|
try {
|
|
1087
|
-
const config =
|
|
1059
|
+
const config = loadConfig();
|
|
1088
1060
|
if (key) {
|
|
1089
1061
|
const value = key.includes(".") ? getNestedValue(config, key) : config[key];
|
|
1090
1062
|
if (isJsonMode()) {
|
|
@@ -1114,7 +1086,7 @@ function registerConfig(program2) {
|
|
|
1114
1086
|
handleError(error);
|
|
1115
1087
|
}
|
|
1116
1088
|
});
|
|
1117
|
-
configCmd.command("set").argument("<key>", "Config key, supports dot notation (e.g. llm.provider
|
|
1089
|
+
configCmd.command("set").argument("<key>", "Config key, supports dot notation (e.g. llm.provider)").argument("<value>", "Config value").action((key, value) => {
|
|
1118
1090
|
try {
|
|
1119
1091
|
const leafKey = key.includes(".") ? key.split(".").pop() : key;
|
|
1120
1092
|
if (SAFEGUARD_KEYS.has(leafKey) && !key.includes(".")) {
|
|
@@ -1134,7 +1106,7 @@ function registerConfig(program2) {
|
|
|
1134
1106
|
printBlank();
|
|
1135
1107
|
return;
|
|
1136
1108
|
}
|
|
1137
|
-
const config =
|
|
1109
|
+
const config = loadConfig();
|
|
1138
1110
|
let parsed = value;
|
|
1139
1111
|
if (value === "true") parsed = true;
|
|
1140
1112
|
else if (value === "false") parsed = false;
|
|
@@ -1150,7 +1122,7 @@ function registerConfig(program2) {
|
|
|
1150
1122
|
} else {
|
|
1151
1123
|
config[key] = parsed;
|
|
1152
1124
|
}
|
|
1153
|
-
|
|
1125
|
+
saveConfig(config);
|
|
1154
1126
|
if (isJsonMode()) {
|
|
1155
1127
|
printJson({ [key]: parsed });
|
|
1156
1128
|
return;
|
|
@@ -1587,8 +1559,8 @@ function registerLock(program2) {
|
|
|
1587
1559
|
if (!pin) {
|
|
1588
1560
|
throw new Error("PIN required to unlock agent");
|
|
1589
1561
|
}
|
|
1590
|
-
const { T2000:
|
|
1591
|
-
await
|
|
1562
|
+
const { T2000: T200027 } = await import("@t2000/sdk");
|
|
1563
|
+
await T200027.create({ pin });
|
|
1592
1564
|
const enforcer = new SafeguardEnforcer3(CONFIG_DIR4);
|
|
1593
1565
|
enforcer.load();
|
|
1594
1566
|
enforcer.unlock();
|
|
@@ -2028,8 +2000,8 @@ function registerExchange(program2) {
|
|
|
2028
2000
|
}
|
|
2029
2001
|
|
|
2030
2002
|
// src/commands/mcp.ts
|
|
2031
|
-
import { readFile as
|
|
2032
|
-
import { join as join5, dirname } from "path";
|
|
2003
|
+
import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir4 } from "fs/promises";
|
|
2004
|
+
import { join as join5, dirname as dirname2 } from "path";
|
|
2033
2005
|
import { homedir as homedir7 } from "os";
|
|
2034
2006
|
import { existsSync as existsSync4 } from "fs";
|
|
2035
2007
|
var MCP_CONFIG = {
|
|
@@ -2044,32 +2016,36 @@ function getPlatformConfigs() {
|
|
|
2044
2016
|
path: join5(home, "Library", "Application Support", "Claude", "claude_desktop_config.json")
|
|
2045
2017
|
},
|
|
2046
2018
|
{
|
|
2047
|
-
name: "Cursor
|
|
2019
|
+
name: "Cursor",
|
|
2048
2020
|
path: join5(home, ".cursor", "mcp.json")
|
|
2021
|
+
},
|
|
2022
|
+
{
|
|
2023
|
+
name: "Windsurf",
|
|
2024
|
+
path: join5(home, ".codeium", "windsurf", "mcp_config.json")
|
|
2049
2025
|
}
|
|
2050
2026
|
];
|
|
2051
2027
|
}
|
|
2052
2028
|
async function readJsonFile(path) {
|
|
2053
2029
|
try {
|
|
2054
|
-
const content = await
|
|
2030
|
+
const content = await readFile4(path, "utf-8");
|
|
2055
2031
|
return JSON.parse(content);
|
|
2056
2032
|
} catch {
|
|
2057
2033
|
return {};
|
|
2058
2034
|
}
|
|
2059
2035
|
}
|
|
2060
2036
|
async function writeJsonFile(path, data) {
|
|
2061
|
-
const dir =
|
|
2037
|
+
const dir = dirname2(path);
|
|
2062
2038
|
if (!existsSync4(dir)) {
|
|
2063
|
-
await
|
|
2039
|
+
await mkdir4(dir, { recursive: true });
|
|
2064
2040
|
}
|
|
2065
|
-
await
|
|
2041
|
+
await writeFile4(path, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
2066
2042
|
}
|
|
2067
2043
|
function registerMcp(program2) {
|
|
2068
2044
|
const mcp = program2.command("mcp").description("MCP server for AI platforms");
|
|
2069
2045
|
mcp.command("start", { isDefault: true }).description("Start MCP server (stdio transport)").option("--key <path>", "Key file path").action(async (opts) => {
|
|
2070
2046
|
let mod;
|
|
2071
2047
|
try {
|
|
2072
|
-
mod = await import("./dist-
|
|
2048
|
+
mod = await import("./dist-UJGH2XLF.js");
|
|
2073
2049
|
} catch {
|
|
2074
2050
|
console.error(
|
|
2075
2051
|
"MCP server not installed. Run:\n npm install -g @t2000/mcp"
|
|
@@ -2078,22 +2054,22 @@ function registerMcp(program2) {
|
|
|
2078
2054
|
}
|
|
2079
2055
|
await mod.startMcpServer({ keyPath: opts.key });
|
|
2080
2056
|
});
|
|
2081
|
-
mcp.command("install").description("Auto-configure MCP in Claude Desktop and
|
|
2057
|
+
mcp.command("install").description("Auto-configure MCP in Claude Desktop, Cursor, and Windsurf").action(async () => {
|
|
2082
2058
|
try {
|
|
2083
2059
|
const platforms = getPlatformConfigs();
|
|
2084
2060
|
const results = [];
|
|
2085
|
-
for (const
|
|
2086
|
-
const config = await readJsonFile(
|
|
2061
|
+
for (const platform2 of platforms) {
|
|
2062
|
+
const config = await readJsonFile(platform2.path);
|
|
2087
2063
|
if (config.mcpServers && config.mcpServers["t2000"]) {
|
|
2088
|
-
results.push({ name:
|
|
2064
|
+
results.push({ name: platform2.name, status: "exists" });
|
|
2089
2065
|
continue;
|
|
2090
2066
|
}
|
|
2091
2067
|
config.mcpServers = {
|
|
2092
2068
|
...config.mcpServers ?? {},
|
|
2093
2069
|
t2000: MCP_CONFIG
|
|
2094
2070
|
};
|
|
2095
|
-
await writeJsonFile(
|
|
2096
|
-
results.push({ name:
|
|
2071
|
+
await writeJsonFile(platform2.path, config);
|
|
2072
|
+
results.push({ name: platform2.name, status: "added" });
|
|
2097
2073
|
}
|
|
2098
2074
|
if (isJsonMode()) {
|
|
2099
2075
|
printJson({ installed: results });
|
|
@@ -2115,23 +2091,23 @@ function registerMcp(program2) {
|
|
|
2115
2091
|
handleError(error);
|
|
2116
2092
|
}
|
|
2117
2093
|
});
|
|
2118
|
-
mcp.command("uninstall").description("Remove t2000 MCP config from Claude Desktop and
|
|
2094
|
+
mcp.command("uninstall").description("Remove t2000 MCP config from Claude Desktop, Cursor, and Windsurf").action(async () => {
|
|
2119
2095
|
try {
|
|
2120
2096
|
const platforms = getPlatformConfigs();
|
|
2121
2097
|
const results = [];
|
|
2122
|
-
for (const
|
|
2123
|
-
if (!existsSync4(
|
|
2124
|
-
results.push({ name:
|
|
2098
|
+
for (const platform2 of platforms) {
|
|
2099
|
+
if (!existsSync4(platform2.path)) {
|
|
2100
|
+
results.push({ name: platform2.name, removed: false });
|
|
2125
2101
|
continue;
|
|
2126
2102
|
}
|
|
2127
|
-
const config = await readJsonFile(
|
|
2103
|
+
const config = await readJsonFile(platform2.path);
|
|
2128
2104
|
if (!config.mcpServers || !config.mcpServers["t2000"]) {
|
|
2129
|
-
results.push({ name:
|
|
2105
|
+
results.push({ name: platform2.name, removed: false });
|
|
2130
2106
|
continue;
|
|
2131
2107
|
}
|
|
2132
2108
|
delete config.mcpServers["t2000"];
|
|
2133
|
-
await writeJsonFile(
|
|
2134
|
-
results.push({ name:
|
|
2109
|
+
await writeJsonFile(platform2.path, config);
|
|
2110
|
+
results.push({ name: platform2.name, removed: true });
|
|
2135
2111
|
}
|
|
2136
2112
|
if (isJsonMode()) {
|
|
2137
2113
|
printJson({ uninstalled: results });
|
|
@@ -2723,9 +2699,9 @@ function registerInvest(program2) {
|
|
|
2723
2699
|
printBlank();
|
|
2724
2700
|
if (result.executed.length > 0) {
|
|
2725
2701
|
printSuccess(`Executed ${result.executed.length} auto-invest run(s)`);
|
|
2726
|
-
for (const
|
|
2727
|
-
const target =
|
|
2728
|
-
printKeyValue(target, formatUsd15(
|
|
2702
|
+
for (const exec of result.executed) {
|
|
2703
|
+
const target = exec.strategy ?? exec.asset ?? "?";
|
|
2704
|
+
printKeyValue(target, formatUsd15(exec.amount));
|
|
2729
2705
|
}
|
|
2730
2706
|
}
|
|
2731
2707
|
if (result.skipped.length > 0) {
|
|
@@ -2899,279 +2875,12 @@ function registerClaimRewards(program2) {
|
|
|
2899
2875
|
});
|
|
2900
2876
|
}
|
|
2901
2877
|
|
|
2902
|
-
// src/commands/gateway.ts
|
|
2903
|
-
import pc16 from "picocolors";
|
|
2904
|
-
import { T2000 as T200027 } from "@t2000/sdk";
|
|
2905
|
-
import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync4, unlinkSync } from "fs";
|
|
2906
|
-
import { join as join6 } from "path";
|
|
2907
|
-
import { homedir as homedir8, platform as platform2 } from "os";
|
|
2908
|
-
import { execSync } from "child_process";
|
|
2909
|
-
var PLIST_LABEL = "com.t2000.gateway";
|
|
2910
|
-
var SYSTEMD_UNIT = "t2000-gateway";
|
|
2911
|
-
function getLaunchAgentPath() {
|
|
2912
|
-
return join6(homedir8(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
2913
|
-
}
|
|
2914
|
-
function getSystemdPath() {
|
|
2915
|
-
return join6(homedir8(), ".config", "systemd", "user", `${SYSTEMD_UNIT}.service`);
|
|
2916
|
-
}
|
|
2917
|
-
function getLogDir() {
|
|
2918
|
-
return join6(homedir8(), ".t2000", "logs");
|
|
2919
|
-
}
|
|
2920
|
-
function getT2000Bin() {
|
|
2921
|
-
try {
|
|
2922
|
-
return execSync("which t2000", { encoding: "utf-8" }).trim();
|
|
2923
|
-
} catch {
|
|
2924
|
-
return "npx t2000";
|
|
2925
|
-
}
|
|
2926
|
-
}
|
|
2927
|
-
function registerGateway(program2) {
|
|
2928
|
-
const gw = program2.command("gateway").description("Start AI financial advisor gateway");
|
|
2929
|
-
gw.command("start", { isDefault: true }).description("Start the gateway (foreground)").option("--port <port>", "WebChat port", "2000").option("--no-telegram", "Skip Telegram channel").option("--no-heartbeat", "Skip heartbeat daemon").option("--verbose", "Debug logging").option("--key <path>", "Key file path").action(async (opts) => {
|
|
2930
|
-
try {
|
|
2931
|
-
const pin = await resolvePin();
|
|
2932
|
-
const agent = await T200027.create({ pin, keyPath: opts.key });
|
|
2933
|
-
console.log("");
|
|
2934
|
-
console.log(` ${pc16.bold("t2000 gateway")}`);
|
|
2935
|
-
console.log("");
|
|
2936
|
-
const { Gateway } = await import("./dist-PJEEL7WQ.js");
|
|
2937
|
-
const gateway = await Gateway.create({
|
|
2938
|
-
agent,
|
|
2939
|
-
port: parseInt(opts.port, 10),
|
|
2940
|
-
noTelegram: !opts.telegram,
|
|
2941
|
-
noHeartbeat: !opts.heartbeat,
|
|
2942
|
-
verbose: opts.verbose
|
|
2943
|
-
});
|
|
2944
|
-
const info = await gateway.start();
|
|
2945
|
-
console.log("");
|
|
2946
|
-
const truncAddr = info.address.slice(0, 6) + "..." + info.address.slice(-4);
|
|
2947
|
-
printSuccess(`Agent unlocked (${truncAddr})`);
|
|
2948
|
-
printSuccess(`${info.llmProvider === "anthropic" ? "Claude" : "GPT"} connected (${info.llmModel})`);
|
|
2949
|
-
if (info.webchatUrl) printSuccess(`WebChat at ${pc16.underline(info.webchatUrl)}`);
|
|
2950
|
-
if (info.telegramConnected) {
|
|
2951
|
-
printSuccess("Telegram connected");
|
|
2952
|
-
} else if (opts.telegram) {
|
|
2953
|
-
printWarning("Telegram not connected");
|
|
2954
|
-
}
|
|
2955
|
-
if (info.heartbeatTasks > 0) printSuccess(`Heartbeat started (${info.heartbeatTasks} tasks)`);
|
|
2956
|
-
console.log("");
|
|
2957
|
-
printSuccess(pc16.bold("Ready \u2014 talk to your agent"));
|
|
2958
|
-
console.log("");
|
|
2959
|
-
await new Promise(() => {
|
|
2960
|
-
});
|
|
2961
|
-
} catch (error) {
|
|
2962
|
-
handleError(error);
|
|
2963
|
-
}
|
|
2964
|
-
});
|
|
2965
|
-
gw.command("status").description("Check if gateway is running").option("--port <port>", "WebChat port to check", "2000").action(async (opts) => {
|
|
2966
|
-
try {
|
|
2967
|
-
const port = parseInt(opts.port, 10);
|
|
2968
|
-
const response = await fetch(`http://127.0.0.1:${port}/health`);
|
|
2969
|
-
if (response.ok) {
|
|
2970
|
-
const data = await response.json();
|
|
2971
|
-
printSuccess(`Gateway is running on port ${port} (${data.status})`);
|
|
2972
|
-
}
|
|
2973
|
-
} catch {
|
|
2974
|
-
console.log(` ${pc16.yellow("\u25CB")} Gateway is not running on port ${opts.port}`);
|
|
2975
|
-
}
|
|
2976
|
-
});
|
|
2977
|
-
gw.command("install").description("Install gateway as a background daemon").option("--port <port>", "WebChat port", "2000").action(async (opts) => {
|
|
2978
|
-
try {
|
|
2979
|
-
const os = platform2();
|
|
2980
|
-
const bin = getT2000Bin();
|
|
2981
|
-
if (os === "darwin") {
|
|
2982
|
-
installLaunchd(bin, opts.port);
|
|
2983
|
-
} else if (os === "linux") {
|
|
2984
|
-
installSystemd(bin, opts.port);
|
|
2985
|
-
} else {
|
|
2986
|
-
throw new Error(`Unsupported platform: ${os}. Use macOS or Linux.`);
|
|
2987
|
-
}
|
|
2988
|
-
} catch (error) {
|
|
2989
|
-
handleError(error);
|
|
2990
|
-
}
|
|
2991
|
-
});
|
|
2992
|
-
gw.command("uninstall").description("Remove gateway daemon").action(async () => {
|
|
2993
|
-
try {
|
|
2994
|
-
const os = platform2();
|
|
2995
|
-
if (os === "darwin") {
|
|
2996
|
-
uninstallLaunchd();
|
|
2997
|
-
} else if (os === "linux") {
|
|
2998
|
-
uninstallSystemd();
|
|
2999
|
-
} else {
|
|
3000
|
-
throw new Error(`Unsupported platform: ${os}`);
|
|
3001
|
-
}
|
|
3002
|
-
} catch (error) {
|
|
3003
|
-
handleError(error);
|
|
3004
|
-
}
|
|
3005
|
-
});
|
|
3006
|
-
gw.command("logs").description("Tail gateway logs").option("-n <lines>", "Number of lines", "50").option("-f, --follow", "Follow log output").action(async (opts) => {
|
|
3007
|
-
try {
|
|
3008
|
-
const logPath = join6(getLogDir(), "gateway.log");
|
|
3009
|
-
if (!existsSync5(logPath)) {
|
|
3010
|
-
printWarning("No gateway logs found yet.");
|
|
3011
|
-
printInfo(`Log path: ${logPath}`);
|
|
3012
|
-
return;
|
|
3013
|
-
}
|
|
3014
|
-
printBlank();
|
|
3015
|
-
printInfo(`Log file: ${logPath}`);
|
|
3016
|
-
printBlank();
|
|
3017
|
-
const content = readFileSync4(logPath, "utf-8");
|
|
3018
|
-
const lines = content.trim().split("\n");
|
|
3019
|
-
const tail = lines.slice(-parseInt(opts.n, 10));
|
|
3020
|
-
for (const line of tail) {
|
|
3021
|
-
try {
|
|
3022
|
-
const entry = JSON.parse(line);
|
|
3023
|
-
const time = new Date(entry.ts).toLocaleTimeString();
|
|
3024
|
-
const levelColor = entry.level === "error" ? pc16.red : entry.level === "warn" ? pc16.yellow : pc16.dim;
|
|
3025
|
-
printLine(`${pc16.dim(time)} ${levelColor(entry.level.padEnd(5))} ${entry.msg}`);
|
|
3026
|
-
} catch {
|
|
3027
|
-
printLine(line);
|
|
3028
|
-
}
|
|
3029
|
-
}
|
|
3030
|
-
if (opts.follow) {
|
|
3031
|
-
printBlank();
|
|
3032
|
-
printInfo("Following... (Ctrl+C to stop)");
|
|
3033
|
-
const { spawn } = await import("child_process");
|
|
3034
|
-
const child = spawn("tail", ["-f", logPath], { stdio: "inherit" });
|
|
3035
|
-
process.on("SIGINT", () => {
|
|
3036
|
-
child.kill();
|
|
3037
|
-
process.exit(0);
|
|
3038
|
-
});
|
|
3039
|
-
await new Promise(() => {
|
|
3040
|
-
});
|
|
3041
|
-
}
|
|
3042
|
-
printBlank();
|
|
3043
|
-
} catch (error) {
|
|
3044
|
-
handleError(error);
|
|
3045
|
-
}
|
|
3046
|
-
});
|
|
3047
|
-
}
|
|
3048
|
-
function installLaunchd(bin, port) {
|
|
3049
|
-
const logDir = getLogDir();
|
|
3050
|
-
const plistPath = getLaunchAgentPath();
|
|
3051
|
-
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
3052
|
-
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3053
|
-
<plist version="1.0">
|
|
3054
|
-
<dict>
|
|
3055
|
-
<key>Label</key>
|
|
3056
|
-
<string>${PLIST_LABEL}</string>
|
|
3057
|
-
<key>ProgramArguments</key>
|
|
3058
|
-
<array>
|
|
3059
|
-
<string>${bin}</string>
|
|
3060
|
-
<string>gateway</string>
|
|
3061
|
-
<string>start</string>
|
|
3062
|
-
<string>--port</string>
|
|
3063
|
-
<string>${port}</string>
|
|
3064
|
-
</array>
|
|
3065
|
-
<key>RunAtLoad</key>
|
|
3066
|
-
<true/>
|
|
3067
|
-
<key>KeepAlive</key>
|
|
3068
|
-
<true/>
|
|
3069
|
-
<key>StandardOutPath</key>
|
|
3070
|
-
<string>${logDir}/gateway-stdout.log</string>
|
|
3071
|
-
<key>StandardErrorPath</key>
|
|
3072
|
-
<string>${logDir}/gateway-stderr.log</string>
|
|
3073
|
-
<key>EnvironmentVariables</key>
|
|
3074
|
-
<dict>
|
|
3075
|
-
<key>PATH</key>
|
|
3076
|
-
<string>/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin</string>
|
|
3077
|
-
</dict>
|
|
3078
|
-
</dict>
|
|
3079
|
-
</plist>`;
|
|
3080
|
-
if (existsSync5(plistPath)) {
|
|
3081
|
-
try {
|
|
3082
|
-
execSync(`launchctl unload "${plistPath}" 2>/dev/null`);
|
|
3083
|
-
} catch {
|
|
3084
|
-
}
|
|
3085
|
-
}
|
|
3086
|
-
writeFileSync4(plistPath, plist);
|
|
3087
|
-
execSync(`launchctl load "${plistPath}"`);
|
|
3088
|
-
printBlank();
|
|
3089
|
-
printSuccess("Gateway daemon installed");
|
|
3090
|
-
printSuccess(`Starts on boot \u2014 runs in background`);
|
|
3091
|
-
printLine(` ${pc16.dim("Logs:")} ${logDir}/gateway.log`);
|
|
3092
|
-
printLine(` ${pc16.dim("Stop:")} t2000 gateway uninstall`);
|
|
3093
|
-
printBlank();
|
|
3094
|
-
}
|
|
3095
|
-
function uninstallLaunchd() {
|
|
3096
|
-
const plistPath = getLaunchAgentPath();
|
|
3097
|
-
if (!existsSync5(plistPath)) {
|
|
3098
|
-
printWarning("Gateway daemon is not installed.");
|
|
3099
|
-
return;
|
|
3100
|
-
}
|
|
3101
|
-
try {
|
|
3102
|
-
execSync(`launchctl unload "${plistPath}" 2>/dev/null`);
|
|
3103
|
-
} catch {
|
|
3104
|
-
}
|
|
3105
|
-
unlinkSync(plistPath);
|
|
3106
|
-
printBlank();
|
|
3107
|
-
printSuccess("Gateway daemon removed");
|
|
3108
|
-
printBlank();
|
|
3109
|
-
}
|
|
3110
|
-
function installSystemd(bin, port) {
|
|
3111
|
-
const logDir = getLogDir();
|
|
3112
|
-
const unitPath = getSystemdPath();
|
|
3113
|
-
const unitDir = join6(homedir8(), ".config", "systemd", "user");
|
|
3114
|
-
const unit = `[Unit]
|
|
3115
|
-
Description=t2000 Gateway \u2014 AI Financial Advisor
|
|
3116
|
-
After=network-online.target
|
|
3117
|
-
Wants=network-online.target
|
|
3118
|
-
|
|
3119
|
-
[Service]
|
|
3120
|
-
Type=simple
|
|
3121
|
-
ExecStart=${bin} gateway start --port ${port}
|
|
3122
|
-
Restart=on-failure
|
|
3123
|
-
RestartSec=10
|
|
3124
|
-
StandardOutput=append:${logDir}/gateway-stdout.log
|
|
3125
|
-
StandardError=append:${logDir}/gateway-stderr.log
|
|
3126
|
-
|
|
3127
|
-
[Install]
|
|
3128
|
-
WantedBy=default.target
|
|
3129
|
-
`;
|
|
3130
|
-
if (!existsSync5(unitDir)) {
|
|
3131
|
-
execSync(`mkdir -p "${unitDir}"`);
|
|
3132
|
-
}
|
|
3133
|
-
writeFileSync4(unitPath, unit);
|
|
3134
|
-
execSync("systemctl --user daemon-reload");
|
|
3135
|
-
execSync(`systemctl --user enable ${SYSTEMD_UNIT}`);
|
|
3136
|
-
execSync(`systemctl --user start ${SYSTEMD_UNIT}`);
|
|
3137
|
-
printBlank();
|
|
3138
|
-
printSuccess("Gateway daemon installed (systemd)");
|
|
3139
|
-
printSuccess("Starts on login \u2014 runs in background");
|
|
3140
|
-
printLine(` ${pc16.dim("Logs:")} ${logDir}/gateway.log`);
|
|
3141
|
-
printLine(` ${pc16.dim("Status:")} systemctl --user status ${SYSTEMD_UNIT}`);
|
|
3142
|
-
printLine(` ${pc16.dim("Stop:")} t2000 gateway uninstall`);
|
|
3143
|
-
printBlank();
|
|
3144
|
-
}
|
|
3145
|
-
function uninstallSystemd() {
|
|
3146
|
-
const unitPath = getSystemdPath();
|
|
3147
|
-
if (!existsSync5(unitPath)) {
|
|
3148
|
-
printWarning("Gateway daemon is not installed.");
|
|
3149
|
-
return;
|
|
3150
|
-
}
|
|
3151
|
-
try {
|
|
3152
|
-
execSync(`systemctl --user stop ${SYSTEMD_UNIT} 2>/dev/null`);
|
|
3153
|
-
} catch {
|
|
3154
|
-
}
|
|
3155
|
-
try {
|
|
3156
|
-
execSync(`systemctl --user disable ${SYSTEMD_UNIT} 2>/dev/null`);
|
|
3157
|
-
} catch {
|
|
3158
|
-
}
|
|
3159
|
-
unlinkSync(unitPath);
|
|
3160
|
-
try {
|
|
3161
|
-
execSync("systemctl --user daemon-reload");
|
|
3162
|
-
} catch {
|
|
3163
|
-
}
|
|
3164
|
-
printBlank();
|
|
3165
|
-
printSuccess("Gateway daemon removed");
|
|
3166
|
-
printBlank();
|
|
3167
|
-
}
|
|
3168
|
-
|
|
3169
2878
|
// src/program.ts
|
|
3170
2879
|
var require2 = createRequire(import.meta.url);
|
|
3171
2880
|
var { version: CLI_VERSION } = require2("../package.json");
|
|
3172
2881
|
function createProgram() {
|
|
3173
2882
|
const program2 = new Command();
|
|
3174
|
-
program2.name("t2000").description("
|
|
2883
|
+
program2.name("t2000").description("A bank account for AI agents").version(`${CLI_VERSION} (beta)`).option("--json", "Output in JSON format").hook("preAction", (thisCommand) => {
|
|
3175
2884
|
const opts = thisCommand.optsWithGlobals();
|
|
3176
2885
|
if (opts.json) setJsonMode(true);
|
|
3177
2886
|
});
|
|
@@ -3205,7 +2914,6 @@ function createProgram() {
|
|
|
3205
2914
|
registerInvest(program2);
|
|
3206
2915
|
registerPortfolio(program2);
|
|
3207
2916
|
registerClaimRewards(program2);
|
|
3208
|
-
registerGateway(program2);
|
|
3209
2917
|
return program2;
|
|
3210
2918
|
}
|
|
3211
2919
|
|