tsoft-cli 3.4.3 → 3.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/package.json +1 -1
- package/src/commands/login.js +1 -1
- package/src/commands/theme-dev.js +4 -28
- package/src/commands/theme.js +2 -8
- package/src/commands/whoami.js +1 -1
- package/src/storage.js +16 -9
- package/src/ui/prompt-wrapper.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,23 @@ All notable changes to T-Soft CLI will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [3.5.1] - 2026-04-09
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- Reduced terminal noise — lock, keep-alive, and shutdown messages are now silent
|
|
12
|
+
- Fixed misleading "cd" tip after theme create — now shows `tsoft theme dev`
|
|
13
|
+
|
|
14
|
+
## [3.5.0] - 2026-04-09
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- Config storage moved from working directory to `~/.tsoft-cli/` (cross-platform)
|
|
18
|
+
- Login once, use from any directory
|
|
19
|
+
- Confirm prompts default to "Yes" selection
|
|
20
|
+
- Removed author field from theme creation flow
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
- Login check before theme create prevents crash when not logged in
|
|
24
|
+
|
|
8
25
|
## [3.4.3] - 2026-04-08
|
|
9
26
|
|
|
10
27
|
### Fixed
|
package/package.json
CHANGED
package/src/commands/login.js
CHANGED
|
@@ -82,7 +82,7 @@ export async function loginCommand() {
|
|
|
82
82
|
console.log(chalk.gray(` Store: ${store}`));
|
|
83
83
|
console.log(chalk.gray(` Kullanıcı: ${tokens.user.name} ${tokens.user.surname}`));
|
|
84
84
|
console.log(chalk.gray(` Email: ${tokens.user.email}`));
|
|
85
|
-
console.log(chalk.gray(` Config:
|
|
85
|
+
console.log(chalk.gray(` Config: ~/.tsoft-cli/${store.replace(/\./g, '-').toLowerCase()}/\n`));
|
|
86
86
|
|
|
87
87
|
console.log(chalk.gray('💡 İpucu: ') + chalk.white(t('login.tip').replace('💡 ', '').replace('Tip: ', '') + '\n'));
|
|
88
88
|
|
|
@@ -194,28 +194,16 @@ function startKeepAlive(themeUuid) {
|
|
|
194
194
|
try {
|
|
195
195
|
const apiClient = await createApiClient();
|
|
196
196
|
await apiClient.post(`/theme/${themeUuid}/mark-synced`, {});
|
|
197
|
-
console.log(chalk.gray(`[${new Date().toLocaleTimeString()}] 🔄 Keep-alive (mark-synced)`));
|
|
198
197
|
} catch (error) {
|
|
199
|
-
|
|
198
|
+
// sessiz — keep-alive hatası kullanıcıyı ilgilendirmez
|
|
200
199
|
}
|
|
201
200
|
}, 30000);
|
|
202
201
|
}
|
|
203
202
|
|
|
204
203
|
function setupGracefulShutdown(watcher, keepAliveInterval) {
|
|
205
204
|
process.on('SIGINT', async () => {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
if (watcher) {
|
|
209
|
-
await watcher.close();
|
|
210
|
-
console.log(chalk.green(t('dev.watch_stopped')));
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
if (keepAliveInterval) {
|
|
214
|
-
clearInterval(keepAliveInterval);
|
|
215
|
-
console.log(chalk.green(t('dev.keepalive_stopped')));
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
console.log(chalk.gray(' ' + t('dev.lock_kept')));
|
|
205
|
+
if (watcher) await watcher.close();
|
|
206
|
+
if (keepAliveInterval) clearInterval(keepAliveInterval);
|
|
219
207
|
|
|
220
208
|
console.log(chalk.green('\n' + t('dev.exit_success') + '\n'));
|
|
221
209
|
process.exit(0);
|
|
@@ -372,23 +360,14 @@ export async function themeDevCommand(themeName) {
|
|
|
372
360
|
return;
|
|
373
361
|
}
|
|
374
362
|
|
|
375
|
-
console.log(chalk.yellow(t('dev.checking_lock')));
|
|
376
363
|
const lockStatus = await checkLockStatus(themeInfo.uuid);
|
|
377
364
|
|
|
378
365
|
if (!lockStatus.locked) {
|
|
379
|
-
console.log(chalk.green(t('dev.not_locked') + '\n'));
|
|
380
|
-
console.log(chalk.yellow(t('dev.acquiring_lock')));
|
|
381
366
|
await acquireLock(themeInfo.uuid);
|
|
382
|
-
console.log(chalk.green(t('dev.lock_acquired') + '\n'));
|
|
383
|
-
|
|
384
367
|
await pullAndSync(themeInfo.uuid, themePath);
|
|
385
368
|
|
|
386
369
|
} else if (lockStatus.isCurrentDeveloper) {
|
|
387
|
-
if (lockStatus.developerSynced) {
|
|
388
|
-
console.log(chalk.green(t('dev.already_locked')));
|
|
389
|
-
console.log(chalk.green(t('dev.already_synced') + '\n'));
|
|
390
|
-
} else {
|
|
391
|
-
console.log(chalk.yellow(t('dev.not_synced') + '\n'));
|
|
370
|
+
if (!lockStatus.developerSynced) {
|
|
392
371
|
await pullAndSync(themeInfo.uuid, themePath);
|
|
393
372
|
}
|
|
394
373
|
} else {
|
|
@@ -406,10 +385,7 @@ export async function themeDevCommand(themeName) {
|
|
|
406
385
|
return;
|
|
407
386
|
}
|
|
408
387
|
|
|
409
|
-
console.log(chalk.yellow('\n' + t('dev.lock_override')));
|
|
410
388
|
await acquireLock(themeInfo.uuid);
|
|
411
|
-
console.log(chalk.green(t('dev.lock_acquired') + '\n'));
|
|
412
|
-
|
|
413
389
|
await pullAndSync(themeInfo.uuid, themePath);
|
|
414
390
|
}
|
|
415
391
|
|
package/src/commands/theme.js
CHANGED
|
@@ -94,13 +94,9 @@ export async function themeCreateCommand() {
|
|
|
94
94
|
message: t('theme.description_prompt'), default: '',
|
|
95
95
|
});
|
|
96
96
|
|
|
97
|
-
const author = await input({
|
|
98
|
-
message: t('theme.author_prompt'), default: '',
|
|
99
|
-
});
|
|
100
|
-
|
|
101
97
|
|
|
102
98
|
const minimal = await brandedConfirm({
|
|
103
|
-
message: t('theme.minimal_prompt'),
|
|
99
|
+
message: t('theme.minimal_prompt'),
|
|
104
100
|
}, t('theme.minimal_title'));
|
|
105
101
|
|
|
106
102
|
const themeSlug = slugify(name);
|
|
@@ -127,7 +123,6 @@ export async function themeCreateCommand() {
|
|
|
127
123
|
|
|
128
124
|
const themeData = {
|
|
129
125
|
name: name.trim(),
|
|
130
|
-
author: author.trim() || null,
|
|
131
126
|
theme_folder: themeSlug,
|
|
132
127
|
description: description.trim() || null,
|
|
133
128
|
active: 0,
|
|
@@ -281,7 +276,6 @@ export async function themeCreateCommand() {
|
|
|
281
276
|
minimal: minimal,
|
|
282
277
|
name: name.trim(),
|
|
283
278
|
description: description.trim() || undefined,
|
|
284
|
-
author: author.trim() || undefined,
|
|
285
279
|
};
|
|
286
280
|
|
|
287
281
|
console.log(chalk.yellow(t('theme.downloading_files')));
|
|
@@ -312,7 +306,7 @@ export async function themeCreateCommand() {
|
|
|
312
306
|
console.log(chalk.bold.green(t('theme.create_success')));
|
|
313
307
|
console.log(chalk.gray(' ' + t('theme.create_location', { path: `${storeSlug}/${themeSlug}/` }) + '\n'));
|
|
314
308
|
console.log(chalk.cyan(t('theme.dev_start_tip')));
|
|
315
|
-
console.log(chalk.white(
|
|
309
|
+
console.log(chalk.white(' tsoft theme dev\n'));
|
|
316
310
|
});
|
|
317
311
|
|
|
318
312
|
writer.on('error', (error) => {
|
package/src/commands/whoami.js
CHANGED
|
@@ -101,7 +101,7 @@ export async function whoamiCommand() {
|
|
|
101
101
|
|
|
102
102
|
// Config dizini
|
|
103
103
|
console.log(chalk.cyan(t('whoami.config_dir_label')));
|
|
104
|
-
console.log(chalk.gray(`
|
|
104
|
+
console.log(chalk.gray(` ~/.tsoft-cli/${tokens.store.replace(/\./g, '-').toLowerCase()}/\n`));
|
|
105
105
|
|
|
106
106
|
// Son güncelleme
|
|
107
107
|
if (tokens.updatedAt) {
|
package/src/storage.js
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import fs from 'fs/promises';
|
|
2
2
|
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
3
4
|
import axios from 'axios';
|
|
4
5
|
import * as config from './config.js';
|
|
5
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Global config dizini (~/.tsoft-cli/)
|
|
9
|
+
* Token, store bilgileri ve active-store burada tutulur
|
|
10
|
+
*/
|
|
11
|
+
const GLOBAL_CONFIG_DIR = path.join(os.homedir(), '.tsoft-cli');
|
|
12
|
+
|
|
6
13
|
/**
|
|
7
14
|
* Store domain'i dizin adına uygun formata çevirir
|
|
8
15
|
* @param {string} domain - Store domain (örn: birtan.1isim.com)
|
|
@@ -13,13 +20,13 @@ export function normalizeStoreDomain(domain) {
|
|
|
13
20
|
}
|
|
14
21
|
|
|
15
22
|
/**
|
|
16
|
-
* Store'a özel config dizinini döner (
|
|
23
|
+
* Store'a özel config dizinini döner (global ~/.tsoft-cli/)
|
|
17
24
|
* @param {string} store - Store domain
|
|
18
25
|
* @returns {string} Config dizin path'i
|
|
19
26
|
*/
|
|
20
27
|
export function getStoreConfigDir(store) {
|
|
21
28
|
const storeSlug = normalizeStoreDomain(store);
|
|
22
|
-
return path.join(
|
|
29
|
+
return path.join(GLOBAL_CONFIG_DIR, storeSlug);
|
|
23
30
|
}
|
|
24
31
|
|
|
25
32
|
/**
|
|
@@ -46,8 +53,8 @@ export function getStoreEnvFile(store) {
|
|
|
46
53
|
* @returns {Promise<void>}
|
|
47
54
|
*/
|
|
48
55
|
export async function setActiveStore(store) {
|
|
49
|
-
const activeStoreFile = path.join(
|
|
50
|
-
await fs.mkdir(
|
|
56
|
+
const activeStoreFile = path.join(GLOBAL_CONFIG_DIR, 'active-store.txt');
|
|
57
|
+
await fs.mkdir(GLOBAL_CONFIG_DIR, { recursive: true });
|
|
51
58
|
await fs.writeFile(activeStoreFile, store, 'utf-8');
|
|
52
59
|
}
|
|
53
60
|
|
|
@@ -57,7 +64,7 @@ export async function setActiveStore(store) {
|
|
|
57
64
|
*/
|
|
58
65
|
export async function getActiveStore() {
|
|
59
66
|
try {
|
|
60
|
-
const activeStoreFile = path.join(
|
|
67
|
+
const activeStoreFile = path.join(GLOBAL_CONFIG_DIR, 'active-store.txt');
|
|
61
68
|
return (await fs.readFile(activeStoreFile, 'utf-8')).trim();
|
|
62
69
|
} catch (error) {
|
|
63
70
|
if (error.code === 'ENOENT') {
|
|
@@ -372,7 +379,7 @@ export async function deleteConfig(store = null) {
|
|
|
372
379
|
await fs.rm(configDir, { recursive: true, force: true });
|
|
373
380
|
|
|
374
381
|
// Active store dosyasını da sil
|
|
375
|
-
const activeStoreFile = path.join(
|
|
382
|
+
const activeStoreFile = path.join(GLOBAL_CONFIG_DIR, 'active-store.txt');
|
|
376
383
|
await fs.unlink(activeStoreFile).catch(() => {}); // Hata varsa sessizce yoksay
|
|
377
384
|
} catch (error) {
|
|
378
385
|
if (error.code !== 'ENOENT') {
|
|
@@ -440,8 +447,8 @@ export function slugify(text) {
|
|
|
440
447
|
* @returns {Promise<void>}
|
|
441
448
|
*/
|
|
442
449
|
export async function setActiveTheme(theme) {
|
|
443
|
-
const activeThemeFile = path.join(
|
|
444
|
-
await fs.mkdir(
|
|
450
|
+
const activeThemeFile = path.join(GLOBAL_CONFIG_DIR, 'active-theme.txt');
|
|
451
|
+
await fs.mkdir(GLOBAL_CONFIG_DIR, { recursive: true });
|
|
445
452
|
await fs.writeFile(activeThemeFile, theme, 'utf-8');
|
|
446
453
|
}
|
|
447
454
|
|
|
@@ -451,7 +458,7 @@ export async function setActiveTheme(theme) {
|
|
|
451
458
|
*/
|
|
452
459
|
export async function getActiveTheme() {
|
|
453
460
|
try {
|
|
454
|
-
const activeThemeFile = path.join(
|
|
461
|
+
const activeThemeFile = path.join(GLOBAL_CONFIG_DIR, 'active-theme.txt');
|
|
455
462
|
return (await fs.readFile(activeThemeFile, 'utf-8')).trim();
|
|
456
463
|
} catch (error) {
|
|
457
464
|
if (error.code === 'ENOENT') {
|
package/src/ui/prompt-wrapper.js
CHANGED
|
@@ -53,7 +53,7 @@ export function showBrandedBox(message, title = '', options = {}) {
|
|
|
53
53
|
* @param {string} boxTitle - Box başlığı
|
|
54
54
|
*/
|
|
55
55
|
export async function brandedConfirm(options, boxTitle = t('ui.label.confirm')) {
|
|
56
|
-
const {message, default: defaultValue =
|
|
56
|
+
const {message, default: defaultValue = true, ...restOptions} = options;
|
|
57
57
|
|
|
58
58
|
// message içinde \n\n varsa: ilk satır = prompt sorusu, kalan = box açıklaması
|
|
59
59
|
let promptMessage = message;
|