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.
Files changed (3) hide show
  1. package/README.md +51 -64
  2. package/bin/tm.js +91 -49
  3. 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> <password> # Create a new account
23
- tm login <email> <password> # Login to your account
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 name "John Doe" # Update your name
34
- tm profile phone "+1234567890" # Update phone
35
- tm profile address "123 Main St" # Update address
36
- tm profile city "Berlin" # Update city
37
- tm profile country "DE" # Update country
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
- Example:
103
+ ### Aliases & Rewards
104
+
91
105
  ```bash
92
- tm ai list # See available models
93
- tm ai topup 10 # Add $10 credits
94
- tm ai run text-rewrite "Fix this text" # Run AI model
95
- tm ai credits # Check remaining balance
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 include:
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
- ## Seller Tiers
158
-
159
- | Tier | Price | Products | Commission | Features |
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
- .argument("[field]", "Field to set (name, phone, address, city, country)")
236
- .argument("[value...]", "Value to set")
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
- const result = await apiGet("/auth/status");
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(' TERMINAL MARKET') + chalk.green.bold(' ║'));
1391
- console.log(chalk.green.bold(' ║') + chalk.dim(' The marketplace for developers') + chalk.green.bold(' ║'));
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('Install:')} ${chalk.green('npm i -g terminalmarket')}`);
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 = 35;
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(' TerminalMarket CLI ', W - 6)) + chalk.dim('v0.7.1') + chalk.green.bold('║'));
1495
- console.log(chalk.green.bold(' ║') + chalk.dim(pad(' Marketplace for developers', W)) + chalk.green.bold('║'));
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.2",
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": "./bin/tm.js"
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",