@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.
@@ -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 = defaultDependencies) {
13
- const {
14
- console = global.console,
15
- basePath = process.cwd(),
16
- promptService = createPromptService({ inquirer: await import('@inquirer/prompts') }),
17
- verifyApiKey = defaultVerifyApiKey,
18
- gitUtils = { updateGitignore },
19
- configUtils = configService
20
- } = deps;
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
- const existingConfig = await configUtils.getAuthConfig(basePath);
20
+ const existingConfig = await configUtils.getAuthConfig(basePath);
23
21
 
24
- if (existingConfig?.api_key) {
25
- console.log(chalk.yellow('\n⚠️ Warning: This will replace your existing API key configuration'));
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
- const apiKey = process.env.LOCALHERO_API_KEY || (
29
- console.log(chalk.blue('\nℹ️ Please enter your API key from https://localhero.ai/api-keys\n')),
30
- await promptService.getApiKey()
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
- if (!API_KEY_PATTERN.test(apiKey)) {
34
- throw new Error('Invalid API key format');
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
- const result = await verifyApiKey(apiKey);
41
+ const result = await verifyApiKey(apiKey);
38
42
 
39
- if (result.error) {
40
- throw new Error(result.error.message);
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
- const config = {
44
- api_key: apiKey,
45
- last_verified: new Date().toISOString()
46
- };
52
+ const config = {
53
+ api_key: apiKey,
54
+ last_verified: new Date().toISOString()
55
+ };
47
56
 
48
- await configUtils.saveAuthConfig(config, basePath);
49
- const gitignoreUpdated = await gitUtils.updateGitignore(basePath);
57
+ await configUtils.saveAuthConfig(config, basePath);
58
+ const gitignoreUpdated = await gitUtils.updateGitignore(basePath);
50
59
 
51
- console.log(chalk.green('\n✓ API key verified and saved to .localhero_key'));
52
- if (gitignoreUpdated) {
53
- console.log(chalk.green('✓ Added .localhero_key to .gitignore'));
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
- console.log(chalk.blue(`💼️ Organization: ${result.organization.name}`));
57
- console.log(chalk.blue(`📚 Projects: ${result.organization.projects.map(p => p.name).join(', ')}`));
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
- const projectConfig = await configUtils.getProjectConfig(basePath);
70
+ const projectConfig = await configUtils.getProjectConfig(basePath);
60
71
 
61
- if (!projectConfig) {
62
- console.log(chalk.yellow('\n⚠️ Almost there! You need to set up your project configuration.'));
63
- console.log(chalk.blue('Run this next:'));
64
- console.log(chalk.white('\n npx localhero init\n'));
65
- } else {
66
- console.log('\nYou\'re ready to start translating!');
67
- console.log('Try running: npx localhero translate');
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
+ }