alnilam-cli
Version:
Git-native AI career coach that converts multi-year ambitions into weekly execution
239 lines (238 loc) ⢠9.79 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.nudgeCommand = exports.planReviewCommand = void 0;
const commander_1 = require("commander");
const api_js_1 = require("../lib/api.js");
const readline = __importStar(require("readline"));
const planReviewCommand = new commander_1.Command('review');
exports.planReviewCommand = planReviewCommand;
planReviewCommand
.description('Interactive plan approval workflow')
.option('--auto-approve', 'Auto-approve all pending plans')
.option('--json', 'Output as JSON')
.action(async (options) => {
try {
console.log('š Plan Review Dashboard');
console.log('ā'.repeat(50));
// Fetch pending nudges
const response = await api_js_1.restClient.get('/nudges', {
params: {
select: '*',
'requires_approval': 'eq.true',
'approved': 'eq.false',
order: 'created_at.desc'
}
});
const pendingNudges = response.data || [];
if (pendingNudges.length === 0) {
console.log('ā
No pending approvals! All plans are up to date.');
console.log('š” Generate a new plan with: alnl plan');
return;
}
if (options.json) {
console.log(JSON.stringify(pendingNudges, null, 2));
return;
}
console.log(`š Found ${pendingNudges.length} pending approval(s)\n`);
for (let i = 0; i < pendingNudges.length; i++) {
const nudge = pendingNudges[i];
const isWeeklyPlan = nudge.type === 'weekly_plan';
console.log(`š Reviewing ${i + 1}/${pendingNudges.length}`);
console.log('ā'.repeat(40));
// Display plan details
console.log(`š Type: ${nudge.type}`);
console.log(`š
Created: ${new Date(nudge.created_at).toLocaleString()}`);
console.log(`š Content: ${nudge.content}\n`);
if (isWeeklyPlan && nudge.metadata) {
// Show weekly plan details
const metadata = nudge.metadata;
if (metadata.target_week) {
console.log(`šļø Target Week: ${metadata.target_week}`);
}
if (metadata.estimated_cost) {
console.log(`š° Estimated Cost: $${metadata.estimated_cost}`);
}
if (metadata.proposed_goals && metadata.proposed_goals.length > 0) {
console.log('\nšÆ Proposed Goals:');
metadata.proposed_goals.forEach((goal, index) => {
const priority = goal.priority === 'high' ? 'š“' :
goal.priority === 'medium' ? 'š”' : 'š¢';
console.log(` ${index + 1}. ${goal.title} ${priority}`);
console.log(` ${goal.description.substring(0, 60)}...`);
console.log(` ā±ļø ${goal.estimated_hours}h | š” ${goal.rationale.substring(0, 40)}...`);
});
}
if (metadata.focus_areas && metadata.focus_areas.length > 0) {
console.log('\nšÆ Focus Areas:');
metadata.focus_areas.forEach((area) => {
console.log(` ⢠${area}`);
});
}
if (metadata.risk_mitigations && metadata.risk_mitigations.length > 0) {
console.log('\nš”ļø Risk Mitigations:');
metadata.risk_mitigations.forEach((mitigation) => {
console.log(` ⢠${mitigation}`);
});
}
}
// Auto-approve if requested
if (options.autoApprove || options['auto-approve']) {
await approveNudge(nudge.id);
console.log('ā
Auto-approved!');
continue;
}
// Interactive approval
const approved = await promptForApproval();
if (approved) {
await approveNudge(nudge.id);
console.log('ā
Approved!');
}
else {
console.log('ā Rejected (nudge remains pending)');
}
console.log(''); // Add spacing between reviews
}
console.log('ā'.repeat(50));
console.log('š Plan review complete!');
console.log('š Check updated status with: alnl plan list');
}
catch (error) {
console.error('ā Plan review error:', error.message);
process.exit(1);
}
});
// Helper function to approve a nudge
async function approveNudge(nudgeId) {
const now = new Date().toISOString();
await api_js_1.restClient.patch(`/nudges?id=eq.${nudgeId}`, {
approved: true,
approved_at: now
});
}
// Helper function to prompt for approval
function promptForApproval() {
return new Promise((resolve) => {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const prompt = () => {
rl.question('\nš¤ Approve this plan? (y/n/s=skip): ', (answer) => {
const response = answer.toLowerCase().trim();
if (response === 'y' || response === 'yes') {
rl.close();
resolve(true);
}
else if (response === 'n' || response === 'no') {
rl.close();
resolve(false);
}
else if (response === 's' || response === 'skip') {
rl.close();
resolve(false);
}
else {
console.log('Please enter y(es), n(o), or s(kip)');
prompt();
}
});
};
prompt();
});
}
// Nudge management command
const nudgeCommand = new commander_1.Command('nudges');
exports.nudgeCommand = nudgeCommand;
nudgeCommand
.description('Manage AI-generated nudges and proposals')
.option('--pending', 'Show only pending nudges')
.option('--approved', 'Show only approved nudges')
.option('--json', 'Output as JSON')
.action(async (options) => {
try {
console.log('š” Nudge Management');
console.log('ā'.repeat(40));
let queryParams = { select: '*', order: 'created_at.desc' };
if (options.pending) {
queryParams['requires_approval'] = 'eq.true';
queryParams['approved'] = 'eq.false';
}
else if (options.approved) {
queryParams['approved'] = 'eq.true';
}
const response = await api_js_1.restClient.get('/nudges', { params: queryParams });
const nudges = response.data || [];
if (options.json) {
console.log(JSON.stringify(nudges, null, 2));
return;
}
if (nudges.length === 0) {
console.log('š No nudges found.');
return;
}
nudges.forEach((nudge, index) => {
const status = nudge.approved ? 'ā
' : 'ā³';
const age = getTimeAgo(nudge.created_at);
console.log(`${index + 1}. ${status} ${nudge.type} (${age})`);
console.log(` ${nudge.content}`);
if (nudge.type === 'weekly_plan' && nudge.metadata?.proposed_goals) {
console.log(` šÆ ${nudge.metadata.proposed_goals.length} goals proposed`);
}
console.log('');
});
const pending = nudges.filter(n => !n.approved).length;
if (pending > 0) {
console.log(`š” Review pending items with: alnl plan review`);
}
}
catch (error) {
console.error('ā Nudge management error:', error.message);
process.exit(1);
}
});
// Helper function for relative time
function getTimeAgo(dateString) {
const date = new Date(dateString);
const now = new Date();
const diffMs = now.getTime() - date.getTime();
const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
if (diffHours < 1)
return 'just now';
if (diffHours < 24)
return `${diffHours}h ago`;
return `${diffDays}d ago`;
}