Skip to content

Commit 7ea91a1

Browse files
feat: 分离 config 系统
1 parent 5ca4957 commit 7ea91a1

354 files changed

Lines changed: 1093 additions & 1155 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

How-to-refact-all-claude-code.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# 架构重构方案
2+
3+
1. 编写调研文档, 输出现有架构
4+
1. 注意模块解耦, 明确系统边界
5+
2. 合理抽象整合新模块, 如果有外部依赖, 我们可以提供抽象接口, 然后实现它
6+
2. 得到一个大而全的架构调整方案
7+
1. 人工审阅
8+
3. 启动 CC 开始将这个大方案切割为 n 个小方向
9+
1. CC 需要并发去编写 /spec/feature-xxx/design.md 文档
10+
2. 并发完成之后, 并发让他们根据 design.md 编写 plan.md 文档. plan.md 文档是代码详细设计, 用于执行代码编写
11+
3. 由于太多的 feature, 我们需要一个 v6/todo.md 文档来编排任务
12+
4. 开始进行按照计划指导 CC 们进行代码编写
13+
4. 人工验证
14+
1. 注意编写完成之后, 需要测试及替换原有代码实现
15+
2. 每一轮执行完成之后, 都会重启 cc 保证自己运行自己, 大部分能力是稳定的

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
"@anthropic-ai/mcpb": "^2.1.2",
6666
"@anthropic-ai/sandbox-runtime": "^0.0.44",
6767
"@anthropic/agent": "workspace:*",
68+
"@anthropic/config": "workspace:*",
6869
"@anthropic-ai/sdk": "^0.80.0",
6970
"@anthropic-ai/vertex-sdk": "^0.14.4",
7071
"@aws-sdk/client-bedrock": "^3.1020.0",

packages/config/feature-flags.ts

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/**
2+
* FeatureFlagProvider — Unified feature flag interface
3+
*
4+
* Provides higher-level feature flag access beyond the basic `feature()`
5+
* builtin. For boolean compile-time feature flags, continue using
6+
* `import { feature } from 'bun:bundle'` directly — `feature()` requires
7+
* string literal arguments and cannot be wrapped dynamically.
8+
*
9+
* This module provides:
10+
* - Typed feature value access (non-boolean, GrowthBook-backed)
11+
* - Refresh lifecycle (subscribe, trigger)
12+
* - Env override inspection
13+
*/
14+
15+
import {
16+
getFeatureValue_CACHED_MAY_BE_STALE,
17+
onGrowthBookRefresh,
18+
refreshGrowthBookFeatures,
19+
hasGrowthBookEnvOverride,
20+
getAllGrowthBookFeatures,
21+
getGrowthBookConfigOverrides,
22+
setGrowthBookConfigOverride,
23+
clearGrowthBookConfigOverrides,
24+
} from '../../src/services/analytics/growthbook.js'
25+
26+
/** Unsubscribe function returned by onRefresh() */
27+
type Unsubscribe = () => void
28+
29+
/**
30+
* FeatureFlagProvider — access GrowthBook feature values and lifecycle.
31+
*
32+
* For boolean feature flags, use `feature('FLAG_NAME')` from `bun:bundle`.
33+
* For typed values (numbers, strings, objects) and refresh management, use this.
34+
*
35+
* Usage:
36+
* import { FeatureFlagProvider } from '@anthropic/config/feature-flags'
37+
*
38+
* const val = FeatureFlagProvider.getValue<number>('MY_CONFIG')
39+
* const unsub = FeatureFlagProvider.onRefresh(() => { ... })
40+
*/
41+
export const FeatureFlagProvider = {
42+
/**
43+
* Get a typed feature value from GrowthBook.
44+
* Returns `undefined` if the feature is not set or not yet loaded.
45+
*
46+
* WARNING: This value may be stale if GrowthBook hasn't refreshed yet.
47+
*/
48+
getValue<T>(name: string): T | undefined {
49+
return getFeatureValue_CACHED_MAY_BE_STALE<T>(name)
50+
},
51+
52+
/**
53+
* Check if a feature has an environment variable override.
54+
*/
55+
hasEnvOverride(name: string): boolean {
56+
return hasGrowthBookEnvOverride(name)
57+
},
58+
59+
/**
60+
* Get all known GrowthBook features and their resolved values.
61+
*/
62+
getAll(): Record<string, unknown> {
63+
return getAllGrowthBookFeatures()
64+
},
65+
66+
/**
67+
* Get local config overrides (ant-only).
68+
*/
69+
getConfigOverrides(): Record<string, unknown> {
70+
return getGrowthBookConfigOverrides()
71+
},
72+
73+
/**
74+
* Set a local config override (ant-only).
75+
*/
76+
setConfigOverride(name: string, value: unknown): void {
77+
setGrowthBookConfigOverride(name, value)
78+
},
79+
80+
/**
81+
* Clear all local config overrides (ant-only).
82+
*/
83+
clearConfigOverrides(): void {
84+
clearGrowthBookConfigOverrides()
85+
},
86+
87+
/**
88+
* Subscribe to GrowthBook refresh events.
89+
* Called after each successful refresh.
90+
* Returns an unsubscribe function.
91+
*/
92+
onRefresh(callback: () => void): Unsubscribe {
93+
return onGrowthBookRefresh(callback)
94+
},
95+
96+
/**
97+
* Manually trigger a GrowthBook feature refresh.
98+
* Usually not needed — periodic refresh is handled by the analytics service.
99+
*/
100+
async refresh(): Promise<void> {
101+
return refreshGrowthBookFeatures()
102+
},
103+
} as const
Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,46 +4,46 @@ import { unwatchFile, watchFile } from 'fs'
44
import memoize from 'lodash-es/memoize.js'
55
import pickBy from 'lodash-es/pickBy.js'
66
import { basename, dirname, join, resolve } from 'path'
7-
import { getOriginalCwd, getSessionTrustAccepted } from '../bootstrap/state.js'
8-
import { getAutoMemEntrypoint } from '../memdir/paths.js'
9-
import { logEvent } from '../services/analytics/index.js'
10-
import type { McpServerConfig } from '../services/mcp/types.js'
7+
import { getOriginalCwd, getSessionTrustAccepted } from '../../../src/bootstrap/state.js'
8+
import { getAutoMemEntrypoint } from '../../../src/memdir/paths.js'
9+
import { logEvent } from '../../../src/services/analytics/index.js'
10+
import type { McpServerConfig } from '../../../src/services/mcp/types.js'
1111
import type {
1212
BillingType,
1313
ReferralEligibilityResponse,
14-
} from '../services/oauth/types.js'
15-
import { getCwd } from '../utils/cwd.js'
16-
import { registerCleanup } from './cleanupRegistry.js'
17-
import { logForDebugging } from './debug.js'
18-
import { logForDiagnosticsNoPII } from './diagLogs.js'
19-
import { getGlobalClaudeFile } from './env.js'
20-
import { getClaudeConfigHomeDir, isEnvTruthy } from './envUtils.js'
21-
import { ConfigParseError, getErrnoCode } from './errors.js'
22-
import { writeFileSyncAndFlush_DEPRECATED } from './file.js'
23-
import { getFsImplementation } from './fsOperations.js'
24-
import { findCanonicalGitRoot } from './git.js'
25-
import { safeParseJSON } from './json.js'
26-
import { stripBOM } from './jsonRead.js'
27-
import * as lockfile from './lockfile.js'
28-
import { logError } from './log.js'
29-
import type { MemoryType } from './memory/types.js'
30-
import { normalizePathForConfigKey } from './path.js'
31-
import { getEssentialTrafficOnlyReason } from './privacyLevel.js'
32-
import { getManagedFilePath } from './settings/managedPath.js'
33-
import type { ThemeSetting } from './theme.js'
14+
} from '../../../src/services/oauth/types.js'
15+
import { getCwd } from '../../../src/utils/cwd.js'
16+
import { registerCleanup } from '../../../src/utils/cleanupRegistry.js'
17+
import { logForDebugging } from '../../../src/utils/debug.js'
18+
import { logForDiagnosticsNoPII } from '../../../src/utils/diagLogs.js'
19+
import { getGlobalClaudeFile } from '../../../src/utils/env.js'
20+
import { getClaudeConfigHomeDir, isEnvTruthy } from '../../../src/utils/envUtils.js'
21+
import { ConfigParseError, getErrnoCode } from '../../../src/utils/errors.js'
22+
import { writeFileSyncAndFlush_DEPRECATED } from '../../../src/utils/file.js'
23+
import { getFsImplementation } from '../../../src/utils/fsOperations.js'
24+
import { findCanonicalGitRoot } from '../../../src/utils/git.js'
25+
import { safeParseJSON } from '../../../src/utils/json.js'
26+
import { stripBOM } from '../../../src/utils/jsonRead.js'
27+
import * as lockfile from '../../../src/utils/lockfile.js'
28+
import { logError } from '../../../src/utils/log.js'
29+
import type { MemoryType } from '../../../src/utils/memory/types.js'
30+
import { normalizePathForConfigKey } from '../../../src/utils/path.js'
31+
import { getEssentialTrafficOnlyReason } from '../../../src/utils/privacyLevel.js'
32+
import { getManagedFilePath } from '../settings/managedPath.js'
33+
import type { ThemeSetting } from '../../../src/utils/theme.js'
3434

3535
/* eslint-disable @typescript-eslint/no-require-imports */
3636
const teamMemPaths = feature('TEAMMEM')
37-
? (require('../memdir/teamMemPaths.js') as typeof import('../memdir/teamMemPaths.js'))
37+
? (require('../../../src/memdir/teamMemPaths.js') as typeof import('../../../src/memdir/teamMemPaths.js'))
3838
: null
3939
const ccrAutoConnect = feature('CCR_AUTO_CONNECT')
40-
? (require('../bridge/bridgeEnabled.js') as typeof import('../bridge/bridgeEnabled.js'))
40+
? (require('../../../src/bridge/bridgeEnabled.js') as typeof import('../../../src/bridge/bridgeEnabled.js'))
4141
: null
4242

4343
/* eslint-enable @typescript-eslint/no-require-imports */
44-
import type { ImageDimensions } from './imageResizer.js'
45-
import type { ModelOption } from './model/modelOptions.js'
46-
import { jsonParse, jsonStringify } from './slowOperations.js'
44+
import type { ImageDimensions } from '../../../src/utils/imageResizer.js'
45+
import type { ModelOption } from '../../../src/utils/model/modelOptions.js'
46+
import { jsonParse, jsonStringify } from '../../../src/utils/slowOperations.js'
4747

4848
// Re-entrancy guard: prevents getConfig → logEvent → getGlobalConfig → getConfig
4949
// infinite recursion when the config file is corrupted. logEvent's sampling check
@@ -152,9 +152,9 @@ export type InstallMethod = 'local' | 'native' | 'global' | 'unknown'
152152
export {
153153
EDITOR_MODES,
154154
NOTIFICATION_CHANNELS,
155-
} from './configConstants.js'
155+
} from './constants.js'
156156

157-
import type { EDITOR_MODES, NOTIFICATION_CHANNELS } from './configConstants.js'
157+
import type { EDITOR_MODES, NOTIFICATION_CHANNELS } from './constants.js'
158158

159159
export type NotificationChannel = (typeof NOTIFICATION_CHANNELS)[number]
160160

@@ -267,7 +267,7 @@ export type GlobalConfig = {
267267
}
268268

269269
// /buddy companion soul — bones regenerated from userId on read. See src/buddy/.
270-
companion?: import('../buddy/types.js').StoredCompanion
270+
companion?: import('../../../src/buddy/types.js').StoredCompanion
271271
companionMuted?: boolean
272272

273273
// Feedback survey tracking

0 commit comments

Comments
 (0)