@scitus/hazel 0.0.1

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/LICENSE ADDED
@@ -0,0 +1,40 @@
1
+ Proprietary Software License Agreement
2
+
3
+ Copyright (c) 2024-2026 Scitus Solutions Ltd. All Rights Reserved.
4
+
5
+ This software and associated documentation files (the "Software") are the
6
+ exclusive property of Scitus Solutions Ltd.
7
+
8
+ TERMS AND CONDITIONS:
9
+
10
+ 1. NO LICENSE GRANTED
11
+ No license, express or implied, is granted to any person or entity to use,
12
+ copy, modify, merge, publish, distribute, sublicense, and/or sell copies
13
+ of the Software.
14
+
15
+ 2. RESTRICTIONS
16
+ You may NOT:
17
+ - Use the Software for any purpose without explicit written permission
18
+ - Copy, reproduce, or duplicate the Software
19
+ - Modify, adapt, or create derivative works
20
+ - Distribute, sublicense, lease, or lend the Software
21
+ - Reverse engineer, decompile, or disassemble the Software
22
+ - Remove or alter any proprietary notices
23
+
24
+ 3. AUTHORIZED USE
25
+ Use of this Software is permitted ONLY with a valid license agreement
26
+ from Scitus Solutions Ltd. Contact licensing@scitus.ca for inquiries.
27
+
28
+ 4. NO WARRANTY
29
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
30
+ OR IMPLIED. SCITUS SOLUTIONS LTD. SHALL NOT BE LIABLE FOR ANY DAMAGES
31
+ ARISING FROM THE USE OR INABILITY TO USE THE SOFTWARE.
32
+
33
+ 5. TERMINATION
34
+ Any unauthorized use automatically terminates any permissions granted
35
+ and may result in legal action.
36
+
37
+ For licensing inquiries: licensing@scitus.ca
38
+ Website: https://scitus.ca
39
+
40
+ Scitus Solutions Ltd.
package/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # @hazel/cli
2
+
3
+ Hazel CLI - Your dedicated AI coding companion from Scitus Solutions Ltd.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g @hazel/cli
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```bash
14
+ hazel
15
+ ```
16
+
17
+ ## Features
18
+
19
+ - AI-powered coding assistant using Gemini
20
+ - File reading (text, PDF, DOCX, XLSX, images, videos)
21
+ - Code editing and writing
22
+ - Gmail integration
23
+ - Local and API modes
24
+
25
+ ## Requirements
26
+
27
+ - Node.js >= 18.0.0
28
+ - Google Cloud Project (for local mode) or Hazel API access
29
+
30
+ ## Security
31
+
32
+ See [SECURITY.md](./SECURITY.md) for security information.
33
+
34
+ ## License
35
+
36
+ Proprietary - Copyright (c) 2024-2026 Scitus Solutions Ltd. All Rights Reserved.
37
+
38
+ See [LICENSE](./LICENSE) for details.
package/SECURITY.md ADDED
@@ -0,0 +1,85 @@
1
+ # Security Policy
2
+
3
+ ## Overview
4
+
5
+ Hazel CLI is an AI-powered coding assistant. This document outlines security considerations for users and contributors.
6
+
7
+ ## Security Features
8
+
9
+ ### Authentication
10
+
11
+ - **Password Hashing**: Passwords are hashed using bcrypt with a cost factor of 12
12
+ - **Token Storage**: Authentication tokens are stored with secure file permissions (0600)
13
+ - **Session Management**: Sessions expire after 7 days
14
+
15
+ ### File System Access
16
+
17
+ - **Path Traversal Protection**: Read, write, and edit operations validate paths to prevent directory traversal attacks
18
+ - **Sensitive File Blocking**: Access to system files (`/etc/`, `/.ssh/`, credentials files) is blocked
19
+ - **Working Directory Restriction**: Write/edit operations are restricted to the current working directory
20
+
21
+ ### Code Execution
22
+
23
+ #### Bash Tool
24
+ - Executes shell commands (by design)
25
+ - **Environment Variable Filtering**: Sensitive environment variables (API keys, tokens, secrets) are NOT passed to spawned processes
26
+ - **Timeout Protection**: Commands timeout after configurable duration (default: 2 minutes)
27
+
28
+ #### Python Tool
29
+ - Executes Python code with restrictions
30
+ - **Blocked Operations**:
31
+ - File access (`open`, `read`, `write`)
32
+ - Network access (`socket`, `urllib`, `requests`)
33
+ - System access (`os`, `subprocess`, `sys`)
34
+ - Code execution (`eval`, `exec`, `__import__`)
35
+ - Dangerous introspection (`__builtins__`, `__globals__`, `__subclasses__`)
36
+ - **Allowed Modules**: `math`, `datetime`, `json`, `re`, `random`, `statistics`, `decimal`, `fractions`, `collections`
37
+ - **Timeout**: 30 second execution limit
38
+
39
+ **Important**: The Python tool's restrictions are pattern-based and not a true sandbox. Sophisticated attacks may bypass these restrictions. For high-security environments, consider containerized execution.
40
+
41
+ ## Reporting Security Issues
42
+
43
+ If you discover a security vulnerability, please report it by:
44
+
45
+ 1. **DO NOT** create a public GitHub issue
46
+ 2. Email security concerns to the maintainers
47
+ 3. Include:
48
+ - Description of the vulnerability
49
+ - Steps to reproduce
50
+ - Potential impact
51
+ - Suggested fix (if any)
52
+
53
+ ## Security Best Practices for Users
54
+
55
+ 1. **API Keys**: Never commit API keys or tokens to version control
56
+ 2. **Permissions**: Run Hazel with minimum necessary permissions
57
+ 3. **Review**: Review AI-generated code before execution
58
+ 4. **Updates**: Keep Hazel updated to get security patches
59
+
60
+ ## Development Security Guidelines
61
+
62
+ 1. **Dependencies**: Regularly run `npm audit` and update vulnerable packages
63
+ 2. **Input Validation**: All user input must be validated before use
64
+ 3. **Path Handling**: Always use path validation functions for file operations
65
+ 4. **Credentials**: Never log or expose credentials in error messages
66
+
67
+ ## Known Limitations
68
+
69
+ 1. **Bash Tool**: By design, allows arbitrary command execution. Users must trust the AI or review commands.
70
+ 2. **Python Sandbox**: Pattern-based blocking can be bypassed by sophisticated attacks
71
+ 3. **Local Authentication**: The local auth module is for convenience, not for high-security scenarios. Use device flow authentication for production.
72
+
73
+ ## Dependency Notes
74
+
75
+ - **bcrypt**: Uses `@mapbox/node-pre-gyp` for native binary installation, which has a build-time dependency on `tar`. Any reported vulnerabilities in these packages only affect the installation process, not runtime security.
76
+ - Run `npm audit` regularly to check for new vulnerabilities
77
+
78
+ ## Changelog
79
+
80
+ ### v0.1.0
81
+ - Initial security implementation
82
+ - bcrypt password hashing
83
+ - Path traversal protection
84
+ - Environment variable filtering
85
+ - Python execution restrictions
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Device Flow Authentication for Hazel CLI
3
+ *
4
+ * This module handles CLI authentication using device authorization flow.
5
+ * No local HTTP server needed - user enters code shown in browser.
6
+ *
7
+ * Environment Variables:
8
+ * SCITUS_CA_URL - Scitus CA OIDC provider URL (e.g., http://localhost:4025)
9
+ * AUTH_DISABLED - Set to 'true' to disable auth (dev mode)
10
+ * DEV_USER - Username for dev mode
11
+ */
12
+ interface LocalConfig {
13
+ scitus_ca_url?: string;
14
+ hazel_api_url?: string;
15
+ }
16
+ /**
17
+ * Save local config to ~/.hazel/config.json
18
+ */
19
+ export declare function saveLocalConfig(config: LocalConfig): Promise<void>;
20
+ /**
21
+ * Get the local config file path (for display to user)
22
+ */
23
+ export declare function getConfigFilePath(): string;
24
+ /**
25
+ * Get the current Scitus CA URL (exported for OAuth device flow only)
26
+ * Note: Other API calls should use getHazelApiUrl() instead
27
+ */
28
+ export declare function getScitusCaUrl(): Promise<string>;
29
+ /**
30
+ * Get Hazel API URL for all API calls (except OAuth device flow)
31
+ * Priority: Local config file > env var > production default
32
+ *
33
+ * The Hazel API proxies requests to Scitus CA with server-side API key auth,
34
+ * so CLI doesn't need to know about Scitus CA API keys.
35
+ */
36
+ export declare function getHazelApiUrl(): Promise<string>;
37
+ /**
38
+ * Check if auth is disabled (dev mode)
39
+ */
40
+ export declare function isAuthDisabled(): boolean;
41
+ /**
42
+ * Check if device auth is configured
43
+ */
44
+ export declare function isDeviceAuthConfigured(): boolean;
45
+ /**
46
+ * Clear tokens (logout)
47
+ */
48
+ export declare function clearTokens(): Promise<void>;
49
+ /**
50
+ * Get current authenticated user
51
+ */
52
+ export declare function getCurrentUser(): Promise<{
53
+ authenticated: boolean;
54
+ user?: {
55
+ sub: string;
56
+ email?: string;
57
+ name?: string;
58
+ username?: string;
59
+ };
60
+ }>;
61
+ /**
62
+ * Main authentication function using device flow
63
+ */
64
+ export declare function authenticate(callbacks?: {
65
+ onShowCode?: (userCode: string, verificationUri: string) => void;
66
+ onWaitingForUser?: () => void;
67
+ onReadInput?: () => Promise<string>;
68
+ }): Promise<{
69
+ success: boolean;
70
+ user?: {
71
+ sub: string;
72
+ email?: string;
73
+ name?: string;
74
+ username?: string;
75
+ };
76
+ error?: string;
77
+ }>;
78
+ /**
79
+ * Logout - clear tokens
80
+ */
81
+ export declare function logout(): Promise<{
82
+ success: boolean;
83
+ message: string;
84
+ }>;
85
+ /**
86
+ * Get stored access token (for API calls)
87
+ */
88
+ export declare function getAccessToken(): Promise<string | null>;
89
+ export {};
90
+ //# sourceMappingURL=device.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../src/auth/device.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAeH,UAAU,WAAW;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAcD;;GAEG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAKxE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AA4DD;;;GAGG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAEtD;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAKtD;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAMhD;AAsCD;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAOjD;AAED;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC;IAC9C,aAAa,EAAE,OAAO,CAAC;IACvB,IAAI,CAAC,EAAE;QACL,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH,CAAC,CA8BD;AAkED;;GAEG;AACH,wBAAsB,YAAY,CAChC,SAAS,CAAC,EAAE;IACV,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,KAAK,IAAI,CAAC;IACjE,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CACrC,GACA,OAAO,CAAC;IACT,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE;QACL,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CA0GD;AAED;;GAEG;AACH,wBAAsB,MAAM,IAAI,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAW7E;AAED;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAO7D"}
@@ -0,0 +1,345 @@
1
+ /**
2
+ * Device Flow Authentication for Hazel CLI
3
+ *
4
+ * This module handles CLI authentication using device authorization flow.
5
+ * No local HTTP server needed - user enters code shown in browser.
6
+ *
7
+ * Environment Variables:
8
+ * SCITUS_CA_URL - Scitus CA OIDC provider URL (e.g., http://localhost:4025)
9
+ * AUTH_DISABLED - Set to 'true' to disable auth (dev mode)
10
+ * DEV_USER - Username for dev mode
11
+ */
12
+ import { readFile, writeFile, mkdir } from 'fs/promises';
13
+ import { existsSync } from 'fs';
14
+ import { join } from 'path';
15
+ import { homedir } from 'os';
16
+ const AUTH_DIR = join(homedir(), '.hazel');
17
+ const TOKEN_FILE = join(AUTH_DIR, 'tokens.json');
18
+ const CONFIG_FILE = join(AUTH_DIR, 'config.json');
19
+ // Default production URLs - no .env needed
20
+ const DEFAULT_SCITUS_CA_URL = 'https://scitus.ca';
21
+ const DEFAULT_HAZEL_API_URL = 'https://api.scitus.ca';
22
+ /**
23
+ * Load local config from ~/.hazel/config.json
24
+ */
25
+ async function loadLocalConfig() {
26
+ try {
27
+ const content = await readFile(CONFIG_FILE, 'utf-8');
28
+ return JSON.parse(content);
29
+ }
30
+ catch {
31
+ return {};
32
+ }
33
+ }
34
+ /**
35
+ * Save local config to ~/.hazel/config.json
36
+ */
37
+ export async function saveLocalConfig(config) {
38
+ await ensureAuthDir();
39
+ const existing = await loadLocalConfig();
40
+ const merged = { ...existing, ...config };
41
+ await writeFile(CONFIG_FILE, JSON.stringify(merged, null, 2), { mode: 0o600 });
42
+ }
43
+ /**
44
+ * Get the local config file path (for display to user)
45
+ */
46
+ export function getConfigFilePath() {
47
+ return CONFIG_FILE;
48
+ }
49
+ // Cached config to avoid repeated file reads
50
+ let cachedLocalConfig = null;
51
+ /**
52
+ * Get Scitus CA OIDC provider URL
53
+ * Priority: Local config file > env var > production default
54
+ */
55
+ async function getAuthServerUrlAsync() {
56
+ if (!cachedLocalConfig) {
57
+ cachedLocalConfig = await loadLocalConfig();
58
+ }
59
+ return cachedLocalConfig.scitus_ca_url || process.env.SCITUS_CA_URL || DEFAULT_SCITUS_CA_URL;
60
+ }
61
+ /**
62
+ * Get Scitus CA OIDC provider URL (sync version for backward compat)
63
+ * Uses cached value if available, otherwise falls back to env/default
64
+ */
65
+ function getAuthServerUrl() {
66
+ return cachedLocalConfig?.scitus_ca_url || process.env.SCITUS_CA_URL || DEFAULT_SCITUS_CA_URL;
67
+ }
68
+ /**
69
+ * Get the current Scitus CA URL (exported for OAuth device flow only)
70
+ * Note: Other API calls should use getHazelApiUrl() instead
71
+ */
72
+ export async function getScitusCaUrl() {
73
+ return getAuthServerUrlAsync();
74
+ }
75
+ /**
76
+ * Get Hazel API URL for all API calls (except OAuth device flow)
77
+ * Priority: Local config file > env var > production default
78
+ *
79
+ * The Hazel API proxies requests to Scitus CA with server-side API key auth,
80
+ * so CLI doesn't need to know about Scitus CA API keys.
81
+ */
82
+ export async function getHazelApiUrl() {
83
+ if (!cachedLocalConfig) {
84
+ cachedLocalConfig = await loadLocalConfig();
85
+ }
86
+ return cachedLocalConfig.hazel_api_url || process.env.HAZEL_API_URL || DEFAULT_HAZEL_API_URL;
87
+ }
88
+ /**
89
+ * Check if auth is disabled (dev mode)
90
+ */
91
+ export function isAuthDisabled() {
92
+ return process.env.AUTH_DISABLED === 'true';
93
+ }
94
+ /**
95
+ * Check if device auth is configured
96
+ */
97
+ export function isDeviceAuthConfigured() {
98
+ if (isAuthDisabled()) {
99
+ return true; // Skip check if auth is disabled
100
+ }
101
+ // Device auth just needs the auth server URL
102
+ return !!getAuthServerUrl();
103
+ }
104
+ /**
105
+ * Ensure auth directory exists
106
+ */
107
+ async function ensureAuthDir() {
108
+ if (!existsSync(AUTH_DIR)) {
109
+ await mkdir(AUTH_DIR, { recursive: true });
110
+ }
111
+ }
112
+ /**
113
+ * Load stored tokens
114
+ */
115
+ async function loadTokens() {
116
+ try {
117
+ const content = await readFile(TOKEN_FILE, 'utf-8');
118
+ const tokens = JSON.parse(content);
119
+ // Check if expired
120
+ if (new Date(tokens.expiresAt) < new Date()) {
121
+ return null;
122
+ }
123
+ return tokens;
124
+ }
125
+ catch {
126
+ return null;
127
+ }
128
+ }
129
+ /**
130
+ * Save tokens
131
+ */
132
+ async function saveTokens(tokens) {
133
+ await ensureAuthDir();
134
+ await writeFile(TOKEN_FILE, JSON.stringify(tokens, null, 2), { mode: 0o600 });
135
+ }
136
+ /**
137
+ * Clear tokens (logout)
138
+ */
139
+ export async function clearTokens() {
140
+ try {
141
+ const { unlink } = await import('fs/promises');
142
+ await unlink(TOKEN_FILE);
143
+ }
144
+ catch {
145
+ // Ignore
146
+ }
147
+ }
148
+ /**
149
+ * Get current authenticated user
150
+ */
151
+ export async function getCurrentUser() {
152
+ // Dev mode - return dev user
153
+ if (isAuthDisabled()) {
154
+ const devUser = process.env.DEV_USER || 'developer';
155
+ return {
156
+ authenticated: true,
157
+ user: {
158
+ sub: 'dev-user',
159
+ email: `${devUser}@localhost`,
160
+ name: devUser,
161
+ username: devUser,
162
+ },
163
+ };
164
+ }
165
+ const tokens = await loadTokens();
166
+ if (!tokens) {
167
+ return { authenticated: false };
168
+ }
169
+ return {
170
+ authenticated: true,
171
+ user: {
172
+ sub: tokens.user.sub,
173
+ email: tokens.user.email,
174
+ name: tokens.user.name,
175
+ username: tokens.user.preferred_username || tokens.user.email?.split('@')[0],
176
+ },
177
+ };
178
+ }
179
+ /**
180
+ * Start device authorization flow
181
+ */
182
+ async function startDeviceAuth() {
183
+ const authServerUrl = await getAuthServerUrlAsync();
184
+ const response = await fetch(`${authServerUrl}/device/start`, {
185
+ method: 'POST',
186
+ headers: { 'Content-Type': 'application/json' },
187
+ body: JSON.stringify({ client_id: 'hazel-cli', scope: 'openid profile email' }),
188
+ });
189
+ if (!response.ok) {
190
+ const error = await response.text();
191
+ throw new Error(`Failed to start device auth: ${error}`);
192
+ }
193
+ return response.json();
194
+ }
195
+ /**
196
+ * Poll for tokens after user authorizes
197
+ */
198
+ async function pollForTokens(deviceCode, userCode, interval, expiresIn) {
199
+ const authServerUrl = await getAuthServerUrlAsync();
200
+ const startTime = Date.now();
201
+ const expiresAt = startTime + expiresIn * 1000;
202
+ while (Date.now() < expiresAt) {
203
+ await new Promise(resolve => setTimeout(resolve, interval * 1000));
204
+ const response = await fetch(`${authServerUrl}/device/token`, {
205
+ method: 'POST',
206
+ headers: { 'Content-Type': 'application/json' },
207
+ body: JSON.stringify({ device_code: deviceCode, user_code: userCode }),
208
+ });
209
+ const result = await response.json();
210
+ if (result.error === 'authorization_pending') {
211
+ // Keep polling
212
+ continue;
213
+ }
214
+ if (result.error === 'expired_token') {
215
+ throw new Error('Authorization expired. Please try again.');
216
+ }
217
+ if (result.error) {
218
+ throw new Error(result.error_description || result.error);
219
+ }
220
+ if (result.access_token) {
221
+ return result;
222
+ }
223
+ }
224
+ throw new Error('Authorization timeout');
225
+ }
226
+ /**
227
+ * Main authentication function using device flow
228
+ */
229
+ export async function authenticate(callbacks) {
230
+ // Dev mode - skip authentication
231
+ if (isAuthDisabled()) {
232
+ const devUser = process.env.DEV_USER || 'developer';
233
+ return {
234
+ success: true,
235
+ user: {
236
+ sub: 'dev-user',
237
+ email: `${devUser}@localhost`,
238
+ name: devUser,
239
+ username: devUser,
240
+ },
241
+ };
242
+ }
243
+ // Check for existing valid tokens
244
+ const existingTokens = await loadTokens();
245
+ if (existingTokens) {
246
+ return {
247
+ success: true,
248
+ user: {
249
+ sub: existingTokens.user.sub,
250
+ email: existingTokens.user.email,
251
+ name: existingTokens.user.name,
252
+ username: existingTokens.user.preferred_username || existingTokens.user.email?.split('@')[0],
253
+ },
254
+ };
255
+ }
256
+ try {
257
+ // Start device authorization
258
+ const deviceAuth = await startDeviceAuth();
259
+ // Show code to user
260
+ if (callbacks?.onShowCode) {
261
+ callbacks.onShowCode(deviceAuth.user_code, deviceAuth.verification_uri);
262
+ }
263
+ else {
264
+ console.log('\n To login, open this URL in your browser:');
265
+ console.log(` ${deviceAuth.verification_uri}`);
266
+ console.log('\n Or go to your auth server and enter code:');
267
+ console.log(` ${deviceAuth.user_code}\n`);
268
+ }
269
+ // Open browser automatically
270
+ try {
271
+ const open = await import('open');
272
+ await open.default(deviceAuth.verification_uri);
273
+ }
274
+ catch {
275
+ // Browser open failed, user can manually open URL
276
+ }
277
+ // Wait for user to enter the code
278
+ if (callbacks?.onWaitingForUser) {
279
+ callbacks.onWaitingForUser();
280
+ }
281
+ else {
282
+ console.log(' Waiting for you to login in the browser...');
283
+ }
284
+ // If we have a way to read input, wait for user to enter code
285
+ if (callbacks?.onReadInput) {
286
+ console.log('\n After logging in, enter the code shown in the browser:');
287
+ const enteredCode = await callbacks.onReadInput();
288
+ if (enteredCode.trim().toUpperCase() !== deviceAuth.user_code) {
289
+ return { success: false, error: 'Code mismatch. Please try again.' };
290
+ }
291
+ }
292
+ // Poll for tokens
293
+ const tokens = await pollForTokens(deviceAuth.device_code, deviceAuth.user_code, deviceAuth.interval, deviceAuth.expires_in);
294
+ if (!tokens.access_token || !tokens.user) {
295
+ return { success: false, error: 'Failed to get tokens' };
296
+ }
297
+ // Save tokens
298
+ const storedTokens = {
299
+ accessToken: tokens.access_token,
300
+ idToken: tokens.id_token,
301
+ refreshToken: tokens.refresh_token,
302
+ expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(), // 7 days
303
+ user: tokens.user,
304
+ };
305
+ await saveTokens(storedTokens);
306
+ return {
307
+ success: true,
308
+ user: {
309
+ sub: tokens.user.sub,
310
+ email: tokens.user.email,
311
+ name: tokens.user.name,
312
+ username: tokens.user.preferred_username || tokens.user.email?.split('@')[0],
313
+ },
314
+ };
315
+ }
316
+ catch (error) {
317
+ return {
318
+ success: false,
319
+ error: error instanceof Error ? error.message : 'Authentication failed',
320
+ };
321
+ }
322
+ }
323
+ /**
324
+ * Logout - clear tokens
325
+ */
326
+ export async function logout() {
327
+ const tokens = await loadTokens();
328
+ if (!tokens) {
329
+ return { success: false, message: 'Not logged in' };
330
+ }
331
+ const userName = tokens.user.name || tokens.user.email || 'User';
332
+ await clearTokens();
333
+ return { success: true, message: `Goodbye, ${userName}! See you next time.` };
334
+ }
335
+ /**
336
+ * Get stored access token (for API calls)
337
+ */
338
+ export async function getAccessToken() {
339
+ if (isAuthDisabled()) {
340
+ return 'dev-token';
341
+ }
342
+ const tokens = await loadTokens();
343
+ return tokens?.accessToken || null;
344
+ }
345
+ //# sourceMappingURL=device.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device.js","sourceRoot":"","sources":["../../src/auth/device.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * API Mode - Thin client that connects to Hazel API
3
+ *
4
+ * Zero-config mode: gets everything from server after authentication.
5
+ * No local tools, no providers - all execution happens server-side.
6
+ */
7
+ /**
8
+ * Run CLI in API mode
9
+ */
10
+ export declare function runApiMode(): Promise<void>;
11
+ //# sourceMappingURL=api-mode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-mode.d.ts","sourceRoot":"","sources":["../../src/cli/api-mode.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA6PH;;GAEG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAiJhD"}
@@ -0,0 +1,309 @@
1
+ /**
2
+ * API Mode - Thin client that connects to Hazel API
3
+ *
4
+ * Zero-config mode: gets everything from server after authentication.
5
+ * No local tools, no providers - all execution happens server-side.
6
+ */
7
+ import * as readline from 'readline';
8
+ import chalk from 'chalk';
9
+ import { getApiUrl } from './mode.js';
10
+ import { authenticate, logout, isDeviceAuthConfigured, getAccessToken } from '../auth/device.js';
11
+ // Hazel's brand colors
12
+ const hazel = {
13
+ primary: chalk.hex('#8B7355'),
14
+ accent: chalk.hex('#A0522D'),
15
+ soft: chalk.hex('#D2B48C'),
16
+ highlight: chalk.hex('#DEB887'),
17
+ success: chalk.green,
18
+ error: chalk.red,
19
+ muted: chalk.gray,
20
+ };
21
+ // Token storage (in-memory for session)
22
+ let authToken = null;
23
+ let serverConfig = null;
24
+ function showStartupBanner() {
25
+ console.log('');
26
+ console.log(hazel.primary(' ██╗ ██╗ █████╗ ███████╗███████╗██╗ '));
27
+ console.log(hazel.primary(' ██║ ██║██╔══██╗╚══███╔╝██╔════╝██║ '));
28
+ console.log(hazel.primary(' ███████║███████║ ███╔╝ █████╗ ██║ '));
29
+ console.log(hazel.primary(' ██╔══██║██╔══██║ ███╔╝ ██╔══╝ ██║ '));
30
+ console.log(hazel.primary(' ██║ ██║██║ ██║███████╗███████╗███████╗'));
31
+ console.log(hazel.primary(' ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚══════╝╚══════╝'));
32
+ console.log('');
33
+ console.log(hazel.soft(' Your dedicated coding companion'));
34
+ console.log(hazel.muted(' from Scitus Solutions Ltd.'));
35
+ console.log(hazel.muted(' [API Mode - Server-side execution]'));
36
+ console.log('');
37
+ }
38
+ /**
39
+ * Fetch config from server
40
+ */
41
+ async function fetchConfig(token) {
42
+ const API_URL = getApiUrl();
43
+ try {
44
+ const res = await fetch(`${API_URL}/api/config`, {
45
+ headers: { Authorization: `Bearer ${token}` },
46
+ });
47
+ if (!res.ok) {
48
+ console.error(hazel.error(` Failed to fetch config: ${res.status}`));
49
+ return null;
50
+ }
51
+ return await res.json();
52
+ }
53
+ catch (error) {
54
+ console.error(hazel.error(` Failed to connect to server: ${error instanceof Error ? error.message : 'Unknown error'}`));
55
+ return null;
56
+ }
57
+ }
58
+ /**
59
+ * Send chat message to server (streaming)
60
+ */
61
+ async function chat(token, messages, cwd, onText, onToolStart, onToolResult, onError) {
62
+ const API_URL = getApiUrl();
63
+ try {
64
+ const res = await fetch(`${API_URL}/api/chat`, {
65
+ method: 'POST',
66
+ headers: {
67
+ 'Content-Type': 'application/json',
68
+ Authorization: `Bearer ${token}`,
69
+ },
70
+ body: JSON.stringify({ messages, cwd, stream: true }),
71
+ });
72
+ if (!res.ok) {
73
+ const errorBody = await res.json().catch(() => ({ error: 'Request failed' }));
74
+ onError(errorBody.error || `Server error: ${res.status}`);
75
+ return;
76
+ }
77
+ if (!res.body) {
78
+ onError('No response body');
79
+ return;
80
+ }
81
+ const reader = res.body.getReader();
82
+ const decoder = new TextDecoder();
83
+ let buffer = '';
84
+ while (true) {
85
+ const { done, value } = await reader.read();
86
+ if (done)
87
+ break;
88
+ buffer += decoder.decode(value, { stream: true });
89
+ const lines = buffer.split('\n');
90
+ buffer = lines.pop() || '';
91
+ for (const line of lines) {
92
+ if (line.startsWith('data: ')) {
93
+ try {
94
+ const event = JSON.parse(line.substring(6));
95
+ switch (event.type) {
96
+ case 'text':
97
+ if (event.content)
98
+ onText(event.content);
99
+ break;
100
+ case 'tool_start':
101
+ if (event.tool)
102
+ onToolStart(event.tool);
103
+ break;
104
+ case 'tool_result':
105
+ if (event.tool)
106
+ onToolResult(event.tool, event.success || false, event.preview || '');
107
+ break;
108
+ case 'error':
109
+ onError(event.error || 'Unknown error');
110
+ break;
111
+ case 'done':
112
+ // Conversation complete
113
+ break;
114
+ }
115
+ }
116
+ catch {
117
+ // Skip malformed JSON
118
+ }
119
+ }
120
+ }
121
+ }
122
+ }
123
+ catch (error) {
124
+ onError(error instanceof Error ? error.message : 'Request failed');
125
+ }
126
+ }
127
+ function handleCommand(input, rl, messages, config) {
128
+ const parts = input.split(' ');
129
+ const cmd = parts[0];
130
+ switch (cmd) {
131
+ case '/quit':
132
+ case '/exit':
133
+ case '/q':
134
+ rl.close();
135
+ return 'quit';
136
+ case '/logout':
137
+ logout().then((result) => {
138
+ console.log(hazel.soft(`\n ${result.message}\n`));
139
+ rl.close();
140
+ });
141
+ return 'quit';
142
+ case '/help':
143
+ case '/h':
144
+ console.log(hazel.soft('\n Commands:\n'));
145
+ console.log(hazel.muted(' /help, /h - Show this help'));
146
+ console.log(hazel.muted(' /tools, /t - List available tools'));
147
+ console.log(hazel.muted(' /clear, /c - Clear conversation'));
148
+ console.log(hazel.muted(' /whoami - Show current user'));
149
+ console.log(hazel.muted(' /logout - Logout and exit'));
150
+ console.log(hazel.muted(' /quit, /q - Exit'));
151
+ console.log('');
152
+ return 'help';
153
+ case '/tools':
154
+ case '/t':
155
+ console.log(hazel.soft('\n Available tools:\n'));
156
+ for (const tool of config.tools) {
157
+ const badge = tool.security === 'internal' ? hazel.accent(' [full]') : '';
158
+ console.log(hazel.highlight(` ${tool.name}`) + badge);
159
+ console.log(hazel.muted(` ${tool.description}\n`));
160
+ }
161
+ return 'tools';
162
+ case '/clear':
163
+ case '/c':
164
+ messages.length = 0;
165
+ console.log(hazel.soft('\n Conversation cleared.\n'));
166
+ return 'clear';
167
+ case '/whoami':
168
+ console.log(hazel.soft(`\n Logged in as ${config.user.name || config.user.email}`));
169
+ console.log(hazel.muted(` Email: ${config.user.email}`));
170
+ if (config.user.username) {
171
+ console.log(hazel.muted(` Username: @${config.user.username}`));
172
+ }
173
+ console.log('');
174
+ return 'whoami';
175
+ default:
176
+ console.log(hazel.accent(`\n Unknown command: "${cmd}"`));
177
+ console.log(hazel.muted(' Type /help for available commands.\n'));
178
+ return 'unknown';
179
+ }
180
+ }
181
+ /**
182
+ * Run CLI in API mode
183
+ */
184
+ export async function runApiMode() {
185
+ const API_URL = getApiUrl();
186
+ showStartupBanner();
187
+ // Check if auth is configured
188
+ if (!isDeviceAuthConfigured()) {
189
+ console.error(hazel.error(' Authentication not configured.\n'));
190
+ console.log(hazel.muted(' Please set HAZEL_API_URL environment variable.'));
191
+ console.log('');
192
+ process.exit(1);
193
+ }
194
+ // Check if server is reachable
195
+ try {
196
+ const healthRes = await fetch(`${API_URL}/health`);
197
+ if (!healthRes.ok) {
198
+ console.error(hazel.error(' Cannot connect to Hazel server.'));
199
+ console.log(hazel.muted(` Server: ${API_URL}`));
200
+ process.exit(1);
201
+ }
202
+ }
203
+ catch {
204
+ console.error(hazel.error(' Cannot connect to Hazel server.'));
205
+ console.log(hazel.muted(` Server: ${API_URL}`));
206
+ console.log(hazel.muted(' Please check your internet connection.'));
207
+ process.exit(1);
208
+ }
209
+ // Authenticate via device flow
210
+ console.log(hazel.muted(' Authenticating...'));
211
+ const authResult = await authenticate({
212
+ onShowCode: (userCode, verificationUri) => {
213
+ console.log('');
214
+ console.log(hazel.highlight(' To login, open this URL in your browser:'));
215
+ console.log(hazel.primary(` ${verificationUri}`));
216
+ console.log('');
217
+ },
218
+ onWaitingForUser: () => {
219
+ console.log(hazel.muted(' Waiting for you to login in the browser...'));
220
+ console.log(hazel.muted(' After logging in, enter the code shown in the browser below.\n'));
221
+ },
222
+ });
223
+ if (!authResult.success) {
224
+ console.error(hazel.error(`\n ${authResult.error || 'Authentication failed'}\n`));
225
+ process.exit(1);
226
+ }
227
+ // Get access token from auth module
228
+ const token = await getAccessToken();
229
+ if (!token) {
230
+ console.error(hazel.error('\n Failed to get access token\n'));
231
+ process.exit(1);
232
+ }
233
+ authToken = token;
234
+ console.log(hazel.success(` ✓ Logged in as ${authResult.user?.name || authResult.user?.email}\n`));
235
+ // Fetch config from server
236
+ serverConfig = await fetchConfig(authToken);
237
+ if (!serverConfig) {
238
+ console.error(hazel.error(' Failed to load configuration from server.\n'));
239
+ process.exit(1);
240
+ }
241
+ // Create readline interface
242
+ const rl = readline.createInterface({
243
+ input: process.stdin,
244
+ output: process.stdout,
245
+ terminal: process.stdin.isTTY ?? false,
246
+ });
247
+ // Show config info
248
+ console.log(hazel.muted(` Model: ${serverConfig.config.model}`));
249
+ console.log(hazel.muted(` Tools: ${serverConfig.tools.map(t => t.name).join(', ')}`));
250
+ console.log(hazel.muted(` Directory: ${process.cwd()}`));
251
+ console.log('');
252
+ console.log(hazel.highlight(` Hello${serverConfig.user.name ? `, ${serverConfig.user.name}` : ''}! How can I help you today?`));
253
+ console.log(hazel.muted(' Type /help for commands, or start chatting!\n'));
254
+ // Conversation state
255
+ const messages = [];
256
+ const cwd = process.cwd();
257
+ // Handle input
258
+ const askQuestion = () => {
259
+ rl.question(hazel.primary('❯ '), async (input) => {
260
+ const trimmed = input.trim();
261
+ if (!trimmed) {
262
+ askQuestion();
263
+ return;
264
+ }
265
+ // Handle commands
266
+ if (trimmed.startsWith('/')) {
267
+ const handled = handleCommand(trimmed, rl, messages, serverConfig);
268
+ if (handled !== 'quit') {
269
+ askQuestion();
270
+ }
271
+ return;
272
+ }
273
+ // Add user message
274
+ messages.push({ role: 'user', content: trimmed });
275
+ // Send to server
276
+ process.stdout.write(hazel.soft('\n'));
277
+ await chat(authToken, messages, cwd,
278
+ // onText
279
+ (text) => process.stdout.write(text),
280
+ // onToolStart
281
+ (tool) => console.log(hazel.accent(`\n Using ${tool}...`)),
282
+ // onToolResult
283
+ (tool, success, preview) => {
284
+ if (success) {
285
+ console.log(hazel.success(` ✓ Done`));
286
+ if (preview) {
287
+ const lines = preview.split('\n').slice(0, 3);
288
+ console.log(hazel.muted(lines.map(l => ` ${l}`).join('\n')));
289
+ }
290
+ }
291
+ else {
292
+ console.log(hazel.error(` ✗ Failed`));
293
+ }
294
+ },
295
+ // onError
296
+ (error) => console.error(hazel.error(`\n Error: ${error}`)));
297
+ console.log('\n');
298
+ askQuestion();
299
+ });
300
+ };
301
+ // Handle Ctrl+C gracefully
302
+ rl.on('close', () => {
303
+ console.log(hazel.soft('\n Take care! It was lovely helping you.\n'));
304
+ process.exit(0);
305
+ });
306
+ // Start the conversation
307
+ askQuestion();
308
+ }
309
+ //# sourceMappingURL=api-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-mode.js","sourceRoot":"","sources":["../../src/cli/api-mode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Hazel CLI - Your dedicated coding companion from Scitus Solutions Ltd.
4
+ *
5
+ * Thin client that connects to Hazel API server.
6
+ * All tools and AI execution happens server-side.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AAEA;;;;;GAKG"}
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Hazel CLI - Your dedicated coding companion from Scitus Solutions Ltd.
4
+ *
5
+ * Thin client that connects to Hazel API server.
6
+ * All tools and AI execution happens server-side.
7
+ */
8
+ // Load .env file first
9
+ import { config as loadEnv } from 'dotenv';
10
+ import { resolve } from 'path';
11
+ loadEnv({ path: resolve(process.cwd(), '.env') });
12
+ import chalk from 'chalk';
13
+ import { runApiMode } from './api-mode.js';
14
+ const hazel = {
15
+ error: chalk.red,
16
+ };
17
+ async function main() {
18
+ try {
19
+ await runApiMode();
20
+ }
21
+ catch (error) {
22
+ console.error(hazel.error(` Error: ${error instanceof Error ? error.message : 'Unknown error'}`));
23
+ process.exit(1);
24
+ }
25
+ }
26
+ main();
27
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AAEH,uBAAuB;AACvB,OAAO,EAAE,MAAM,IAAI,OAAO,EAAE,MAAM,QAAQ,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;AAElD,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C,MAAM,KAAK,GAAG;IACZ,KAAK,EAAE,KAAK,CAAC,GAAG;CACjB,CAAC;AAEF,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,MAAM,UAAU,EAAE,CAAC;IACrB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC;QACnG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * CLI Configuration
3
+ */
4
+ /**
5
+ * Get the Hazel API URL.
6
+ * Defaults to production URL if not specified.
7
+ */
8
+ export declare function getApiUrl(): string;
9
+ //# sourceMappingURL=mode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mode.d.ts","sourceRoot":"","sources":["../../src/cli/mode.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,wBAAgB,SAAS,IAAI,MAAM,CAElC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * CLI Configuration
3
+ */
4
+ /**
5
+ * Get the Hazel API URL.
6
+ * Defaults to production URL if not specified.
7
+ */
8
+ export function getApiUrl() {
9
+ return process.env.HAZEL_API_URL || 'https://hazel.scitus.ca';
10
+ }
11
+ //# sourceMappingURL=mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mode.js","sourceRoot":"","sources":["../../src/cli/mode.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,MAAM,UAAU,SAAS;IACvB,OAAO,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,yBAAyB,CAAC;AAChE,CAAC"}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@scitus/hazel",
3
+ "version": "0.0.1",
4
+ "description": "Hazel CLI - Your dedicated AI coding companion from Scitus Solutions Ltd.",
5
+ "type": "module",
6
+ "main": "dist/cli/index.js",
7
+ "bin": {
8
+ "hazel": "dist/cli/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsx src/cli/index.ts",
13
+ "start": "node dist/cli/index.js",
14
+ "clean": "rm -rf dist"
15
+ },
16
+ "dependencies": {
17
+ "chalk": "^5.3.0",
18
+ "dotenv": "^17.2.3",
19
+ "open": "^11.0.0"
20
+ },
21
+ "devDependencies": {
22
+ "@types/node": "^22.10.5",
23
+ "tsx": "^4.19.2",
24
+ "typescript": "^5.7.3"
25
+ },
26
+ "engines": {
27
+ "node": ">=18.0.0"
28
+ },
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "keywords": [
33
+ "ai",
34
+ "cli",
35
+ "coding-assistant",
36
+ "gemini",
37
+ "llm",
38
+ "hazel",
39
+ "scitus"
40
+ ],
41
+ "author": "Scitus Solutions Ltd.",
42
+ "files": [
43
+ "dist",
44
+ "README.md",
45
+ "SECURITY.md",
46
+ "LICENSE"
47
+ ],
48
+ "license": "SEE LICENSE IN LICENSE"
49
+ }