add ability to remove accounts. ensure accounts are not / added / removed when server is running
This commit is contained in:
@@ -10,6 +10,7 @@
|
|||||||
"accounts": "node src/accounts-cli.js",
|
"accounts": "node src/accounts-cli.js",
|
||||||
"accounts:add": "node src/accounts-cli.js add",
|
"accounts:add": "node src/accounts-cli.js add",
|
||||||
"accounts:list": "node src/accounts-cli.js list",
|
"accounts:list": "node src/accounts-cli.js list",
|
||||||
|
"accounts:remove": "node src/accounts-cli.js remove",
|
||||||
"accounts:verify": "node src/accounts-cli.js verify",
|
"accounts:verify": "node src/accounts-cli.js verify",
|
||||||
"test": "node tests/run-all.cjs",
|
"test": "node tests/run-all.cjs",
|
||||||
"test:signatures": "node tests/test-thinking-signatures.cjs",
|
"test:signatures": "node tests/test-thinking-signatures.cjs",
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ import { stdin, stdout } from 'process';
|
|||||||
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
||||||
import { dirname } from 'path';
|
import { dirname } from 'path';
|
||||||
import { exec } from 'child_process';
|
import { exec } from 'child_process';
|
||||||
import { ACCOUNT_CONFIG_PATH } from './constants.js';
|
import net from 'net';
|
||||||
|
import { ACCOUNT_CONFIG_PATH, DEFAULT_PORT } from './constants.js';
|
||||||
import {
|
import {
|
||||||
getAuthorizationUrl,
|
getAuthorizationUrl,
|
||||||
startCallbackServer,
|
startCallbackServer,
|
||||||
@@ -28,6 +29,51 @@ import {
|
|||||||
} from './oauth.js';
|
} from './oauth.js';
|
||||||
|
|
||||||
const MAX_ACCOUNTS = 10;
|
const MAX_ACCOUNTS = 10;
|
||||||
|
const SERVER_PORT = process.env.PORT || DEFAULT_PORT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the Antigravity Proxy server is running
|
||||||
|
* Returns true if port is occupied
|
||||||
|
*/
|
||||||
|
function isServerRunning() {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const socket = new net.Socket();
|
||||||
|
socket.setTimeout(1000);
|
||||||
|
|
||||||
|
socket.on('connect', () => {
|
||||||
|
socket.destroy();
|
||||||
|
resolve(true); // Server is running
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('timeout', () => {
|
||||||
|
socket.destroy();
|
||||||
|
resolve(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('error', (err) => {
|
||||||
|
socket.destroy();
|
||||||
|
resolve(false); // Port free
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.connect(SERVER_PORT, 'localhost');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enforce that server is stopped before proceeding
|
||||||
|
*/
|
||||||
|
async function ensureServerStopped() {
|
||||||
|
const isRunning = await isServerRunning();
|
||||||
|
if (isRunning) {
|
||||||
|
console.error(`
|
||||||
|
\x1b[31mError: Antigravity Proxy server is currently running on port ${SERVER_PORT}.\x1b[0m
|
||||||
|
|
||||||
|
Please stop the server (Ctrl+C) before adding or managing accounts.
|
||||||
|
This ensures that your account changes are loaded correctly when you restart the server.
|
||||||
|
`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create readline interface
|
* Create readline interface
|
||||||
@@ -183,7 +229,51 @@ async function addAccount(existingAccounts) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interactive add accounts flow
|
* Interactive remove accounts flow
|
||||||
|
*/
|
||||||
|
async function interactiveRemove(rl) {
|
||||||
|
while (true) {
|
||||||
|
const accounts = loadAccounts();
|
||||||
|
if (accounts.length === 0) {
|
||||||
|
console.log('\nNo accounts to remove.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
displayAccounts(accounts);
|
||||||
|
console.log('\nEnter account number to remove (or 0 to cancel)');
|
||||||
|
|
||||||
|
const answer = await rl.question('> ');
|
||||||
|
const index = parseInt(answer, 10);
|
||||||
|
|
||||||
|
if (isNaN(index) || index < 0 || index > accounts.length) {
|
||||||
|
console.log('\n❌ Invalid selection.');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index === 0) {
|
||||||
|
return; // Exit
|
||||||
|
}
|
||||||
|
|
||||||
|
const removed = accounts[index - 1]; // 1-based to 0-based
|
||||||
|
const confirm = await rl.question(`\nAre you sure you want to remove ${removed.email}? [y/N]: `);
|
||||||
|
|
||||||
|
if (confirm.toLowerCase() === 'y') {
|
||||||
|
accounts.splice(index - 1, 1);
|
||||||
|
saveAccounts(accounts);
|
||||||
|
console.log(`\n✓ Removed ${removed.email}`);
|
||||||
|
} else {
|
||||||
|
console.log('\nCancelled.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeMore = await rl.question('\nRemove another account? [y/N]: ');
|
||||||
|
if (removeMore.toLowerCase() !== 'y') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interactive add accounts flow (Main Menu)
|
||||||
*/
|
*/
|
||||||
async function interactiveAdd(rl) {
|
async function interactiveAdd(rl) {
|
||||||
const accounts = loadAccounts();
|
const accounts = loadAccounts();
|
||||||
@@ -191,13 +281,19 @@ async function interactiveAdd(rl) {
|
|||||||
if (accounts.length > 0) {
|
if (accounts.length > 0) {
|
||||||
displayAccounts(accounts);
|
displayAccounts(accounts);
|
||||||
|
|
||||||
const choice = await rl.question('\n(a)dd new account(s) or (f)resh start? [a/f]: ');
|
const choice = await rl.question('\n(a)dd new, (r)emove existing, or (f)resh start? [a/r/f]: ');
|
||||||
|
const c = choice.toLowerCase();
|
||||||
|
|
||||||
if (choice.toLowerCase() === 'f') {
|
if (c === 'r') {
|
||||||
|
await interactiveRemove(rl);
|
||||||
|
return; // Return to main or exit? Given this is "add", we probably exit after sub-task.
|
||||||
|
} else if (c === 'f') {
|
||||||
console.log('\nStarting fresh - existing accounts will be replaced.');
|
console.log('\nStarting fresh - existing accounts will be replaced.');
|
||||||
accounts.length = 0;
|
accounts.length = 0;
|
||||||
} else {
|
} else if (c === 'a') {
|
||||||
console.log('\nAdding to existing accounts.');
|
console.log('\nAdding to existing accounts.');
|
||||||
|
} else {
|
||||||
|
console.log('\nInvalid choice, defaulting to add.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,12 +401,14 @@ async function main() {
|
|||||||
try {
|
try {
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case 'add':
|
case 'add':
|
||||||
|
await ensureServerStopped();
|
||||||
await interactiveAdd(rl);
|
await interactiveAdd(rl);
|
||||||
break;
|
break;
|
||||||
case 'list':
|
case 'list':
|
||||||
await listAccounts();
|
await listAccounts();
|
||||||
break;
|
break;
|
||||||
case 'clear':
|
case 'clear':
|
||||||
|
await ensureServerStopped();
|
||||||
await clearAccounts(rl);
|
await clearAccounts(rl);
|
||||||
break;
|
break;
|
||||||
case 'verify':
|
case 'verify':
|
||||||
@@ -324,6 +422,10 @@ async function main() {
|
|||||||
console.log(' node src/accounts-cli.js clear Remove all accounts');
|
console.log(' node src/accounts-cli.js clear Remove all accounts');
|
||||||
console.log(' node src/accounts-cli.js help Show this help');
|
console.log(' node src/accounts-cli.js help Show this help');
|
||||||
break;
|
break;
|
||||||
|
case 'remove':
|
||||||
|
await ensureServerStopped();
|
||||||
|
await interactiveRemove(rl);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.log(`Unknown command: ${command}`);
|
console.log(`Unknown command: ${command}`);
|
||||||
console.log('Run with "help" for usage information.');
|
console.log('Run with "help" for usage information.');
|
||||||
|
|||||||
Reference in New Issue
Block a user