tether-name-cli 1.0.0
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 +111 -0
- package/dist/cli.js +396 -0
- package/dist/cli.js.map +1 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# tether-name-cli
|
|
2
|
+
|
|
3
|
+
CLI for [tether.name](https://tether.name) — AI agent identity verification.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g tether-name-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Requires Node.js >= 18.
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Interactive setup — configure credentials and generate a keypair
|
|
17
|
+
tether init
|
|
18
|
+
|
|
19
|
+
# Verify your agent identity
|
|
20
|
+
tether verify
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Commands
|
|
24
|
+
|
|
25
|
+
### `tether init`
|
|
26
|
+
|
|
27
|
+
Interactive setup wizard. Walks you through:
|
|
28
|
+
|
|
29
|
+
1. Entering your credential ID (or reads `TETHER_CREDENTIAL_ID`)
|
|
30
|
+
2. Providing a private key path (or reads `TETHER_PRIVATE_KEY_PATH`)
|
|
31
|
+
3. Optionally generating a new RSA-2048 keypair
|
|
32
|
+
|
|
33
|
+
Saves configuration to `~/.tether/config.json`.
|
|
34
|
+
|
|
35
|
+
### `tether verify`
|
|
36
|
+
|
|
37
|
+
Performs a full verification cycle:
|
|
38
|
+
|
|
39
|
+
1. Requests a challenge from the Tether API
|
|
40
|
+
2. Signs it with your private key
|
|
41
|
+
3. Submits proof and displays the result
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
tether verify
|
|
45
|
+
tether verify --json # Machine-readable output
|
|
46
|
+
tether verify --verbose # Debug output
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### `tether status`
|
|
50
|
+
|
|
51
|
+
Shows current configuration — credential ID (masked), key file path, and API URL.
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
tether status
|
|
55
|
+
tether status --json
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### `tether challenge`
|
|
59
|
+
|
|
60
|
+
Request a challenge code from the API and print it.
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
tether challenge
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### `tether sign <challenge>`
|
|
67
|
+
|
|
68
|
+
Sign a challenge string with your private key and print the proof.
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
tether sign abc123
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### `tether check <code>`
|
|
75
|
+
|
|
76
|
+
Check the status of a challenge by its code.
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
tether check abc123
|
|
80
|
+
tether check abc123 --json
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Configuration
|
|
84
|
+
|
|
85
|
+
Config is resolved in this order (first match wins):
|
|
86
|
+
|
|
87
|
+
1. **CLI flags** — `--credential-id`, `--key-path`, `--api-url`
|
|
88
|
+
2. **Environment variables** — `TETHER_CREDENTIAL_ID`, `TETHER_PRIVATE_KEY_PATH`, `TETHER_API_URL`
|
|
89
|
+
3. **Config file** — `~/.tether/config.json`
|
|
90
|
+
|
|
91
|
+
### Environment Variables
|
|
92
|
+
|
|
93
|
+
| Variable | Description |
|
|
94
|
+
|---|---|
|
|
95
|
+
| `TETHER_CREDENTIAL_ID` | Your agent credential ID |
|
|
96
|
+
| `TETHER_PRIVATE_KEY_PATH` | Path to your private key file |
|
|
97
|
+
| `TETHER_API_URL` | API base URL (default: `https://api.tether.name`) |
|
|
98
|
+
|
|
99
|
+
## Development
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
git clone https://github.com/tether-name/tether-name-cli.git
|
|
103
|
+
cd tether-name-cli
|
|
104
|
+
npm install
|
|
105
|
+
npm run build
|
|
106
|
+
npm test
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## License
|
|
110
|
+
|
|
111
|
+
MIT
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cli.ts
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import chalk4 from "chalk";
|
|
6
|
+
|
|
7
|
+
// src/utils/display.ts
|
|
8
|
+
import chalk from "chalk";
|
|
9
|
+
function maskId(id) {
|
|
10
|
+
if (id.length <= 4) return id;
|
|
11
|
+
return "\u2022\u2022\u2022\u2022" + id.slice(-4);
|
|
12
|
+
}
|
|
13
|
+
function printVerifyResult(result) {
|
|
14
|
+
const width = 48;
|
|
15
|
+
const hr = "\u2500".repeat(width);
|
|
16
|
+
console.log();
|
|
17
|
+
if (result.verified) {
|
|
18
|
+
console.log(chalk.green("\u250C" + hr + "\u2510"));
|
|
19
|
+
console.log(chalk.green("\u2502") + center(chalk.green.bold("\u2713 Identity Verified"), width, 19) + chalk.green("\u2502"));
|
|
20
|
+
console.log(chalk.green("\u251C" + hr + "\u2524"));
|
|
21
|
+
if (result.agentName) {
|
|
22
|
+
console.log(chalk.green("\u2502") + padLine(` Agent: ${result.agentName}`, width) + chalk.green("\u2502"));
|
|
23
|
+
}
|
|
24
|
+
if (result.verifyUrl) {
|
|
25
|
+
console.log(chalk.green("\u2502") + padLine(` URL: ${result.verifyUrl}`, width) + chalk.green("\u2502"));
|
|
26
|
+
}
|
|
27
|
+
if (result.registeredSince) {
|
|
28
|
+
const date = formatDate(result.registeredSince);
|
|
29
|
+
console.log(chalk.green("\u2502") + padLine(` Since: ${date}`, width) + chalk.green("\u2502"));
|
|
30
|
+
}
|
|
31
|
+
console.log(chalk.green("\u2514" + hr + "\u2518"));
|
|
32
|
+
} else {
|
|
33
|
+
console.log(chalk.red("\u250C" + hr + "\u2510"));
|
|
34
|
+
console.log(chalk.red("\u2502") + center(chalk.red.bold("\u2717 Verification Failed"), width, 21) + chalk.red("\u2502"));
|
|
35
|
+
console.log(chalk.red("\u251C" + hr + "\u2524"));
|
|
36
|
+
if (result.error) {
|
|
37
|
+
console.log(chalk.red("\u2502") + padLine(` ${result.error}`, width) + chalk.red("\u2502"));
|
|
38
|
+
}
|
|
39
|
+
console.log(chalk.red("\u2514" + hr + "\u2518"));
|
|
40
|
+
}
|
|
41
|
+
console.log();
|
|
42
|
+
}
|
|
43
|
+
function printVerifyResultJSON(result) {
|
|
44
|
+
console.log(JSON.stringify(result, null, 2));
|
|
45
|
+
}
|
|
46
|
+
function printStatus(config, keyExists) {
|
|
47
|
+
console.log();
|
|
48
|
+
console.log(chalk.bold(" Tether Configuration"));
|
|
49
|
+
console.log(chalk.dim(" " + "\u2500".repeat(30)));
|
|
50
|
+
console.log(` Credential: ${config.credentialId ? maskId(config.credentialId) : chalk.dim("(not set)")}`);
|
|
51
|
+
console.log(` Key path: ${config.keyPath || chalk.dim("(not set)")}`);
|
|
52
|
+
if (config.keyPath) {
|
|
53
|
+
console.log(` Key exists: ${keyExists ? chalk.green("yes") : chalk.red("no")}`);
|
|
54
|
+
}
|
|
55
|
+
console.log(` API URL: ${config.apiUrl}`);
|
|
56
|
+
console.log();
|
|
57
|
+
}
|
|
58
|
+
function printStatusJSON(config, keyExists) {
|
|
59
|
+
console.log(JSON.stringify({
|
|
60
|
+
credentialId: config.credentialId ? maskId(config.credentialId) : null,
|
|
61
|
+
keyPath: config.keyPath || null,
|
|
62
|
+
keyExists,
|
|
63
|
+
apiUrl: config.apiUrl
|
|
64
|
+
}, null, 2));
|
|
65
|
+
}
|
|
66
|
+
function printError(message) {
|
|
67
|
+
console.error(chalk.red(`Error: ${message}`));
|
|
68
|
+
}
|
|
69
|
+
function printVerbose(message, verbose) {
|
|
70
|
+
if (verbose) {
|
|
71
|
+
console.error(chalk.dim(`[debug] ${message}`));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
var BANNER = `
|
|
75
|
+
\u2554\u2566\u2557\u2554\u2550\u2557\u2554\u2566\u2557\u2566 \u2566\u2554\u2550\u2557\u2566\u2550\u2557
|
|
76
|
+
\u2551 \u2551\u2563 \u2551 \u2560\u2550\u2563\u2551\u2563 \u2560\u2566\u255D
|
|
77
|
+
\u2569 \u255A\u2550\u255D \u2569 \u2569 \u2569\u255A\u2550\u255D\u2569\u255A\u2550
|
|
78
|
+
`;
|
|
79
|
+
function padLine(text, width) {
|
|
80
|
+
const visible = stripAnsi(text);
|
|
81
|
+
const pad = width - visible.length;
|
|
82
|
+
return text + " ".repeat(Math.max(0, pad));
|
|
83
|
+
}
|
|
84
|
+
function center(text, width, visibleLength) {
|
|
85
|
+
const leftPad = Math.floor((width - visibleLength) / 2);
|
|
86
|
+
const rightPad = width - visibleLength - leftPad;
|
|
87
|
+
return " ".repeat(leftPad) + text + " ".repeat(rightPad);
|
|
88
|
+
}
|
|
89
|
+
function stripAnsi(str) {
|
|
90
|
+
return str.replace(/\x1b\[[0-9;]*m/g, "");
|
|
91
|
+
}
|
|
92
|
+
function formatDate(iso) {
|
|
93
|
+
try {
|
|
94
|
+
return new Date(iso).toLocaleDateString("en-US", {
|
|
95
|
+
year: "numeric",
|
|
96
|
+
month: "long",
|
|
97
|
+
day: "numeric"
|
|
98
|
+
});
|
|
99
|
+
} catch {
|
|
100
|
+
return iso;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// src/commands/init.ts
|
|
105
|
+
import { createInterface } from "readline";
|
|
106
|
+
import { generateKeyPairSync } from "crypto";
|
|
107
|
+
import { writeFileSync as writeFileSync2, existsSync as existsSync2 } from "fs";
|
|
108
|
+
import { resolve } from "path";
|
|
109
|
+
import chalk2 from "chalk";
|
|
110
|
+
|
|
111
|
+
// src/config.ts
|
|
112
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
113
|
+
import { join } from "path";
|
|
114
|
+
import { homedir } from "os";
|
|
115
|
+
var CONFIG_DIR = join(homedir(), ".tether");
|
|
116
|
+
var CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
117
|
+
var DEFAULT_API_URL = "https://api.tether.name";
|
|
118
|
+
function getConfigPath() {
|
|
119
|
+
return CONFIG_FILE;
|
|
120
|
+
}
|
|
121
|
+
function loadConfigFile() {
|
|
122
|
+
try {
|
|
123
|
+
if (!existsSync(CONFIG_FILE)) {
|
|
124
|
+
return {};
|
|
125
|
+
}
|
|
126
|
+
const raw = readFileSync(CONFIG_FILE, "utf-8");
|
|
127
|
+
return JSON.parse(raw);
|
|
128
|
+
} catch {
|
|
129
|
+
return {};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function saveConfig(config) {
|
|
133
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
134
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
135
|
+
}
|
|
136
|
+
function resolveConfig(flags = {}) {
|
|
137
|
+
const file = loadConfigFile();
|
|
138
|
+
return {
|
|
139
|
+
credentialId: flags.credentialId || process.env.TETHER_CREDENTIAL_ID || file.credentialId || "",
|
|
140
|
+
keyPath: flags.keyPath || process.env.TETHER_PRIVATE_KEY_PATH || file.keyPath || "",
|
|
141
|
+
apiUrl: flags.apiUrl || process.env.TETHER_API_URL || file.apiUrl || DEFAULT_API_URL
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// src/commands/init.ts
|
|
146
|
+
function prompt(rl, question) {
|
|
147
|
+
return new Promise((resolve2) => {
|
|
148
|
+
rl.question(question, (answer) => resolve2(answer.trim()));
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
async function initCommand(opts) {
|
|
152
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
153
|
+
try {
|
|
154
|
+
console.log();
|
|
155
|
+
console.log(chalk2.bold(" Tether Setup"));
|
|
156
|
+
console.log(chalk2.dim(" " + "\u2500".repeat(30)));
|
|
157
|
+
console.log();
|
|
158
|
+
const envCredential = process.env.TETHER_CREDENTIAL_ID;
|
|
159
|
+
let credentialId;
|
|
160
|
+
if (envCredential) {
|
|
161
|
+
console.log(chalk2.dim(` Using TETHER_CREDENTIAL_ID from environment`));
|
|
162
|
+
credentialId = envCredential;
|
|
163
|
+
} else {
|
|
164
|
+
credentialId = await prompt(rl, " Credential ID: ");
|
|
165
|
+
}
|
|
166
|
+
if (!credentialId) {
|
|
167
|
+
console.log(chalk2.red("\n Credential ID is required."));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const envKeyPath = process.env.TETHER_PRIVATE_KEY_PATH;
|
|
171
|
+
let keyPath;
|
|
172
|
+
if (envKeyPath) {
|
|
173
|
+
console.log(chalk2.dim(` Using TETHER_PRIVATE_KEY_PATH from environment`));
|
|
174
|
+
keyPath = envKeyPath;
|
|
175
|
+
} else {
|
|
176
|
+
const genAnswer = await prompt(rl, " Generate a new RSA keypair? (y/N): ");
|
|
177
|
+
if (genAnswer.toLowerCase() === "y") {
|
|
178
|
+
keyPath = await generateKeypair(opts.verbose);
|
|
179
|
+
} else {
|
|
180
|
+
keyPath = await prompt(rl, " Path to private key: ");
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (!keyPath) {
|
|
184
|
+
console.log(chalk2.red("\n Private key path is required."));
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
keyPath = resolve(keyPath);
|
|
188
|
+
if (!existsSync2(keyPath)) {
|
|
189
|
+
console.log(chalk2.yellow(`
|
|
190
|
+
Warning: Key file not found at ${keyPath}`));
|
|
191
|
+
}
|
|
192
|
+
saveConfig({ credentialId, keyPath });
|
|
193
|
+
console.log();
|
|
194
|
+
console.log(chalk2.green(" \u2713 Configuration saved to " + getConfigPath()));
|
|
195
|
+
console.log();
|
|
196
|
+
} finally {
|
|
197
|
+
rl.close();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function generateKeypair(verbose) {
|
|
201
|
+
const privatePath = resolve(".tether-private-key.pem");
|
|
202
|
+
const publicPath = resolve(".tether-public-key.pem");
|
|
203
|
+
if (verbose) {
|
|
204
|
+
console.log(chalk2.dim(` [debug] Generating RSA-2048 keypair...`));
|
|
205
|
+
}
|
|
206
|
+
const { publicKey, privateKey } = generateKeyPairSync("rsa", {
|
|
207
|
+
modulusLength: 2048,
|
|
208
|
+
publicKeyEncoding: { type: "spki", format: "pem" },
|
|
209
|
+
privateKeyEncoding: { type: "pkcs1", format: "pem" }
|
|
210
|
+
});
|
|
211
|
+
writeFileSync2(privatePath, privateKey, { mode: 384 });
|
|
212
|
+
writeFileSync2(publicPath, publicKey);
|
|
213
|
+
console.log(chalk2.green(` \u2713 Private key: ${privatePath}`));
|
|
214
|
+
console.log(chalk2.green(` \u2713 Public key: ${publicPath}`));
|
|
215
|
+
console.log();
|
|
216
|
+
console.log(chalk2.dim(" Upload the public key to tether.name to complete registration."));
|
|
217
|
+
return privatePath;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// src/commands/verify.ts
|
|
221
|
+
import { TetherClient } from "tether-name";
|
|
222
|
+
async function verifyCommand(opts) {
|
|
223
|
+
const config = resolveConfig(opts);
|
|
224
|
+
if (!config.credentialId) {
|
|
225
|
+
printError('No credential ID configured. Run "tether init" or set TETHER_CREDENTIAL_ID.');
|
|
226
|
+
process.exitCode = 1;
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
if (!config.keyPath) {
|
|
230
|
+
printError('No private key path configured. Run "tether init" or set TETHER_PRIVATE_KEY_PATH.');
|
|
231
|
+
process.exitCode = 1;
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const verbose = opts.verbose ?? false;
|
|
235
|
+
try {
|
|
236
|
+
printVerbose(`Credential ID: ${config.credentialId}`, verbose);
|
|
237
|
+
printVerbose(`Key path: ${config.keyPath}`, verbose);
|
|
238
|
+
printVerbose(`API URL: ${config.apiUrl}`, verbose);
|
|
239
|
+
const client = new TetherClient({
|
|
240
|
+
credentialId: config.credentialId,
|
|
241
|
+
privateKeyPath: config.keyPath,
|
|
242
|
+
baseUrl: config.apiUrl
|
|
243
|
+
});
|
|
244
|
+
printVerbose("Requesting challenge...", verbose);
|
|
245
|
+
const challenge = await client.requestChallenge();
|
|
246
|
+
printVerbose(`Challenge: ${challenge}`, verbose);
|
|
247
|
+
printVerbose("Signing challenge...", verbose);
|
|
248
|
+
const proof = client.sign(challenge);
|
|
249
|
+
printVerbose(`Proof: ${proof.slice(0, 32)}...`, verbose);
|
|
250
|
+
printVerbose("Submitting proof...", verbose);
|
|
251
|
+
const result = await client.submitProof(challenge, proof);
|
|
252
|
+
if (opts.json) {
|
|
253
|
+
printVerifyResultJSON(result);
|
|
254
|
+
} else {
|
|
255
|
+
printVerifyResult(result);
|
|
256
|
+
}
|
|
257
|
+
if (!result.verified) {
|
|
258
|
+
process.exitCode = 1;
|
|
259
|
+
}
|
|
260
|
+
} catch (err) {
|
|
261
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
262
|
+
if (opts.json) {
|
|
263
|
+
console.log(JSON.stringify({ verified: false, error: message }, null, 2));
|
|
264
|
+
} else {
|
|
265
|
+
printError(message);
|
|
266
|
+
}
|
|
267
|
+
process.exitCode = 1;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// src/commands/status.ts
|
|
272
|
+
import { existsSync as existsSync3 } from "fs";
|
|
273
|
+
function statusCommand(opts) {
|
|
274
|
+
const config = resolveConfig(opts);
|
|
275
|
+
const keyExists = config.keyPath ? existsSync3(config.keyPath) : false;
|
|
276
|
+
if (opts.json) {
|
|
277
|
+
printStatusJSON(config, keyExists);
|
|
278
|
+
} else {
|
|
279
|
+
printStatus(config, keyExists);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// src/commands/challenge.ts
|
|
284
|
+
import { TetherClient as TetherClient2 } from "tether-name";
|
|
285
|
+
async function challengeCommand(opts) {
|
|
286
|
+
const config = resolveConfig(opts);
|
|
287
|
+
if (!config.credentialId) {
|
|
288
|
+
printError('No credential ID configured. Run "tether init" or set TETHER_CREDENTIAL_ID.');
|
|
289
|
+
process.exitCode = 1;
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
if (!config.keyPath) {
|
|
293
|
+
printError('No private key path configured. Run "tether init" or set TETHER_PRIVATE_KEY_PATH.');
|
|
294
|
+
process.exitCode = 1;
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
try {
|
|
298
|
+
printVerbose(`API URL: ${config.apiUrl}`, opts.verbose ?? false);
|
|
299
|
+
const client = new TetherClient2({
|
|
300
|
+
credentialId: config.credentialId,
|
|
301
|
+
privateKeyPath: config.keyPath,
|
|
302
|
+
baseUrl: config.apiUrl
|
|
303
|
+
});
|
|
304
|
+
const code = await client.requestChallenge();
|
|
305
|
+
console.log(code);
|
|
306
|
+
} catch (err) {
|
|
307
|
+
printError(err instanceof Error ? err.message : String(err));
|
|
308
|
+
process.exitCode = 1;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// src/commands/sign.ts
|
|
313
|
+
import { loadPrivateKey, signChallenge } from "tether-name";
|
|
314
|
+
function signCommand(challenge, opts) {
|
|
315
|
+
const config = resolveConfig(opts);
|
|
316
|
+
if (!config.keyPath) {
|
|
317
|
+
printError('No private key path configured. Run "tether init" or set TETHER_PRIVATE_KEY_PATH.');
|
|
318
|
+
process.exitCode = 1;
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
try {
|
|
322
|
+
printVerbose(`Key path: ${config.keyPath}`, opts.verbose ?? false);
|
|
323
|
+
const privateKey = loadPrivateKey({ keyPath: config.keyPath });
|
|
324
|
+
const proof = signChallenge(privateKey, challenge);
|
|
325
|
+
console.log(proof);
|
|
326
|
+
} catch (err) {
|
|
327
|
+
printError(err instanceof Error ? err.message : String(err));
|
|
328
|
+
process.exitCode = 1;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// src/commands/check.ts
|
|
333
|
+
import chalk3 from "chalk";
|
|
334
|
+
async function checkCommand(code, opts) {
|
|
335
|
+
const config = resolveConfig(opts);
|
|
336
|
+
const baseUrl = config.apiUrl;
|
|
337
|
+
const verbose = opts.verbose ?? false;
|
|
338
|
+
try {
|
|
339
|
+
const url = `${baseUrl}/challenge/${encodeURIComponent(code)}`;
|
|
340
|
+
printVerbose(`GET ${url}`, verbose);
|
|
341
|
+
const response = await fetch(url, {
|
|
342
|
+
headers: { "Accept": "application/json" }
|
|
343
|
+
});
|
|
344
|
+
if (!response.ok) {
|
|
345
|
+
const text = await response.text().catch(() => "");
|
|
346
|
+
printError(`API returned ${response.status}: ${text || response.statusText}`);
|
|
347
|
+
process.exitCode = 1;
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
const data = await response.json();
|
|
351
|
+
if (opts.json) {
|
|
352
|
+
console.log(JSON.stringify(data, null, 2));
|
|
353
|
+
} else {
|
|
354
|
+
console.log();
|
|
355
|
+
console.log(chalk3.bold(" Challenge Status"));
|
|
356
|
+
console.log(chalk3.dim(" " + "\u2500".repeat(30)));
|
|
357
|
+
console.log(` Code: ${data.code}`);
|
|
358
|
+
console.log(` Status: ${data.status}`);
|
|
359
|
+
if (data.createdAt) {
|
|
360
|
+
console.log(` Created: ${data.createdAt}`);
|
|
361
|
+
}
|
|
362
|
+
if (data.verifiedAt) {
|
|
363
|
+
console.log(` Verified: ${data.verifiedAt}`);
|
|
364
|
+
}
|
|
365
|
+
console.log();
|
|
366
|
+
}
|
|
367
|
+
} catch (err) {
|
|
368
|
+
printError(err instanceof Error ? err.message : String(err));
|
|
369
|
+
process.exitCode = 1;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// src/cli.ts
|
|
374
|
+
var VERSION = "0.1.0";
|
|
375
|
+
var program = new Command();
|
|
376
|
+
program.name("tether").description("CLI for tether.name \u2014 AI agent identity verification").version(chalk4.cyan(BANNER) + ` v${VERSION}
|
|
377
|
+
`, "-v, --version", "Show version");
|
|
378
|
+
var addGlobalOpts = (cmd) => cmd.option("--credential-id <id>", "Credential ID").option("--key-path <path>", "Path to private key file").option("--api-url <url>", "Tether API base URL").option("--verbose", "Enable debug output");
|
|
379
|
+
program.command("init").description("Interactive setup wizard").option("--verbose", "Enable debug output").action((opts) => initCommand(opts));
|
|
380
|
+
addGlobalOpts(
|
|
381
|
+
program.command("verify").description("Perform a full identity verification").option("--json", "Output result as JSON")
|
|
382
|
+
).action((opts) => verifyCommand(opts));
|
|
383
|
+
addGlobalOpts(
|
|
384
|
+
program.command("status").description("Show current configuration").option("--json", "Output result as JSON")
|
|
385
|
+
).action((opts) => statusCommand(opts));
|
|
386
|
+
addGlobalOpts(
|
|
387
|
+
program.command("challenge").description("Request a challenge code from the API")
|
|
388
|
+
).action((opts) => challengeCommand(opts));
|
|
389
|
+
addGlobalOpts(
|
|
390
|
+
program.command("sign <challenge>").description("Sign a challenge string and print the proof")
|
|
391
|
+
).action((challenge, opts) => signCommand(challenge, opts));
|
|
392
|
+
addGlobalOpts(
|
|
393
|
+
program.command("check <code>").description("Check the status of a challenge by code").option("--json", "Output result as JSON")
|
|
394
|
+
).action((code, opts) => checkCommand(code, opts));
|
|
395
|
+
program.parse();
|
|
396
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/utils/display.ts","../src/commands/init.ts","../src/config.ts","../src/commands/verify.ts","../src/commands/status.ts","../src/commands/challenge.ts","../src/commands/sign.ts","../src/commands/check.ts"],"sourcesContent":["import { Command } from 'commander';\nimport chalk from 'chalk';\nimport { BANNER } from './utils/display.js';\nimport { initCommand } from './commands/init.js';\nimport { verifyCommand } from './commands/verify.js';\nimport { statusCommand } from './commands/status.js';\nimport { challengeCommand } from './commands/challenge.js';\nimport { signCommand } from './commands/sign.js';\nimport { checkCommand } from './commands/check.js';\n\nconst VERSION = '0.1.0';\n\nconst program = new Command();\n\nprogram\n .name('tether')\n .description('CLI for tether.name — AI agent identity verification')\n .version(chalk.cyan(BANNER) + ` v${VERSION}\\n`, '-v, --version', 'Show version');\n\n// Global options\nconst addGlobalOpts = (cmd: Command): Command =>\n cmd\n .option('--credential-id <id>', 'Credential ID')\n .option('--key-path <path>', 'Path to private key file')\n .option('--api-url <url>', 'Tether API base URL')\n .option('--verbose', 'Enable debug output');\n\n// tether init\nprogram\n .command('init')\n .description('Interactive setup wizard')\n .option('--verbose', 'Enable debug output')\n .action((opts) => initCommand(opts));\n\n// tether verify\naddGlobalOpts(\n program\n .command('verify')\n .description('Perform a full identity verification')\n .option('--json', 'Output result as JSON'),\n).action((opts) => verifyCommand(opts));\n\n// tether status\naddGlobalOpts(\n program\n .command('status')\n .description('Show current configuration')\n .option('--json', 'Output result as JSON'),\n).action((opts) => statusCommand(opts));\n\n// tether challenge\naddGlobalOpts(\n program\n .command('challenge')\n .description('Request a challenge code from the API'),\n).action((opts) => challengeCommand(opts));\n\n// tether sign <challenge>\naddGlobalOpts(\n program\n .command('sign <challenge>')\n .description('Sign a challenge string and print the proof'),\n).action((challenge, opts) => signCommand(challenge, opts));\n\n// tether check <code>\naddGlobalOpts(\n program\n .command('check <code>')\n .description('Check the status of a challenge by code')\n .option('--json', 'Output result as JSON'),\n).action((code, opts) => checkCommand(code, opts));\n\nprogram.parse();\n","import chalk from 'chalk';\nimport type { VerificationResult } from 'tether-name';\nimport type { TetherConfig } from '../config.js';\n\nexport function maskId(id: string): string {\n if (id.length <= 4) return id;\n return '••••' + id.slice(-4);\n}\n\nexport function printVerifyResult(result: VerificationResult): void {\n const width = 48;\n const hr = '─'.repeat(width);\n\n console.log();\n if (result.verified) {\n console.log(chalk.green('┌' + hr + '┐'));\n console.log(chalk.green('│') + center(chalk.green.bold('✓ Identity Verified'), width, 19) + chalk.green('│'));\n console.log(chalk.green('├' + hr + '┤'));\n\n if (result.agentName) {\n console.log(chalk.green('│') + padLine(` Agent: ${result.agentName}`, width) + chalk.green('│'));\n }\n if (result.verifyUrl) {\n console.log(chalk.green('│') + padLine(` URL: ${result.verifyUrl}`, width) + chalk.green('│'));\n }\n if (result.registeredSince) {\n const date = formatDate(result.registeredSince);\n console.log(chalk.green('│') + padLine(` Since: ${date}`, width) + chalk.green('│'));\n }\n\n console.log(chalk.green('└' + hr + '┘'));\n } else {\n console.log(chalk.red('┌' + hr + '┐'));\n console.log(chalk.red('│') + center(chalk.red.bold('✗ Verification Failed'), width, 21) + chalk.red('│'));\n console.log(chalk.red('├' + hr + '┤'));\n\n if (result.error) {\n console.log(chalk.red('│') + padLine(` ${result.error}`, width) + chalk.red('│'));\n }\n\n console.log(chalk.red('└' + hr + '┘'));\n }\n console.log();\n}\n\nexport function printVerifyResultJSON(result: VerificationResult): void {\n console.log(JSON.stringify(result, null, 2));\n}\n\nexport function printStatus(config: TetherConfig, keyExists: boolean): void {\n console.log();\n console.log(chalk.bold(' Tether Configuration'));\n console.log(chalk.dim(' ' + '─'.repeat(30)));\n console.log(` Credential: ${config.credentialId ? maskId(config.credentialId) : chalk.dim('(not set)')}`);\n console.log(` Key path: ${config.keyPath || chalk.dim('(not set)')}`);\n if (config.keyPath) {\n console.log(` Key exists: ${keyExists ? chalk.green('yes') : chalk.red('no')}`);\n }\n console.log(` API URL: ${config.apiUrl}`);\n console.log();\n}\n\nexport function printStatusJSON(config: TetherConfig, keyExists: boolean): void {\n console.log(JSON.stringify({\n credentialId: config.credentialId ? maskId(config.credentialId) : null,\n keyPath: config.keyPath || null,\n keyExists,\n apiUrl: config.apiUrl,\n }, null, 2));\n}\n\nexport function printError(message: string): void {\n console.error(chalk.red(`Error: ${message}`));\n}\n\nexport function printVerbose(message: string, verbose: boolean): void {\n if (verbose) {\n console.error(chalk.dim(`[debug] ${message}`));\n }\n}\n\nexport const BANNER = `\n ╔╦╗╔═╗╔╦╗╦ ╦╔═╗╦═╗\n ║ ║╣ ║ ╠═╣║╣ ╠╦╝\n ╩ ╚═╝ ╩ ╩ ╩╚═╝╩╚═\n`;\n\nfunction padLine(text: string, width: number): string {\n const visible = stripAnsi(text);\n const pad = width - visible.length;\n return text + ' '.repeat(Math.max(0, pad));\n}\n\nfunction center(text: string, width: number, visibleLength: number): string {\n const leftPad = Math.floor((width - visibleLength) / 2);\n const rightPad = width - visibleLength - leftPad;\n return ' '.repeat(leftPad) + text + ' '.repeat(rightPad);\n}\n\nfunction stripAnsi(str: string): string {\n // eslint-disable-next-line no-control-regex\n return str.replace(/\\x1b\\[[0-9;]*m/g, '');\n}\n\nfunction formatDate(iso: string): string {\n try {\n return new Date(iso).toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n });\n } catch {\n return iso;\n }\n}\n","import { createInterface } from 'readline';\nimport { generateKeyPairSync } from 'crypto';\nimport { writeFileSync, existsSync } from 'fs';\nimport { resolve } from 'path';\nimport chalk from 'chalk';\nimport { saveConfig, getConfigPath } from '../config.js';\n\nfunction prompt(rl: ReturnType<typeof createInterface>, question: string): Promise<string> {\n return new Promise((resolve) => {\n rl.question(question, (answer) => resolve(answer.trim()));\n });\n}\n\nexport async function initCommand(opts: { verbose?: boolean }): Promise<void> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n\n try {\n console.log();\n console.log(chalk.bold(' Tether Setup'));\n console.log(chalk.dim(' ' + '─'.repeat(30)));\n console.log();\n\n // Credential ID\n const envCredential = process.env.TETHER_CREDENTIAL_ID;\n let credentialId: string;\n if (envCredential) {\n console.log(chalk.dim(` Using TETHER_CREDENTIAL_ID from environment`));\n credentialId = envCredential;\n } else {\n credentialId = await prompt(rl, ' Credential ID: ');\n }\n\n if (!credentialId) {\n console.log(chalk.red('\\n Credential ID is required.'));\n return;\n }\n\n // Private key\n const envKeyPath = process.env.TETHER_PRIVATE_KEY_PATH;\n let keyPath: string;\n\n if (envKeyPath) {\n console.log(chalk.dim(` Using TETHER_PRIVATE_KEY_PATH from environment`));\n keyPath = envKeyPath;\n } else {\n const genAnswer = await prompt(rl, ' Generate a new RSA keypair? (y/N): ');\n\n if (genAnswer.toLowerCase() === 'y') {\n keyPath = await generateKeypair(opts.verbose);\n } else {\n keyPath = await prompt(rl, ' Path to private key: ');\n }\n }\n\n if (!keyPath) {\n console.log(chalk.red('\\n Private key path is required.'));\n return;\n }\n\n keyPath = resolve(keyPath);\n\n if (!existsSync(keyPath)) {\n console.log(chalk.yellow(`\\n Warning: Key file not found at ${keyPath}`));\n }\n\n // Save config\n saveConfig({ credentialId, keyPath });\n\n console.log();\n console.log(chalk.green(' ✓ Configuration saved to ' + getConfigPath()));\n console.log();\n } finally {\n rl.close();\n }\n}\n\nfunction generateKeypair(verbose?: boolean): string {\n const privatePath = resolve('.tether-private-key.pem');\n const publicPath = resolve('.tether-public-key.pem');\n\n if (verbose) {\n console.log(chalk.dim(` [debug] Generating RSA-2048 keypair...`));\n }\n\n const { publicKey, privateKey } = generateKeyPairSync('rsa', {\n modulusLength: 2048,\n publicKeyEncoding: { type: 'spki', format: 'pem' },\n privateKeyEncoding: { type: 'pkcs1', format: 'pem' },\n });\n\n writeFileSync(privatePath, privateKey, { mode: 0o600 });\n writeFileSync(publicPath, publicKey);\n\n console.log(chalk.green(` ✓ Private key: ${privatePath}`));\n console.log(chalk.green(` ✓ Public key: ${publicPath}`));\n console.log();\n console.log(chalk.dim(' Upload the public key to tether.name to complete registration.'));\n\n return privatePath;\n}\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\n\nexport interface TetherConfig {\n credentialId: string;\n keyPath: string;\n apiUrl: string;\n}\n\nexport interface CLIFlags {\n credentialId?: string;\n keyPath?: string;\n apiUrl?: string;\n}\n\nconst CONFIG_DIR = join(homedir(), '.tether');\nconst CONFIG_FILE = join(CONFIG_DIR, 'config.json');\nconst DEFAULT_API_URL = 'https://api.tether.name';\n\nexport function getConfigPath(): string {\n return CONFIG_FILE;\n}\n\nexport function getConfigDir(): string {\n return CONFIG_DIR;\n}\n\nexport function loadConfigFile(): Partial<TetherConfig> {\n try {\n if (!existsSync(CONFIG_FILE)) {\n return {};\n }\n const raw = readFileSync(CONFIG_FILE, 'utf-8');\n return JSON.parse(raw);\n } catch {\n return {};\n }\n}\n\nexport function saveConfig(config: Partial<TetherConfig>): void {\n mkdirSync(CONFIG_DIR, { recursive: true });\n writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + '\\n', 'utf-8');\n}\n\nexport function resolveConfig(flags: CLIFlags = {}): TetherConfig {\n const file = loadConfigFile();\n\n return {\n credentialId:\n flags.credentialId ||\n process.env.TETHER_CREDENTIAL_ID ||\n file.credentialId ||\n '',\n keyPath:\n flags.keyPath ||\n process.env.TETHER_PRIVATE_KEY_PATH ||\n file.keyPath ||\n '',\n apiUrl:\n flags.apiUrl ||\n process.env.TETHER_API_URL ||\n file.apiUrl ||\n DEFAULT_API_URL,\n };\n}\n","import { TetherClient } from 'tether-name';\nimport { resolveConfig, type CLIFlags } from '../config.js';\nimport { printVerifyResult, printVerifyResultJSON, printError, printVerbose } from '../utils/display.js';\n\nexport async function verifyCommand(opts: CLIFlags & { json?: boolean; verbose?: boolean }): Promise<void> {\n const config = resolveConfig(opts);\n\n if (!config.credentialId) {\n printError('No credential ID configured. Run \"tether init\" or set TETHER_CREDENTIAL_ID.');\n process.exitCode = 1;\n return;\n }\n\n if (!config.keyPath) {\n printError('No private key path configured. Run \"tether init\" or set TETHER_PRIVATE_KEY_PATH.');\n process.exitCode = 1;\n return;\n }\n\n const verbose = opts.verbose ?? false;\n\n try {\n printVerbose(`Credential ID: ${config.credentialId}`, verbose);\n printVerbose(`Key path: ${config.keyPath}`, verbose);\n printVerbose(`API URL: ${config.apiUrl}`, verbose);\n\n const client = new TetherClient({\n credentialId: config.credentialId,\n privateKeyPath: config.keyPath,\n baseUrl: config.apiUrl,\n });\n\n printVerbose('Requesting challenge...', verbose);\n const challenge = await client.requestChallenge();\n printVerbose(`Challenge: ${challenge}`, verbose);\n\n printVerbose('Signing challenge...', verbose);\n const proof = client.sign(challenge);\n printVerbose(`Proof: ${proof.slice(0, 32)}...`, verbose);\n\n printVerbose('Submitting proof...', verbose);\n const result = await client.submitProof(challenge, proof);\n\n if (opts.json) {\n printVerifyResultJSON(result);\n } else {\n printVerifyResult(result);\n }\n\n if (!result.verified) {\n process.exitCode = 1;\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n if (opts.json) {\n console.log(JSON.stringify({ verified: false, error: message }, null, 2));\n } else {\n printError(message);\n }\n process.exitCode = 1;\n }\n}\n","import { existsSync } from 'fs';\nimport { resolveConfig, type CLIFlags } from '../config.js';\nimport { printStatus, printStatusJSON } from '../utils/display.js';\n\nexport function statusCommand(opts: CLIFlags & { json?: boolean }): void {\n const config = resolveConfig(opts);\n const keyExists = config.keyPath ? existsSync(config.keyPath) : false;\n\n if (opts.json) {\n printStatusJSON(config, keyExists);\n } else {\n printStatus(config, keyExists);\n }\n}\n","import { TetherClient } from 'tether-name';\nimport { resolveConfig, type CLIFlags } from '../config.js';\nimport { printError, printVerbose } from '../utils/display.js';\n\nexport async function challengeCommand(opts: CLIFlags & { verbose?: boolean }): Promise<void> {\n const config = resolveConfig(opts);\n\n if (!config.credentialId) {\n printError('No credential ID configured. Run \"tether init\" or set TETHER_CREDENTIAL_ID.');\n process.exitCode = 1;\n return;\n }\n\n if (!config.keyPath) {\n printError('No private key path configured. Run \"tether init\" or set TETHER_PRIVATE_KEY_PATH.');\n process.exitCode = 1;\n return;\n }\n\n try {\n printVerbose(`API URL: ${config.apiUrl}`, opts.verbose ?? false);\n\n const client = new TetherClient({\n credentialId: config.credentialId,\n privateKeyPath: config.keyPath,\n baseUrl: config.apiUrl,\n });\n\n const code = await client.requestChallenge();\n console.log(code);\n } catch (err) {\n printError(err instanceof Error ? err.message : String(err));\n process.exitCode = 1;\n }\n}\n","import { loadPrivateKey, signChallenge } from 'tether-name';\nimport { resolveConfig, type CLIFlags } from '../config.js';\nimport { printError, printVerbose } from '../utils/display.js';\n\nexport function signCommand(challenge: string, opts: CLIFlags & { verbose?: boolean }): void {\n const config = resolveConfig(opts);\n\n if (!config.keyPath) {\n printError('No private key path configured. Run \"tether init\" or set TETHER_PRIVATE_KEY_PATH.');\n process.exitCode = 1;\n return;\n }\n\n try {\n printVerbose(`Key path: ${config.keyPath}`, opts.verbose ?? false);\n\n const privateKey = loadPrivateKey({ keyPath: config.keyPath });\n const proof = signChallenge(privateKey, challenge);\n console.log(proof);\n } catch (err) {\n printError(err instanceof Error ? err.message : String(err));\n process.exitCode = 1;\n }\n}\n","import chalk from 'chalk';\nimport { resolveConfig, type CLIFlags } from '../config.js';\nimport { printError, printVerbose } from '../utils/display.js';\n\ninterface ChallengeStatusResponse {\n code: string;\n status: string;\n credentialId?: string;\n createdAt?: string;\n verifiedAt?: string;\n [key: string]: unknown;\n}\n\nexport async function checkCommand(\n code: string,\n opts: CLIFlags & { json?: boolean; verbose?: boolean },\n): Promise<void> {\n const config = resolveConfig(opts);\n const baseUrl = config.apiUrl;\n const verbose = opts.verbose ?? false;\n\n try {\n const url = `${baseUrl}/challenge/${encodeURIComponent(code)}`;\n printVerbose(`GET ${url}`, verbose);\n\n const response = await fetch(url, {\n headers: { 'Accept': 'application/json' },\n });\n\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n printError(`API returned ${response.status}: ${text || response.statusText}`);\n process.exitCode = 1;\n return;\n }\n\n const data = (await response.json()) as ChallengeStatusResponse;\n\n if (opts.json) {\n console.log(JSON.stringify(data, null, 2));\n } else {\n console.log();\n console.log(chalk.bold(' Challenge Status'));\n console.log(chalk.dim(' ' + '─'.repeat(30)));\n console.log(` Code: ${data.code}`);\n console.log(` Status: ${data.status}`);\n if (data.createdAt) {\n console.log(` Created: ${data.createdAt}`);\n }\n if (data.verifiedAt) {\n console.log(` Verified: ${data.verifiedAt}`);\n }\n console.log();\n }\n } catch (err) {\n printError(err instanceof Error ? err.message : String(err));\n process.exitCode = 1;\n }\n}\n"],"mappings":"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","names":["chalk","writeFileSync","existsSync","chalk","resolve","chalk","existsSync","writeFileSync","existsSync","existsSync","TetherClient","TetherClient","chalk","chalk","chalk"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tether-name-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CLI for tether.name - AI agent identity verification",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"tether": "./dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/cli.js",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsup",
|
|
15
|
+
"dev": "tsup --watch",
|
|
16
|
+
"test": "vitest run",
|
|
17
|
+
"test:watch": "vitest",
|
|
18
|
+
"typecheck": "tsc --noEmit"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"tether",
|
|
22
|
+
"tether.name",
|
|
23
|
+
"agent",
|
|
24
|
+
"identity",
|
|
25
|
+
"verification",
|
|
26
|
+
"ai",
|
|
27
|
+
"cli"
|
|
28
|
+
],
|
|
29
|
+
"author": "Commit 451 <jawnnypoo@gmail.com>",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"homepage": "https://tether.name",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/tether-name/tether-name-cli.git"
|
|
35
|
+
},
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/tether-name/tether-name-cli/issues"
|
|
38
|
+
},
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=18"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"chalk": "^5.4.1",
|
|
44
|
+
"commander": "^13.1.0",
|
|
45
|
+
"tether-name": "^1.0.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/node": "^22.13.0",
|
|
49
|
+
"tsup": "^8.4.0",
|
|
50
|
+
"typescript": "^5.7.0",
|
|
51
|
+
"vitest": "^3.0.0"
|
|
52
|
+
}
|
|
53
|
+
}
|