@localheroai/cli 0.0.2 → 0.0.5
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 +98 -0
- package/package.json +63 -58
- package/src/api/auth.js +20 -11
- package/src/api/client.js +70 -28
- package/src/api/imports.js +15 -13
- package/src/api/projects.js +17 -17
- package/src/api/translations.js +50 -29
- package/src/cli.js +49 -42
- package/src/commands/init.js +436 -236
- package/src/commands/login.js +59 -48
- package/src/commands/sync.js +28 -0
- package/src/commands/translate.js +232 -247
- package/src/utils/auth.js +15 -15
- package/src/utils/config.js +115 -86
- package/src/utils/files.js +358 -116
- package/src/utils/git.js +64 -8
- package/src/utils/github.js +83 -47
- package/src/utils/import-service.js +111 -129
- package/src/utils/prompt-service.js +66 -50
- package/src/utils/sync-service.js +147 -0
- package/src/utils/translation-updater/common.js +44 -0
- package/src/utils/translation-updater/index.js +36 -0
- package/src/utils/translation-updater/json-handler.js +111 -0
- package/src/utils/translation-updater/yaml-handler.js +207 -0
- package/src/utils/translation-utils.js +278 -0
- package/src/utils/defaults.js +0 -7
- package/src/utils/helpers.js +0 -3
- package/src/utils/project-service.js +0 -11
- package/src/utils/translation-updater.js +0 -154
package/src/commands/login.js
CHANGED
|
@@ -1,69 +1,80 @@
|
|
|
1
|
-
import { promises as fs } from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
1
|
import chalk from 'chalk';
|
|
4
2
|
import { createPromptService } from '../utils/prompt-service.js';
|
|
5
3
|
import { updateGitignore } from '../utils/git.js';
|
|
6
|
-
import { defaultDependencies } from '../utils/defaults.js';
|
|
7
4
|
import { verifyApiKey as defaultVerifyApiKey } from '../api/auth.js';
|
|
8
5
|
import { configService } from '../utils/config.js';
|
|
9
6
|
|
|
10
7
|
const API_KEY_PATTERN = /^tk_[a-zA-Z0-9]{48}$/;
|
|
11
8
|
|
|
12
|
-
export async function login(deps =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
9
|
+
export async function login(deps = {}) {
|
|
10
|
+
const {
|
|
11
|
+
console = global.console,
|
|
12
|
+
basePath = process.cwd(),
|
|
13
|
+
promptService = createPromptService({ inquirer: await import('@inquirer/prompts') }),
|
|
14
|
+
verifyApiKey = defaultVerifyApiKey,
|
|
15
|
+
gitUtils = { updateGitignore },
|
|
16
|
+
configUtils = configService,
|
|
17
|
+
isCalledFromInit = false
|
|
18
|
+
} = deps;
|
|
21
19
|
|
|
22
|
-
|
|
20
|
+
const existingConfig = await configUtils.getAuthConfig(basePath);
|
|
23
21
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
if (existingConfig?.api_key) {
|
|
23
|
+
console.log(chalk.yellow('\n⚠️ Warning: This will replace your existing API key configuration'));
|
|
24
|
+
}
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
)
|
|
26
|
+
const apiKey = process.env.LOCALHERO_API_KEY || (
|
|
27
|
+
console.log('\n→ Get your API key from: https://localhero.ai/api-keys'),
|
|
28
|
+
console.log('→ New to LocalHero? Sign up at: https://localhero.ai/signup'),
|
|
29
|
+
console.log(chalk.gray('The API key will be saved to .localhero_key, and automatically added to your .gitignore file.\n')),
|
|
30
|
+
await promptService.getApiKey()
|
|
31
|
+
);
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
if (!apiKey) {
|
|
34
|
+
throw new Error('User cancelled');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (!API_KEY_PATTERN.test(apiKey)) {
|
|
38
|
+
throw new Error('Invalid API key format');
|
|
39
|
+
}
|
|
36
40
|
|
|
37
|
-
|
|
41
|
+
const result = await verifyApiKey(apiKey);
|
|
38
42
|
|
|
39
|
-
|
|
40
|
-
|
|
43
|
+
if (result.error) {
|
|
44
|
+
if (result.error.code === 'invalid_api_key') {
|
|
45
|
+
console.log(chalk.red('\n❌ ' + result.error.message));
|
|
46
|
+
console.log(chalk.blue('\nℹ️ Get a new API key at https://localhero.ai/api-keys'));
|
|
47
|
+
process.exit(1);
|
|
41
48
|
}
|
|
49
|
+
throw new Error(result.error.message);
|
|
50
|
+
}
|
|
42
51
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
52
|
+
const config = {
|
|
53
|
+
api_key: apiKey,
|
|
54
|
+
last_verified: new Date().toISOString()
|
|
55
|
+
};
|
|
47
56
|
|
|
48
|
-
|
|
49
|
-
|
|
57
|
+
await configUtils.saveAuthConfig(config, basePath);
|
|
58
|
+
const gitignoreUpdated = await gitUtils.updateGitignore(basePath);
|
|
50
59
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
60
|
+
console.log(chalk.green('\n✓ API key verified and saved to .localhero_key'));
|
|
61
|
+
if (gitignoreUpdated) {
|
|
62
|
+
console.log(chalk.green('✓ Added .localhero_key to .gitignore'));
|
|
63
|
+
}
|
|
55
64
|
|
|
56
|
-
|
|
57
|
-
|
|
65
|
+
console.log(chalk.blue(`💼️ Organization: ${result.organization.name}`));
|
|
66
|
+
if (result.organization.projects.length > 0) {
|
|
67
|
+
console.log(chalk.blue(`\n📚 Projects: ${result.organization.projects.map(p => p.name).join(', ')}`));
|
|
68
|
+
}
|
|
58
69
|
|
|
59
|
-
|
|
70
|
+
const projectConfig = await configUtils.getProjectConfig(basePath);
|
|
60
71
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
72
|
+
if (!projectConfig && !isCalledFromInit) {
|
|
73
|
+
console.log(chalk.yellow('\n⚠️ Almost there! You need to set up your project configuration.'));
|
|
74
|
+
console.log(chalk.blue('Run this next:'));
|
|
75
|
+
console.log(chalk.white('\n npx @localheroai/cli init\n'));
|
|
76
|
+
} else if (!isCalledFromInit) {
|
|
77
|
+
console.log('\nYou\'re ready to start translating!');
|
|
78
|
+
console.log('Try running: npx @localheroai/cli translate');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { syncService as defaultSyncService } from '../utils/sync-service.js';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
|
|
4
|
+
export async function sync({ verbose = false } = {}, deps = { syncService: defaultSyncService }) {
|
|
5
|
+
const { syncService } = deps;
|
|
6
|
+
const { hasUpdates, updates } = await syncService.checkForUpdates({ verbose });
|
|
7
|
+
|
|
8
|
+
if (!hasUpdates) {
|
|
9
|
+
console.log(chalk.green('✓ All translations are up to date'));
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const result = await syncService.applyUpdates(updates, { verbose });
|
|
14
|
+
|
|
15
|
+
const { totalUpdates = 0, totalDeleted = 0 } = result;
|
|
16
|
+
|
|
17
|
+
if (!verbose) {
|
|
18
|
+
if (totalUpdates > 0) {
|
|
19
|
+
console.log(chalk.green(`✓ Updated ${totalUpdates} translations`));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (totalDeleted > 0) {
|
|
23
|
+
console.log(chalk.green(`✓ Deleted ${totalDeleted} keys`));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return result;
|
|
28
|
+
}
|