feat: 开源发布 — 完整 README、MIT 许可证、22+ 大模型厂商支持

- 重写 README.md:项目简介、快速开始、22+ 厂商列表、功能特性、架构说明、配置指南、FAQ、贡献指南
- 新增 MIT LICENSE
- 包含全部源码与文档
This commit is contained in:
weiqianpu
2026-04-02 02:34:24 +00:00
parent 5d0bc60cce
commit cf1707bbb0
2890 changed files with 1904 additions and 771 deletions
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
View File
Regular → Executable
View File
Regular → Executable
View File
View File
Regular → Executable
View File
View File
View File
Regular → Executable
View File
Regular → Executable
View File
View File
View File
View File
View File
View File
View File
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
+1 -1
View File
@@ -166,7 +166,7 @@ export function checkBridgeMinVersion(): string | null {
minVersion: string
}>('tengu_bridge_min_version', { minVersion: '0.0.0' })
if (config.minVersion && lt(MACRO.VERSION, config.minVersion)) {
return `Your version of Claude Code (${MACRO.VERSION}) is too old for Remote Control.\nVersion ${config.minVersion} or higher is required. Run \`claude update\` to update.`
return `Your version of 嘉陵江-code (${MACRO.VERSION}) is too old for Remote Control.\nVersion ${config.minVersion} or higher is required. Run \`jialing update\` to update.`
}
}
return null
Regular → Executable
View File
Regular → Executable
View File
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
+1 -1
View File
@@ -147,7 +147,7 @@ export async function getEnvLessBridgeConfig(): Promise<EnvLessBridgeConfig> {
export async function checkEnvLessBridgeMinVersion(): Promise<string | null> {
const cfg = await getEnvLessBridgeConfig()
if (cfg.min_version && lt(MACRO.VERSION, cfg.min_version)) {
return `Your version of Claude Code (${MACRO.VERSION}) is too old for Remote Control.\nVersion ${cfg.min_version} or higher is required. Run \`claude update\` to update.`
return `Your version of 嘉陵江-code (${MACRO.VERSION}) is too old for Remote Control.\nVersion ${cfg.min_version} or higher is required. Run \`jialing update\` to update.`
}
return null
}
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
View File
Regular → Executable
View File
Regular → Executable
View File
View File
Regular → Executable
+1 -1
View File
@@ -147,7 +147,7 @@ export async function enrollTrustedDevice(): Promise<void> {
device_id?: string
}>(
`${baseUrl}/api/auth/trusted_devices`,
{ display_name: `Claude Code on ${hostname()} · ${process.platform}` },
{ display_name: `嘉陵江-code on ${hostname()} · ${process.platform}` },
{
headers: {
Authorization: `Bearer ${accessToken}`,
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
+3 -3
View File
@@ -165,7 +165,7 @@ function spriteColWidth(nameWidth: number): number {
// Narrow terminals: 0 — REPL.tsx stacks the one-liner on its own row
// (above input in fullscreen, below in scrollback), so no reservation.
export function companionReservedColumns(terminalColumns: number, speaking: boolean): number {
if (!feature('BUDDY')) return 0;
if (!true) return 0;
const companion = getCompanion();
if (!companion || getGlobalConfig().companionMuted) return 0;
if (terminalColumns < MIN_COLS_FOR_FULL_SPRITE) return 0;
@@ -212,7 +212,7 @@ export function CompanionSprite(): React.ReactNode {
return () => clearTimeout(timer);
// eslint-disable-next-line react-hooks/exhaustive-deps -- tick intentionally captured at reaction-change, not tracked
}, [reaction, setAppState]);
if (!feature('BUDDY')) return null;
if (!true) return null;
const companion = getCompanion();
if (!companion || getGlobalConfig().companionMuted) return null;
const color = RARITY_COLORS[companion.rarity];
@@ -337,7 +337,7 @@ export function CompanionFloatingBubble() {
t3 = $[4];
}
useEffect(t2, t3);
if (!feature("BUDDY") || !reaction) {
if (!true || !reaction) {
return null;
}
const companion = getCompanion();
Regular → Executable
+49 -2
View File
@@ -1,4 +1,7 @@
import { getGlobalConfig } from '../utils/config.js'
import { existsSync, readFileSync } from 'fs'
import { join } from 'path'
import { homedir } from 'os'
import { getGlobalConfig, saveGlobalConfig } from '../utils/config.js'
import {
type Companion,
type CompanionBones,
@@ -8,6 +11,7 @@ import {
RARITY_WEIGHTS,
type Rarity,
SPECIES,
type Species,
STAT_NAMES,
type StatName,
} from './types.js'
@@ -121,13 +125,56 @@ export function companionUserId(): string {
return config.oauthAccount?.accountUuid ?? config.userID ?? 'anon'
}
// ── Jialing config fallback ─────────────────────────────────────────────────
// Read companion from ~/.jialing-code/config.json as a fallback when the
// global claude config doesn't have it (setup wizard writes there first).
let jialingCompanionMigrated = false
function tryMigrateJialingCompanion(): void {
if (jialingCompanionMigrated) return
jialingCompanionMigrated = true
try {
const jialingConfigPath = join(homedir(), '.jialing-code', 'config.json')
if (!existsSync(jialingConfigPath)) return
const jialingConfig = JSON.parse(readFileSync(jialingConfigPath, 'utf-8'))
if (!jialingConfig.companion) return
// Check if global config already has companion
const globalConfig = getGlobalConfig()
if (globalConfig.companion) return
// Migrate companion from jialing config to global config
saveGlobalConfig(current => ({
...current,
companion: {
name: jialingConfig.companion.name || 'Buddy',
personality: jialingConfig.companion.personality || '',
hatchedAt: jialingConfig.companion.hatchedAt || Date.now(),
},
companionSpeciesOverride: jialingConfig.companion.species,
}))
} catch {
// Silent — best effort migration
}
}
// Regenerate bones from userId, merge with stored soul. Bones never persist
// so species renames and SPECIES-array edits can't break stored companions,
// and editing config.companion can't fake a rarity.
export function getCompanion(): Companion | undefined {
const stored = getGlobalConfig().companion
// Try migrating companion from jialing config if not in global config
tryMigrateJialingCompanion()
const config = getGlobalConfig()
const stored = config.companion
if (!stored) return undefined
const { bones } = roll(companionUserId())
// Allow user-chosen species override from setup wizard
const speciesOverride = (config as any).companionSpeciesOverride
if (speciesOverride && SPECIES.includes(speciesOverride as Species)) {
bones.species = speciesOverride as Species
}
// bones last so stale bones fields in old-format configs get overridden
return { ...stored, ...bones }
}
Regular → Executable
+1 -1
View File
@@ -15,7 +15,7 @@ When the user addresses ${name} directly (by name), its bubble will answer. Your
export function getCompanionIntroAttachment(
messages: Message[] | undefined,
): Attachment[] {
if (!feature('BUDDY')) return []
if (!true) return []
const companion = getCompanion()
if (!companion || getGlobalConfig().companionMuted) return []
Regular → Executable
View File
Regular → Executable
View File
+2 -2
View File
@@ -50,7 +50,7 @@ export function useBuddyNotification() {
let t1;
if ($[0] !== addNotification || $[1] !== removeNotification) {
t0 = () => {
if (!feature("BUDDY")) {
if (!true) {
return;
}
const config = getGlobalConfig();
@@ -80,7 +80,7 @@ export function findBuddyTriggerPositions(text: string): Array<{
start: number;
end: number;
}> {
if (!feature('BUDDY')) return [];
if (!true) return [];
const triggers: Array<{
start: number;
end: number;
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
Regular → Executable
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File

Some files were not shown because too many files have changed in this diff Show More