@globio/cli 0.1.8 → 0.1.9

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,30 +1,70 @@
1
- import chalk from 'chalk';
2
1
  import { config } from '../lib/config.js';
2
+ import { manageRequest, type ManageProjectServices } from '../lib/manage.js';
3
+ import {
4
+ footer,
5
+ getCliVersion,
6
+ green,
7
+ header,
8
+ inactive,
9
+ muted,
10
+ orange,
11
+ renderTable,
12
+ } from '../lib/banner.js';
3
13
 
4
- const ALL_SERVICES = [
5
- 'id',
6
- 'doc',
7
- 'vault',
8
- 'pulse',
9
- 'scope',
10
- 'sync',
11
- 'signal',
12
- 'mart',
13
- 'brain',
14
- 'code',
15
- ];
14
+ const version = getCliVersion();
15
+
16
+ const SERVICE_DESCRIPTIONS: Record<string, string> = {
17
+ id: 'Authentication and user management',
18
+ doc: 'Document database',
19
+ vault: 'File storage',
20
+ pulse: 'Feature flags and remote config',
21
+ scope: 'Analytics and event tracking',
22
+ sync: 'Real-time multiplayer rooms',
23
+ signal: 'Push notifications',
24
+ mart: 'Game economy and payments',
25
+ brain: 'AI agents and LLM routing',
26
+ code: 'Edge functions and GC Hooks',
27
+ };
16
28
 
17
29
  export async function servicesList(options: { profile?: string } = {}) {
18
- void options.profile;
19
- void config;
20
- console.log('');
21
- console.log(chalk.cyan('Available Globio services:'));
22
- ALL_SERVICES.forEach((service) => {
23
- console.log(' ' + chalk.white(service));
30
+ const profileName = options.profile ?? config.getActiveProfile() ?? 'default';
31
+ const profile = config.getProfile(profileName);
32
+ let serviceStatuses: ManageProjectServices = {};
33
+
34
+ if (profile?.active_project_id) {
35
+ try {
36
+ serviceStatuses = await manageRequest<ManageProjectServices>(
37
+ `/projects/${profile.active_project_id}/services`,
38
+ { profileName }
39
+ );
40
+ } catch {
41
+ serviceStatuses = {};
42
+ }
43
+ }
44
+
45
+ const rows = Object.entries(SERVICE_DESCRIPTIONS).map(([slug, desc]) => {
46
+ const enabled = serviceStatuses[slug] ?? null;
47
+ return [
48
+ orange(slug),
49
+ muted(desc),
50
+ enabled === true
51
+ ? green('enabled')
52
+ : enabled === false
53
+ ? inactive('disabled')
54
+ : inactive('—'),
55
+ ];
24
56
  });
25
- console.log('');
57
+
58
+ console.log(header(version));
26
59
  console.log(
27
- chalk.gray('Manage service access via console.globio.stanlink.online')
60
+ renderTable({
61
+ columns: [
62
+ { header: 'Service', width: 10 },
63
+ { header: 'Description', width: 42 },
64
+ { header: 'Status', width: 10 },
65
+ ],
66
+ rows,
67
+ })
28
68
  );
29
- console.log('');
69
+ console.log(footer('Manage services at console.globio.stanlink.online'));
30
70
  }
package/src/lib/banner.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { readFileSync } from 'fs';
2
2
  import figlet from 'figlet';
3
3
  import gradientString from 'gradient-string';
4
+ export * from './table.js';
4
5
 
5
6
  const globioGradient = gradientString(
6
7
  '#e85d04',
@@ -39,12 +40,6 @@ export function printInfo(message: string) {
39
40
  console.log('\x1b[2m›\x1b[0m ' + message);
40
41
  }
41
42
 
42
- export const orange = (s: string) => '\x1b[38;2;244;140;6m' + s + '\x1b[0m';
43
-
44
- export const gold = (s: string) => '\x1b[38;2;255;208;0m' + s + '\x1b[0m';
45
-
46
- export const muted = (s: string) => '\x1b[2m' + s + '\x1b[0m';
47
-
48
43
  export function getCliVersion() {
49
44
  const file = readFileSync(new URL('../package.json', import.meta.url), 'utf8');
50
45
  return (JSON.parse(file) as { version: string }).version;
package/src/lib/config.ts CHANGED
@@ -11,6 +11,7 @@ export interface ProfileData {
11
11
  pat: string;
12
12
  account_email: string;
13
13
  account_name: string;
14
+ org_name?: string;
14
15
  active_project_id?: string;
15
16
  active_project_name?: string;
16
17
  project_api_key?: string;
@@ -88,6 +89,7 @@ export const config = {
88
89
  pat: data.pat ?? existing?.pat ?? '',
89
90
  account_email: data.account_email ?? existing?.account_email ?? '',
90
91
  account_name: data.account_name ?? existing?.account_name ?? '',
92
+ org_name: data.org_name ?? existing?.org_name,
91
93
  active_project_id: data.active_project_id ?? existing?.active_project_id,
92
94
  active_project_name: data.active_project_name ?? existing?.active_project_name,
93
95
  project_api_key: data.project_api_key ?? existing?.project_api_key,
package/src/lib/manage.ts CHANGED
@@ -36,6 +36,10 @@ export interface ManageProject {
36
36
  active: boolean;
37
37
  }
38
38
 
39
+ export interface ManageProjectServices {
40
+ [key: string]: boolean;
41
+ }
42
+
39
43
  export interface ManageProjectKey {
40
44
  id: string;
41
45
  name: string;
@@ -0,0 +1,97 @@
1
+ export interface Column {
2
+ header: string;
3
+ width: number;
4
+ color?: (val: string) => string;
5
+ }
6
+
7
+ export interface TableOptions {
8
+ columns: Column[];
9
+ rows: string[][];
10
+ }
11
+
12
+ const ANSI_PATTERN = /\x1b\[[0-9;]*m/g;
13
+
14
+ export const orange = (s: string) => '\x1b[38;2;244;140;6m' + s;
15
+ export const gold = (s: string) => '\x1b[38;2;255;208;0m' + s;
16
+ export const dim = (s: string) => '\x1b[2m' + s + '\x1b[0m';
17
+ export const white = (s: string) => '\x1b[97m' + s;
18
+ export const green = (s: string) => '\x1b[38;2;34;197;94m' + s;
19
+ export const muted = (s: string) => '\x1b[38;2;85;85;85m' + s;
20
+ export const inactive = (s: string) => '\x1b[38;2;68;68;68m' + s;
21
+ export const failure = (s: string) => '\x1b[38;2;232;93;4m' + s;
22
+ export const reset = '\x1b[0m';
23
+
24
+ function stripAnsi(value: string): string {
25
+ return value.replace(ANSI_PATTERN, '');
26
+ }
27
+
28
+ function fitCell(value: string, width: number): string {
29
+ const plain = stripAnsi(value);
30
+ if (plain.length <= width) {
31
+ return value + ' '.repeat(width - plain.length);
32
+ }
33
+
34
+ const truncated = plain.slice(0, width);
35
+ return truncated;
36
+ }
37
+
38
+ export function renderTable(options: TableOptions): string {
39
+ const { columns, rows } = options;
40
+ const lines: string[] = [];
41
+
42
+ lines.push(
43
+ ' ┌' + columns.map((c) => '─'.repeat(c.width + 2)).join('┬') + '┐'
44
+ );
45
+
46
+ lines.push(
47
+ ' │' +
48
+ columns
49
+ .map((c) => ' ' + dim(c.header.padEnd(c.width)) + ' │')
50
+ .join('')
51
+ );
52
+
53
+ lines.push(
54
+ ' ├' + columns.map((c) => '─'.repeat(c.width + 2)).join('┼') + '┤'
55
+ );
56
+
57
+ for (const row of rows) {
58
+ lines.push(
59
+ ' │' +
60
+ columns
61
+ .map((c, i) => {
62
+ const raw = row[i] ?? '';
63
+ const fitted = fitCell(raw, c.width);
64
+ const colored = c.color
65
+ ? fitCell(c.color(stripAnsi(raw)), c.width)
66
+ : fitted;
67
+ return ' ' + colored + ' ' + reset + '│';
68
+ })
69
+ .join('')
70
+ );
71
+ }
72
+
73
+ lines.push(
74
+ ' └' + columns.map((c) => '─'.repeat(c.width + 2)).join('┴') + '┘'
75
+ );
76
+
77
+ return lines.join('\n');
78
+ }
79
+
80
+ export function header(version: string, subtitle?: string): string {
81
+ const lines = [
82
+ '',
83
+ orange(' ⇒⇒') + reset + ' globio ' + dim(version),
84
+ dim(' ──────────────────────────────────────────'),
85
+ ];
86
+
87
+ if (subtitle) {
88
+ lines.push(' ' + subtitle);
89
+ }
90
+
91
+ lines.push('');
92
+ return lines.join('\n');
93
+ }
94
+
95
+ export function footer(text: string): string {
96
+ return '\n' + dim(' ' + text) + '\n';
97
+ }