@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 +40 -0
- package/README.md +38 -0
- package/SECURITY.md +85 -0
- package/dist/auth/device.d.ts +90 -0
- package/dist/auth/device.d.ts.map +1 -0
- package/dist/auth/device.js +345 -0
- package/dist/auth/device.js.map +1 -0
- package/dist/cli/api-mode.d.ts +11 -0
- package/dist/cli/api-mode.d.ts.map +1 -0
- package/dist/cli/api-mode.js +309 -0
- package/dist/cli/api-mode.js.map +1 -0
- package/dist/cli/index.d.ts +9 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +27 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/mode.d.ts +9 -0
- package/dist/cli/mode.d.ts.map +1 -0
- package/dist/cli/mode.js +11 -0
- package/dist/cli/mode.js.map +1 -0
- package/package.json +49 -0
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 @@
|
|
|
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 @@
|
|
|
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"}
|
package/dist/cli/mode.js
ADDED
|
@@ -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
|
+
}
|