terminalmarket 0.7.2 → 0.7.4
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 +51 -64
- package/bin/tm.js +91 -49
- package/package.json +34 -6
package/README.md
CHANGED
|
@@ -4,10 +4,20 @@ The official command-line interface for [TerminalMarket](https://terminalmarket.
|
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
|
+
### npm (requires Node.js)
|
|
8
|
+
|
|
7
9
|
```bash
|
|
8
10
|
npm install -g terminalmarket
|
|
9
11
|
```
|
|
10
12
|
|
|
13
|
+
### Standalone binary (no Node.js needed)
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
curl -fsSL https://terminalmarket.app/install.sh | sh
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
This installs `tm` into `~/.local/bin`.
|
|
20
|
+
|
|
11
21
|
## Usage
|
|
12
22
|
|
|
13
23
|
```bash
|
|
@@ -19,22 +29,25 @@ tm <command> [options]
|
|
|
19
29
|
### Authentication
|
|
20
30
|
|
|
21
31
|
```bash
|
|
22
|
-
tm register <email>
|
|
23
|
-
tm login <email>
|
|
32
|
+
tm register <email> [password] # Create a new account
|
|
33
|
+
tm login <email> [password] # Login to your account
|
|
24
34
|
tm logout # Logout
|
|
25
35
|
tm whoami # Show current user info
|
|
26
36
|
tm me # Alias for whoami
|
|
37
|
+
tm auth github # Login with GitHub (opens browser)
|
|
38
|
+
tm github # Shortcut for GitHub auth
|
|
27
39
|
```
|
|
28
40
|
|
|
29
41
|
### Profile
|
|
30
42
|
|
|
31
43
|
```bash
|
|
32
44
|
tm profile # View your profile
|
|
33
|
-
tm profile
|
|
34
|
-
tm profile
|
|
35
|
-
tm profile
|
|
36
|
-
tm profile
|
|
37
|
-
tm profile
|
|
45
|
+
tm profile view # View your profile
|
|
46
|
+
tm profile set name "John Doe" # Update your name
|
|
47
|
+
tm profile set phone "+1234567890" # Update phone
|
|
48
|
+
tm profile set address "123 Main" # Update address
|
|
49
|
+
tm profile set city "Berlin" # Update city
|
|
50
|
+
tm profile set country "DE" # Update country
|
|
38
51
|
```
|
|
39
52
|
|
|
40
53
|
### Shopping
|
|
@@ -87,32 +100,29 @@ tm credits # Check credits (shortcut)
|
|
|
87
100
|
tm topup <amount> # Add credits (shortcut)
|
|
88
101
|
```
|
|
89
102
|
|
|
90
|
-
|
|
103
|
+
### Aliases & Rewards
|
|
104
|
+
|
|
91
105
|
```bash
|
|
92
|
-
tm
|
|
93
|
-
tm
|
|
94
|
-
tm
|
|
95
|
-
tm
|
|
106
|
+
tm alias list # List your aliases
|
|
107
|
+
tm alias add <name> <command> # Create alias
|
|
108
|
+
tm alias remove <name> # Remove alias
|
|
109
|
+
tm aliases # Shortcut for alias list
|
|
110
|
+
|
|
111
|
+
tm reward list # List reward rules
|
|
112
|
+
tm reward add <product> <pushes> # Auto-order after N pushes
|
|
113
|
+
tm reward remove <id> # Remove reward rule
|
|
114
|
+
tm rewards # Shortcut for reward list
|
|
96
115
|
```
|
|
97
116
|
|
|
98
|
-
### Service Types
|
|
99
|
-
|
|
100
|
-
Products have different service types:
|
|
101
|
-
- Global — SaaS, digital products, worldwide delivery
|
|
102
|
-
- National — Country-wide delivery/services
|
|
103
|
-
- Local — City-specific services (food delivery, coworking, etc.)
|
|
104
|
-
|
|
105
117
|
### Categories & Offers
|
|
106
118
|
|
|
107
119
|
```bash
|
|
108
120
|
tm categories # List all categories
|
|
109
121
|
tm category <slug> # List products in category
|
|
110
122
|
tm offers # List all offers
|
|
111
|
-
tm offers --product <id> # Filter by product
|
|
112
|
-
tm offers --seller <id> # Filter by seller
|
|
113
123
|
```
|
|
114
124
|
|
|
115
|
-
Available categories
|
|
125
|
+
Available categories:
|
|
116
126
|
- `coffee` — Specialty coffee for developers
|
|
117
127
|
- `lunch` — Meal subscriptions & delivery
|
|
118
128
|
- `snacks` — Healthy snacks & energy packs
|
|
@@ -134,6 +144,7 @@ tm config set api <url> # Set API endpoint
|
|
|
134
144
|
```bash
|
|
135
145
|
tm about # About TerminalMarket
|
|
136
146
|
tm help # Show help
|
|
147
|
+
tm help <command> # Help for specific command
|
|
137
148
|
tm --version # Show version
|
|
138
149
|
```
|
|
139
150
|
|
|
@@ -152,49 +163,11 @@ tm review 1 5 "Great coffee, fast delivery!"
|
|
|
152
163
|
|
|
153
164
|
# View your order history
|
|
154
165
|
tm orders
|
|
155
|
-
```
|
|
156
166
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
| Free | $0/mo | 5 | 5% | Basic analytics |
|
|
162
|
-
| Basic | $29/mo | 50 | 4% | Priority support |
|
|
163
|
-
| Premium | $99/mo | 1000 | 2.5% | Stripe Connect, Terminal Checkout |
|
|
164
|
-
|
|
165
|
-
## API Endpoints Used
|
|
166
|
-
|
|
167
|
-
### Public
|
|
168
|
-
- `GET /api/products` — List products
|
|
169
|
-
- `GET /api/products/:id` — Get product details
|
|
170
|
-
- `GET /api/products/slug/:slug` — Get product by slug
|
|
171
|
-
- `GET /api/products/category/:category` — Products by category
|
|
172
|
-
- `GET /api/products/search` — Search products
|
|
173
|
-
- `GET /api/categories` — List categories
|
|
174
|
-
- `GET /api/sellers` — List sellers
|
|
175
|
-
- `GET /api/sellers/:slug` — Get seller details
|
|
176
|
-
- `GET /api/offers` — List offers
|
|
177
|
-
- `GET /api/stores/:id/reviews` — Get store reviews
|
|
178
|
-
- `GET /api/stores/:id/rating` — Get store rating
|
|
179
|
-
|
|
180
|
-
### Authenticated
|
|
181
|
-
- `POST /api/auth/register` — Create account
|
|
182
|
-
- `POST /api/auth/login` — Login
|
|
183
|
-
- `POST /api/auth/logout` — Logout
|
|
184
|
-
- `GET /api/auth/status` — Check auth status
|
|
185
|
-
- `PATCH /api/profile` — Update profile
|
|
186
|
-
- `GET /api/cart` — Get cart
|
|
187
|
-
- `POST /api/cart/add` — Add to cart
|
|
188
|
-
- `POST /api/cart/remove` — Remove from cart
|
|
189
|
-
- `POST /api/cart/clear` — Clear cart
|
|
190
|
-
- `GET /api/orders` — Get orders
|
|
191
|
-
- `POST /api/stores/:id/reviews` — Leave review
|
|
192
|
-
- `GET /api/credits` — Get AI credits balance
|
|
193
|
-
- `POST /api/credits/topup` — Create Stripe checkout for credits
|
|
194
|
-
- `POST /api/ai/run/:model` — Run AI model
|
|
195
|
-
- `GET /api/ai/history` — Get AI usage history
|
|
196
|
-
- `POST /api/clicks` — Track clicks
|
|
197
|
-
- `POST /api/intents` — Create purchase intent
|
|
167
|
+
# Use AI services
|
|
168
|
+
tm ai topup 10
|
|
169
|
+
tm ai run text-rewrite "Fix this text"
|
|
170
|
+
```
|
|
198
171
|
|
|
199
172
|
## Configuration
|
|
200
173
|
|
|
@@ -204,6 +177,20 @@ The CLI stores configuration in `~/.config/terminalmarket/config.json`:
|
|
|
204
177
|
- `sessionCookie`: Session cookie for authentication
|
|
205
178
|
- `user`: Cached user info
|
|
206
179
|
|
|
180
|
+
## Building Binaries
|
|
181
|
+
|
|
182
|
+
See [INSTALL_BINARIES.md](./INSTALL_BINARIES.md) for instructions on building standalone binaries.
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
npm ci
|
|
186
|
+
npm run build:bin
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
This produces binaries in `dist/`:
|
|
190
|
+
- `tm-linux-x64`
|
|
191
|
+
- `tm-macos-x64`
|
|
192
|
+
- `tm-macos-arm64`
|
|
193
|
+
|
|
207
194
|
## License
|
|
208
195
|
|
|
209
196
|
MIT
|
package/bin/tm.js
CHANGED
|
@@ -229,55 +229,87 @@ program
|
|
|
229
229
|
// -----------------
|
|
230
230
|
// profile command
|
|
231
231
|
// -----------------
|
|
232
|
-
program
|
|
232
|
+
const profile = program
|
|
233
233
|
.command("profile")
|
|
234
|
-
.description("View or edit your profile")
|
|
235
|
-
|
|
236
|
-
|
|
234
|
+
.description("View or edit your profile");
|
|
235
|
+
|
|
236
|
+
async function showProfile() {
|
|
237
|
+
const result = await apiGet("/auth/status");
|
|
238
|
+
if (!result.isAuthenticated) {
|
|
239
|
+
console.log(chalk.yellow("Not logged in. Use 'tm login' first."));
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
const user = result.user;
|
|
243
|
+
console.log();
|
|
244
|
+
console.log(chalk.green.bold('┌─────────────────────────────────────┐'));
|
|
245
|
+
console.log(chalk.green.bold('│') + chalk.white.bold(' Your Profile') + ' '.repeat(22) + chalk.green.bold('│'));
|
|
246
|
+
console.log(chalk.green.bold('└─────────────────────────────────────┘'));
|
|
247
|
+
console.log();
|
|
248
|
+
console.log(` ${chalk.dim('Username:')} ${chalk.white(user.username || user.email?.split('@')[0] || '-')}`);
|
|
249
|
+
console.log(` ${chalk.dim('Email:')} ${chalk.cyan(user.email || '-')}`);
|
|
250
|
+
console.log(` ${chalk.dim('Name:')} ${user.name || chalk.dim('(not set)')}`);
|
|
251
|
+
console.log(` ${chalk.dim('Phone:')} ${user.phone || chalk.dim('(not set)')}`);
|
|
252
|
+
console.log(` ${chalk.dim('Address:')} ${user.address || chalk.dim('(not set)')}`);
|
|
253
|
+
console.log(` ${chalk.dim('City:')} ${user.city || chalk.dim('(not set)')}`);
|
|
254
|
+
console.log(` ${chalk.dim('Country:')} ${user.country || chalk.dim('(not set)')}`);
|
|
255
|
+
console.log();
|
|
256
|
+
console.log(chalk.dim(' Use: tm profile set <field> <value>'));
|
|
257
|
+
console.log();
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
async function setProfileField(field, value) {
|
|
261
|
+
const result = await apiGet("/auth/status");
|
|
262
|
+
if (!result.isAuthenticated) {
|
|
263
|
+
console.log(chalk.yellow("Not logged in. Use 'tm login' first."));
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
const validFields = ["name", "phone", "address", "city", "country"];
|
|
267
|
+
if (!validFields.includes(field)) {
|
|
268
|
+
console.error(chalk.red(`✗ Invalid field. Valid fields: ${validFields.join(", ")}`));
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
const newValue = value.join(" ");
|
|
272
|
+
if (!newValue) {
|
|
273
|
+
console.error(chalk.red("✗ Value is required."));
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
await apiPatch("/profile", { [field]: newValue });
|
|
277
|
+
console.log(chalk.green(`✓ Updated ${field} to "${newValue}"`));
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
profile
|
|
281
|
+
.command("view")
|
|
282
|
+
.description("Show your profile")
|
|
283
|
+
.action(async () => {
|
|
284
|
+
try {
|
|
285
|
+
await showProfile();
|
|
286
|
+
} catch (e) {
|
|
287
|
+
console.error(chalk.red(e?.message || String(e)));
|
|
288
|
+
process.exitCode = 1;
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
profile
|
|
293
|
+
.command("set <field> [value...]")
|
|
294
|
+
.description("Update profile field (name, phone, address, city, country)")
|
|
237
295
|
.action(async (field, value) => {
|
|
238
296
|
try {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
if (!result.isAuthenticated) {
|
|
242
|
-
console.log(chalk.yellow("Not logged in. Use 'tm login' first."));
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
if (!field) {
|
|
247
|
-
const user = result.user;
|
|
248
|
-
console.log(chalk.bold("Your Profile"));
|
|
249
|
-
console.log("");
|
|
250
|
-
console.log(`${chalk.dim("name:")} ${user.name || "(not set)"}`);
|
|
251
|
-
console.log(`${chalk.dim("email:")} ${user.email}`);
|
|
252
|
-
console.log(`${chalk.dim("phone:")} ${user.phone || "(not set)"}`);
|
|
253
|
-
console.log(`${chalk.dim("address:")} ${user.address || "(not set)"}`);
|
|
254
|
-
console.log(`${chalk.dim("city:")} ${user.city || "(not set)"}`);
|
|
255
|
-
console.log(`${chalk.dim("country:")} ${user.country || "(not set)"}`);
|
|
256
|
-
console.log("");
|
|
257
|
-
console.log(chalk.dim("To update: tm profile <field> <value>"));
|
|
258
|
-
return;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
const validFields = ["name", "phone", "address", "city", "country"];
|
|
262
|
-
if (!validFields.includes(field)) {
|
|
263
|
-
console.error(chalk.red(`Invalid field. Valid fields: ${validFields.join(", ")}`));
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
const newValue = value.join(" ");
|
|
268
|
-
if (!newValue) {
|
|
269
|
-
console.error(chalk.red("Value is required."));
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
await apiPatch("/profile", { [field]: newValue });
|
|
274
|
-
console.log(chalk.green(`Updated ${field} to "${newValue}"`));
|
|
297
|
+
await setProfileField(field, value);
|
|
275
298
|
} catch (e) {
|
|
276
299
|
console.error(chalk.red(e?.message || String(e)));
|
|
277
300
|
process.exitCode = 1;
|
|
278
301
|
}
|
|
279
302
|
});
|
|
280
303
|
|
|
304
|
+
profile.action(async () => {
|
|
305
|
+
try {
|
|
306
|
+
await showProfile();
|
|
307
|
+
} catch (e) {
|
|
308
|
+
console.error(chalk.red(e?.message || String(e)));
|
|
309
|
+
process.exitCode = 1;
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
|
|
281
313
|
// -----------------
|
|
282
314
|
// cart commands
|
|
283
315
|
// -----------------
|
|
@@ -1385,11 +1417,15 @@ program
|
|
|
1385
1417
|
.command("about")
|
|
1386
1418
|
.description("About TerminalMarket")
|
|
1387
1419
|
.action(() => {
|
|
1420
|
+
const W = 40;
|
|
1421
|
+
const line = '═'.repeat(W);
|
|
1422
|
+
const pad = (s, w) => s + ' '.repeat(Math.max(0, w - s.length));
|
|
1423
|
+
|
|
1388
1424
|
console.log();
|
|
1389
|
-
console.log(chalk.green.bold('
|
|
1390
|
-
console.log(chalk.green.bold(' ║') + chalk.white.bold('
|
|
1391
|
-
console.log(chalk.green.bold(' ║') + chalk.dim('
|
|
1392
|
-
console.log(chalk.green.bold('
|
|
1425
|
+
console.log(chalk.green.bold(' ╔' + line + '╗'));
|
|
1426
|
+
console.log(chalk.green.bold(' ║') + chalk.white.bold(pad(' TERMINAL MARKET', W)) + chalk.green.bold('║'));
|
|
1427
|
+
console.log(chalk.green.bold(' ║') + chalk.dim(pad(' The marketplace for developers', W)) + chalk.green.bold('║'));
|
|
1428
|
+
console.log(chalk.green.bold(' ╚' + line + '╝'));
|
|
1393
1429
|
console.log();
|
|
1394
1430
|
console.log(chalk.white(' We connect developers with premium services:'));
|
|
1395
1431
|
console.log();
|
|
@@ -1402,9 +1438,15 @@ program
|
|
|
1402
1438
|
console.log();
|
|
1403
1439
|
console.log(chalk.dim(' ─────────────────────────────────────────────'));
|
|
1404
1440
|
console.log();
|
|
1441
|
+
console.log(chalk.white(' Install:'));
|
|
1442
|
+
console.log();
|
|
1443
|
+
console.log(` ${chalk.dim('npm:')} ${chalk.green('npm i -g terminalmarket')}`);
|
|
1444
|
+
console.log(` ${chalk.dim('curl:')} ${chalk.cyan('curl -fsSL https://terminalmarket.app/install.sh | sh')}`);
|
|
1445
|
+
console.log();
|
|
1446
|
+
console.log(chalk.dim(' ─────────────────────────────────────────────'));
|
|
1447
|
+
console.log();
|
|
1405
1448
|
console.log(` ${chalk.dim('Website:')} ${chalk.cyan('https://terminalmarket.app')}`);
|
|
1406
|
-
console.log(` ${chalk.dim('
|
|
1407
|
-
console.log(` ${chalk.dim('Version:')} ${chalk.white('0.7.1')}`);
|
|
1449
|
+
console.log(` ${chalk.dim('Version:')} ${chalk.white('0.7.2')}`);
|
|
1408
1450
|
console.log();
|
|
1409
1451
|
});
|
|
1410
1452
|
|
|
@@ -1485,14 +1527,14 @@ function showHelp(commandName = null) {
|
|
|
1485
1527
|
}
|
|
1486
1528
|
|
|
1487
1529
|
// Show all commands grouped
|
|
1488
|
-
const W =
|
|
1530
|
+
const W = 38;
|
|
1489
1531
|
const line = '═'.repeat(W);
|
|
1490
1532
|
const pad = (s, w) => s + ' '.repeat(Math.max(0, w - s.length));
|
|
1491
1533
|
|
|
1492
1534
|
console.log();
|
|
1493
1535
|
console.log(chalk.green.bold(' ╔' + line + '╗'));
|
|
1494
|
-
console.log(chalk.green.bold(' ║') + chalk.white.bold(pad('
|
|
1495
|
-
console.log(chalk.green.bold(' ║') + chalk.dim(pad('
|
|
1536
|
+
console.log(chalk.green.bold(' ║') + chalk.white.bold(pad(' TerminalMarket CLI', W - 8)) + chalk.dim(' v0.7.2 ') + chalk.green.bold('║'));
|
|
1537
|
+
console.log(chalk.green.bold(' ║') + chalk.dim(pad(' Marketplace for developers', W)) + chalk.green.bold('║'));
|
|
1496
1538
|
console.log(chalk.green.bold(' ╚' + line + '╝'));
|
|
1497
1539
|
console.log();
|
|
1498
1540
|
console.log(chalk.magenta.bold('Usage:'), chalk.green('tm'), chalk.cyan('<command>'), chalk.dim('[options]'));
|
package/package.json
CHANGED
|
@@ -1,28 +1,56 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "terminalmarket",
|
|
3
|
-
"version": "0.7.
|
|
4
|
-
"description": "TerminalMarket CLI — marketplace for developers (client for terminalmarket.app)",
|
|
3
|
+
"version": "0.7.4",
|
|
4
|
+
"description": "TerminalMarket CLI — a curated marketplace for developers & founders (client for terminalmarket.app)",
|
|
5
5
|
"bin": {
|
|
6
|
-
"tm": "
|
|
6
|
+
"tm": "bin/tm.js"
|
|
7
7
|
},
|
|
8
8
|
"type": "module",
|
|
9
9
|
"keywords": [
|
|
10
10
|
"cli",
|
|
11
|
-
"marketplace",
|
|
12
11
|
"terminal",
|
|
12
|
+
"marketplace",
|
|
13
13
|
"developers",
|
|
14
|
+
"founders",
|
|
14
15
|
"food",
|
|
15
16
|
"subscription",
|
|
16
17
|
"saas",
|
|
17
|
-
"coworking"
|
|
18
|
+
"coworking",
|
|
19
|
+
"tools",
|
|
20
|
+
"telegram",
|
|
21
|
+
"discord"
|
|
18
22
|
],
|
|
19
23
|
"author": "TerminalMarket",
|
|
20
24
|
"license": "MIT",
|
|
21
25
|
"repository": {
|
|
22
26
|
"type": "git",
|
|
23
|
-
"url": "https://github.com/terminalmarket/cli"
|
|
27
|
+
"url": "git+https://github.com/terminalmarket/cli.git"
|
|
28
|
+
},
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/terminalmarket/cli/issues"
|
|
24
31
|
},
|
|
25
32
|
"homepage": "https://terminalmarket.app",
|
|
33
|
+
"files": [
|
|
34
|
+
"bin/",
|
|
35
|
+
"src/",
|
|
36
|
+
"dist/",
|
|
37
|
+
"README.md",
|
|
38
|
+
"LICENSE"
|
|
39
|
+
],
|
|
40
|
+
"scripts": {
|
|
41
|
+
"bundle:cli": "esbuild bin/tm.js --bundle --platform=node --format=cjs --outfile=dist/tm.cjs",
|
|
42
|
+
"build:bin": "npm run bundle:cli && pkg dist/tm.cjs --targets node18-linux-x64,node18-macos-x64,node18-macos-arm64,node18-win-x64 --output dist/tm",
|
|
43
|
+
"build:bin:linux": "npm run bundle:cli && pkg dist/tm.cjs --targets node18-linux-x64 --output dist/tm",
|
|
44
|
+
"build:bin:mac": "npm run bundle:cli && pkg dist/tm.cjs --targets node18-macos-x64,node18-macos-arm64 --output dist/tm",
|
|
45
|
+
"build:bin:win": "npm run bundle:cli && pkg dist/tm.cjs --targets node18-win-x64 --output dist/tm",
|
|
46
|
+
"clean": "rm -rf dist",
|
|
47
|
+
"prepack": "npm run clean",
|
|
48
|
+
"test:smoke": "node bin/tm.js --help"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"esbuild": "^0.25.0",
|
|
52
|
+
"pkg": "^5.8.1"
|
|
53
|
+
},
|
|
26
54
|
"dependencies": {
|
|
27
55
|
"chalk": "^5.3.0",
|
|
28
56
|
"commander": "^12.1.0",
|