154 lines
6.0 KiB
Bash
154 lines
6.0 KiB
Bash
#!/bin/sh
|
|||
|
|
# Substitute the app port in supervisord template and start supervisord.
|
||
|
|
# Default port 8088; override at runtime with -e MASKANX_PORT=3000.
|
||
|
|
set -e
|
||
|
|
export ADCLAW_PORT="${MASKANX_PORT:-${ADCLAW_PORT:-8088}}"
|
||
|
|
export ADCLAW_WORKING_DIR="${MASKANX_WORKING_DIR:-${ADCLAW_WORKING_DIR:-/app/working}}"
|
||
|
|
export ADCLAW_SECRET_DIR="${MASKANX_SECRET_DIR:-${ADCLAW_SECRET_DIR:-/app/working.secret}}"
|
||
|
|
export ADCLAW_ENABLED_CHANNELS="${MASKANX_ENABLED_CHANNELS:-${ADCLAW_ENABLED_CHANNELS:-discord,dingtalk,feishu,qq,console,telegram}}"
|
||
|
|
export ADCLAW_STORAGE_BACKEND="${MASKANX_STORAGE_BACKEND:-${ADCLAW_STORAGE_BACKEND:-json}}"
|
||
|
|
|
||
|
|
# Ensure config.json exists (first run only  don't overwrite user config)
|
||
|
|
CONFIG="${ADCLAW_WORKING_DIR}/config.json"
|
||
|
|
if [ ! -f "$CONFIG" ] || [ ! -s "$CONFIG" ]; then
|
||
|
|
echo "entrypoint: No config.json found, generating default..."
|
||
|
|
maskanx init --defaults --accept-security 2>/dev/null || true
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Migrate config.json  apply new defaults to existing config without overwriting user data
|
||
|
|
python3 -c "
|
||
|
|
import json, os, sys
|
||
|
|
cfg_path = os.environ.get('ADCLAW_WORKING_DIR', '/app/working') + '/config.json'
|
||
|
|
if not os.path.isfile(cfg_path):
|
||
|
|
sys.exit(0)
|
||
|
|
with open(cfg_path) as f:
|
||
|
|
cfg = json.load(f)
|
||
|
|
changed = False
|
||
|
|
# Force correct defaults that should never be True in production
|
||
|
|
if cfg.get('show_tool_details') is not False:
|
||
|
|
cfg['show_tool_details'] = False
|
||
|
|
changed = True
|
||
|
|
# Ensure filter_tool_messages=True on all channels
|
||
|
|
for ch_name, ch_cfg in cfg.get('channels', {}).items():
|
||
|
|
if isinstance(ch_cfg, dict) and ch_cfg.get('filter_tool_messages') is not True:
|
||
|
|
ch_cfg['filter_tool_messages'] = True
|
||
|
|
changed = True
|
||
|
|
if changed:
|
||
|
|
with open(cfg_path, 'w') as f:
|
||
|
|
json.dump(cfg, f, indent=2, ensure_ascii=False)
|
||
|
|
print('entrypoint: config.json migrated (applied new defaults)')
|
||
|
|
else:
|
||
|
|
print('entrypoint: config.json OK (no migration needed)')
|
||
|
|
" 2>/dev/null || true
|
||
|
|
|
||
|
|
# Enable Citedy MCP client if API key is provided at runtime
|
||
|
|
if [ -n "$CITEDY_API_KEY" ]; then
|
||
|
|
CONFIG="${ADCLAW_WORKING_DIR}/config.json"
|
||
|
|
if [ -f "$CONFIG" ]; then
|
||
|
|
python3 -c "
|
||
|
|
import json, os
|
||
|
|
cfg_path = os.environ.get('ADCLAW_WORKING_DIR', '/app/working') + '/config.json'
|
||
|
|
with open(cfg_path) as f:
|
||
|
|
cfg = json.load(f)
|
||
|
|
mcp = cfg.setdefault('mcp', {}).setdefault('clients', {})
|
||
|
|
key = os.environ['CITEDY_API_KEY']
|
||
|
|
mcp['citedy'] = {
|
||
|
|
'name': 'citedy_mcp',
|
||
|
|
'description': 'Citedy SEO & Marketing Tools (70+ tools)',
|
||
|
|
'enabled': True,
|
||
|
|
'transport': 'streamable_http',
|
||
|
|
'url': 'https://mcp.citedy.com/mcp',
|
||
|
|
'headers': {'Authorization': f'Bearer {key}', 'Accept': 'application/json, text/event-stream'},
|
||
|
|
'env': {'CITEDY_API_KEY': key},
|
||
|
|
}
|
||
|
|
with open(cfg_path, 'w') as f:
|
||
|
|
json.dump(cfg, f, indent=2)
|
||
|
|
print('entrypoint: Citedy MCP client enabled')
|
||
|
|
" 2>/dev/null || true
|
||
|
|
fi
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Enable Exa search MCP if API key is provided at runtime
|
||
|
|
if [ -n "$EXA_API_KEY" ]; then
|
||
|
|
CONFIG="${ADCLAW_WORKING_DIR}/config.json"
|
||
|
|
if [ -f "$CONFIG" ]; then
|
||
|
|
python3 -c "
|
||
|
|
import json, os
|
||
|
|
cfg_path = os.environ.get('ADCLAW_WORKING_DIR', '/app/working') + '/config.json'
|
||
|
|
with open(cfg_path) as f:
|
||
|
|
cfg = json.load(f)
|
||
|
|
mcp = cfg.setdefault('mcp', {}).setdefault('clients', {})
|
||
|
|
key = os.environ['EXA_API_KEY']
|
||
|
|
mcp['exa'] = {
|
||
|
|
'name': 'exa_mcp',
|
||
|
|
'description': 'Exa AI search: web, code, people, companies',
|
||
|
|
'enabled': True,
|
||
|
|
'command': 'npx',
|
||
|
|
'args': ['-y', 'exa-mcp-server'],
|
||
|
|
'env': {'EXA_API_KEY': key},
|
||
|
|
}
|
||
|
|
with open(cfg_path, 'w') as f:
|
||
|
|
json.dump(cfg, f, indent=2)
|
||
|
|
print('entrypoint: Exa MCP client enabled')
|
||
|
|
" 2>/dev/null || true
|
||
|
|
fi
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Enable Telegram channel if bot token is provided at runtime
|
||
|
|
if [ -n "$TELEGRAM_BOT_TOKEN" ]; then
|
||
|
|
CONFIG="${ADCLAW_WORKING_DIR}/config.json"
|
||
|
|
if [ -f "$CONFIG" ]; then
|
||
|
|
python3 -c "
|
||
|
|
import json, os
|
||
|
|
cfg_path = os.environ.get('ADCLAW_WORKING_DIR', '/app/working') + '/config.json'
|
||
|
|
with open(cfg_path) as f:
|
||
|
|
cfg = json.load(f)
|
||
|
|
tg = cfg.setdefault('channels', {}).setdefault('telegram', {})
|
||
|
|
tg['enabled'] = True
|
||
|
|
tg['bot_token'] = os.environ['TELEGRAM_BOT_TOKEN']
|
||
|
|
with open(cfg_path, 'w') as f:
|
||
|
|
json.dump(cfg, f, indent=2)
|
||
|
|
print('entrypoint: Telegram channel enabled')
|
||
|
|
" 2>/dev/null || true
|
||
|
|
fi
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Sync new built-in skills to active_skills (non-destructive: skip existing)
|
||
|
|
python3 -c "
|
||
|
|
from adclaw.agents.skills_manager import sync_skills_to_working_dir
|
||
|
|
synced, skipped = sync_skills_to_working_dir(skill_names=None, force=False)
|
||
|
|
if synced:
|
||
|
|
print(f'entrypoint: synced {synced} new skill(s) to active_skills')
|
||
|
|
else:
|
||
|
|
print(f'entrypoint: all skills up to date ({skipped} existing)')
|
||
|
|
" 2>/dev/null || true
|
||
|
|
|
||
|
|
# Ensure working dirs are owned by MaskanX user (entrypoint runs as root)
|
||
|
|
mkdir -p /app/logs 2>/dev/null || true
|
||
|
|
chown -R maskanx:maskanx "${ADCLAW_WORKING_DIR}" "${ADCLAW_SECRET_DIR}" /app/logs 2>/dev/null || true
|
||
|
|
|
||
|
|
# Run Postgres migrations when requested. Keep JSON/file mode as the default so
|
||
|
|
# local users can still start the app without a database.
|
||
|
|
case "$(printf '%s' "$ADCLAW_STORAGE_BACKEND" | tr '[:upper:]' '[:lower:]')" in
|
||
|
|
postgres|postgresql|pg)
|
||
|
|
echo "entrypoint: PostgreSQL storage enabled, running migrations..."
|
||
|
|
maskanx db migrate
|
||
|
|
;;
|
||
|
|
esac
|
||
|
|
|
||
|
|
# Generate supervisord.conf from templates based on MASKANX_VARIANT.
|
||
|
|
# core → base template only (supervisord + app).
|
||
|
|
# browser/full → base + browser template (adds dbus, xvfb, xfce4, pinchtab).
|
||
|
|
MASKANX_VARIANT="${MASKANX_VARIANT:-${ADCLAW_VARIANT:-full}}"
|
||
|
|
SUPERVISORD_CONF="/etc/supervisor/conf.d/supervisord.conf"
|
||
|
|
envsubst '${ADCLAW_PORT}' \
|
||
|
|
< /etc/supervisor/conf.d/supervisord.conf.template \
|
||
|
|
> "$SUPERVISORD_CONF"
|
||
|
|
if [ "$MASKANX_VARIANT" != "core" ] && [ -f /etc/supervisor/conf.d/supervisord.browser.conf.template ]; then
|
||
|
|
cat /etc/supervisor/conf.d/supervisord.browser.conf.template >> "$SUPERVISORD_CONF"
|
||
|
|
echo "entrypoint: supervisord configured with browser programs (variant=${MASKANX_VARIANT})"
|
||
|
|
else
|
||
|
|
echo "entrypoint: supervisord configured without browser (variant=${MASKANX_VARIANT})"
|
||
|
|
fi
|
||
|
|
exec /usr/bin/supervisord -c "$SUPERVISORD_CONF"
|