WS2: Developer Portal (portal/) - Standalone Next.js 14 + Tailwind CSS app — independent deployment - Home page: hero, feature grid, CTA to /get-started - /pricing: free tier limits table (10 agents, 1k calls/day) + paid tier CTA - /sdks: all 4 SDKs (Node.js, Python, Go, Java) with install + code examples - /api-explorer: Swagger UI from NEXT_PUBLIC_API_URL/openapi.json, persistAuthorization - /get-started: 4-step wizard (setup → register agent → credentials → SDK snippet) - Shared Nav component with active-link highlighting - Build: 8/8 static pages, zero TypeScript errors WS3: CLI Tool (cli/ — npm package: sentryagent) - configure, register-agent, list-agents, issue-token, rotate-credentials, tail-audit-log - Auto OAuth2 token fetch + 30s-buffer cache via client_credentials flow - chalk-formatted table output, confirmation prompts, bounded audit log dedup - bash + zsh shell completion scripts - README with installation, all commands, and completion setup - Build: tsc clean, node dist/index.js --help verified Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
64 lines
1.7 KiB
TypeScript
64 lines
1.7 KiB
TypeScript
import * as readline from 'readline';
|
|
import { Command } from 'commander';
|
|
import chalk from 'chalk';
|
|
import { writeConfig } from '../config';
|
|
|
|
function prompt(rl: readline.Interface, question: string): Promise<string> {
|
|
return new Promise((resolve) => {
|
|
rl.question(question, (answer) => {
|
|
resolve(answer.trim());
|
|
});
|
|
});
|
|
}
|
|
|
|
export function registerConfigure(program: Command): void {
|
|
program
|
|
.command('configure')
|
|
.description('Configure the CLI with API URL and credentials')
|
|
.action(async () => {
|
|
const rl = readline.createInterface({
|
|
input: process.stdin,
|
|
output: process.stdout,
|
|
});
|
|
|
|
try {
|
|
console.log(chalk.bold('SentryAgent CLI Configuration'));
|
|
console.log(chalk.dim('─'.repeat(40)));
|
|
|
|
const apiUrl = await prompt(
|
|
rl,
|
|
chalk.cyan('API URL') + ' (e.g. https://api.sentryagent.ai): ',
|
|
);
|
|
if (apiUrl === '') {
|
|
console.error(chalk.red('API URL cannot be empty.'));
|
|
process.exit(1);
|
|
}
|
|
|
|
const clientId = await prompt(rl, chalk.cyan('Client ID') + ': ');
|
|
if (clientId === '') {
|
|
console.error(chalk.red('Client ID cannot be empty.'));
|
|
process.exit(1);
|
|
}
|
|
|
|
const clientSecret = await prompt(
|
|
rl,
|
|
chalk.cyan('Client Secret') + ': ',
|
|
);
|
|
if (clientSecret === '') {
|
|
console.error(chalk.red('Client Secret cannot be empty.'));
|
|
process.exit(1);
|
|
}
|
|
|
|
writeConfig({ apiUrl, clientId, clientSecret });
|
|
|
|
console.log();
|
|
console.log(
|
|
chalk.green('✓') +
|
|
' Configuration saved to ~/.sentryagent/config.json',
|
|
);
|
|
} finally {
|
|
rl.close();
|
|
}
|
|
});
|
|
}
|