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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsoft-cli",
3
- "version": "3.4.3",
3
+ "version": "3.5.1",
4
4
  "description": "tsoft360 tema geliştirme ve yönetim aracı",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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: .tsoft/${store.replace(/\./g, '-').toLowerCase()}/\n`));
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
- console.log(chalk.gray(`[${new Date().toLocaleTimeString()}] ` + t('dev.keepalive_error')));
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
- console.log(chalk.yellow('\n\n' + t('dev.stopping') + '\n'));
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
 
@@ -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'), default: false,
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(` cd ${storeSlug}/${themeSlug}\n`));
309
+ console.log(chalk.white(' tsoft theme dev\n'));
316
310
  });
317
311
 
318
312
  writer.on('error', (error) => {
@@ -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(` .tsoft/${tokens.store.replace(/\./g, '-').toLowerCase()}/\n`));
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 (CWD bazlı)
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(process.cwd(), '.tsoft', storeSlug);
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(process.cwd(), '.tsoft', 'active-store.txt');
50
- await fs.mkdir(path.dirname(activeStoreFile), { recursive: true });
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(process.cwd(), '.tsoft', 'active-store.txt');
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(process.cwd(), '.tsoft', 'active-store.txt');
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(process.cwd(), '.tsoft', 'active-theme.txt');
444
- await fs.mkdir(path.dirname(activeThemeFile), { recursive: true });
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(process.cwd(), '.tsoft', 'active-theme.txt');
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') {
@@ -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 = false, ...restOptions} = options;
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;