Merge main into PR #221 to resolve conflicts
Resolved merge conflicts in public/views/settings.html: - Fixed HTML entity escaping for quote characters in presetHint text - Fixed HTML entity escaping for pendingPresetName text
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "antigravity-claude-proxy",
|
||||
"version": "1.2.6",
|
||||
"version": "2.4.2",
|
||||
"description": "Proxy server to use Antigravity's Claude models with Claude Code CLI",
|
||||
"main": "src/index.js",
|
||||
"type": "module",
|
||||
|
||||
@@ -77,8 +77,12 @@
|
||||
<div class="flex flex-col">
|
||||
<span class="text-sm font-bold tracking-wide text-white"
|
||||
x-text="$store.global.t('systemName')">ANTIGRAVITY</span>
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="text-[10px] text-gray-500 font-mono tracking-wider"
|
||||
x-text="$store.global.t('systemDesc')">CLAUDE PROXY SYSTEM</span>
|
||||
<span class="text-[10px] text-gray-500 font-mono tracking-wider"
|
||||
x-text="'v' + $store.global.version">v1.0.0</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -211,11 +215,15 @@
|
||||
</nav>
|
||||
|
||||
<!-- Footer Info -->
|
||||
<div class="mt-auto px-6 text-[10px] text-gray-700 font-mono">
|
||||
<div class="flex justify-between">
|
||||
<span x-text="'V ' + $store.global.version">V 1.0.0</span>
|
||||
<div class="mt-auto px-6 text-xs text-gray-400 font-mono">
|
||||
<div class="flex justify-center">
|
||||
<a href="https://github.com/badri-s2001/antigravity-claude-proxy" target="_blank" rel="noopener noreferrer"
|
||||
class="hover:text-neon-purple transition-colors" x-text="$store.global.t('github')">GitHub</a>
|
||||
class="flex items-center gap-1.5 hover:text-neon-purple transition-colors">
|
||||
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
|
||||
</svg>
|
||||
<span x-text="$store.global.t('github')">GitHub</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,21 @@
|
||||
window.Components = window.Components || {};
|
||||
|
||||
window.Components.models = () => ({
|
||||
editingModelId: null,
|
||||
newMapping: '',
|
||||
|
||||
isEditing(modelId) {
|
||||
return this.editingModelId === modelId;
|
||||
},
|
||||
|
||||
startEditing(modelId) {
|
||||
this.editingModelId = modelId;
|
||||
},
|
||||
|
||||
stopEditing() {
|
||||
this.editingModelId = null;
|
||||
},
|
||||
|
||||
init() {
|
||||
// Ensure data is fetched when this tab becomes active (skip initial trigger)
|
||||
this.$watch('$store.global.activeTab', (val, oldVal) => {
|
||||
|
||||
@@ -301,10 +301,7 @@
|
||||
<span x-show="deletingPreset" class="loading loading-spinner loading-xs"></span>
|
||||
</button>
|
||||
</div>
|
||||
<p class="text-[10px] text-gray-600 mt-2"
|
||||
x-text="$store.global.t('presetHint') || 'Select a preset to load it. Click \" Apply to Claude
|
||||
CLI\" to save changes.'">Select a preset to load it. Click "Apply to Claude CLI" to save
|
||||
changes.</p>
|
||||
<p class="text-[10px] text-gray-600 mt-2" x-text="$store.global.t('presetHint') || 'Select a preset to load it. Click "Apply to Claude CLI" to save changes.'">Select a preset to load it. Click "Apply to Claude CLI" to save changes.</p>
|
||||
</div>
|
||||
|
||||
<!-- Base URL -->
|
||||
@@ -700,8 +697,7 @@
|
||||
x-text="$store.global.t('unsavedChangesMessage') || 'Your current configuration doesn\'t match any saved preset.'">Your
|
||||
current configuration doesn't match any saved preset.</span>
|
||||
<br><br>
|
||||
<span class="text-yellow-400/80" x-text="'Load \"' + pendingPresetName + ' \" and lose
|
||||
current changes?'"></span>
|
||||
<span class="text-yellow-400/80" x-text="'Load "' + pendingPresetName + '" and lose current changes?'"></span>
|
||||
</p>
|
||||
<div class="modal-action">
|
||||
<button class="btn btn-ghost text-gray-400" @click="cancelLoadPreset()"
|
||||
@@ -762,7 +758,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Tab 3: Models Configuration -->
|
||||
<div x-show="activeTab === 'models'" x-data="window.Components.modelManager()"
|
||||
<div x-show="activeTab === 'models'" x-data="window.Components.models()"
|
||||
class="space-y-6 max-w-3xl animate-fade-in">
|
||||
|
||||
<div class="flex items-center justify-between">
|
||||
|
||||
@@ -141,9 +141,10 @@ export function extractCodeFromInput(input) {
|
||||
* Attempt to bind server to a specific port
|
||||
* @param {http.Server} server - HTTP server instance
|
||||
* @param {number} port - Port to bind to
|
||||
* @param {string} host - Host to bind to
|
||||
* @returns {Promise<number>} Resolves with port on success, rejects on error
|
||||
*/
|
||||
function tryBindPort(server, port) {
|
||||
function tryBindPort(server, port, host = '0.0.0.0') {
|
||||
return new Promise((resolve, reject) => {
|
||||
const onError = (err) => {
|
||||
server.removeListener('listening', onSuccess);
|
||||
@@ -155,7 +156,7 @@ function tryBindPort(server, port) {
|
||||
};
|
||||
server.once('error', onError);
|
||||
server.once('listening', onSuccess);
|
||||
server.listen(port);
|
||||
server.listen(port, host);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -173,6 +174,7 @@ export function startCallbackServer(expectedState, timeoutMs = 120000) {
|
||||
let timeoutId = null;
|
||||
let isAborted = false;
|
||||
let actualPort = OAUTH_CONFIG.callbackPort;
|
||||
const host = process.env.HOST || '0.0.0.0';
|
||||
|
||||
const promise = new Promise(async (resolve, reject) => {
|
||||
// Build list of ports to try: primary + fallbacks
|
||||
@@ -180,7 +182,7 @@ export function startCallbackServer(expectedState, timeoutMs = 120000) {
|
||||
const errors = [];
|
||||
|
||||
server = http.createServer((req, res) => {
|
||||
const url = new URL(req.url, `http://localhost:${actualPort}`);
|
||||
const url = new URL(req.url, `http://${host === '0.0.0.0' ? 'localhost' : host}:${actualPort}`);
|
||||
|
||||
if (url.pathname !== '/oauth-callback') {
|
||||
res.writeHead(404);
|
||||
@@ -264,14 +266,14 @@ export function startCallbackServer(expectedState, timeoutMs = 120000) {
|
||||
let boundSuccessfully = false;
|
||||
for (const port of portsToTry) {
|
||||
try {
|
||||
await tryBindPort(server, port);
|
||||
await tryBindPort(server, port, host);
|
||||
actualPort = port;
|
||||
boundSuccessfully = true;
|
||||
|
||||
if (port !== OAUTH_CONFIG.callbackPort) {
|
||||
logger.warn(`[OAuth] Primary port ${OAUTH_CONFIG.callbackPort} unavailable, using fallback port ${port}`);
|
||||
} else {
|
||||
logger.info(`[OAuth] Callback server listening on port ${port}`);
|
||||
logger.info(`[OAuth] Callback server listening on ${host}:${port}`);
|
||||
}
|
||||
break;
|
||||
} catch (err) {
|
||||
|
||||
20
src/index.js
20
src/index.js
@@ -8,9 +8,12 @@ import { DEFAULT_PORT } from './constants.js';
|
||||
import { logger } from './utils/logger.js';
|
||||
import { config } from './config.js';
|
||||
import { getStrategyLabel, STRATEGY_NAMES, DEFAULT_STRATEGY } from './account-manager/strategies/index.js';
|
||||
import { getPackageVersion } from './utils/helpers.js';
|
||||
import path from 'path';
|
||||
import os from 'os';
|
||||
|
||||
const packageVersion = getPackageVersion();
|
||||
|
||||
// Parse command line arguments
|
||||
const args = process.argv.slice(2);
|
||||
const isDebug = args.includes('--debug') || process.env.DEBUG === 'true';
|
||||
@@ -46,12 +49,22 @@ if (isFallbackEnabled) {
|
||||
export const FALLBACK_ENABLED = isFallbackEnabled;
|
||||
|
||||
const PORT = process.env.PORT || DEFAULT_PORT;
|
||||
const HOST = process.env.HOST || '0.0.0.0';
|
||||
|
||||
if (process.env.HOST) {
|
||||
logger.info(`[Startup] Using HOST environment variable: ${process.env.HOST}`);
|
||||
}
|
||||
|
||||
// Home directory for account storage
|
||||
const HOME_DIR = os.homedir();
|
||||
const CONFIG_DIR = path.join(HOME_DIR, '.antigravity-claude-proxy');
|
||||
|
||||
const server = app.listen(PORT, () => {
|
||||
const server = app.listen(PORT, HOST, () => {
|
||||
// Get actual bound address
|
||||
const address = server.address();
|
||||
const boundHost = typeof address === 'string' ? address : address.address;
|
||||
const boundPort = typeof address === 'string' ? null : address.port;
|
||||
|
||||
// Clear console for a clean start
|
||||
console.clear();
|
||||
|
||||
@@ -90,10 +103,11 @@ const server = app.listen(PORT, () => {
|
||||
|
||||
logger.log(`
|
||||
╔══════════════════════════════════════════════════════════════╗
|
||||
║ Antigravity Claude Proxy Server ║
|
||||
║ Antigravity Claude Proxy Server v${packageVersion} ║
|
||||
╠══════════════════════════════════════════════════════════════╣
|
||||
║ ║
|
||||
${border} ${align(`Server and WebUI running at: http://localhost:${PORT}`)}${border}
|
||||
${border} ${align(`Server and WebUI running at: http://${HOST === '0.0.0.0' ? 'localhost' : HOST}:${PORT}`)}${border}
|
||||
${border} ${align(`Bound to: ${boundHost}:${boundPort}`)}${border}
|
||||
${statusSection}║ ║
|
||||
${controlSection}
|
||||
║ ║
|
||||
|
||||
@@ -186,10 +186,10 @@ app.use((req, res, next) => {
|
||||
res.on('finish', () => {
|
||||
const duration = Date.now() - start;
|
||||
const status = res.statusCode;
|
||||
const logMsg = `[${req.method}] ${req.path} ${status} (${duration}ms)`;
|
||||
const logMsg = `[${req.method}] ${req.originalUrl} ${status} (${duration}ms)`;
|
||||
|
||||
// Skip standard logging for event logging batch unless in debug mode
|
||||
if (req.path === '/api/event_logging/batch' || req.path === '/v1/messages/count_tokens') {
|
||||
if (req.originalUrl === '/api/event_logging/batch' || req.originalUrl === '/v1/messages/count_tokens' || req.originalUrl.startsWith('/.well-known/')) {
|
||||
if (logger.isDebugEnabled) {
|
||||
logger.debug(logMsg);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,30 @@
|
||||
import { readFileSync } from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
import path from 'path';
|
||||
|
||||
/**
|
||||
* Shared Utility Functions
|
||||
*
|
||||
* General-purpose helper functions used across multiple modules.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the package version from package.json
|
||||
* @param {string} [defaultVersion='1.0.0'] - Default version if package.json cannot be read
|
||||
* @returns {string} The package version
|
||||
*/
|
||||
export function getPackageVersion(defaultVersion = '1.0.0') {
|
||||
try {
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const packageJsonPath = path.join(__dirname, '../../package.json');
|
||||
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
||||
return packageJson.version || defaultVersion;
|
||||
} catch {
|
||||
return defaultVersion;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format duration in milliseconds to human-readable string
|
||||
* @param {number} ms - Duration in milliseconds
|
||||
|
||||
@@ -13,8 +13,6 @@
|
||||
*/
|
||||
|
||||
import path from 'path';
|
||||
import { readFileSync } from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
import express from 'express';
|
||||
import { getPublicConfig, saveConfig, config } from '../config.js';
|
||||
import { DEFAULT_PORT, ACCOUNT_CONFIG_PATH, MAX_ACCOUNTS, DEFAULT_PRESETS } from '../constants.js';
|
||||
@@ -22,18 +20,10 @@ import { readClaudeConfig, updateClaudeConfig, replaceClaudeConfig, getClaudeCon
|
||||
import { logger } from '../utils/logger.js';
|
||||
import { getAuthorizationUrl, completeOAuthFlow, startCallbackServer } from '../auth/oauth.js';
|
||||
import { loadAccounts, saveAccounts } from '../account-manager/storage.js';
|
||||
import { getPackageVersion } from '../utils/helpers.js';
|
||||
|
||||
// Get package version
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
let packageVersion = '1.0.0';
|
||||
try {
|
||||
const packageJsonPath = path.join(__dirname, '../../package.json');
|
||||
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
||||
packageVersion = packageJson.version;
|
||||
} catch (error) {
|
||||
logger.warn('[WebUI] Could not read package.json version, using default');
|
||||
}
|
||||
const packageVersion = getPackageVersion();
|
||||
|
||||
// OAuth state storage (state -> { server, verifier, state, timestamp })
|
||||
// Maps state ID to active OAuth flow data
|
||||
|
||||
Reference in New Issue
Block a user