feat: PNG头像替换SVG + 支持/init命令
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
{ cmd: '/mode', desc: '查看/切换权限模式' },
|
||||
{ cmd: '/cost', desc: '查看会话费用' },
|
||||
{ cmd: '/compact', desc: '压缩上下文' },
|
||||
{ cmd: '/init', desc: '生成/更新 CLAUDE.md' },
|
||||
{ cmd: '/help', desc: '显示帮助' },
|
||||
];
|
||||
|
||||
|
||||
BIN
public/claude.png
Normal file
BIN
public/claude.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
BIN
public/codex.png
Normal file
BIN
public/codex.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
@@ -1021,10 +1021,10 @@ body.session-loading-active {
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
/* Codex avatar: GPT logo on green bg */
|
||||
/* Codex avatar: transparent bg to match the supplied asset */
|
||||
.msg.assistant.agent-codex .msg-avatar {
|
||||
background: #10a37f;
|
||||
color: #fff;
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.msg-bubble {
|
||||
|
||||
37
server.js
37
server.js
@@ -437,27 +437,27 @@ const activeTokens = new Set();
|
||||
const AUTH_FAIL_WINDOW = 5 * 60 * 1000; // 5 minutes
|
||||
const AUTH_FAIL_MAX = 3;
|
||||
const authFailures = new Map(); // ip -> [timestamp, ...]
|
||||
let bannedIPs = new Set();
|
||||
let bannedIPs = new Set();
|
||||
|
||||
// Tailscale / loopback whitelist — never ban these IPs.
|
||||
// Extra whitelist can be provided via env var (comma/space separated):
|
||||
// CC_WEB_IP_WHITELIST="<ip1>,<ip2>"
|
||||
const EXTRA_WHITELIST_IPS = new Set(
|
||||
// Tailscale / loopback whitelist — never ban these IPs.
|
||||
// Extra whitelist can be provided via env var (comma/space separated):
|
||||
// CC_WEB_IP_WHITELIST="<ip1>,<ip2>"
|
||||
const EXTRA_WHITELIST_IPS = new Set(
|
||||
String(process.env.CC_WEB_IP_WHITELIST || '')
|
||||
.split(/[\s,]+/)
|
||||
.map(s => s.trim())
|
||||
.filter(Boolean)
|
||||
.map(s => s.replace(/^::ffff:/, ''))
|
||||
);
|
||||
);
|
||||
|
||||
function isWhitelistedIP(ip) {
|
||||
function isWhitelistedIP(ip) {
|
||||
if (!ip) return false;
|
||||
const cleaned = ip.replace(/^::ffff:/, '');
|
||||
return cleaned === '127.0.0.1'
|
||||
|| cleaned === '::1'
|
||||
|| cleaned.startsWith('100.')
|
||||
|| EXTRA_WHITELIST_IPS.has(cleaned);
|
||||
}
|
||||
}
|
||||
|
||||
function loadBannedIPs() {
|
||||
try {
|
||||
@@ -2055,6 +2055,25 @@ function handleSlashCommand(ws, text, sessionId, fallbackAgent) {
|
||||
break;
|
||||
}
|
||||
|
||||
case '/init': {
|
||||
if (agent !== 'claude') {
|
||||
wsSend(ws, { type: 'system_message', message: '/init 仅支持 Claude,Codex 暂不支持该命令。' });
|
||||
break;
|
||||
}
|
||||
if (!sessionId || !session) {
|
||||
wsSend(ws, { type: 'system_message', message: '请先进入一个会话后再执行 /init。' });
|
||||
break;
|
||||
}
|
||||
if (activeProcesses.has(sessionId)) {
|
||||
wsSend(ws, { type: 'system_message', message: '当前会话正在处理中,请先等待完成或点击停止。' });
|
||||
break;
|
||||
}
|
||||
wsSend(ws, { type: 'system_message', message: '正在分析项目并生成 CLAUDE.md ...' });
|
||||
pendingSlashCommands.set(session.id, { kind: 'init' });
|
||||
handleMessage(ws, { text: '/init', sessionId: session.id, mode: session.permissionMode || 'yolo' }, { hideInHistory: true });
|
||||
break;
|
||||
}
|
||||
|
||||
case '/mode': {
|
||||
const modeInput = parts[1];
|
||||
const VALID_MODES = ['default', 'plan', 'yolo'];
|
||||
@@ -2088,7 +2107,7 @@ function handleSlashCommand(ws, text, sessionId, fallbackAgent) {
|
||||
type: 'system_message',
|
||||
message: agent === 'codex'
|
||||
? base + '\n/model [名称] — 查看/切换 Codex 模型(自由输入)\n/compact — 执行 Codex /compact 压缩上下文'
|
||||
: base + '\n/model [名称] — 查看/切换模型(opus, sonnet, haiku)\n/compact — 执行 Claude 原生上下文压缩(保留压缩计划并可自动续跑)',
|
||||
: base + '\n/model [名称] — 查看/切换模型(opus, sonnet, haiku)\n/compact — 执行 Claude 原生上下文压缩(保留压缩计划并可自动续跑)\n/init — 分析项目并生成/更新 CLAUDE.md',
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user