mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-17 22:05:50 +00:00
- /teleport: 从 claude.ai 恢复会话 - /recap: 生成会话摘要 - /break-cache: 提示缓存管理(once/always/off/status) - /env: 环境信息展示(含密钥脱敏) - /tui: 无闪烁 TUI 模式管理 - /onboarding: 引导流程 - /perf-issue: 性能问题诊断 - /debug-tool-call: 工具调用调试 - /usage: 用量统计(合并 /cost 和 /stats 别名) Co-Authored-By: glm-5-turbo <zai-org@claude-code-best.win>
103 lines
2.7 KiB
TypeScript
103 lines
2.7 KiB
TypeScript
import type { Command, LocalCommandResult } from '../../types/command.js'
|
|
import { getSessionId } from '../../bootstrap/state.js'
|
|
|
|
/**
|
|
* /env — show the user a snapshot of the current environment, claude config,
|
|
* feature flags, and version info. All secrets are masked.
|
|
*
|
|
* Pure-local command: no Anthropic backend dependency. Restored from stub
|
|
* 2026-04-29 (was Anthropic-internal in upstream; safe to expose to fork
|
|
* users since output is local-only).
|
|
*/
|
|
|
|
const SECRET_KEY_PATTERNS = [
|
|
/token/i,
|
|
/secret/i,
|
|
/password/i,
|
|
/api[_-]?key/i,
|
|
/auth/i,
|
|
/private/i,
|
|
/credential/i,
|
|
/jwt/i,
|
|
/session[_-]?id$/i,
|
|
]
|
|
|
|
function isSecretKey(key: string): boolean {
|
|
return SECRET_KEY_PATTERNS.some(rx => rx.test(key))
|
|
}
|
|
|
|
function maskValue(value: string): string {
|
|
if (value.length <= 8) return '***'
|
|
return `${value.slice(0, 4)}…${value.slice(-2)} (${value.length} chars)`
|
|
}
|
|
|
|
const ENV_PREFIX_ALLOWLIST = [
|
|
'CLAUDE_',
|
|
'FEATURE_',
|
|
'ANTHROPIC_',
|
|
'BUN_',
|
|
'NODE_',
|
|
'GEMINI_',
|
|
'OPENAI_',
|
|
'GROK_',
|
|
'CCR_',
|
|
'KAIROS_',
|
|
'BUGHUNTER_',
|
|
]
|
|
|
|
function shouldShowEnv(key: string): boolean {
|
|
return ENV_PREFIX_ALLOWLIST.some(prefix => key.startsWith(prefix))
|
|
}
|
|
|
|
function formatEnvVars(): string {
|
|
const entries = Object.entries(process.env)
|
|
.filter(([k]) => shouldShowEnv(k))
|
|
.map(([k, v]): [string, string] => {
|
|
const display = isSecretKey(k) && v ? maskValue(v) : (v ?? '')
|
|
return [k, display]
|
|
})
|
|
.sort(([a], [b]) => a.localeCompare(b))
|
|
|
|
if (entries.length === 0) {
|
|
return ' (no recognized env vars set)'
|
|
}
|
|
return entries.map(([k, v]) => ` ${k}=${v}`).join('\n')
|
|
}
|
|
|
|
function formatRuntime(): string {
|
|
const lines = [
|
|
` platform: ${process.platform} ${process.arch}`,
|
|
` cwd: ${process.cwd()}`,
|
|
` pid: ${process.pid}`,
|
|
` bun: ${typeof Bun !== 'undefined' ? Bun.version : 'n/a'}`,
|
|
` node: ${process.version}`,
|
|
` session: ${getSessionId()}`,
|
|
]
|
|
return lines.join('\n')
|
|
}
|
|
|
|
const env: Command = {
|
|
type: 'local',
|
|
name: 'env',
|
|
description: 'Show current environment, runtime, and feature flags',
|
|
isHidden: false,
|
|
isEnabled: () => true,
|
|
supportsNonInteractive: true,
|
|
load: async () => ({
|
|
call: async (): Promise<LocalCommandResult> => {
|
|
const text = [
|
|
'## Runtime',
|
|
formatRuntime(),
|
|
'',
|
|
'## Environment Variables (allowlisted prefixes)',
|
|
formatEnvVars(),
|
|
'',
|
|
'_Secrets matching token/password/auth/api_key are masked. Set additional `CLAUDE_*` / `FEATURE_*` env vars to see them here._',
|
|
].join('\n')
|
|
return { type: 'text', value: text }
|
|
},
|
|
}),
|
|
}
|
|
|
|
export default env
|