langctl 0.1.1 → 0.1.2

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,39 +1,44 @@
1
1
  import chalk from 'chalk';
2
2
  import ora from 'ora';
3
- import { getSupabase } from '../supabase.js';
4
- import { isAuthenticated, getOrganizationId } from '../auth.js';
3
+ import { isAuthenticated, getApiKey } from '../auth.js';
4
+ const LIST_PROJECTS_URL = 'https://bcgnmvkgkbhbxzzflwdb.supabase.co/functions/v1/list-projects';
5
+ const MANAGE_PROJECTS_URL = 'https://bcgnmvkgkbhbxzzflwdb.supabase.co/functions/v1/manage-projects';
5
6
  export async function projectsListCommand() {
6
7
  // Check authentication
7
8
  if (!isAuthenticated()) {
8
9
  console.log(chalk.red('✗ Not authenticated. Please run "langctl auth <api-key>" first.\n'));
9
10
  return;
10
11
  }
11
- const organizationId = getOrganizationId();
12
- if (!organizationId) {
13
- console.log(chalk.red('✗ Organization ID not found. Please run "langctl init" again.\n'));
12
+ const apiKey = getApiKey();
13
+ if (!apiKey) {
14
+ console.log(chalk.red('✗ API key not found. Please run "langctl auth <api-key>" again.\n'));
14
15
  return;
15
16
  }
16
17
  const spinner = ora('Fetching projects...').start();
17
18
  try {
18
- const supabase = getSupabase();
19
- const { data, error } = await supabase
20
- .from('projects')
21
- .select('*')
22
- .eq('organization_id', organizationId)
23
- .is('deleted_at', null)
24
- .order('created_at', { ascending: false });
25
- if (error) {
26
- spinner.fail(chalk.red('Failed to fetch projects'));
27
- console.error(chalk.red(`Error: ${error.message}\n`));
28
- return;
19
+ // Call list-projects Edge Function
20
+ const response = await fetch(LIST_PROJECTS_URL, {
21
+ method: 'POST',
22
+ headers: {
23
+ 'Content-Type': 'application/json',
24
+ 'X-API-Key': apiKey
25
+ }
26
+ });
27
+ if (!response.ok) {
28
+ const errorData = await response.json().catch(() => ({}));
29
+ throw new Error(errorData.error || `HTTP ${response.status}: ${response.statusText}`);
30
+ }
31
+ const data = await response.json();
32
+ if (!data.success) {
33
+ throw new Error(data.error || 'Failed to fetch projects');
29
34
  }
30
35
  spinner.stop();
31
- if (!data || data.length === 0) {
36
+ if (!data.projects || data.projects.length === 0) {
32
37
  console.log(chalk.yellow('\nNo projects found. Create one in the dashboard first.\n'));
33
38
  return;
34
39
  }
35
- console.log(chalk.blue.bold(`\n📦 Projects (${data.length})\n`));
36
- data.forEach((project) => {
40
+ console.log(chalk.blue.bold(`\n📦 Projects (${data.projects.length})\n`));
41
+ data.projects.forEach((project) => {
37
42
  console.log(chalk.white.bold(project.name));
38
43
  console.log(chalk.gray(` Slug: ${project.slug}`));
39
44
  if (project.description) {
@@ -41,14 +46,357 @@ export async function projectsListCommand() {
41
46
  }
42
47
  console.log(chalk.gray(` Languages: ${project.languages.join(', ')}`));
43
48
  console.log(chalk.gray(` Default: ${project.default_language}`));
49
+ if (project.modules && project.modules.length > 0) {
50
+ console.log(chalk.gray(` Modules: ${project.modules.join(', ')}`));
51
+ }
44
52
  console.log('');
45
53
  });
46
- console.log(chalk.blue('To pull translations, run:'));
47
- console.log(chalk.white(` langctl pull ${data[0].slug}\n`));
54
+ console.log(chalk.blue('To export translations, run:'));
55
+ console.log(chalk.white(` langctl export ${data.projects[0].slug} -l en\n`));
48
56
  }
49
57
  catch (error) {
50
58
  spinner.fail(chalk.red('Failed to fetch projects'));
51
59
  console.error(chalk.red(`Error: ${error.message}\n`));
52
60
  }
53
61
  }
62
+ /**
63
+ * Create new project
64
+ */
65
+ export async function projectsCreateCommand(name, options) {
66
+ if (!isAuthenticated()) {
67
+ console.log(chalk.red('✗ Not authenticated. Please run "langctl auth <api-key>" first.\n'));
68
+ return;
69
+ }
70
+ const apiKey = getApiKey();
71
+ const spinner = ora('Creating project...').start();
72
+ try {
73
+ const languages = options.languages ? options.languages.split(',') : ['en'];
74
+ const defaultLanguage = options.defaultLanguage || languages[0];
75
+ const response = await fetch(MANAGE_PROJECTS_URL, {
76
+ method: 'POST',
77
+ headers: {
78
+ 'Content-Type': 'application/json',
79
+ 'X-API-Key': apiKey
80
+ },
81
+ body: JSON.stringify({
82
+ action: 'create',
83
+ name,
84
+ description: options.description,
85
+ languages,
86
+ defaultLanguage
87
+ })
88
+ });
89
+ const data = await response.json();
90
+ if (!data.success) {
91
+ throw new Error(data.error);
92
+ }
93
+ spinner.succeed(chalk.green(`Created project: ${name} (${data.project.slug})`));
94
+ console.log('');
95
+ }
96
+ catch (error) {
97
+ spinner.fail(chalk.red('Failed to create project'));
98
+ console.error(chalk.red(`Error: ${error.message}\n`));
99
+ }
100
+ }
101
+ /**
102
+ * Get project details
103
+ */
104
+ export async function projectsGetCommand(slug) {
105
+ if (!isAuthenticated()) {
106
+ console.log(chalk.red('✗ Not authenticated. Please run "langctl auth <api-key>" first.\n'));
107
+ return;
108
+ }
109
+ const apiKey = getApiKey();
110
+ const spinner = ora('Fetching project...').start();
111
+ try {
112
+ // Get project from list first
113
+ const listResponse = await fetch(LIST_PROJECTS_URL, {
114
+ method: 'POST',
115
+ headers: {
116
+ 'Content-Type': 'application/json',
117
+ 'X-API-Key': apiKey
118
+ }
119
+ });
120
+ const listData = await listResponse.json();
121
+ const project = listData.projects?.find((p) => p.slug === slug);
122
+ if (!project) {
123
+ spinner.fail(chalk.red(`Project "${slug}" not found`));
124
+ return;
125
+ }
126
+ spinner.stop();
127
+ console.log(chalk.blue.bold('\n📦 Project Details\n'));
128
+ console.log(chalk.white.bold(project.name));
129
+ console.log(chalk.gray(`Slug: ${project.slug}`));
130
+ console.log(chalk.gray(`ID: ${project.id}`));
131
+ if (project.description) {
132
+ console.log(chalk.gray(`Description: ${project.description}`));
133
+ }
134
+ console.log(chalk.gray(`Languages: ${project.languages.join(', ')}`));
135
+ console.log(chalk.gray(`Default Language: ${project.default_language}`));
136
+ if (project.modules && project.modules.length > 0) {
137
+ console.log(chalk.gray(`Modules: ${project.modules.join(', ')}`));
138
+ }
139
+ console.log('');
140
+ }
141
+ catch (error) {
142
+ spinner.fail(chalk.red('Failed to fetch project'));
143
+ console.error(chalk.red(`Error: ${error.message}\n`));
144
+ }
145
+ }
146
+ /**
147
+ * Update project
148
+ */
149
+ export async function projectsUpdateCommand(slug, options) {
150
+ if (!isAuthenticated()) {
151
+ console.log(chalk.red('✗ Not authenticated. Please run "langctl auth <api-key>" first.\n'));
152
+ return;
153
+ }
154
+ const apiKey = getApiKey();
155
+ const spinner = ora('Updating project...').start();
156
+ try {
157
+ // Get project ID from slug
158
+ const listResponse = await fetch(LIST_PROJECTS_URL, {
159
+ method: 'POST',
160
+ headers: {
161
+ 'Content-Type': 'application/json',
162
+ 'X-API-Key': apiKey
163
+ }
164
+ });
165
+ const listData = await listResponse.json();
166
+ const project = listData.projects?.find((p) => p.slug === slug);
167
+ if (!project) {
168
+ spinner.fail(chalk.red(`Project "${slug}" not found`));
169
+ return;
170
+ }
171
+ const updateData = { projectId: project.id, action: 'update' };
172
+ if (options.name)
173
+ updateData.name = options.name;
174
+ if (options.description !== undefined)
175
+ updateData.description = options.description;
176
+ if (options.languages)
177
+ updateData.languages = options.languages.split(',');
178
+ if (options.defaultLanguage)
179
+ updateData.defaultLanguage = options.defaultLanguage;
180
+ const response = await fetch(MANAGE_PROJECTS_URL, {
181
+ method: 'POST',
182
+ headers: {
183
+ 'Content-Type': 'application/json',
184
+ 'X-API-Key': apiKey
185
+ },
186
+ body: JSON.stringify(updateData)
187
+ });
188
+ const data = await response.json();
189
+ if (!data.success) {
190
+ throw new Error(data.error);
191
+ }
192
+ spinner.succeed(chalk.green(`Updated project: ${slug}`));
193
+ console.log('');
194
+ }
195
+ catch (error) {
196
+ spinner.fail(chalk.red('Failed to update project'));
197
+ console.error(chalk.red(`Error: ${error.message}\n`));
198
+ }
199
+ }
200
+ /**
201
+ * Delete project
202
+ */
203
+ export async function projectsDeleteCommand(slug) {
204
+ if (!isAuthenticated()) {
205
+ console.log(chalk.red('✗ Not authenticated. Please run "langctl auth <api-key>" first.\n'));
206
+ return;
207
+ }
208
+ const apiKey = getApiKey();
209
+ const spinner = ora('Deleting project...').start();
210
+ try {
211
+ // Get project ID from slug
212
+ const listResponse = await fetch(LIST_PROJECTS_URL, {
213
+ method: 'POST',
214
+ headers: {
215
+ 'Content-Type': 'application/json',
216
+ 'X-API-Key': apiKey
217
+ }
218
+ });
219
+ const listData = await listResponse.json();
220
+ const project = listData.projects?.find((p) => p.slug === slug);
221
+ if (!project) {
222
+ spinner.fail(chalk.red(`Project "${slug}" not found`));
223
+ return;
224
+ }
225
+ const response = await fetch(MANAGE_PROJECTS_URL, {
226
+ method: 'POST',
227
+ headers: {
228
+ 'Content-Type': 'application/json',
229
+ 'X-API-Key': apiKey
230
+ },
231
+ body: JSON.stringify({
232
+ action: 'delete',
233
+ projectId: project.id
234
+ })
235
+ });
236
+ const data = await response.json();
237
+ if (!data.success) {
238
+ throw new Error(data.error);
239
+ }
240
+ spinner.succeed(chalk.green(`Deleted project: ${slug}`));
241
+ console.log('');
242
+ }
243
+ catch (error) {
244
+ spinner.fail(chalk.red('Failed to delete project'));
245
+ console.error(chalk.red(`Error: ${error.message}\n`));
246
+ }
247
+ }
248
+ /**
249
+ * Add language to project
250
+ */
251
+ export async function projectsAddLanguageCommand(slug, language) {
252
+ if (!isAuthenticated()) {
253
+ console.log(chalk.red('✗ Not authenticated. Please run "langctl auth <api-key>" first.\n'));
254
+ return;
255
+ }
256
+ const apiKey = getApiKey();
257
+ const spinner = ora(`Adding language ${language}...`).start();
258
+ try {
259
+ // Get project ID from slug
260
+ const listResponse = await fetch(LIST_PROJECTS_URL, {
261
+ method: 'POST',
262
+ headers: {
263
+ 'Content-Type': 'application/json',
264
+ 'X-API-Key': apiKey
265
+ }
266
+ });
267
+ const listData = await listResponse.json();
268
+ const project = listData.projects?.find((p) => p.slug === slug);
269
+ if (!project) {
270
+ spinner.fail(chalk.red(`Project "${slug}" not found`));
271
+ return;
272
+ }
273
+ const response = await fetch(MANAGE_PROJECTS_URL, {
274
+ method: 'POST',
275
+ headers: {
276
+ 'Content-Type': 'application/json',
277
+ 'X-API-Key': apiKey
278
+ },
279
+ body: JSON.stringify({
280
+ action: 'add-language',
281
+ projectId: project.id,
282
+ language
283
+ })
284
+ });
285
+ const data = await response.json();
286
+ if (!data.success) {
287
+ throw new Error(data.error);
288
+ }
289
+ spinner.succeed(chalk.green(data.message));
290
+ console.log('');
291
+ }
292
+ catch (error) {
293
+ spinner.fail(chalk.red('Failed to add language'));
294
+ console.error(chalk.red(`Error: ${error.message}\n`));
295
+ }
296
+ }
297
+ /**
298
+ * Remove language from project
299
+ */
300
+ export async function projectsRemoveLanguageCommand(slug, language) {
301
+ if (!isAuthenticated()) {
302
+ console.log(chalk.red('✗ Not authenticated. Please run "langctl auth <api-key>" first.\n'));
303
+ return;
304
+ }
305
+ const apiKey = getApiKey();
306
+ const spinner = ora(`Removing language ${language}...`).start();
307
+ try {
308
+ // Get project ID from slug
309
+ const listResponse = await fetch(LIST_PROJECTS_URL, {
310
+ method: 'POST',
311
+ headers: {
312
+ 'Content-Type': 'application/json',
313
+ 'X-API-Key': apiKey
314
+ }
315
+ });
316
+ const listData = await listResponse.json();
317
+ const project = listData.projects?.find((p) => p.slug === slug);
318
+ if (!project) {
319
+ spinner.fail(chalk.red(`Project "${slug}" not found`));
320
+ return;
321
+ }
322
+ const response = await fetch(MANAGE_PROJECTS_URL, {
323
+ method: 'POST',
324
+ headers: {
325
+ 'Content-Type': 'application/json',
326
+ 'X-API-Key': apiKey
327
+ },
328
+ body: JSON.stringify({
329
+ action: 'remove-language',
330
+ projectId: project.id,
331
+ language
332
+ })
333
+ });
334
+ const data = await response.json();
335
+ if (!data.success) {
336
+ throw new Error(data.error);
337
+ }
338
+ spinner.succeed(chalk.green(data.message));
339
+ console.log('');
340
+ }
341
+ catch (error) {
342
+ spinner.fail(chalk.red('Failed to remove language'));
343
+ console.error(chalk.red(`Error: ${error.message}\n`));
344
+ }
345
+ }
346
+ /**
347
+ * Get project statistics
348
+ */
349
+ export async function projectsStatsCommand(slug) {
350
+ if (!isAuthenticated()) {
351
+ console.log(chalk.red('✗ Not authenticated. Please run "langctl auth <api-key>" first.\n'));
352
+ return;
353
+ }
354
+ const apiKey = getApiKey();
355
+ const spinner = ora('Fetching statistics...').start();
356
+ try {
357
+ // Get project ID from slug
358
+ const listResponse = await fetch(LIST_PROJECTS_URL, {
359
+ method: 'POST',
360
+ headers: {
361
+ 'Content-Type': 'application/json',
362
+ 'X-API-Key': apiKey
363
+ }
364
+ });
365
+ const listData = await listResponse.json();
366
+ const project = listData.projects?.find((p) => p.slug === slug);
367
+ if (!project) {
368
+ spinner.fail(chalk.red(`Project "${slug}" not found`));
369
+ return;
370
+ }
371
+ const response = await fetch(MANAGE_PROJECTS_URL, {
372
+ method: 'POST',
373
+ headers: {
374
+ 'Content-Type': 'application/json',
375
+ 'X-API-Key': apiKey
376
+ },
377
+ body: JSON.stringify({
378
+ action: 'stats',
379
+ projectId: project.id
380
+ })
381
+ });
382
+ const data = await response.json();
383
+ if (!data.success) {
384
+ throw new Error(data.error);
385
+ }
386
+ spinner.stop();
387
+ console.log(chalk.blue.bold('\n📊 Project Statistics\n'));
388
+ console.log(chalk.white(`Total Keys: ${data.stats.total_keys}`));
389
+ console.log(chalk.green(`Published Keys: ${data.stats.published_keys}`));
390
+ console.log(chalk.yellow(`Unpublished Keys: ${data.stats.unpublished_keys}`));
391
+ console.log(chalk.white(`Modules: ${data.stats.modules}`));
392
+ if (data.stats.module_names && data.stats.module_names.length > 0) {
393
+ console.log(chalk.gray(` ${data.stats.module_names.join(', ')}`));
394
+ }
395
+ console.log('');
396
+ }
397
+ catch (error) {
398
+ spinner.fail(chalk.red('Failed to fetch statistics'));
399
+ console.error(chalk.red(`Error: ${error.message}\n`));
400
+ }
401
+ }
54
402
  //# sourceMappingURL=projects.js.map
@@ -0,0 +1,29 @@
1
+ /**
2
+ * List all team members
3
+ */
4
+ export declare function listTeamCommand(): Promise<void>;
5
+ /**
6
+ * Get team member details
7
+ */
8
+ export declare function getTeamMemberCommand(email: string): Promise<void>;
9
+ /**
10
+ * Invite team member
11
+ */
12
+ export declare function inviteTeamMemberCommand(email: string, options: any): Promise<void>;
13
+ /**
14
+ * Remove team member
15
+ */
16
+ export declare function removeTeamMemberCommand(email: string): Promise<void>;
17
+ /**
18
+ * Update team member role
19
+ */
20
+ export declare function updateTeamRoleCommand(email: string, role: string): Promise<void>;
21
+ /**
22
+ * List invitations
23
+ */
24
+ export declare function listInvitationsCommand(options: any): Promise<void>;
25
+ /**
26
+ * Revoke invitation
27
+ */
28
+ export declare function revokeInvitationCommand(email: string): Promise<void>;
29
+ //# sourceMappingURL=team.d.ts.map