codlyy 1.0.2 → 1.0.5
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/bin/codlyy.js +59 -67
- package/package.json +3 -2
- package/src/commands/info.js +34 -0
- package/src/commands/login.js +116 -0
- package/src/commands/logout.js +7 -0
- package/src/repl.js +82 -0
- package/src/utils/config.js +41 -0
package/bin/codlyy.js
CHANGED
|
@@ -1,71 +1,63 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
figlet.textSync("CODLYY", {
|
|
20
|
-
font: "Block",
|
|
21
|
-
horizontalLayout: "default",
|
|
22
|
-
verticalLayout: "default"
|
|
23
|
-
})
|
|
24
|
-
)
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { readFileSync } from 'fs';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import { dirname, join } from 'path';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import { login } from '../src/commands/login.js';
|
|
9
|
+
import { logout } from '../src/commands/logout.js';
|
|
10
|
+
import { info } from '../src/commands/info.js';
|
|
11
|
+
import { startRepl } from '../src/repl.js';
|
|
12
|
+
import { getConfig } from '../src/utils/config.js';
|
|
13
|
+
|
|
14
|
+
// ---- GET VERSION FROM package.json ----
|
|
15
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
16
|
+
const __dirname = dirname(__filename);
|
|
17
|
+
const pkg = JSON.parse(
|
|
18
|
+
readFileSync(join(__dirname, "../package.json"), "utf-8")
|
|
25
19
|
);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
20
|
+
const VERSION = pkg.version;
|
|
21
|
+
|
|
22
|
+
const program = new Command();
|
|
23
|
+
|
|
24
|
+
program
|
|
25
|
+
.name('codlyy')
|
|
26
|
+
.description('Codlyy AI CLI – Ocean Blue developer assistant')
|
|
27
|
+
.version(VERSION);
|
|
28
|
+
|
|
29
|
+
program
|
|
30
|
+
.command('login')
|
|
31
|
+
.description('Login to Codlyy with your browser')
|
|
32
|
+
.action(async () => {
|
|
33
|
+
await login();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
program
|
|
37
|
+
.command('logout')
|
|
38
|
+
.description('Logout from Codlyy')
|
|
39
|
+
.action(async () => {
|
|
40
|
+
await logout();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
program
|
|
44
|
+
.command('info')
|
|
45
|
+
.description('Show CLI status and available commands')
|
|
46
|
+
.action(async () => {
|
|
47
|
+
await info(VERSION);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Handle default command (REPL)
|
|
51
|
+
if (process.argv.length <= 2) {
|
|
52
|
+
const config = getConfig();
|
|
53
|
+
if (config.token) {
|
|
54
|
+
// User is logged in, start REPL
|
|
55
|
+
startRepl(VERSION);
|
|
56
|
+
} else {
|
|
57
|
+
// User is not logged in
|
|
58
|
+
console.log(chalk.yellow('\nYou are not logged in.'));
|
|
59
|
+
console.log(`Please run ${chalk.cyan('codlyy login')} to authenticate.\n`);
|
|
53
60
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
chalk.blueBright("\n🚧 Coming soon...")
|
|
58
|
-
);
|
|
59
|
-
console.log(
|
|
60
|
-
chalk.gray("Codlyy AI engine is under development.\n")
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
// Wait for next prompt
|
|
64
|
-
rl.prompt();
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
// Ctrl + C handling
|
|
68
|
-
rl.on("SIGINT", () => {
|
|
69
|
-
console.log(chalk.gray("\n👋 Codlyy closed.\n"));
|
|
70
|
-
process.exit(0);
|
|
71
|
-
});
|
|
61
|
+
} else {
|
|
62
|
+
program.parse(process.argv);
|
|
63
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codlyy",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Codlyy AI CLI – Ocean Blue developer assistant",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"clear": "^0.1.0",
|
|
25
25
|
"commander": "^14.0.2",
|
|
26
26
|
"figlet": "^1.10.0",
|
|
27
|
-
"gradient-string": "^3.0.0"
|
|
27
|
+
"gradient-string": "^3.0.0",
|
|
28
|
+
"open": "^11.0.0"
|
|
28
29
|
}
|
|
29
30
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { getConfig } from '../utils/config.js';
|
|
3
|
+
|
|
4
|
+
export async function info(version) {
|
|
5
|
+
const config = getConfig();
|
|
6
|
+
const isLoggedIn = !!config.token;
|
|
7
|
+
|
|
8
|
+
console.log(chalk.bold.blue('\n⚡ Codlyy CLI Information\n'));
|
|
9
|
+
|
|
10
|
+
// Version Info
|
|
11
|
+
console.log(`${chalk.bold('Version:')} ${version}`);
|
|
12
|
+
|
|
13
|
+
// User Info
|
|
14
|
+
if (isLoggedIn) {
|
|
15
|
+
console.log(`${chalk.bold('Status:')} ${chalk.green('Logged In')}`);
|
|
16
|
+
console.log(`${chalk.bold('User:')} ${config.name || config.email || 'Unknown'}`);
|
|
17
|
+
if (config.email && config.name) {
|
|
18
|
+
console.log(`${chalk.bold('Email:')} ${config.email}`);
|
|
19
|
+
}
|
|
20
|
+
} else {
|
|
21
|
+
console.log(`${chalk.bold('Status:')} ${chalk.yellow('Not Logged In')}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
console.log(''); // Spacer
|
|
25
|
+
|
|
26
|
+
// Commands List
|
|
27
|
+
console.log(chalk.bold('Available Commands:'));
|
|
28
|
+
console.log(` ${chalk.cyan('codlyy login')} ${chalk.gray('Login using your browser')}`);
|
|
29
|
+
console.log(` ${chalk.cyan('codlyy logout')} ${chalk.gray('Logout and clear credentials')}`);
|
|
30
|
+
console.log(` ${chalk.cyan('codlyy info')} ${chalk.gray('Show this information page')}`);
|
|
31
|
+
console.log(` ${chalk.cyan('codlyy')} ${chalk.gray('Start the AI assistant REPL (requires login)')}`);
|
|
32
|
+
|
|
33
|
+
console.log('');
|
|
34
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import http from 'http';
|
|
2
|
+
import open from 'open';
|
|
3
|
+
import { saveConfig, getConfig } from '../utils/config.js';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import readline from 'readline';
|
|
6
|
+
|
|
7
|
+
const PORT = 8989;
|
|
8
|
+
|
|
9
|
+
export async function login() {
|
|
10
|
+
console.log(chalk.blue('Opening browser for authentication...'));
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
const userData = await startAuthServer();
|
|
14
|
+
|
|
15
|
+
// Save initial data immediately
|
|
16
|
+
saveConfig(userData);
|
|
17
|
+
|
|
18
|
+
console.log(chalk.green(`\nSuccessfully logged in as ${userData.name || userData.email}!`));
|
|
19
|
+
|
|
20
|
+
// Ask if they want to update their name
|
|
21
|
+
await askToEditName(userData);
|
|
22
|
+
|
|
23
|
+
} catch (err) {
|
|
24
|
+
console.error(chalk.red('\nLogin failed:'), err.message);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function startAuthServer() {
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
const server = http.createServer((req, res) => {
|
|
32
|
+
const url = new URL(req.url, `http://localhost:${PORT}`);
|
|
33
|
+
|
|
34
|
+
if (url.pathname === '/callback') {
|
|
35
|
+
const token = url.searchParams.get('token');
|
|
36
|
+
const email = url.searchParams.get('email');
|
|
37
|
+
const name = url.searchParams.get('name');
|
|
38
|
+
const picture = url.searchParams.get('picture');
|
|
39
|
+
|
|
40
|
+
if (token) {
|
|
41
|
+
// 1. Display success message to user in browser
|
|
42
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
43
|
+
res.end(`
|
|
44
|
+
<html>
|
|
45
|
+
<body style="font-family: sans-serif; text-align: center; padding: 50px;">
|
|
46
|
+
<h1>Login Successful</h1>
|
|
47
|
+
<p>You can close this tab now and return to the CLI.</p>
|
|
48
|
+
<script>window.close()</script>
|
|
49
|
+
</body>
|
|
50
|
+
</html>
|
|
51
|
+
`);
|
|
52
|
+
|
|
53
|
+
// 2. Stop the server and resolve
|
|
54
|
+
res.on('finish', () => {
|
|
55
|
+
server.close();
|
|
56
|
+
resolve({ token, email, name, picture });
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
} else {
|
|
60
|
+
res.writeHead(400);
|
|
61
|
+
res.end('No token found');
|
|
62
|
+
server.close();
|
|
63
|
+
reject(new Error('No token received'));
|
|
64
|
+
}
|
|
65
|
+
} else {
|
|
66
|
+
res.writeHead(404);
|
|
67
|
+
res.end();
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
server.listen(PORT, async () => {
|
|
72
|
+
try {
|
|
73
|
+
await open(`https://codlyy.vercel.app/auth/cli-login?port=${PORT}`);
|
|
74
|
+
} catch (err) {
|
|
75
|
+
console.error(chalk.red('Failed to open browser:'), err);
|
|
76
|
+
console.log(chalk.yellow(`Please open this URL manually: https://codlyy.vercel.app/auth/cli-login?port=${PORT}`));
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
server.on('error', (err) => {
|
|
81
|
+
reject(err);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function askToEditName(userData) {
|
|
87
|
+
const rl = readline.createInterface({
|
|
88
|
+
input: process.stdin,
|
|
89
|
+
output: process.stdout
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
return new Promise((resolve) => {
|
|
93
|
+
// Add a small delay/newline to visually separate from previous logs
|
|
94
|
+
console.log('');
|
|
95
|
+
|
|
96
|
+
rl.question(chalk.yellow(`Your display name is currently "${userData.name}". Do you want to edit it? (y/N) `), (answer) => {
|
|
97
|
+
if (answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes') {
|
|
98
|
+
rl.question(chalk.cyan('Enter new name: '), (newName) => {
|
|
99
|
+
const trimmedName = newName.trim();
|
|
100
|
+
if (trimmedName) {
|
|
101
|
+
saveConfig({ ...userData, name: trimmedName });
|
|
102
|
+
console.log(chalk.green(`Name updated to: ${trimmedName}`));
|
|
103
|
+
} else {
|
|
104
|
+
console.log(chalk.gray('Name unchanged.'));
|
|
105
|
+
}
|
|
106
|
+
rl.close();
|
|
107
|
+
resolve();
|
|
108
|
+
});
|
|
109
|
+
} else {
|
|
110
|
+
console.log(chalk.gray('Name unchanged.'));
|
|
111
|
+
rl.close();
|
|
112
|
+
resolve();
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
}
|
package/src/repl.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import clear from "clear";
|
|
2
|
+
import figlet from "figlet";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import gradient from "gradient-string";
|
|
5
|
+
import readline from "readline";
|
|
6
|
+
import { getConfig } from "./utils/config.js";
|
|
7
|
+
|
|
8
|
+
export function startRepl(version) {
|
|
9
|
+
// Clear terminal
|
|
10
|
+
clear();
|
|
11
|
+
|
|
12
|
+
// Ocean blue gradient
|
|
13
|
+
const ocean = gradient(["#00c6ff", "#0072ff"]);
|
|
14
|
+
|
|
15
|
+
// Banner
|
|
16
|
+
console.log(
|
|
17
|
+
ocean(
|
|
18
|
+
figlet.textSync("CODLYY", {
|
|
19
|
+
font: "Block",
|
|
20
|
+
horizontalLayout: "default",
|
|
21
|
+
verticalLayout: "default",
|
|
22
|
+
})
|
|
23
|
+
)
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
const config = getConfig();
|
|
27
|
+
const displayName = config.name || config.email || "User";
|
|
28
|
+
|
|
29
|
+
// Header info
|
|
30
|
+
console.log(
|
|
31
|
+
chalk.gray(`⚡ Codlyy CLI v${version} · Research Preview`)
|
|
32
|
+
);
|
|
33
|
+
console.log(chalk.blue(`Welcome back, ${displayName}!`));
|
|
34
|
+
console.log(chalk.gray("Type your prompt and press Enter"));
|
|
35
|
+
console.log(chalk.gray("Type 'exit' to quit\n"));
|
|
36
|
+
|
|
37
|
+
// Readline interface
|
|
38
|
+
const rl = readline.createInterface({
|
|
39
|
+
input: process.stdin,
|
|
40
|
+
output: process.stdout,
|
|
41
|
+
prompt: chalk.cyanBright("❯ "),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Start prompt
|
|
45
|
+
rl.prompt();
|
|
46
|
+
|
|
47
|
+
// Handle input
|
|
48
|
+
rl.on("line", (input) => {
|
|
49
|
+
const prompt = input.trim().toLowerCase();
|
|
50
|
+
|
|
51
|
+
if (prompt === "exit" || prompt === "quit") {
|
|
52
|
+
console.log(chalk.gray("\n👋 Exiting Codlyy. See you soon!\n"));
|
|
53
|
+
process.exit(0);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (prompt === "version" || prompt === "--version" || prompt === "-v") {
|
|
57
|
+
console.log(chalk.blueBright(`\nCodlyy CLI v${version}\n`));
|
|
58
|
+
rl.prompt();
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (prompt.length === 0) {
|
|
63
|
+
rl.prompt();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Coming soon response
|
|
68
|
+
console.log(chalk.blueBright("\n🚧 Coming soon..."));
|
|
69
|
+
console.log(
|
|
70
|
+
chalk.gray("Codlyy AI engine is under development.\n")
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
// Wait for next prompt
|
|
74
|
+
rl.prompt();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Ctrl + C handling
|
|
78
|
+
rl.on("SIGINT", () => {
|
|
79
|
+
console.log(chalk.gray("\n👋 Codlyy closed.\n"));
|
|
80
|
+
process.exit(0);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
|
|
5
|
+
const CONFIG_PATH = path.join(os.homedir(), '.codlyyrc');
|
|
6
|
+
|
|
7
|
+
export function saveConfig(data) {
|
|
8
|
+
try {
|
|
9
|
+
const current = getConfig();
|
|
10
|
+
const newConfig = { ...current, ...data };
|
|
11
|
+
fs.writeFileSync(CONFIG_PATH, JSON.stringify(newConfig, null, 2));
|
|
12
|
+
return true;
|
|
13
|
+
} catch (error) {
|
|
14
|
+
console.error('Error saving config:', error);
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function getConfig() {
|
|
20
|
+
try {
|
|
21
|
+
if (fs.existsSync(CONFIG_PATH)) {
|
|
22
|
+
const data = fs.readFileSync(CONFIG_PATH, 'utf-8');
|
|
23
|
+
return JSON.parse(data);
|
|
24
|
+
}
|
|
25
|
+
} catch (error) {
|
|
26
|
+
// Ignore error if file doesn't exist or is invalid
|
|
27
|
+
}
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function clearConfig() {
|
|
32
|
+
try {
|
|
33
|
+
if(fs.existsSync(CONFIG_PATH)) {
|
|
34
|
+
fs.unlinkSync(CONFIG_PATH);
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.error('Error clearing config:', error);
|
|
39
|
+
}
|
|
40
|
+
return false;
|
|
41
|
+
}
|