tsoft-cli 3.4.2 → 3.5.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/CHANGELOG.md +20 -0
- package/locales/en.json +4 -1
- package/locales/tr.json +4 -1
- package/package.json +1 -1
- package/src/commands/login.js +1 -1
- package/src/commands/theme.js +6 -7
- package/src/commands/whoami.js +1 -1
- package/src/storage.js +16 -9
- package/src/ui/prompt-wrapper.js +18 -8
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,26 @@ 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.0] - 2026-04-09
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- Config storage moved from working directory to `~/.tsoft-cli/` (cross-platform)
|
|
12
|
+
- Login once, use from any directory
|
|
13
|
+
- Confirm prompts default to "Yes" selection
|
|
14
|
+
- Removed author field from theme creation flow
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- Login check before theme create prevents crash when not logged in
|
|
18
|
+
|
|
19
|
+
## [3.4.3] - 2026-04-08
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
- Login check before theme create — no more crash when not logged in
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
- Confirm prompts now use Evet/Hayır select instead of y/N
|
|
26
|
+
- "Minimal tema" renamed to "Starter tema"
|
|
27
|
+
|
|
8
28
|
## [3.4.2] - 2026-04-08
|
|
9
29
|
|
|
10
30
|
### Fixed
|
package/locales/en.json
CHANGED
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
"ui.label.theme_selection": "🎨 Theme Selection",
|
|
10
10
|
"ui.label.loading": "⏳ Processing",
|
|
11
11
|
"ui.prompt.continue": "Do you want to continue?",
|
|
12
|
+
"ui.label.yes": "Yes",
|
|
13
|
+
"ui.label.no": "No",
|
|
12
14
|
"ui.label.disabled": "(Disabled)",
|
|
13
15
|
|
|
14
16
|
"error.push.pending_review.message": "Cannot push: theme is pending review.",
|
|
@@ -87,12 +89,13 @@
|
|
|
87
89
|
"theme.no_themes": "⚠️ No themes found yet.",
|
|
88
90
|
"theme.count": "Total {{count}} themes found:",
|
|
89
91
|
"theme.folder_label": "Folder:",
|
|
92
|
+
"theme.login_required": "You must log in first. Run: tsoft login",
|
|
90
93
|
"theme.creating": "🎨 Creating new theme...",
|
|
91
94
|
"theme.name_prompt": "Theme Name:",
|
|
92
95
|
"theme.name_required": "Theme name cannot be empty",
|
|
93
96
|
"theme.description_prompt": "Description:",
|
|
94
97
|
"theme.author_prompt": "Developer:",
|
|
95
|
-
"theme.minimal_prompt": "
|
|
98
|
+
"theme.minimal_prompt": "Start with a starter theme?\n\nStarter theme includes only basic blocks, suitable for building from scratch.",
|
|
96
99
|
"theme.minimal_title": "🎨 Theme Type",
|
|
97
100
|
"theme.dir_exists_title": "⚠️ Directory Exists",
|
|
98
101
|
"theme.dir_exists_prompt": "Directory already exists!\n\nLocation: {{path}}\n\nOverwrite?",
|
package/locales/tr.json
CHANGED
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
"ui.label.theme_selection": "🎨 Tema Seçimi",
|
|
10
10
|
"ui.label.loading": "⏳ İşlem Devam Ediyor",
|
|
11
11
|
"ui.prompt.continue": "Devam etmek istiyor musunuz?",
|
|
12
|
+
"ui.label.yes": "Evet",
|
|
13
|
+
"ui.label.no": "Hayır",
|
|
12
14
|
"ui.label.disabled": "(Devre Dışı)",
|
|
13
15
|
|
|
14
16
|
"error.push.pending_review.message": "Push yapilamaz: tema inceleme bekliyor.",
|
|
@@ -87,12 +89,13 @@
|
|
|
87
89
|
"theme.no_themes": "⚠️ Henüz tema bulunmuyor.",
|
|
88
90
|
"theme.count": "Toplam {{count}} tema bulundu:",
|
|
89
91
|
"theme.folder_label": "Klasör:",
|
|
92
|
+
"theme.login_required": "Önce giriş yapmalısınız. Çalıştırın: tsoft login",
|
|
90
93
|
"theme.creating": "🎨 Yeni tema oluşturuluyor...",
|
|
91
94
|
"theme.name_prompt": "Tema Adı:",
|
|
92
95
|
"theme.name_required": "Tema adı boş olamaz",
|
|
93
96
|
"theme.description_prompt": "Açıklama:",
|
|
94
97
|
"theme.author_prompt": "Geliştirici:",
|
|
95
|
-
"theme.minimal_prompt": "
|
|
98
|
+
"theme.minimal_prompt": "Starter tema ile başlansın mı?\n\nStarter tema sadece temel blokları içerir, sıfırdan geliştirmeye uygundur.",
|
|
96
99
|
"theme.minimal_title": "🎨 Tema Tipi",
|
|
97
100
|
"theme.dir_exists_title": "⚠️ Dizin Mevcut",
|
|
98
101
|
"theme.dir_exists_prompt": "Dizin zaten mevcut!\n\nKonum: {{path}}\n\nÜzerine yazılsın mı?",
|
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
|
|
package/src/commands/theme.js
CHANGED
|
@@ -73,6 +73,12 @@ export async function themeListCommand() {
|
|
|
73
73
|
|
|
74
74
|
export async function themeCreateCommand() {
|
|
75
75
|
try {
|
|
76
|
+
const store = await getActiveStore();
|
|
77
|
+
if (!store) {
|
|
78
|
+
showWarning(t('theme.login_required'));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
76
82
|
console.log(chalk.cyan(t('theme.creating') + '\n'));
|
|
77
83
|
|
|
78
84
|
const name = await input({
|
|
@@ -88,17 +94,12 @@ export async function themeCreateCommand() {
|
|
|
88
94
|
message: t('theme.description_prompt'), default: '',
|
|
89
95
|
});
|
|
90
96
|
|
|
91
|
-
const author = await input({
|
|
92
|
-
message: t('theme.author_prompt'), default: '',
|
|
93
|
-
});
|
|
94
|
-
|
|
95
97
|
|
|
96
98
|
const minimal = await brandedConfirm({
|
|
97
99
|
message: t('theme.minimal_prompt'), default: false,
|
|
98
100
|
}, t('theme.minimal_title'));
|
|
99
101
|
|
|
100
102
|
const themeSlug = slugify(name);
|
|
101
|
-
const store = await getActiveStore();
|
|
102
103
|
const storeSlug = normalizeStoreDomain(store);
|
|
103
104
|
const themePath = path.join(process.cwd(), storeSlug, themeSlug);
|
|
104
105
|
|
|
@@ -122,7 +123,6 @@ export async function themeCreateCommand() {
|
|
|
122
123
|
|
|
123
124
|
const themeData = {
|
|
124
125
|
name: name.trim(),
|
|
125
|
-
author: author.trim() || null,
|
|
126
126
|
theme_folder: themeSlug,
|
|
127
127
|
description: description.trim() || null,
|
|
128
128
|
active: 0,
|
|
@@ -276,7 +276,6 @@ export async function themeCreateCommand() {
|
|
|
276
276
|
minimal: minimal,
|
|
277
277
|
name: name.trim(),
|
|
278
278
|
description: description.trim() || undefined,
|
|
279
|
-
author: author.trim() || undefined,
|
|
280
279
|
};
|
|
281
280
|
|
|
282
281
|
console.log(chalk.yellow(t('theme.downloading_files')));
|
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,16 +53,26 @@ 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, ...restOptions} = options;
|
|
57
|
-
|
|
58
|
-
//
|
|
59
|
-
|
|
56
|
+
const {message, default: defaultValue = true, ...restOptions} = options;
|
|
57
|
+
|
|
58
|
+
// message içinde \n\n varsa: ilk satır = prompt sorusu, kalan = box açıklaması
|
|
59
|
+
let promptMessage = message;
|
|
60
|
+
if (message.includes('\n\n')) {
|
|
61
|
+
const [question, ...descParts] = message.split('\n\n');
|
|
62
|
+
promptMessage = question;
|
|
63
|
+
showBrandedBox(descParts.join('\n\n'), boxTitle);
|
|
64
|
+
}
|
|
60
65
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
66
|
+
const answer = await inquirerSelect({
|
|
67
|
+
message: promptMessage,
|
|
68
|
+
choices: [
|
|
69
|
+
{ name: t('ui.label.yes'), value: true },
|
|
70
|
+
{ name: t('ui.label.no'), value: false },
|
|
71
|
+
],
|
|
72
|
+
default: defaultValue,
|
|
65
73
|
});
|
|
74
|
+
|
|
75
|
+
return answer;
|
|
66
76
|
}
|
|
67
77
|
|
|
68
78
|
/**
|