alnilam-cli
Version:
Git-native AI career coach that converts multi-year ambitions into weekly execution
221 lines (220 loc) • 8.8 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.apiKeyCommand = void 0;
const commander_1 = require("commander");
const auth_1 = require("../lib/auth");
const crypto = __importStar(require("crypto"));
exports.apiKeyCommand = new commander_1.Command('api-key')
.description('Manage API keys for external integrations');
// Generate API key
exports.apiKeyCommand
.command('create')
.description('Create a new API key')
.requiredOption('--name <name>', 'Human-readable name for the API key')
.option('--expires <date>', 'Expiration date (YYYY-MM-DD) or days (number)', '0')
.option('--scopes <scopes>', 'Comma-separated permissions (read,write)', 'read')
.option('--json', 'Output as JSON')
.action(async (options) => {
try {
const authToken = await (0, auth_1.getCurrentAuthToken)();
if (!authToken) {
console.error('❌ Not authenticated. Run `alnl auth login` first.');
process.exit(1);
}
// Generate secure API key
const apiKey = generateApiKey();
const keyHash = crypto.createHash('sha256').update(apiKey).digest('hex');
const keyPrefix = apiKey.substring(0, 12); // Show first 12 chars for identification
// Parse expiration - support both dates (YYYY-MM-DD) and days (number)
let expiresAt = null;
if (options.expires !== '0') {
const expiresInDays = parseInt(options.expires);
if (!isNaN(expiresInDays) && expiresInDays > 0) {
// Number of days
expiresAt = new Date(Date.now() + expiresInDays * 24 * 60 * 60 * 1000).toISOString();
}
else {
// Try to parse as date
const expiresDate = new Date(options.expires);
if (!isNaN(expiresDate.getTime())) {
expiresAt = expiresDate.toISOString();
}
else {
console.error('❌ Invalid expiration format. Use YYYY-MM-DD or number of days.');
process.exit(1);
}
}
}
// Parse scopes
const scopes = options.scopes.split(',').map(s => s.trim());
const supabase = (0, auth_1.createAuthenticatedSupabaseClient)();
const { data, error } = await supabase
.from('api_keys')
.insert({
name: options.name,
key_hash: keyHash,
key_prefix: keyPrefix,
scopes: scopes,
expires_at: expiresAt
})
.select()
.single();
if (error) {
console.error('❌ Failed to create API key:', error.message);
process.exit(1);
}
if (options.json) {
console.log(JSON.stringify({
id: data.id,
name: data.name,
api_key: apiKey,
prefix: keyPrefix,
scopes: data.scopes,
expires_at: data.expires_at,
created_at: data.created_at
}, null, 2));
}
else {
console.log('✅ API key created successfully!');
console.log('');
console.log(`🔑 API Key: ${apiKey}`);
console.log(`📝 Name: ${data.name}`);
console.log(`🏷️ Prefix: ${keyPrefix}...`);
console.log(`🛡️ Scopes: ${data.scopes.join(', ')}`);
if (expiresAt) {
console.log(`⏰ Expires: ${new Date(expiresAt).toLocaleDateString()}`);
}
else {
console.log('⏰ Expires: Never');
}
console.log('');
console.log('⚠️ Store this API key securely - it won\'t be shown again!');
console.log('💡 Use this key for ChatGPT integration and other external tools.');
}
}
catch (error) {
console.error('❌ Error:', error.message);
process.exit(1);
}
});
// List API keys
exports.apiKeyCommand
.command('list')
.description('List all API keys')
.option('--json', 'Output as JSON')
.action(async (options) => {
try {
const authToken = await (0, auth_1.getCurrentAuthToken)();
if (!authToken) {
console.error('❌ Not authenticated. Run `alnl auth login` first.');
process.exit(1);
}
const supabase = (0, auth_1.createAuthenticatedSupabaseClient)();
const { data, error } = await supabase
.from('api_keys')
.select('id, name, key_prefix, scopes, last_used_at, expires_at, created_at')
.order('created_at', { ascending: false });
if (error) {
console.error('❌ Failed to list API keys:', error.message);
process.exit(1);
}
if (options.json) {
console.log(JSON.stringify(data, null, 2));
}
else {
if (data.length === 0) {
console.log('📝 No API keys found. Create one with `alnl api-key create --name "ChatGPT"`');
}
else {
console.log('🔑 Your API Keys:');
console.log('');
data.forEach((key, index) => {
const expired = key.expires_at && new Date(key.expires_at) < new Date();
const status = expired ? '❌ Expired' : '✅ Active';
const lastUsed = key.last_used_at ?
`Last used: ${new Date(key.last_used_at).toLocaleDateString()}` :
'Never used';
console.log(`${index + 1}. ${key.name} (${key.key_prefix}...)`);
console.log(` Status: ${status}`);
console.log(` Scopes: ${key.scopes.join(', ')}`);
console.log(` ${lastUsed}`);
if (key.expires_at) {
console.log(` Expires: ${new Date(key.expires_at).toLocaleDateString()}`);
}
console.log('');
});
}
}
}
catch (error) {
console.error('❌ Error:', error.message);
process.exit(1);
}
});
// Delete API key
exports.apiKeyCommand
.command('delete')
.description('Delete an API key')
.requiredOption('--id <id>', 'API key ID to delete')
.action(async (options) => {
try {
const authToken = await (0, auth_1.getCurrentAuthToken)();
if (!authToken) {
console.error('❌ Not authenticated. Run `alnl auth login` first.');
process.exit(1);
}
const supabase = (0, auth_1.createAuthenticatedSupabaseClient)();
const { error } = await supabase
.from('api_keys')
.delete()
.eq('id', options.id);
if (error) {
console.error('❌ Failed to delete API key:', error.message);
process.exit(1);
}
console.log('✅ API key deleted successfully!');
}
catch (error) {
console.error('❌ Error:', error.message);
process.exit(1);
}
});
function generateApiKey() {
// Generate a secure API key with format: alnl_<32_random_chars>
const randomBytes = crypto.randomBytes(24); // 24 bytes = 32 base64url chars
const randomString = randomBytes.toString('base64url');
return `alnl_${randomString}`;
}