Skip to content

Commit b3ca054

Browse files
Copilotwarengonzaga
andcommitted
📦 new: implement commander.js cli and core modules
Co-authored-by: warengonzaga <15052701+warengonzaga@users.noreply.github.com>
1 parent 4e96bc0 commit b3ca054

13 files changed

Lines changed: 1251 additions & 865 deletions

File tree

package.json

Lines changed: 9 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "magicc",
3-
"version": "0.2.6",
3+
"version": "0.3.0",
44
"author": "Waren Gonzaga",
55
"description": "You can do `magicc`, you can build anything that you desire.",
66
"keywords": [
@@ -38,54 +38,35 @@
3838
"dist"
3939
],
4040
"dependencies": {
41+
"@github/copilot-sdk": "^0.1.20",
42+
"chalk": "^5.3.0",
43+
"commander": "^12.0.0",
4144
"conf": "^12.0.0",
4245
"dotenv": "^16.5.0",
4346
"execa": "^8.0.1",
44-
"ink": "^5.2.1",
45-
"ink-big-text": "^2.0.0",
46-
"ink-gradient": "^3.0.0",
47-
"ink-select-input": "^6.2.0",
47+
"figlet": "^1.7.0",
48+
"inquirer": "^9.2.0",
4849
"is-git-repository": "^2.0.0",
49-
"meow": "^11.0.0",
50-
"openai": "^4.104.0",
51-
"react": "^18.2.0",
52-
"readline": "^1.3.0"
50+
"openai": "^4.104.0"
5351
},
5452
"devDependencies": {
5553
"@babel/cli": "^7.21.0",
56-
"@babel/preset-react": "^7.18.6",
5754
"@vdemedes/prettier-config": "^2.0.1",
5855
"ava": "^5.2.0",
5956
"babel-plugin-inline-json-import": "^0.3.2",
60-
"chalk": "^5.2.0",
61-
"eslint-config-xo-react": "^0.27.0",
62-
"eslint-plugin-react": "^7.32.2",
63-
"eslint-plugin-react-hooks": "^4.6.0",
64-
"import-jsx": "^5.0.0",
65-
"ink-testing-library": "^3.0.0",
6657
"prettier": "^2.8.7",
6758
"xo": "^0.53.1"
6859
},
6960
"ava": {
7061
"environmentVariables": {
7162
"NODE_NO_WARNINGS": "1"
72-
},
73-
"nodeArguments": [
74-
"--loader=import-jsx"
75-
]
63+
}
7664
},
7765
"xo": {
78-
"extends": "xo-react",
79-
"prettier": true,
80-
"rules": {
81-
"react/prop-types": "off"
82-
}
66+
"prettier": true
8367
},
8468
"prettier": "@vdemedes/prettier-config",
8569
"babel": {
86-
"presets": [
87-
"@babel/preset-react"
88-
],
8970
"plugins": [
9071
"inline-json-import"
9172
]

source/app.js

Lines changed: 0 additions & 48 deletions
This file was deleted.

source/cli.js

Lines changed: 121 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,122 @@
11
#!/usr/bin/env node
2-
import React from 'react';
3-
import {render} from 'ink';
4-
import meow from 'meow';
5-
import App from './app.js';
6-
7-
const cli = meow(
8-
`
9-
Usage
10-
$ magicc
11-
12-
Options
13-
--setopenai, -s OpenAI API key
14-
--delopenai, -d Delete OpenAI API key
15-
--help Show help
16-
--version Show version
17-
18-
Examples
19-
$ magicc -s=sk-<api-key>
20-
`,
21-
{
22-
importMeta: import.meta,
23-
flags: {
24-
setopenai: {
25-
type: 'string',
26-
alias: 's',
27-
},
28-
delopenai: {
29-
type: 'boolean',
30-
alias: 'd',
31-
},
32-
},
33-
},
34-
);
35-
36-
render(<App flags={cli.flags}/>);
2+
import {Command} from 'commander';
3+
import {showBanner, showWarning} from './utils/ui.js';
4+
import {commitCommand} from './commands/commit.js';
5+
import {
6+
authenticateWithCopilot,
7+
authenticateWithOpenAI,
8+
showAuthStatusCommand,
9+
logout,
10+
} from './commands/auth.js';
11+
import {showConfig, resetConfig} from './commands/config.js';
12+
import packageJSON from '../package.json';
13+
14+
const program = new Command();
15+
16+
// Setup program metadata
17+
program
18+
.name('magicc')
19+
.description('🪄 You can do magicc, you can build anything that you desire.')
20+
.version(packageJSON.version);
21+
22+
// Show banner on startup (except for --help and --version)
23+
const args = process.argv.slice(2);
24+
if (!args.includes('--help') && !args.includes('-h') &&
25+
!args.includes('--version') && !args.includes('-V')) {
26+
showBanner();
27+
}
28+
29+
// Default command (commit)
30+
program
31+
.action(() => {
32+
// If no command is specified, run commit
33+
commitCommand();
34+
});
35+
36+
// Commit command
37+
const commitCmd = program
38+
.command('commit', {isDefault: false})
39+
.description('Generate AI-powered commit messages')
40+
.option('--all', 'Process all files at once')
41+
.option('--file <path>', 'Process specific file')
42+
.option('--model <model>', 'Specify AI model (e.g., gpt-4, gpt-3.5-turbo)')
43+
.action((options) => {
44+
commitCommand(options);
45+
});
46+
47+
// Auth command
48+
const authCmd = program
49+
.command('auth')
50+
.description('Manage authentication');
51+
52+
authCmd
53+
.command('copilot')
54+
.description('Authenticate with GitHub Copilot')
55+
.option('--token <token>', 'GitHub token')
56+
.action((options) => {
57+
authenticateWithCopilot(options.token);
58+
});
59+
60+
authCmd
61+
.command('openai <key>')
62+
.description('Authenticate with OpenAI (legacy)')
63+
.action((key) => {
64+
authenticateWithOpenAI(key);
65+
});
66+
67+
authCmd
68+
.command('status')
69+
.description('Show authentication status')
70+
.action(() => {
71+
showAuthStatusCommand();
72+
});
73+
74+
authCmd
75+
.command('logout')
76+
.description('Clear all credentials')
77+
.action(() => {
78+
logout();
79+
});
80+
81+
// Config command
82+
const configCmd = program
83+
.command('config')
84+
.description('Manage configuration');
85+
86+
configCmd
87+
.option('--show', 'Show current configuration')
88+
.option('--reset', 'Reset configuration to defaults')
89+
.action((options) => {
90+
if (options.reset) {
91+
resetConfig();
92+
} else {
93+
showConfig();
94+
}
95+
});
96+
97+
// Legacy flags support with deprecation warnings
98+
program
99+
.option('-s, --setopenai <key>', '[DEPRECATED] Set OpenAI API key')
100+
.option('-d, --delopenai', '[DEPRECATED] Delete OpenAI API key');
101+
102+
// Handle legacy flags
103+
program.hook('preAction', (thisCommand) => {
104+
const options = thisCommand.opts();
105+
106+
if (options.setopenai) {
107+
showWarning('The -s flag is deprecated. Use: magicc auth openai <key>');
108+
console.log('');
109+
authenticateWithOpenAI(options.setopenai);
110+
process.exit(0);
111+
}
112+
113+
if (options.delopenai) {
114+
showWarning('The -d flag is deprecated. Use: magicc auth logout');
115+
console.log('');
116+
logout();
117+
process.exit(0);
118+
}
119+
});
120+
121+
// Parse arguments
122+
program.parse();

source/commands/auth.js

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import {setAuthMode, setToken, getToken, clearAll, getAllConfig, getConfigPath} from '../utils/config-manager.js';
2+
import {showSuccess, showError, showWarning, showAuthStatus} from '../utils/ui.js';
3+
4+
/**
5+
* Authentication commands
6+
* Handles GitHub Copilot and OpenAI authentication
7+
*/
8+
9+
export async function authenticateWithCopilot(token = null) {
10+
try {
11+
// Check for token in arguments first
12+
let authToken = token;
13+
14+
// If no token provided, check environment variables
15+
if (!authToken) {
16+
authToken = process.env.COPILOT_GITHUB_TOKEN ||
17+
process.env.GH_TOKEN ||
18+
process.env.GITHUB_TOKEN;
19+
}
20+
21+
if (!authToken) {
22+
showError('No GitHub token found.');
23+
console.log('');
24+
console.log('Please provide a token using one of these methods:');
25+
console.log(' 1. Pass token: magicc auth copilot --token <your-token>');
26+
console.log(' 2. Set environment variable: GITHUB_TOKEN or GH_TOKEN');
27+
console.log(' 3. Use gh CLI: gh auth login (then use: magicc auth copilot)');
28+
console.log('');
29+
console.log('To create a token:');
30+
console.log(' Visit: https://github.com/settings/tokens');
31+
console.log(' Scopes needed: repo, read:user');
32+
process.exit(1);
33+
}
34+
35+
// Store token and set auth mode
36+
setToken('github', authToken);
37+
setAuthMode('copilot');
38+
39+
showSuccess('GitHub Copilot authentication successful!');
40+
console.log('');
41+
console.log(`📁 Config stored at: ${getConfigPath()}`);
42+
console.log('');
43+
console.log('You can now use: magicc commit');
44+
} catch (error) {
45+
showError(`Authentication failed: ${error.message}`);
46+
process.exit(1);
47+
}
48+
}
49+
50+
export async function authenticateWithOpenAI(apiKey) {
51+
try {
52+
if (!apiKey) {
53+
showError('OpenAI API key is required.');
54+
console.log('');
55+
console.log('Usage: magicc auth openai <your-api-key>');
56+
console.log('');
57+
console.log('To get an API key:');
58+
console.log(' Visit: https://platform.openai.com/account/api-keys');
59+
process.exit(1);
60+
}
61+
62+
// Validate the API key format
63+
if (!apiKey.startsWith('sk-')) {
64+
showWarning('API key should start with "sk-". Please verify your key.');
65+
}
66+
67+
// Store the key
68+
setToken('openai', apiKey);
69+
setAuthMode('openai');
70+
71+
showSuccess('OpenAI authentication successful!');
72+
console.log('');
73+
console.log(`📁 Config stored at: ${getConfigPath()}`);
74+
console.log('');
75+
console.log('💡 Consider switching to GitHub Copilot for better integration:');
76+
console.log(' magicc auth copilot');
77+
} catch (error) {
78+
showError(`Authentication failed: ${error.message}`);
79+
process.exit(1);
80+
}
81+
}
82+
83+
export function showAuthStatusCommand() {
84+
const config = getAllConfig();
85+
showAuthStatus(config);
86+
console.log(`📁 Config: ${getConfigPath()}`);
87+
console.log();
88+
}
89+
90+
export function logout() {
91+
try {
92+
clearAll();
93+
showSuccess('All credentials cleared.');
94+
console.log('');
95+
console.log('To authenticate again, use:');
96+
console.log(' magicc auth copilot');
97+
console.log(' magicc auth openai <key>');
98+
} catch (error) {
99+
showError(`Logout failed: ${error.message}`);
100+
process.exit(1);
101+
}
102+
}

0 commit comments

Comments
 (0)