// offending code· 3 files flaggedpatterns: 2
--- package/lib/config.js (excerpt) ---
import Conf from 'conf';
import axios from 'axios';
const config = new Conf({
projectName: 'openclaw-cli',
// Allow overriding config path for testing/sandbox environments
cwd: process.env.OPENCLAW_CONFIG_DIR
});
const DEBUG = process.env.DEBUG === '1' || process.env.OPENCLAW_DEBUG === '1';
if (DEBUG) {
console.error(`[Config] Path: ${config.path}`);
}
export const getApiUrl = () => {
return process.env.OPENCLAW_API_URL || config.get('api_url') || 'https://backend.clawd.org.cn/api';
};
export const getToken = () => {
return config.get('token');
};
export const setToken = (token) => {
config.set('token', token);
};
export const clearToken = () => {
config.delete('token');
};
export const getClient = () => {
const token = getToken();
if (DEBUG) {
console.error(`[Config] Using Token: ${token ? token.slice(0, 5) + '...' : 'NONE'}`);
console.error(`[Config] API URL: ${getApiUrl()}`);
}
// 默认禁用系统代理(axios 会自动读取 HTTP_PROXY/HTTPS_PROXY 环境变量,
// agent 环境通常将代理指向境外,会导致访问国内后端超时或失败)。
// 如有特殊需求,可设置环境变量 OPENCLAW_USE_PROXY=1 来恢复代理。
const useProxy = process.env.OPENCLAW_USE_PROXY === '1';
return axios.create({
baseURL: getApiUrl(),
timeout: 60000, // 60s timeout(原 30s,适当放宽以兼容慢速网络)
maxBodyLength: 5 * 1024 * 1024, // 5MB max request body
proxy: useProxy ? undefined : false, // false = 忽略系统代理环境变量
headers: token ? { Authorization: `Bearer ${token}` } : {}
});
};
export const formatError = (err) => {
if (err.response
--- package/lib/commands/admin.js (excerpt) ---
import chalk from 'chalk';
import ora from 'ora';
import { getClient, formatError } from '../config.js';
export default function(program) {
const admin = program.command('admin').description('Administrative commands');
admin
.command('verify <user_id>')
.description('Set verification status for a user')
.option('-t, --type <type>', 'Verification type (official | expert | none) (Required)')
.option('-r, --reason <reason>', 'Verification reason (Required if type is not none)')
.action(async (user_id, options) => {
if (!options.type) {
console.error(chalk.red('Error: Verification type is required.'));
console.error('Usage: claw admin verify <user_id> --type <official|expert|none> [--reason <reason>]');
process.exit(1);
}
const type = options.type === 'none' ? null : options.type;
const reason = options.reason;
if (type && !reason) {
console.error(chalk.red('Error: Verification reason is required for type ' + type));
process.exit(1);
}
const spinner = ora(`Updating verification for ${user_id}...`).start();
try {
const client = getClient();
await client.post(`/admin/users/${user_id}/verify`, { type, reason });
spinner.succeed(chalk.green('Verification updated successfully!'));
} catch (err) {
spinner.fail(chalk.red(formatError(err)));
}
});
--- package/lib/commands/skill.js (excerpt) ---
import fs from 'fs';
import path from 'path';
import matter from 'gray-matter';
import chalk from 'chalk';
import ora from 'ora';
import ignore from 'ignore';
import { getClient, formatError } from '../config.js';
import os from 'os';
// 内置排除规则(始终排除)
const BUILTIN_IGNORE_RULES = [
'.git',
'.DS_Store',
'node_modules',
'__pycache__',
'.venv',
'*.pyc',
'*.pyo',
'.env',
'.env.*',
'!.env.example',
'*.lock',
];
async function installSkill(client, skillId) {
// 1. Get Metadata (use /package endpoint which auto-counts installs)
const res = await client.get(`/skills/${encodeURIComponent(skillId)}/package`);
const skill = res.data;
// 2. Determine Install Path
const baseDir = process.env.OPENCLAW_INSTALL_DIR ||
(process.env.OPENCLAW_HOME ? path.join(process.env.OPENCLAW_HOME, '.openclaw') : path.join(os.homedir(), '.openclaw'));
// Use unique folder name: owner__name
const folderName = skill.id.replace('/', '__');
const installDir = path.join(baseDir, 'skills', folderName);
if (fs.existsSync(installDir)) {
fs.rmSync(installDir, { recursive: true });
}
fs.mkdirSync(installDir, { recursive: true });
// 2.5 Restore Files
if (skill.files) {
let filesMap = {};
try {
filesMap = typeof skill.files === 'string' ? JSON.parse(skill.files) : skill.files;
} catch (e) {}
for (const [relPath, content] of Object.entries