nexusforge-cli 1.0.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.
@@ -0,0 +1,172 @@
1
+ /**
2
+ * NexusForge CLI Configuration Manager
3
+ *
4
+ * Stores authentication tokens and settings in ~/.nexusforge/config.json
5
+ */
6
+
7
+ import Conf from 'conf';
8
+ import type { CLIConfig } from '../types/index.js';
9
+
10
+ // Default configuration
11
+ const DEFAULT_CONFIG: CLIConfig = {
12
+ apiUrl: 'https://nexusconnectbridge.automatanexus.com/api/v1/bridge',
13
+ defaultModel: 'NexusForge',
14
+ theme: 'dark',
15
+ autoExecute: true,
16
+ };
17
+
18
+ // Configuration schema for type safety
19
+ const schema = {
20
+ apiUrl: {
21
+ type: 'string' as const,
22
+ default: DEFAULT_CONFIG.apiUrl,
23
+ },
24
+ accessToken: {
25
+ type: 'string' as const,
26
+ },
27
+ refreshToken: {
28
+ type: 'string' as const,
29
+ },
30
+ userId: {
31
+ type: 'number' as const,
32
+ },
33
+ username: {
34
+ type: 'string' as const,
35
+ },
36
+ email: {
37
+ type: 'string' as const,
38
+ },
39
+ defaultModel: {
40
+ type: 'string' as const,
41
+ default: DEFAULT_CONFIG.defaultModel,
42
+ },
43
+ theme: {
44
+ type: 'string' as const,
45
+ enum: ['dark', 'light'],
46
+ default: DEFAULT_CONFIG.theme,
47
+ },
48
+ autoExecute: {
49
+ type: 'boolean' as const,
50
+ default: DEFAULT_CONFIG.autoExecute,
51
+ },
52
+ };
53
+
54
+ // Create config instance
55
+ const config = new Conf<CLIConfig>({
56
+ projectName: 'nexusforge',
57
+ schema,
58
+ defaults: DEFAULT_CONFIG,
59
+ });
60
+
61
+ /**
62
+ * Get the full configuration
63
+ */
64
+ export function getConfig(): CLIConfig {
65
+ return {
66
+ apiUrl: config.get('apiUrl'),
67
+ accessToken: config.get('accessToken'),
68
+ refreshToken: config.get('refreshToken'),
69
+ userId: config.get('userId'),
70
+ username: config.get('username'),
71
+ email: config.get('email'),
72
+ defaultModel: config.get('defaultModel'),
73
+ theme: config.get('theme'),
74
+ autoExecute: config.get('autoExecute'),
75
+ };
76
+ }
77
+
78
+ /**
79
+ * Get a specific config value
80
+ */
81
+ export function get<K extends keyof CLIConfig>(key: K): CLIConfig[K] {
82
+ return config.get(key);
83
+ }
84
+
85
+ /**
86
+ * Set a specific config value
87
+ */
88
+ export function set<K extends keyof CLIConfig>(key: K, value: CLIConfig[K]): void {
89
+ config.set(key, value);
90
+ }
91
+
92
+ /**
93
+ * Check if user is authenticated
94
+ */
95
+ export function isAuthenticated(): boolean {
96
+ const token = config.get('accessToken');
97
+ return !!token;
98
+ }
99
+
100
+ /**
101
+ * Save authentication data after successful login
102
+ */
103
+ export function saveAuth(data: {
104
+ accessToken: string;
105
+ refreshToken?: string;
106
+ userId?: number;
107
+ username?: string;
108
+ email?: string;
109
+ }): void {
110
+ config.set('accessToken', data.accessToken);
111
+
112
+ if (data.refreshToken) {
113
+ config.set('refreshToken', data.refreshToken);
114
+ }
115
+ if (data.userId) {
116
+ config.set('userId', data.userId);
117
+ }
118
+ if (data.username) {
119
+ config.set('username', data.username);
120
+ }
121
+ if (data.email) {
122
+ config.set('email', data.email);
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Clear authentication data (logout)
128
+ */
129
+ export function clearAuth(): void {
130
+ config.delete('accessToken');
131
+ config.delete('refreshToken');
132
+ config.delete('userId');
133
+ config.delete('username');
134
+ config.delete('email');
135
+ }
136
+
137
+ /**
138
+ * Get the API URL
139
+ */
140
+ export function getApiUrl(): string {
141
+ return config.get('apiUrl');
142
+ }
143
+
144
+ /**
145
+ * Set the API URL
146
+ */
147
+ export function setApiUrl(url: string): void {
148
+ config.set('apiUrl', url);
149
+ }
150
+
151
+ /**
152
+ * Get the access token
153
+ */
154
+ export function getAccessToken(): string | undefined {
155
+ return config.get('accessToken');
156
+ }
157
+
158
+ /**
159
+ * Get the config file path (for debugging)
160
+ */
161
+ export function getConfigPath(): string {
162
+ return config.path;
163
+ }
164
+
165
+ /**
166
+ * Reset config to defaults
167
+ */
168
+ export function resetConfig(): void {
169
+ config.clear();
170
+ }
171
+
172
+ export { config };
@@ -0,0 +1,163 @@
1
+ /**
2
+ * NexusForge CLI Theme
3
+ *
4
+ * Brand colors matching the NexusForge web UI.
5
+ * - Teal for user messages
6
+ * - Ultra light cream for AI responses
7
+ * - Terracotta accents
8
+ */
9
+
10
+ import chalk from 'chalk';
11
+
12
+ // NexusForge brand colors
13
+ export const COLORS = {
14
+ // Primary colors
15
+ teal: '#14b8a6',
16
+ terracotta: '#c4a484',
17
+ cream: '#faf9f6',
18
+
19
+ // Backgrounds
20
+ darkSlate: '#1e293b',
21
+ warmBg: '#f5ebe0',
22
+
23
+ // Text
24
+ textPrimary: '#111827',
25
+ textSecondary: '#6b7280',
26
+ textMuted: '#9ca3af',
27
+
28
+ // Status
29
+ success: '#10b981',
30
+ warning: '#f59e0b',
31
+ error: '#ef4444',
32
+ info: '#64b5f6',
33
+ };
34
+
35
+ // Theme object for consistent styling
36
+ export const NEXUSFORGE_THEME = {
37
+ // User messages - Teal
38
+ user: {
39
+ label: COLORS.teal,
40
+ text: COLORS.teal,
41
+ },
42
+
43
+ // AI messages - Ultra light cream
44
+ assistant: {
45
+ label: COLORS.terracotta,
46
+ text: COLORS.cream,
47
+ },
48
+
49
+ // System/UI elements
50
+ system: {
51
+ info: COLORS.info,
52
+ success: COLORS.success,
53
+ warning: COLORS.warning,
54
+ error: COLORS.error,
55
+ muted: COLORS.textMuted,
56
+ },
57
+
58
+ // Code blocks
59
+ code: {
60
+ background: COLORS.darkSlate,
61
+ text: '#e2e8f0',
62
+ keyword: COLORS.teal,
63
+ },
64
+
65
+ // Prompt
66
+ prompt: COLORS.teal,
67
+ };
68
+
69
+ // Chalk helpers for consistent coloring
70
+ export const style = {
71
+ // User message styling
72
+ user: (text: string) => chalk.hex(NEXUSFORGE_THEME.user.text)(text),
73
+ userLabel: (text: string) => chalk.hex(NEXUSFORGE_THEME.user.label).bold(text),
74
+
75
+ // AI message styling
76
+ assistant: (text: string) => chalk.hex(NEXUSFORGE_THEME.assistant.text)(text),
77
+ assistantLabel: (text: string) => chalk.hex(NEXUSFORGE_THEME.assistant.label).bold(text),
78
+
79
+ // Status styling
80
+ success: (text: string) => chalk.hex(NEXUSFORGE_THEME.system.success)(text),
81
+ warning: (text: string) => chalk.hex(NEXUSFORGE_THEME.system.warning)(text),
82
+ error: (text: string) => chalk.hex(NEXUSFORGE_THEME.system.error)(text),
83
+ info: (text: string) => chalk.hex(NEXUSFORGE_THEME.system.info)(text),
84
+ muted: (text: string) => chalk.hex(NEXUSFORGE_THEME.system.muted)(text),
85
+
86
+ // Special styling
87
+ prompt: (text: string) => chalk.hex(NEXUSFORGE_THEME.prompt).bold(text),
88
+ code: (text: string) => chalk.bgHex(NEXUSFORGE_THEME.code.background).hex(NEXUSFORGE_THEME.code.text)(text),
89
+ keyword: (text: string) => chalk.hex(NEXUSFORGE_THEME.code.keyword)(text),
90
+
91
+ // Dividers
92
+ divider: () => chalk.hex(NEXUSFORGE_THEME.system.muted)('═'.repeat(56)),
93
+ };
94
+
95
+ // ASCII Art Logo
96
+ export const NEXUSFORGE_ASCII_LOGO = `
97
+ ███╗ ██╗███████╗██╗ ██╗██╗ ██╗███████╗
98
+ ████╗ ██║██╔════╝╚██╗██╔╝██║ ██║██╔════╝
99
+ ██╔██╗ ██║█████╗ ╚███╔╝ ██║ ██║███████╗
100
+ ██║╚██╗██║██╔══╝ ██╔██╗ ██║ ██║╚════██║
101
+ ██║ ╚████║███████╗██╔╝ ██╗╚██████╔╝███████║
102
+ ╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝
103
+
104
+ ███████╗ ██████╗ ██████╗ ██████╗ ███████╗
105
+ ██╔════╝██╔═══██╗██╔══██╗██╔════╝ ██╔════╝
106
+ █████╗ ██║ ██║██████╔╝██║ ███╗█████╗
107
+ ██╔══╝ ██║ ██║██╔══██╗██║ ██║██╔══╝
108
+ ██║ ╚██████╔╝██║ ██║╚██████╔╝███████╗
109
+ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝
110
+ `;
111
+
112
+ /**
113
+ * Display the welcome screen with logo and connection info
114
+ */
115
+ export function displayWelcome(version: string, serverUrl: string, model: string): void {
116
+ // Clear screen
117
+ console.clear();
118
+
119
+ // Logo in teal
120
+ console.log(chalk.hex(NEXUSFORGE_THEME.user.label)(NEXUSFORGE_ASCII_LOGO));
121
+
122
+ // Divider
123
+ console.log(style.divider());
124
+ console.log('');
125
+
126
+ // Welcome message in cream
127
+ console.log(style.assistant(` Welcome to NexusForge CLI v${version}`));
128
+ console.log(style.assistant(' Your AI-powered development companion'));
129
+ console.log('');
130
+ console.log(style.muted(` Connected to: ${serverUrl}`));
131
+ console.log(style.muted(` Model: ${model} | Session: active`));
132
+ console.log('');
133
+ console.log(style.assistant(' Type /help for commands or start chatting!'));
134
+
135
+ console.log('');
136
+ console.log(style.divider());
137
+ console.log('');
138
+ }
139
+
140
+ /**
141
+ * Display a user message
142
+ */
143
+ export function displayUserMessage(content: string): void {
144
+ console.log(`${style.userLabel('You')} ${style.prompt('❯')} ${style.user(content)}`);
145
+ console.log('');
146
+ }
147
+
148
+ /**
149
+ * Display an assistant message
150
+ */
151
+ export function displayAssistantMessage(content: string): void {
152
+ console.log(`${style.assistantLabel('NexusForge')} ${style.prompt('❯')}`);
153
+ console.log(style.assistant(content));
154
+ console.log('');
155
+ }
156
+
157
+ /**
158
+ * Display a system message
159
+ */
160
+ export function displaySystemMessage(content: string, type: 'info' | 'success' | 'warning' | 'error' = 'info'): void {
161
+ const styleFunc = style[type];
162
+ console.log(styleFunc(`[${type.toUpperCase()}] ${content}`));
163
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "lib": ["ES2022"],
7
+ "outDir": "./dist",
8
+ "rootDir": "./src",
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "skipLibCheck": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "resolveJsonModule": true,
14
+ "declaration": true,
15
+ "declarationMap": true,
16
+ "sourceMap": true,
17
+ "jsx": "react",
18
+ "jsxFactory": "React.createElement",
19
+ "jsxFragmentFactory": "React.Fragment"
20
+ },
21
+ "include": ["src/**/*"],
22
+ "exclude": ["node_modules", "dist"]
23
+ }