@token2chat/t2c 0.2.0-beta.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.
Files changed (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +188 -0
  3. package/dist/adapters/aider.d.ts +5 -0
  4. package/dist/adapters/aider.js +29 -0
  5. package/dist/adapters/cline.d.ts +5 -0
  6. package/dist/adapters/cline.js +32 -0
  7. package/dist/adapters/continue.d.ts +5 -0
  8. package/dist/adapters/continue.js +45 -0
  9. package/dist/adapters/cursor.d.ts +5 -0
  10. package/dist/adapters/cursor.js +23 -0
  11. package/dist/adapters/env.d.ts +5 -0
  12. package/dist/adapters/env.js +25 -0
  13. package/dist/adapters/index.d.ts +6 -0
  14. package/dist/adapters/index.js +6 -0
  15. package/dist/adapters/openclaw.d.ts +2 -0
  16. package/dist/adapters/openclaw.js +167 -0
  17. package/dist/cashu-store.d.ts +52 -0
  18. package/dist/cashu-store.js +201 -0
  19. package/dist/commands/audit.d.ts +6 -0
  20. package/dist/commands/audit.js +340 -0
  21. package/dist/commands/balance.d.ts +5 -0
  22. package/dist/commands/balance.js +29 -0
  23. package/dist/commands/config.d.ts +5 -0
  24. package/dist/commands/config.js +62 -0
  25. package/dist/commands/connect.d.ts +1 -0
  26. package/dist/commands/connect.js +43 -0
  27. package/dist/commands/doctor.d.ts +1 -0
  28. package/dist/commands/doctor.js +178 -0
  29. package/dist/commands/init.d.ts +3 -0
  30. package/dist/commands/init.js +50 -0
  31. package/dist/commands/mint.d.ts +5 -0
  32. package/dist/commands/mint.js +168 -0
  33. package/dist/commands/recover.d.ts +1 -0
  34. package/dist/commands/recover.js +61 -0
  35. package/dist/commands/service.d.ts +7 -0
  36. package/dist/commands/service.js +378 -0
  37. package/dist/commands/setup.d.ts +1 -0
  38. package/dist/commands/setup.js +128 -0
  39. package/dist/commands/status.d.ts +5 -0
  40. package/dist/commands/status.js +87 -0
  41. package/dist/config.d.ts +83 -0
  42. package/dist/config.js +224 -0
  43. package/dist/connectors/cursor.d.ts +2 -0
  44. package/dist/connectors/cursor.js +28 -0
  45. package/dist/connectors/env.d.ts +2 -0
  46. package/dist/connectors/env.js +38 -0
  47. package/dist/connectors/index.d.ts +26 -0
  48. package/dist/connectors/index.js +30 -0
  49. package/dist/connectors/interface.d.ts +20 -0
  50. package/dist/connectors/interface.js +1 -0
  51. package/dist/connectors/openclaw.d.ts +2 -0
  52. package/dist/connectors/openclaw.js +202 -0
  53. package/dist/gate-discovery.d.ts +49 -0
  54. package/dist/gate-discovery.js +142 -0
  55. package/dist/index.d.ts +2 -0
  56. package/dist/index.js +177 -0
  57. package/dist/proxy.d.ts +11 -0
  58. package/dist/proxy.js +352 -0
  59. package/package.json +84 -0
@@ -0,0 +1,43 @@
1
+ /**
2
+ * t2c connect <app> - Connect to a specific AI tool
3
+ *
4
+ * Uses the connector system to integrate with various tools.
5
+ */
6
+ import { loadConfig, configExists, ConfigError } from "../config.js";
7
+ import { connectors, listConnectorIds, getConnector } from "../connectors/index.js";
8
+ export async function connectCommand(app) {
9
+ // If no app specified or empty, list available connectors
10
+ if (!app || app.trim() === "") {
11
+ console.log("\n🎟️ Token2Chat Connect\n");
12
+ console.log("Usage: t2c connect <app>\n");
13
+ console.log("Available connectors:\n");
14
+ for (const [id, connector] of connectors) {
15
+ const detected = await connector.detect();
16
+ const status = detected ? "✅" : "⚪";
17
+ const desc = connector.description ? ` - ${connector.description}` : "";
18
+ console.log(` ${status} ${id.padEnd(12)} ${connector.name}${desc}`);
19
+ }
20
+ console.log("\nExamples:\n");
21
+ console.log(" t2c connect openclaw # Configure OpenClaw integration");
22
+ console.log(" t2c connect env # Show environment variables");
23
+ console.log(" t2c connect cursor # Configure Cursor IDE\n");
24
+ return;
25
+ }
26
+ // Check if t2c is initialized
27
+ const hasConfig = await configExists();
28
+ if (!hasConfig) {
29
+ throw new ConfigError("Token2Chat not initialized. Run 't2c init' first to configure gate, mint, and wallet.", true // recoverable
30
+ );
31
+ }
32
+ // Load config
33
+ const config = await loadConfig();
34
+ // Find the connector
35
+ const connector = getConnector(app);
36
+ if (!connector) {
37
+ const available = listConnectorIds().join(", ");
38
+ throw new ConfigError(`Unknown connector: ${app}. Available connectors: ${available}. Run 't2c connect' to see all options.`, true // recoverable
39
+ );
40
+ }
41
+ // Run the connector
42
+ await connector.connect(config);
43
+ }
@@ -0,0 +1 @@
1
+ export declare function doctorCommand(): Promise<void>;
@@ -0,0 +1,178 @@
1
+ /**
2
+ * t2c doctor - Self-diagnostic command
3
+ */
4
+ import fs from "node:fs/promises";
5
+ import os from "node:os";
6
+ import path from "node:path";
7
+ import { loadConfig, configExists, checkGateHealth, checkMintHealth, CONFIG_PATH, WALLET_PATH, } from "../config.js";
8
+ import { CashuStore } from "../cashu-store.js";
9
+ // Platform-specific service paths
10
+ const LAUNCHD_PLIST_PATH = path.join(os.homedir(), "Library", "LaunchAgents", "com.token2chat.proxy.plist");
11
+ const SYSTEMD_UNIT_PATH = path.join(os.homedir(), ".config", "systemd", "user", "t2c-proxy.service");
12
+ async function checkConfig() {
13
+ const exists = await configExists();
14
+ if (exists) {
15
+ return {
16
+ name: "Config",
17
+ ok: true,
18
+ detail: CONFIG_PATH,
19
+ };
20
+ }
21
+ return {
22
+ name: "Config",
23
+ ok: false,
24
+ detail: "Not found",
25
+ fix: "run 't2c setup'",
26
+ };
27
+ }
28
+ async function checkWallet(config) {
29
+ try {
30
+ const wallet = await CashuStore.load(WALLET_PATH, config.mintUrl);
31
+ return {
32
+ name: "Wallet",
33
+ ok: true,
34
+ detail: `${WALLET_PATH} (${wallet.balance} sat)`,
35
+ };
36
+ }
37
+ catch (e) {
38
+ return {
39
+ name: "Wallet",
40
+ ok: false,
41
+ detail: "Not found or unreadable",
42
+ fix: "run 't2c setup'",
43
+ };
44
+ }
45
+ }
46
+ async function checkProxy(port) {
47
+ try {
48
+ const res = await fetch(`http://127.0.0.1:${port}/health`, {
49
+ signal: AbortSignal.timeout(2000),
50
+ });
51
+ if (res.ok) {
52
+ return {
53
+ name: "Proxy",
54
+ ok: true,
55
+ detail: `Running on :${port}`,
56
+ };
57
+ }
58
+ return {
59
+ name: "Proxy",
60
+ ok: false,
61
+ detail: `Port ${port} responded but health check failed`,
62
+ fix: "run 't2c service restart'",
63
+ };
64
+ }
65
+ catch {
66
+ return {
67
+ name: "Proxy",
68
+ ok: false,
69
+ detail: "Not running",
70
+ fix: "run 't2c service start'",
71
+ };
72
+ }
73
+ }
74
+ async function checkGate(url) {
75
+ const ok = await checkGateHealth(url);
76
+ return {
77
+ name: "Gate",
78
+ ok,
79
+ detail: `${url} (${ok ? "reachable" : "unreachable"})`,
80
+ ...(!ok && { fix: "check your internet connection" }),
81
+ };
82
+ }
83
+ async function checkMint(url) {
84
+ let ok = await checkMintHealth(url);
85
+ if (!ok) {
86
+ // Try alternate endpoint
87
+ try {
88
+ const res = await fetch(`${url}/info`, { signal: AbortSignal.timeout(5000) });
89
+ ok = res.ok;
90
+ }
91
+ catch {
92
+ // still unreachable
93
+ }
94
+ }
95
+ return {
96
+ name: "Mint",
97
+ ok,
98
+ detail: `${url} (${ok ? "reachable" : "unreachable"})`,
99
+ ...(!ok && { fix: "check your internet connection" }),
100
+ };
101
+ }
102
+ async function checkService() {
103
+ const platform = os.platform();
104
+ if (platform === "darwin") {
105
+ try {
106
+ await fs.access(LAUNCHD_PLIST_PATH);
107
+ return {
108
+ name: "Service",
109
+ ok: true,
110
+ detail: "Installed (launchd)",
111
+ };
112
+ }
113
+ catch {
114
+ return {
115
+ name: "Service",
116
+ ok: false,
117
+ detail: "Not installed",
118
+ fix: "run 't2c service install'",
119
+ };
120
+ }
121
+ }
122
+ else if (platform === "linux") {
123
+ try {
124
+ await fs.access(SYSTEMD_UNIT_PATH);
125
+ return {
126
+ name: "Service",
127
+ ok: true,
128
+ detail: "Installed (systemd)",
129
+ };
130
+ }
131
+ catch {
132
+ return {
133
+ name: "Service",
134
+ ok: false,
135
+ detail: "Not installed",
136
+ fix: "run 't2c service install'",
137
+ };
138
+ }
139
+ }
140
+ return {
141
+ name: "Service",
142
+ ok: false,
143
+ detail: `Unsupported platform (${platform})`,
144
+ };
145
+ }
146
+ export async function doctorCommand() {
147
+ console.log("\n🎟️ Token2Chat Doctor\n");
148
+ const config = await loadConfig();
149
+ // Run all checks
150
+ const results = await Promise.all([
151
+ checkConfig(),
152
+ checkWallet(config),
153
+ checkProxy(config.proxyPort),
154
+ checkGate(config.gateUrl),
155
+ checkMint(config.mintUrl),
156
+ checkService(),
157
+ ]);
158
+ // Print results
159
+ for (const result of results) {
160
+ const icon = result.ok ? "✅" : "❌";
161
+ console.log(`${icon} ${result.name.padEnd(10)} ${result.detail}`);
162
+ }
163
+ // Print fixes for failed checks
164
+ const failed = results.filter((r) => !r.ok && r.fix);
165
+ if (failed.length > 0) {
166
+ console.log("\n📋 Suggested fixes:\n");
167
+ for (const result of failed) {
168
+ console.log(` ${result.name}: ${result.fix}`);
169
+ }
170
+ }
171
+ const allOk = results.every((r) => r.ok);
172
+ if (allOk) {
173
+ console.log("\n✨ All systems operational!\n");
174
+ }
175
+ else {
176
+ console.log("");
177
+ }
178
+ }
@@ -0,0 +1,3 @@
1
+ export declare function initCommand(opts?: {
2
+ force?: boolean;
3
+ }): Promise<void>;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * t2c init - Core initialization command
3
+ *
4
+ * Uses sensible defaults for gate/mint/port/wallet.
5
+ * No interactive prompts — just validate connectivity and create wallet.
6
+ */
7
+ import { saveConfig, configExists, resolveHome, loadConfig, checkGateHealth, checkMintHealth, DEFAULT_CONFIG, } from "../config.js";
8
+ import { CashuStore } from "../cashu-store.js";
9
+ export async function initCommand(opts) {
10
+ console.log("\n🎟️ Token2Chat Init\n");
11
+ const hasConfig = await configExists();
12
+ if (hasConfig && !opts?.force) {
13
+ const existing = await loadConfig();
14
+ console.log("Already initialized.\n");
15
+ console.log(` Gate: ${existing.gateUrl}`);
16
+ console.log(` Mint: ${existing.mintUrl}`);
17
+ console.log(` Port: ${existing.proxyPort}`);
18
+ console.log(` Wallet: ${existing.walletPath}`);
19
+ console.log("\nRun 't2c init --force' to reinitialize.\n");
20
+ return;
21
+ }
22
+ const config = { ...DEFAULT_CONFIG };
23
+ // Check Gate connectivity
24
+ process.stdout.write(" Checking Gate... ");
25
+ const gateOk = await checkGateHealth(config.gateUrl);
26
+ console.log(gateOk ? "✅" : "❌ Unreachable (will retry on first use)");
27
+ // Check Mint connectivity
28
+ process.stdout.write(" Checking Mint... ");
29
+ const mintOk = await checkMintHealth(config.mintUrl);
30
+ console.log(mintOk ? "✅" : "❌ Unreachable (will retry on first use)");
31
+ // Save config
32
+ await saveConfig(config);
33
+ console.log("\n Config saved to ~/.t2c/config.json");
34
+ // Initialize wallet
35
+ try {
36
+ const resolvedPath = resolveHome(config.walletPath);
37
+ const wallet = await CashuStore.load(resolvedPath, config.mintUrl);
38
+ console.log(` Wallet initialized (balance: ${wallet.balance} sat)`);
39
+ }
40
+ catch (e) {
41
+ console.log(` ⚠️ Wallet init failed: ${e}`);
42
+ }
43
+ // Next steps
44
+ console.log("\n📋 Next steps:\n");
45
+ console.log(" 1. Connect to your AI tool:");
46
+ console.log(" t2c connect openclaw # For OpenClaw");
47
+ console.log(" t2c connect env # For other tools\n");
48
+ console.log(" 2. Add funds:");
49
+ console.log(" t2c mint\n");
50
+ }
@@ -0,0 +1,5 @@
1
+ interface MintOptions {
2
+ check?: boolean;
3
+ }
4
+ export declare function mintCommand(amount: string | undefined, opts: MintOptions): Promise<void>;
5
+ export {};
@@ -0,0 +1,168 @@
1
+ /**
2
+ * t2c mint - Add funds to wallet
3
+ */
4
+ import fs from "node:fs/promises";
5
+ import path from "node:path";
6
+ import { loadConfig, resolveHome, CONFIG_DIR } from "../config.js";
7
+ import { CashuStore } from "../cashu-store.js";
8
+ // Fallback deposit address (Mint's EVM address for USDC/USDT)
9
+ // This is used if /v1/info endpoint doesn't provide a deposit address
10
+ const FALLBACK_DEPOSIT_ADDRESS = "0xDC20821A78C4e1c586BE317e87A12f690E94E6c6";
11
+ const SUPPORTED_CHAINS = [
12
+ { name: "Ethereum", chainId: 1, tokens: ["USDC", "USDT"] },
13
+ { name: "Base", chainId: 8453, tokens: ["USDC", "USDT"] },
14
+ { name: "Arbitrum", chainId: 42161, tokens: ["USDC", "USDT"] },
15
+ { name: "BNB Chain", chainId: 56, tokens: ["USDC", "USDT"] },
16
+ ];
17
+ // Path to store pending quotes
18
+ const PENDING_QUOTES_PATH = path.join(CONFIG_DIR, "pending-quotes.json");
19
+ async function loadPendingQuotes() {
20
+ try {
21
+ const raw = await fs.readFile(PENDING_QUOTES_PATH, "utf-8");
22
+ return JSON.parse(raw);
23
+ }
24
+ catch {
25
+ return { quotes: [] };
26
+ }
27
+ }
28
+ async function savePendingQuotes(data) {
29
+ await fs.mkdir(CONFIG_DIR, { recursive: true, mode: 0o700 });
30
+ await fs.writeFile(PENDING_QUOTES_PATH, JSON.stringify(data, null, 2), { mode: 0o600 });
31
+ }
32
+ async function fetchDepositAddress(mintUrl) {
33
+ try {
34
+ const res = await fetch(`${mintUrl}/v1/info`, {
35
+ signal: AbortSignal.timeout(5000),
36
+ });
37
+ if (res.ok) {
38
+ const data = (await res.json());
39
+ if (data.deposit_address)
40
+ return data.deposit_address;
41
+ if (data.depositAddress)
42
+ return data.depositAddress;
43
+ }
44
+ }
45
+ catch {
46
+ // Fall through to default
47
+ }
48
+ return FALLBACK_DEPOSIT_ADDRESS;
49
+ }
50
+ export async function mintCommand(amount, opts) {
51
+ const config = await loadConfig();
52
+ const walletPath = resolveHome(config.walletPath);
53
+ let wallet;
54
+ try {
55
+ wallet = await CashuStore.load(walletPath, config.mintUrl);
56
+ }
57
+ catch (e) {
58
+ console.error(`Failed to load wallet: ${e}`);
59
+ console.error("Run 't2c setup' first.");
60
+ process.exit(1);
61
+ }
62
+ const currentBalance = wallet.balance;
63
+ console.log("\n🎟️ Token2Chat Funding\n");
64
+ console.log(`Current balance: ${currentBalance.toLocaleString()} sat\n`);
65
+ if (opts.check) {
66
+ // Check for pending Lightning quotes and mint paid ones
67
+ console.log("Checking pending Lightning quotes...\n");
68
+ const pendingData = await loadPendingQuotes();
69
+ if (pendingData.quotes.length === 0) {
70
+ console.log("No pending quotes found.");
71
+ console.log("Use 't2c mint <amount>' to create a Lightning invoice.\n");
72
+ return;
73
+ }
74
+ let mintedTotal = 0;
75
+ const stillPending = [];
76
+ const expired = [];
77
+ const now = Date.now();
78
+ const QUOTE_TTL_MS = 60 * 60 * 1000; // 1 hour
79
+ for (const pq of pendingData.quotes) {
80
+ // Skip expired quotes (older than 1 hour)
81
+ if (now - pq.createdAt > QUOTE_TTL_MS) {
82
+ expired.push(pq);
83
+ continue;
84
+ }
85
+ try {
86
+ const minted = await wallet.mintFromQuote(pq.quote, pq.amount);
87
+ console.log(`✅ Minted ${minted.toLocaleString()} sat from quote ${pq.quote.slice(0, 8)}...`);
88
+ mintedTotal += minted;
89
+ }
90
+ catch (e) {
91
+ const errMsg = e instanceof Error ? e.message : String(e);
92
+ if (errMsg.includes("not paid") || errMsg.includes("UNPAID")) {
93
+ stillPending.push(pq);
94
+ }
95
+ else if (errMsg.includes("ISSUED") || errMsg.includes("already")) {
96
+ // Already minted, skip
97
+ console.log(`ℹ️ Quote ${pq.quote.slice(0, 8)}... already processed`);
98
+ }
99
+ else {
100
+ console.warn(`⚠️ Error checking quote ${pq.quote.slice(0, 8)}...: ${errMsg}`);
101
+ stillPending.push(pq);
102
+ }
103
+ }
104
+ }
105
+ // Update pending quotes file
106
+ await savePendingQuotes({ quotes: stillPending });
107
+ if (mintedTotal > 0) {
108
+ console.log(`\n🎉 Total minted: ${mintedTotal.toLocaleString()} sat`);
109
+ console.log(`New balance: ${wallet.balance.toLocaleString()} sat\n`);
110
+ }
111
+ else if (stillPending.length > 0) {
112
+ console.log(`\n${stillPending.length} quote(s) still awaiting payment.`);
113
+ console.log("Pay the Lightning invoice and run 't2c mint --check' again.\n");
114
+ }
115
+ else {
116
+ console.log("No paid quotes found.\n");
117
+ }
118
+ if (expired.length > 0) {
119
+ console.log(`ℹ️ ${expired.length} expired quote(s) removed.\n`);
120
+ }
121
+ return;
122
+ }
123
+ // Lightning funding (if amount specified)
124
+ if (amount) {
125
+ const sats = parseInt(amount, 10);
126
+ if (isNaN(sats) || sats <= 0) {
127
+ console.error("Invalid amount. Specify sats to fund via Lightning.");
128
+ process.exit(1);
129
+ }
130
+ console.log(`⚡ Creating Lightning invoice for ${sats.toLocaleString()} sat...\n`);
131
+ try {
132
+ const quote = await wallet.createMintQuote(sats);
133
+ // Save to pending quotes
134
+ const pendingData = await loadPendingQuotes();
135
+ pendingData.quotes.push({
136
+ quote: quote.quote,
137
+ amount: sats,
138
+ request: quote.request,
139
+ createdAt: Date.now(),
140
+ });
141
+ await savePendingQuotes(pendingData);
142
+ console.log("Pay this Lightning invoice:\n");
143
+ console.log(` ${quote.request}\n`);
144
+ console.log(`Quote ID: ${quote.quote}`);
145
+ console.log("\nAfter paying, run 't2c mint --check' to mint your tokens.\n");
146
+ }
147
+ catch (e) {
148
+ console.error(`Failed to create Lightning invoice: ${e}`);
149
+ process.exit(1);
150
+ }
151
+ return;
152
+ }
153
+ // Show deposit instructions (EVM stablecoins)
154
+ const depositAddress = await fetchDepositAddress(config.mintUrl);
155
+ console.log("Option 1: Lightning (recommended)\n");
156
+ console.log(" t2c mint <amount_sats> Create a Lightning invoice\n");
157
+ console.log("Option 2: EVM Stablecoins\n");
158
+ console.log(" Send USDC or USDT to:\n");
159
+ console.log(` ${depositAddress}\n`);
160
+ console.log(" Supported chains:");
161
+ for (const chain of SUPPORTED_CHAINS) {
162
+ console.log(` • ${chain.name} (${chain.tokens.join(", ")})`);
163
+ }
164
+ console.log("\n💡 Tips:");
165
+ console.log(" • Lightning deposits are instant");
166
+ console.log(" • EVM deposits: ~1 sat per $0.001 USD");
167
+ console.log(" • Minimum deposit: $1 USD or 1000 sat\n");
168
+ }
@@ -0,0 +1 @@
1
+ export declare function recoverCommand(): Promise<void>;
@@ -0,0 +1,61 @@
1
+ /**
2
+ * t2c recover - Recover failed tokens
3
+ */
4
+ import { loadConfig, resolveHome, FAILED_TOKENS_PATH, loadFailedTokens, saveFailedTokens, } from "../config.js";
5
+ import { CashuStore } from "../cashu-store.js";
6
+ export async function recoverCommand() {
7
+ const config = await loadConfig();
8
+ const walletPath = resolveHome(config.walletPath);
9
+ console.log("\n🔧 Token Recovery\n");
10
+ const failedData = await loadFailedTokens();
11
+ if (failedData.tokens.length === 0) {
12
+ console.log("No failed tokens to recover. ✨\n");
13
+ return;
14
+ }
15
+ console.log(`Found ${failedData.tokens.length} failed token(s) to recover.\n`);
16
+ let wallet;
17
+ try {
18
+ wallet = await CashuStore.load(walletPath, config.mintUrl);
19
+ }
20
+ catch (e) {
21
+ console.error(`Failed to load wallet: ${e}`);
22
+ console.error("Run 't2c setup' first.");
23
+ process.exit(1);
24
+ }
25
+ const stillFailed = [];
26
+ let recoveredTotal = 0;
27
+ for (const ft of failedData.tokens) {
28
+ const shortToken = ft.token.slice(0, 20) + "...";
29
+ const date = new Date(ft.timestamp).toLocaleString();
30
+ console.log(`Attempting to recover ${ft.type} token from ${date}...`);
31
+ try {
32
+ const amount = await wallet.receiveToken(ft.token);
33
+ console.log(` ✅ Recovered ${amount} sat\n`);
34
+ recoveredTotal += amount;
35
+ }
36
+ catch (e) {
37
+ const errMsg = e instanceof Error ? e.message : String(e);
38
+ console.log(` ❌ Failed: ${errMsg}\n`);
39
+ stillFailed.push({
40
+ ...ft,
41
+ error: errMsg,
42
+ timestamp: Date.now(),
43
+ });
44
+ }
45
+ }
46
+ // Save remaining failed tokens
47
+ await saveFailedTokens({ tokens: stillFailed });
48
+ console.log("─".repeat(40));
49
+ if (recoveredTotal > 0) {
50
+ console.log(`\n🎉 Recovered total: ${recoveredTotal.toLocaleString()} sat`);
51
+ console.log(`New wallet balance: ${wallet.balance.toLocaleString()} sat\n`);
52
+ }
53
+ if (stillFailed.length > 0) {
54
+ console.log(`\n⚠️ ${stillFailed.length} token(s) still failed.`);
55
+ console.log(` Saved to: ${FAILED_TOKENS_PATH}`);
56
+ console.log(" You can manually import these tokens or contact support.\n");
57
+ }
58
+ else if (recoveredTotal > 0) {
59
+ console.log("All tokens recovered successfully! ✨\n");
60
+ }
61
+ }
@@ -0,0 +1,7 @@
1
+ interface ServiceOptions {
2
+ foreground?: boolean;
3
+ follow?: boolean;
4
+ lines?: string;
5
+ }
6
+ export declare function serviceCommand(action: "start" | "stop" | "restart" | "logs" | "install" | "uninstall" | "status", opts: ServiceOptions): Promise<void>;
7
+ export {};