cc-haha/adapters/common/__tests__/config.test.ts
程序员阿江(Relakkes) a627bb19f2 feat: support WeChat as a first-class IM channel
WeChat needs a QR-paired path instead of bot-token setup, so the adapter layer now includes the iLink protocol calls, desktop pairing UI, server-side bind/unbind APIs, and shared IM command behavior. Empty project history falls back to the user's default work directory so mobile /new works without pre-opening a desktop project.

Constraint: Tencent iLink login returns a URL that the desktop UI must render as a QR image locally
Constraint: IM adapters should keep /new, /projects, status, permission, and default workdir behavior consistent across WeChat, Feishu, and Telegram
Rejected: Require users to paste absolute project paths for first WeChat sessions | mobile onboarding should work from the default user working directory
Confidence: high
Scope-risk: moderate
Directive: Do not change WeChat polling back to overlapping intervals; getupdates is a long-poll endpoint and must remain serialized
Tested: Real WeChat QR scan, inbound /status, outbound reply, and unbind E2E
Tested: bun run check:adapters
Tested: bun run quality:pr
Not-tested: Re-scan live WeChat after the default-workdir fallback tweak; covered by adapter config tests and PR gate
2026-05-03 17:38:08 +08:00

69 lines
2.6 KiB
TypeScript

import { afterEach, describe, expect, it } from 'bun:test'
import * as fs from 'node:fs'
import * as os from 'node:os'
import * as path from 'node:path'
import { getConfiguredWorkDir, loadConfig } from '../config.js'
describe('adapter config defaults', () => {
const originalConfigDir = process.env.CLAUDE_CONFIG_DIR
const originalAdapterDefaultWorkDir = process.env.CLAUDE_ADAPTER_DEFAULT_WORK_DIR
const originalPwd = process.env.PWD
afterEach(() => {
restoreEnv('CLAUDE_CONFIG_DIR', originalConfigDir)
restoreEnv('CLAUDE_ADAPTER_DEFAULT_WORK_DIR', originalAdapterDefaultWorkDir)
restoreEnv('PWD', originalPwd)
})
it('uses the user shell working directory when no default project is configured', () => {
const configDir = fs.mkdtempSync(path.join(os.tmpdir(), 'adapter-config-'))
const workDir = fs.mkdtempSync(path.join(os.tmpdir(), 'adapter-workdir-'))
try {
process.env.CLAUDE_CONFIG_DIR = configDir
delete process.env.CLAUDE_ADAPTER_DEFAULT_WORK_DIR
process.env.PWD = workDir
const config = loadConfig()
expect(config.telegram.defaultWorkDir).toBe(fs.realpathSync(workDir))
expect(config.feishu.defaultWorkDir).toBe(fs.realpathSync(workDir))
expect(config.wechat.defaultWorkDir).toBe(fs.realpathSync(workDir))
expect(getConfiguredWorkDir(config, config.wechat)).toBe(fs.realpathSync(workDir))
} finally {
fs.rmSync(configDir, { recursive: true, force: true })
fs.rmSync(workDir, { recursive: true, force: true })
}
})
it('keeps the explicit default project ahead of the platform default work dir', () => {
const configDir = fs.mkdtempSync(path.join(os.tmpdir(), 'adapter-config-'))
const defaultProjectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'adapter-project-'))
const workDir = fs.mkdtempSync(path.join(os.tmpdir(), 'adapter-workdir-'))
try {
fs.writeFileSync(
path.join(configDir, 'adapters.json'),
JSON.stringify({ defaultProjectDir }),
)
process.env.CLAUDE_CONFIG_DIR = configDir
process.env.CLAUDE_ADAPTER_DEFAULT_WORK_DIR = workDir
const config = loadConfig()
expect(getConfiguredWorkDir(config, config.wechat)).toBe(defaultProjectDir)
expect(config.wechat.defaultWorkDir).toBe(fs.realpathSync(workDir))
} finally {
fs.rmSync(configDir, { recursive: true, force: true })
fs.rmSync(defaultProjectDir, { recursive: true, force: true })
fs.rmSync(workDir, { recursive: true, force: true })
}
})
})
function restoreEnv(key: string, value: string | undefined): void {
if (value === undefined) {
delete process.env[key]
} else {
process.env[key] = value
}
}