feat: 完成stub

This commit is contained in:
claude-code-best 2026-03-31 20:40:16 +08:00
parent c26d614fb2
commit bd756cc369
905 changed files with 3996 additions and 375 deletions

194
RECORD.md
View File

@ -52,23 +52,32 @@
|------|--------|------| |------|--------|------|
| 初始状态 | ~1800 | 仅缺少 npm 依赖的 TS2307 错误 | | 初始状态 | ~1800 | 仅缺少 npm 依赖的 TS2307 错误 |
| 补全依赖后 | ~1800 | npm 包已安装,开始处理类型 | | 补全依赖后 | ~1800 | npm 包已安装,开始处理类型 |
| 当前状态 | **2123** | 类型 stub 已创建,但存在质量待修问题 | | 第一轮 stub 生成 | ~2163 | 自动 stub 生成但质量问题多(全用 `export type` |
| **第二轮修复后** | **~1341** | 修复了默认导出、补充命名导出、泛型类型 |
### 当前错误分布 ### 当前错误分布(第二轮修复后)
| 错误码 | 数量 | 含义 | | 错误码 | 数量 | 含义 | 性质 |
|--------|------|------| |--------|------|------|------|
| TS2693 | 727 | `export type X` 被当作值使用(应为 `export const/function` | | TS2339 | 701 | 属性不存在 | **主要是源码级问题**unknown 344, never 121, {} 52 |
| TS2339 | 537 | 属性不存在类型收窄、unknown 类型) | | TS2322 | 210 | 类型不匹配 | 源码级 |
| TS2614 | 468 | 模块只有默认导出,但代码用命名导入 | | TS2345 | 134 | 参数类型不匹配 | 源码级 |
| TS2322 | 128 | 类型不匹配 | | TS2367 | 106 | 比较类型无交集 | 源码级(编译时死代码) |
| TS2345 | 57 | 参数类型不匹配 | | TS2307 | 29 | 缺失模块 | 可修但收益小 |
| TS2300 | 34 | 重复标识符stub 文件中 export 重复) | | TS2693 | 13 | type 当值用 | 少量残留 |
| TS2307 | 29 | 仍有缺失模块 | | TS2300 | 10 | 重复标识符 | 小问题 |
| TS2305 | 28 | 缺失导出成员 | | 其他 | ~138 | TS2365/TS2554/TS2578/TS2538/TS2698 等 | 混合 |
| TS2724 | 21 | 导出名称不匹配(如 HookEvent vs HOOK_EVENTS |
| TS2367 | 17 | 比较类型无交集(`"external" === "ant"` 等) | ### 关键发现
| 其他 | ~100 | TS2578/TS2315/TS2365/TS2741 等 |
剩余 1341 个错误中,**绝大多数(~1200+)是源码级别的类型问题**,不是 stub 缺失导致的:
- `unknown` 类型访问属性 (344) — 反编译产生的 `unknown` 需要断言
- `never` 类型 (121) — 联合类型穷尽后的死路径
- `{}` 空对象 (52) — 空 stub 模块的残留影响
- ComputerUseAPI/ComputerUseInputAPI (42) — 私有包声明不够详细
**继续逐个修复类型错误的投入产出比很低。应该改变方向,尝试直接构建运行。**
--- ---
@ -126,111 +135,84 @@
- 自动创建 `export type X = any` stub - 自动创建 `export type X = any` stub
- 已生成 **1206 个 stub 文件,覆盖 2067 个命名导出** - 已生成 **1206 个 stub 文件,覆盖 2067 个命名导出**
### 2.5 第二轮修复 — 默认导出 & 缺失导出 (本次会话)
#### `scripts/fix-default-stubs.mjs` — 修复 120 个 `export default {} as any` 的 stub 文件
- 扫描源码中所有 import 语句,区分 `import type {}` vs `import {}`
- 将纯类型导出为 `export type X = any`,值导出为 `export const X: any = (() => {}) as any`
- **效果**: TS2614 从 632 → 0 (完全消除)
#### `scripts/fix-missing-exports.mjs` — 补全空模块的导出成员
- 解析 TS2339 中 `typeof import("...")` 的错误,给 81 个模块添加了 147 个缺失导出
- 解析 TS2305 添加了 10 个缺失导出
- 解析 TS2724 添加了 4 个命名不匹配的导出
- 创建了 2 个新 stub 文件修复 TS2307
#### 泛型类型修复
将以下类型从非泛型改为泛型(修复 86 个 TS2315
- `DeepImmutable<T>`, `Permutations<T>` (`src/types/utils.ts`)
- `AttachmentMessage<T>`, `ProgressMessage<T>`, `NormalizedAssistantMessage<T>` (`src/types/message.ts` 及其多个副本)
- `WizardContextValue<T>` (`src/components/wizard/types.ts`)
#### 语法修复
修复 4 个 `export const default` 非法语法buddy/fork/peers/workflows 的 index.ts
--- ---
## 三、当前问题分析 ## 三、当前问题分析
### 3.1 TS2693 (727 个) — `export type` 被当作值使用 ⚠️ 关键 ### 3.1 剩余错误已触达 "源码级" 地板
**原因**: `scripts/create-type-stubs.mjs` 统一使用 `export type X = any` 生成 stub但代码中很多地方将导入的名称作为**值**使用(如调用函数、渲染 JSX 组件等)。 剩余 ~1341 个错误绝大多数不是 stub 缺失问题,而是源码本身的类型问题:
**示例**: - **unknown (344)**: 反编译代码中大量 `unknown` 类型变量直接访问属性
- **never (121)**: 联合类型穷尽后的 never 路径(通常是 switch/if-else 的 exhaustive check
- **{} (52)**: 空对象类型
- **类型比较 (106 TS2367)**: 编译时死代码如 `"external" === "ant"`
- **类型不匹配 (210 TS2322 + 134 TS2345)**: stub 类型不够精确
```typescript ### 3.2 继续修类型错误的问题
// stub 中: export type performLogout = any
// 实际使用: performLogout() // TS2693: only refers to a type, but is being used as a value
```
**修复方案**: 将 `export type X = any` 改为 `declare const X: any``export const X: any`。需要区分哪些是纯类型、哪些是值/函数/组件。 1. **投入产出比极低** — 每个 TS2339/TS2322 都需要理解具体上下文
2. **Bun bundler 不强制要求零 TS 错误** — Bun 可以在有类型错误的情况下成功构建
### 3.2 TS2614 (468 个) — 模块只有默认导出 3. **大部分是运行时无影响的类型问题**`unknown as any` 等模式不影响实际执行
**原因**: 部分 stub 文件使用 `export default {} as any`(早期手动创建),但代码用命名导入 `import { Message } from ...`
**示例**: `src/types/message.ts` 当前内容为 `export default {} as any`,但代码 `import type { Message } from '../types/message.js'`
**修复方案**: 将默认导出改为命名导出。
### 3.3 TS2300 (34 个) — 重复标识符
**原因**: stub 文件中有 `export type X = any` 行,同时源文件中也存在同名定义,造成冲突。部分 stub 文件路径不正确(如 `src/components/CustomSelect/select.ts` 既有真实代码又有 stub 导出)。
**修复方案**: 检查这些文件,如果真实文件存在则删除 stub 中的重复导出。
### 3.4 TS2339 (537 个) — 属性不存在
**原因**: `any` 类型的 stub 过于宽松时可以正常工作,但部分地方类型收窄后(如联合类型判别、`unknown` 类型)无法访问属性。
**分类**:
- 内部代码中 `unknown` 类型需要类型断言(源码问题)
- `McpServerConfigForProcessTransport` 等类型定义过窄stub 精度问题)
- `{ ok: true } | { ok: false; error: string }` 联合类型访问 `.error`(源码惯用模式)
**修复方案**: 调整相关 stub 类型定义使其更精确。
### 3.5 TS2307 (29 个) — 仍有缺失模块
主要是路径解析问题产生的重复 stub`src/cli/src/` 下的文件已被删除)以及一些深度嵌套的相对路径。
### 3.6 路径问题
部分 stub 文件被错误创建在 `src/cli/src/` 等嵌套路径下(因为 `import { X } from 'src/something'``src/cli/handlers/auth.ts` 解析时路径计算错误)。已手动删除部分重复文件,但可能仍有残留。
--- ---
## 四、后续处理方案 ## 四、后续方向建议
### Phase 1: 修复脚本 — 区分类型导出 vs 值导出 (预计解决 ~1200 个错误) ### 方向 A: 直接尝试 `bun build` 构建 ⭐ 推荐
改进 `scripts/create-type-stubs.mjs` Bun bundler 对类型错误比 tsc 宽容得多。应该直接尝试构建:
1. **分析 import 语句上下文** ```bash
- `import type { X }` → 纯类型,用 `export type X = any` bun build src/entrypoints/cli.tsx --target=node --outdir=dist
- `import { X }` (无 type) → 可能是值,用 `export const X: any = (() => {}) as any`
- JSX 组件(大写开头 + 在 JSX 中使用)→ `export const X: React.FC<any> = () => null`
2. **分析使用上下文**
- `X()` 调用 → 函数/值导出
- `<X />` → React 组件
- `X.property` → 对象/命名空间
### Phase 2: 修复默认导出问题 (预计解决 ~468 个 TS2614)
将所有 `export default {} as any` 的 stub 文件替换为带命名导出的版本:
```typescript
// 之前
export default {} as any
// 之后 — 根据导入需求
export type Message = any
export type NormalizedUserMessage = any
// ... 等
``` ```
### Phase 3: 清理冲突和路径问题 (预计解决 ~34 个 TS2300 + 29 个 TS2307) 遇到的构建错误才是真正需要修的问题(缺失模块、语法错误等),而非类型错误。
1. 检查所有带 `TS2300` 错误的文件,删除与真实代码冲突的 stub ### 方向 B: 在 tsconfig 中进一步放宽
2. 清理 `src/cli/src/`、`src/components/*/src/` 等错误路径下的 stub 残留
3. 修复 `tsconfig.json``paths` 配置,确保 `src/*` 映射正确
### Phase 4: 精化关键类型定义 (预计解决 ~100+ 个 TS2322/TS2345) ```json
{
"compilerOptions": {
"strict": false,
"noImplicitAny": false,
"strictNullChecks": false
}
}
```
对高频使用的类型提供更精确的定义: 已经是 `strict: false`,但可以进一步添加 `"skipLibCheck": true`(已有)。
1. **SDK 消息类型** — 使 `type` 字段为字面量联合类型,而非 `string` ### 方向 C: 批量 `// @ts-nocheck`
2. **McpServerConfig** — 改为联合类型stdio | sse | http | sse-ide
3. **HookInput** 系列 — 添加 `hook_event_name` 字面量类型
4. **PermissionResult** — 改为判别联合 `allow | deny`
### Phase 5: 处理源码级别的类型问题 (需评估) 对有大量源码级类型错误的文件加 `// @ts-nocheck`,快速消除错误。
这些是源码本身的问题,不属于 stub 范畴:
- `TS2367`: `"external" === "ant"` — 构建时消除的死代码
- `TS2339`: 联合类型属性访问 — 需要类型收窄或断言
- `TS2322`: 类型字面量不匹配(如 `"result"` vs `"result_success"`
--- ---
@ -242,6 +224,9 @@ export type NormalizedUserMessage = any
| `src/types/internal-modules.d.ts` | 内部 npm 包类型声明 | | `src/types/internal-modules.d.ts` | 内部 npm 包类型声明 |
| `src/types/react-compiler-runtime.d.ts` | React compiler runtime | | `src/types/react-compiler-runtime.d.ts` | React compiler runtime |
| `src/types/sdk-stubs.d.ts` | SDK 通配符类型(备用) | | `src/types/sdk-stubs.d.ts` | SDK 通配符类型(备用) |
| `src/types/message.ts` | Message 系列类型 stub (39 types) |
| `src/types/tools.ts` | 工具进度类型 stub |
| `src/types/utils.ts` | DeepImmutable / Permutations 泛型 |
| `src/entrypoints/sdk/controlTypes.ts` | SDK 控制类型 stub | | `src/entrypoints/sdk/controlTypes.ts` | SDK 控制类型 stub |
| `src/entrypoints/sdk/runtimeTypes.ts` | SDK 运行时类型 stub | | `src/entrypoints/sdk/runtimeTypes.ts` | SDK 运行时类型 stub |
| `src/entrypoints/sdk/coreTypes.generated.ts` | SDK 核心类型 stub | | `src/entrypoints/sdk/coreTypes.generated.ts` | SDK 核心类型 stub |
@ -249,6 +234,8 @@ export type NormalizedUserMessage = any
| `src/entrypoints/sdk/toolTypes.ts` | SDK 工具类型 stub | | `src/entrypoints/sdk/toolTypes.ts` | SDK 工具类型 stub |
| `src/entrypoints/sdk/sdkUtilityTypes.ts` | SDK 工具类型 | | `src/entrypoints/sdk/sdkUtilityTypes.ts` | SDK 工具类型 |
| `scripts/create-type-stubs.mjs` | 自动 stub 生成脚本 | | `scripts/create-type-stubs.mjs` | 自动 stub 生成脚本 |
| `scripts/fix-default-stubs.mjs` | 修复 `export default` stub 为命名导出 |
| `scripts/fix-missing-exports.mjs` | 补全空模块缺失的导出成员 |
| `tsconfig.json` | TypeScript 配置 | | `tsconfig.json` | TypeScript 配置 |
| `package.json` | 依赖配置 | | `package.json` | 依赖配置 |
@ -265,4 +252,13 @@ npx tsc --noEmit 2>&1 | grep "error TS" | sed 's/.*error //' | sed 's/:.*//' | s
# 重新生成 stub修复脚本后 # 重新生成 stub修复脚本后
node scripts/create-type-stubs.mjs node scripts/create-type-stubs.mjs
# 修复默认导出 stub
node scripts/fix-default-stubs.mjs
# 补全缺失导出
node scripts/fix-missing-exports.mjs
# 尝试构建(下一步)
bun build src/entrypoints/cli.tsx --target=node --outdir=dist
``` ```

View File

@ -4,7 +4,7 @@
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
"build": "bun build src/entrypoints/cli.ts --outdir dist --target bun", "build": "bun build src/entrypoints/cli.tsx --outdir dist --target bun",
"dev": "bun run --watch src/entrypoints/cli.tsx" "dev": "bun run --watch src/entrypoints/cli.tsx"
}, },
"dependencies": { "dependencies": {

View File

@ -0,0 +1,137 @@
#!/usr/bin/env node
/**
* Analyzes TypeScript errors and creates stub modules with proper named exports.
* Run: node scripts/create-type-stubs.mjs
*/
import { execSync } from 'child_process';
import { writeFileSync, existsSync, mkdirSync } from 'fs';
import { dirname, join } from 'path';
const ROOT = '/Users/konghayao/code/ai/claude-code';
// Run tsc and capture errors (tsc exits non-zero on type errors, that's expected)
let errors;
try {
errors = execSync('npx tsc --noEmit 2>&1', { encoding: 'utf-8', cwd: ROOT });
} catch (e) {
errors = e.stdout || '';
}
// Map: resolved file path -> Set of needed named exports
const stubExports = new Map();
// Map: resolved file path -> Set of needed default export names
const defaultExports = new Map();
for (const line of errors.split('\n')) {
// TS2614: Module '"X"' has no exported member 'Y'. Did you mean to use 'import Y from "X"' instead?
let m = line.match(/error TS2614: Module '"(.+?)"' has no exported member '(.+?)'\. Did you mean to use 'import .* from/);
if (m) {
const [, mod, member] = m;
if (!defaultExports.has(mod)) defaultExports.set(mod, new Set());
defaultExports.get(mod).add(member);
continue;
}
// TS2305: Module '"X"' has no exported member 'Y'
m = line.match(/error TS2305: Module '"(.+?)"' has no exported member '(.+?)'/);
if (m) {
const [, mod, member] = m;
if (!stubExports.has(mod)) stubExports.set(mod, new Set());
stubExports.get(mod).add(member);
}
// TS2724: '"X"' has no exported member named 'Y'. Did you mean 'Z'?
m = line.match(/error TS2724: '"(.+?)"' has no exported member named '(.+?)'/);
if (m) {
const [, mod, member] = m;
if (!stubExports.has(mod)) stubExports.set(mod, new Set());
stubExports.get(mod).add(member);
}
// TS2306: File 'X' is not a module
m = line.match(/error TS2306: File '(.+?)' is not a module/);
if (m) {
const filePath = m[1];
if (!stubExports.has(filePath)) stubExports.set(filePath, new Set());
}
// TS2307: Cannot find module 'X'
m = line.match(/^(.+?)\(\d+,\d+\): error TS2307: Cannot find module '(.+?)'/);
if (m) {
const [srcFile, mod] = [m[1], m[2]];
if (mod.endsWith('.md')) continue;
if (!mod.startsWith('.') && !mod.startsWith('src/')) continue;
// Will be resolved below
const srcDir = dirname(srcFile);
const resolved = join(ROOT, srcDir, mod).replace(/\.js$/, '.ts');
if (resolved.startsWith(ROOT + '/') && !existsSync(resolved)) {
if (!stubExports.has(resolved)) stubExports.set(resolved, new Set());
}
}
}
// Also parse actual import statements from source files to find what's needed
import { readFileSync } from 'fs';
const allSourceFiles = execSync('find src -name "*.ts" -o -name "*.tsx"', { encoding: 'utf-8', cwd: ROOT }).trim().split('\n');
for (const file of allSourceFiles) {
const content = readFileSync(join(ROOT, file), 'utf-8');
const srcDir = dirname(file);
// Find all import { X, Y } from 'module'
const importRegex = /import\s+(?:type\s+)?\{([^}]+)\}\s+from\s+['"](.+?)['"]/g;
let match;
while ((match = importRegex.exec(content)) !== null) {
const members = match[1].split(',').map(s => s.trim().split(/\s+as\s+/)[0].trim()).filter(Boolean);
let mod = match[2];
if (!mod.startsWith('.') && !mod.startsWith('src/')) continue;
const resolved = join(ROOT, srcDir, mod).replace(/\.js$/, '.ts');
if (resolved.startsWith(ROOT + '/') && !existsSync(resolved)) {
if (!stubExports.has(resolved)) stubExports.set(resolved, new Set());
for (const member of members) {
stubExports.get(resolved).add(member);
}
}
}
}
// Now create/update all stub files
let created = 0;
for (const [filePath, exports] of stubExports) {
const relPath = filePath.replace(ROOT + '/', '');
const dir = dirname(filePath);
if (!existsSync(dir)) {
mkdirSync(dir, { recursive: true });
}
const lines = ['// Auto-generated type stub — replace with real implementation'];
for (const exp of exports) {
lines.push(`export type ${exp} = any;`);
}
// Check if there are default exports needed
for (const [mod, defs] of defaultExports) {
// Match the module path
const modNorm = mod.replace(/\.js$/, '').replace(/^src\//, '');
const filePathNorm = relPath.replace(/\.ts$/, '');
if (modNorm === filePathNorm || mod === relPath) {
for (const def of defs) {
lines.push(`export type ${def} = any;`);
}
}
}
// Ensure at least export {}
if (exports.size === 0) {
lines.push('export {};');
}
writeFileSync(filePath, lines.join('\n') + '\n');
created++;
}
console.log(`Created/updated ${created} stub files`);
console.log(`Total named exports resolved: ${[...stubExports.values()].reduce((a, b) => a + b.size, 0)}`);

View File

@ -0,0 +1,160 @@
#!/usr/bin/env node
/**
* Finds all stub files with `export default {} as any` and rewrites them
* with proper named exports based on what the source code actually imports.
*/
import { execSync } from 'child_process';
import { readFileSync, writeFileSync, existsSync } from 'fs';
import { dirname, join, relative, resolve } from 'path';
const ROOT = '/Users/konghayao/code/ai/claude-code';
// Step 1: Find all stub files with only `export default {} as any`
const stubFiles = new Set();
const allTsFiles = execSync('find src -name "*.ts" -o -name "*.tsx"', {
encoding: 'utf-8', cwd: ROOT
}).trim().split('\n');
for (const f of allTsFiles) {
const fullPath = join(ROOT, f);
const content = readFileSync(fullPath, 'utf-8').trim();
if (content === 'export default {} as any') {
stubFiles.add(f); // relative path like src/types/message.ts
}
}
console.log(`Found ${stubFiles.size} stub files with 'export default {} as any'`);
// Step 2: Scan all source files for imports from these stub modules
// Map: stub file path -> { types: Set<string>, values: Set<string> }
const stubNeeds = new Map();
for (const sf of stubFiles) {
stubNeeds.set(sf, { types: new Set(), values: new Set() });
}
// Helper: resolve an import path from a source file to a stub file
function resolveImport(srcFile, importPath) {
// Handle src/ prefix imports
if (importPath.startsWith('src/')) {
const resolved = importPath.replace(/\.js$/, '.ts');
if (stubFiles.has(resolved)) return resolved;
return null;
}
// Handle relative imports
if (importPath.startsWith('.')) {
const srcDir = dirname(srcFile);
const resolved = join(srcDir, importPath).replace(/\.js$/, '.ts');
if (stubFiles.has(resolved)) return resolved;
// Try .tsx
const resolvedTsx = join(srcDir, importPath).replace(/\.js$/, '.tsx');
if (stubFiles.has(resolvedTsx)) return resolvedTsx;
return null;
}
return null;
}
for (const srcFile of allTsFiles) {
if (stubFiles.has(srcFile)) continue; // skip stub files themselves
const fullPath = join(ROOT, srcFile);
const content = readFileSync(fullPath, 'utf-8');
// Match: import type { A, B } from 'path'
const typeImportRegex = /import\s+type\s+\{([^}]+)\}\s+from\s+['"](.+?)['"]/g;
let match;
while ((match = typeImportRegex.exec(content)) !== null) {
const members = match[1].split(',').map(s => {
const parts = s.trim().split(/\s+as\s+/);
return parts[0].trim();
}).filter(Boolean);
const resolved = resolveImport(srcFile, match[2]);
if (resolved && stubNeeds.has(resolved)) {
for (const m of members) stubNeeds.get(resolved).types.add(m);
}
}
// Match: import { A, B } from 'path' (NOT import type)
const valueImportRegex = /import\s+(?!type\s)\{([^}]+)\}\s+from\s+['"](.+?)['"]/g;
while ((match = valueImportRegex.exec(content)) !== null) {
const rawMembers = match[1];
const members = rawMembers.split(',').map(s => {
// Handle `type Foo` inline type imports
const trimmed = s.trim();
if (trimmed.startsWith('type ')) {
return { name: trimmed.replace(/^type\s+/, '').split(/\s+as\s+/)[0].trim(), isType: true };
}
return { name: trimmed.split(/\s+as\s+/)[0].trim(), isType: false };
}).filter(m => m.name);
const resolved = resolveImport(srcFile, match[2]);
if (resolved && stubNeeds.has(resolved)) {
for (const m of members) {
if (m.isType) {
stubNeeds.get(resolved).types.add(m.name);
} else {
stubNeeds.get(resolved).values.add(m.name);
}
}
}
}
// Match: import Default from 'path'
const defaultImportRegex = /import\s+(?!type\s)(\w+)\s+from\s+['"](.+?)['"]/g;
while ((match = defaultImportRegex.exec(content)) !== null) {
const name = match[1];
if (name === 'type') continue;
const resolved = resolveImport(srcFile, match[2]);
if (resolved && stubNeeds.has(resolved)) {
stubNeeds.get(resolved).values.add('__default__:' + name);
}
}
}
// Step 3: Rewrite stub files
let updated = 0;
for (const [stubFile, needs] of stubNeeds) {
const fullPath = join(ROOT, stubFile);
const lines = ['// Auto-generated stub — replace with real implementation'];
let hasDefault = false;
// Add type exports
for (const t of needs.types) {
// Don't add as type if also in values
if (!needs.values.has(t)) {
lines.push(`export type ${t} = any;`);
}
}
// Add value exports (as const with any type)
for (const v of needs.values) {
if (v.startsWith('__default__:')) {
hasDefault = true;
continue;
}
// Check if it's likely a type (starts with uppercase and not a known function pattern)
// But since it's imported without `type`, treat as value to be safe
lines.push(`export const ${v}: any = (() => {}) as any;`);
}
// Add default export if needed
if (hasDefault) {
lines.push(`export default {} as any;`);
}
if (needs.types.size === 0 && needs.values.size === 0) {
lines.push('export {};');
}
writeFileSync(fullPath, lines.join('\n') + '\n');
updated++;
}
console.log(`Updated ${updated} stub files`);
// Print summary
for (const [stubFile, needs] of stubNeeds) {
if (needs.types.size > 0 || needs.values.size > 0) {
console.log(` ${stubFile}: ${needs.types.size} types, ${needs.values.size} values`);
}
}

View File

@ -0,0 +1,228 @@
#!/usr/bin/env node
/**
* Fixes TS2339 "Property X does not exist on type 'typeof import(...)'"
* by adding missing exports to the stub module files.
* Also re-runs TS2305/TS2724 fixes.
*/
import { execSync } from 'child_process';
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
import { dirname, join } from 'path';
const ROOT = '/Users/konghayao/code/ai/claude-code';
// Run tsc and capture errors
let errors;
try {
errors = execSync('npx tsc --noEmit 2>&1', { encoding: 'utf-8', cwd: ROOT, maxBuffer: 50 * 1024 * 1024 });
} catch (e) {
errors = e.stdout || '';
}
// ============================================================
// 1. Fix TS2339 on typeof import(...) - add missing exports
// ============================================================
// Map: module file path -> Set<property name>
const missingExports = new Map();
for (const line of errors.split('\n')) {
// TS2339: Property 'X' does not exist on type 'typeof import("path")'
let m = line.match(/error TS2339: Property '(\w+)' does not exist on type 'typeof import\("(.+?)"\)'/);
if (m) {
const [, prop, modPath] = m;
let filePath;
if (modPath.startsWith('/')) {
filePath = modPath;
} else {
continue; // skip non-absolute paths for now
}
// Try .ts then .tsx
for (const ext of ['.ts', '.tsx']) {
const fp = filePath + ext;
if (existsSync(fp)) {
if (!missingExports.has(fp)) missingExports.set(fp, new Set());
missingExports.get(fp).add(prop);
break;
}
}
}
// TS2339 on type '{ default: typeof import("...") }' (namespace import)
m = line.match(/error TS2339: Property '(\w+)' does not exist on type '\{ default: typeof import\("(.+?)"\)/);
if (m) {
const [, prop, modPath] = m;
for (const ext of ['.ts', '.tsx']) {
const fp = (modPath.startsWith('/') ? modPath : join(ROOT, modPath)) + ext;
if (existsSync(fp)) {
if (!missingExports.has(fp)) missingExports.set(fp, new Set());
missingExports.get(fp).add(prop);
break;
}
}
}
}
console.log(`Found ${missingExports.size} modules needing export additions for TS2339`);
let ts2339Fixed = 0;
for (const [filePath, props] of missingExports) {
const content = readFileSync(filePath, 'utf-8');
const existingExports = new Set();
// Parse existing exports
const exportRegex = /export\s+(?:type|const|function|class|let|var|default)\s+(\w+)/g;
let em;
while ((em = exportRegex.exec(content)) !== null) {
existingExports.add(em[1]);
}
const newExports = [];
for (const prop of props) {
if (!existingExports.has(prop) && !content.includes(`export { ${prop}`) && !content.includes(`, ${prop}`)) {
newExports.push(`export const ${prop}: any = (() => {}) as any;`);
ts2339Fixed++;
}
}
if (newExports.length > 0) {
const newContent = content.trimEnd() + '\n' + newExports.join('\n') + '\n';
writeFileSync(filePath, newContent);
}
}
console.log(`Added ${ts2339Fixed} missing exports for TS2339`);
// ============================================================
// 2. Fix TS2305 - Module has no exported member
// ============================================================
const ts2305Fixes = new Map();
for (const line of errors.split('\n')) {
let m = line.match(/^(.+?)\(\d+,\d+\): error TS2305: Module '"(.+?)"' has no exported member '(.+?)'/);
if (!m) continue;
const [, srcFile, mod, member] = m;
// Resolve module path
let resolvedPath;
if (mod.startsWith('.') || mod.startsWith('src/')) {
const base = mod.startsWith('.') ? join(dirname(srcFile), mod) : mod;
const resolved = join(ROOT, base).replace(/\.js$/, '');
for (const ext of ['.ts', '.tsx']) {
if (existsSync(resolved + ext)) {
resolvedPath = resolved + ext;
break;
}
}
}
if (resolvedPath) {
if (!ts2305Fixes.has(resolvedPath)) ts2305Fixes.set(resolvedPath, new Set());
ts2305Fixes.get(resolvedPath).add(member);
}
}
let ts2305Fixed = 0;
for (const [filePath, members] of ts2305Fixes) {
const content = readFileSync(filePath, 'utf-8');
const newExports = [];
for (const member of members) {
if (!content.includes(`export type ${member}`) && !content.includes(`export const ${member}`) && !content.includes(`export function ${member}`)) {
newExports.push(`export type ${member} = any;`);
ts2305Fixed++;
}
}
if (newExports.length > 0) {
writeFileSync(filePath, content.trimEnd() + '\n' + newExports.join('\n') + '\n');
}
}
console.log(`Added ${ts2305Fixed} missing exports for TS2305`);
// ============================================================
// 3. Fix TS2724 - no exported member named X. Did you mean Y?
// ============================================================
const ts2724Fixes = new Map();
for (const line of errors.split('\n')) {
let m = line.match(/^(.+?)\(\d+,\d+\): error TS2724: '"(.+?)"' has no exported member named '(.+?)'/);
if (!m) continue;
const [, srcFile, mod, member] = m;
let resolvedPath;
if (mod.startsWith('.') || mod.startsWith('src/')) {
const base = mod.startsWith('.') ? join(dirname(srcFile), mod) : mod;
const resolved = join(ROOT, base).replace(/\.js$/, '');
for (const ext of ['.ts', '.tsx']) {
if (existsSync(resolved + ext)) {
resolvedPath = resolved + ext;
break;
}
}
}
if (resolvedPath) {
if (!ts2724Fixes.has(resolvedPath)) ts2724Fixes.set(resolvedPath, new Set());
ts2724Fixes.get(resolvedPath).add(member);
}
}
let ts2724Fixed = 0;
for (const [filePath, members] of ts2724Fixes) {
const content = readFileSync(filePath, 'utf-8');
const newExports = [];
for (const member of members) {
if (!content.includes(`export type ${member}`) && !content.includes(`export const ${member}`)) {
newExports.push(`export type ${member} = any;`);
ts2724Fixed++;
}
}
if (newExports.length > 0) {
writeFileSync(filePath, content.trimEnd() + '\n' + newExports.join('\n') + '\n');
}
}
console.log(`Added ${ts2724Fixed} missing exports for TS2724`);
// ============================================================
// 4. Fix TS2307 - Cannot find module (create stub files)
// ============================================================
let ts2307Fixed = 0;
for (const line of errors.split('\n')) {
let m = line.match(/^(.+?)\(\d+,\d+\): error TS2307: Cannot find module '(.+?)'/);
if (!m) continue;
const [, srcFile, mod] = m;
if (mod.endsWith('.md') || mod.endsWith('.css')) continue;
if (!mod.startsWith('.') && !mod.startsWith('src/')) continue;
const srcDir = dirname(srcFile);
let resolved;
if (mod.startsWith('.')) {
resolved = join(ROOT, srcDir, mod).replace(/\.js$/, '.ts');
} else {
resolved = join(ROOT, mod).replace(/\.js$/, '.ts');
}
if (!existsSync(resolved) && resolved.startsWith(ROOT + '/src/')) {
const dir = dirname(resolved);
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
// Collect imports from the source file for this module
const srcContent = readFileSync(join(ROOT, srcFile), 'utf-8');
const importRegex = new RegExp(`import\\s+(?:type\\s+)?\\{([^}]+)\\}\\s+from\\s+['"]${mod.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}['"]`, 'g');
const members = new Set();
let im;
while ((im = importRegex.exec(srcContent)) !== null) {
im[1].split(',').map(s => s.trim().replace(/^type\s+/, '').split(/\s+as\s+/)[0].trim()).filter(Boolean).forEach(m => members.add(m));
}
const lines = ['// Auto-generated stub'];
for (const member of members) {
lines.push(`export type ${member} = any;`);
}
if (members.size === 0) lines.push('export {};');
writeFileSync(resolved, lines.join('\n') + '\n');
ts2307Fixed++;
}
}
console.log(`Created ${ts2307Fixed} new stub files for TS2307`);

View File

@ -0,0 +1,3 @@
// Auto-generated stub — replace with real implementation
export {};
export const AssistantSessionChooser: any = (() => {}) as any;

3
src/assistant/gate.ts Normal file
View File

@ -0,0 +1,3 @@
// Auto-generated stub — replace with real implementation
export {};
export const isKairosEnabled: any = (() => {}) as any;

8
src/assistant/index.ts Normal file
View File

@ -0,0 +1,8 @@
// Auto-generated stub — replace with real implementation
export {};
export const isAssistantMode: any = (() => {}) as any;
export const initializeAssistantTeam: any = (() => {}) as any;
export const markAssistantForced: any = (() => {}) as any;
export const isAssistantForced: any = (() => {}) as any;
export const getAssistantSystemPromptAddendum: any = (() => {}) as any;
export const getAssistantActivationPath: any = (() => {}) as any;

View File

@ -0,0 +1,3 @@
// Auto-generated stub — replace with real implementation
export type AssistantSession = any;
export const discoverAssistantSessions: any = (() => {}) as any;

View File

@ -0,0 +1,3 @@
// Auto-generated type stub — replace with real implementation
export type HookEvent = any;
export type ModelUsage = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type AgentColorName = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type HookCallbackMatcher = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type SessionId = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type randomUUID = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type ModelSetting = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type ModelStrings = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type SettingSource = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type resetSettingsCache = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type PluginHookMatcher = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type createSignal = any;

View File

@ -1755,4 +1755,4 @@ export function getPromptId(): string | null {
export function setPromptId(id: string | null): void { export function setPromptId(id: string | null): void {
STATE.promptId = id STATE.promptId = id
} }
export type isReplBridgeActive = any;

View File

@ -0,0 +1,3 @@
// Auto-generated stub — replace with real implementation
export {};
export const postInterClaudeMessage: any = (() => {}) as any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type StdoutMessage = any;

View File

@ -0,0 +1,3 @@
// Auto-generated stub — replace with real implementation
export {};
export const sanitizeInboundWebhookContent: any = (() => {}) as any;

7
src/cli/bg.ts Normal file
View File

@ -0,0 +1,7 @@
// Auto-generated stub — replace with real implementation
export {};
export const psHandler: any = (() => {}) as any;
export const logsHandler: any = (() => {}) as any;
export const attachHandler: any = (() => {}) as any;
export const killHandler: any = (() => {}) as any;
export const handleBgFlag: any = (() => {}) as any;

11
src/cli/handlers/ant.ts Normal file
View File

@ -0,0 +1,11 @@
// Auto-generated stub — replace with real implementation
export {};
export const logHandler: any = (() => {}) as any;
export const errorHandler: any = (() => {}) as any;
export const exportHandler: any = (() => {}) as any;
export const taskCreateHandler: any = (() => {}) as any;
export const taskListHandler: any = (() => {}) as any;
export const taskGetHandler: any = (() => {}) as any;
export const taskUpdateHandler: any = (() => {}) as any;
export const taskDirHandler: any = (() => {}) as any;
export const completionHandler: any = (() => {}) as any;

View File

@ -0,0 +1,3 @@
// Auto-generated stub — replace with real implementation
export {};
export const templatesMain: any = (() => {}) as any;

2
src/cli/rollback.ts Normal file
View File

@ -0,0 +1,2 @@
// Auto-generated stub
export {};

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type ask = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type installOAuthTokens = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type RemoteIO = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type StructuredIO = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type collectContextData = any;

View File

@ -0,0 +1,14 @@
// Auto-generated type stub — replace with real implementation
export type SDKStatus = any;
export type ModelInfo = any;
export type SDKMessage = any;
export type SDKUserMessage = any;
export type SDKUserMessageReplay = any;
export type PermissionResult = any;
export type McpServerConfigForProcessTransport = any;
export type McpServerStatus = any;
export type RewindFilesResult = any;
export type HookEvent = any;
export type HookInput = any;
export type HookJSONOutput = any;
export type PermissionUpdate = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type SDKControlElicitationResponseSchema = any;

View File

@ -0,0 +1,9 @@
// Auto-generated type stub — replace with real implementation
export type StdoutMessage = any;
export type SDKControlInitializeRequest = any;
export type SDKControlInitializeResponse = any;
export type SDKControlRequest = any;
export type SDKControlResponse = any;
export type SDKControlMcpSetServersResponse = any;
export type SDKControlReloadPluginsResponse = any;
export type StdinMessage = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type CanUseToolFn = any;

View File

@ -0,0 +1,5 @@
// Auto-generated type stub — replace with real implementation
export type tryGenerateSuggestion = any;
export type logSuggestionOutcome = any;
export type logSuggestionSuppressed = any;
export type PromptVariant = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type getFeatureValue_CACHED_MAY_BE_STALE = any;

View File

@ -0,0 +1,3 @@
// Auto-generated type stub — replace with real implementation
export type logEvent = any;
export type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS = any;

View File

@ -0,0 +1,3 @@
// Auto-generated type stub — replace with real implementation
export type isQualifiedForGrove = any;
export type checkGroveForNonInteractive = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type EMPTY_USAGE = any;

View File

@ -0,0 +1,3 @@
// Auto-generated type stub — replace with real implementation
export type statusListeners = any;
export type ClaudeAILimits = any;

View File

@ -0,0 +1,3 @@
// Auto-generated type stub — replace with real implementation
export type performMCPOAuthFlow = any;
export type revokeServerTokens = any;

View File

@ -0,0 +1,3 @@
// Auto-generated type stub — replace with real implementation
export type isChannelAllowlisted = any;
export type isChannelsEnabled = any;

View File

@ -0,0 +1,5 @@
// Auto-generated type stub — replace with real implementation
export type ChannelMessageNotificationSchema = any;
export type gateChannelServer = any;
export type wrapChannelMessage = any;
export type findChannelEntry = any;

View File

@ -0,0 +1,7 @@
// Auto-generated type stub — replace with real implementation
export type setupSdkMcpClients = any;
export type connectToServer = any;
export type clearServerCache = any;
export type fetchToolsForClient = any;
export type areMcpConfigsEqual = any;
export type reconnectMcpServerImpl = any;

View File

@ -0,0 +1,6 @@
// Auto-generated type stub — replace with real implementation
export type filterMcpServersByPolicy = any;
export type getMcpConfigByName = any;
export type isMcpServerDisabled = any;
export type setMcpServerEnabled = any;
export type getAllMcpConfigs = any;

View File

@ -0,0 +1,3 @@
// Auto-generated type stub — replace with real implementation
export type runElicitationHooks = any;
export type runElicitationResultHooks = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type getMcpPrefix = any;

View File

@ -0,0 +1,4 @@
// Auto-generated type stub — replace with real implementation
export type MCPServerConnection = any;
export type McpSdkServerConfig = any;
export type ScopedMcpServerConfig = any;

View File

@ -0,0 +1,3 @@
// Auto-generated type stub — replace with real implementation
export type commandBelongsToServer = any;
export type filterToolsByServer = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type setupVscodeSdkMcp = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type OAuthService = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type isPolicyAllowed = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type waitForRemoteManagedSettingsToLoad = any;

View File

@ -0,0 +1,3 @@
// Auto-generated type stub — replace with real implementation
export type downloadUserSettings = any;
export type redownloadUserSettings = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type AppState = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type externalMetadataToAppState = any;

3
src/cli/src/tools.ts Normal file
View File

@ -0,0 +1,3 @@
// Auto-generated type stub — replace with real implementation
export type assembleToolPool = any;
export type filterToolsByDenyRules = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type createAbortController = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type uniq = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type getAccountInformation = any;

View File

@ -0,0 +1,4 @@
// Auto-generated type stub — replace with real implementation
export type getLatestVersion = any;
export type InstallStatus = any;
export type installGlobalPackage = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type AwsAuthStatusManager = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type modelSupportsAutoMode = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type registerCleanup = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type createCombinedAbortSignal = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type notifyCommandLifecycle = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type incrementPromptCount = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type regenerateCompletionCache = any;

View File

@ -0,0 +1,4 @@
// Auto-generated type stub — replace with real implementation
export type getGlobalConfig = any;
export type InstallMethod = any;
export type saveGlobalConfig = any;

View File

@ -0,0 +1,3 @@
// Auto-generated type stub — replace with real implementation
export type loadConversationForResume = any;
export type TurnInterruptionState = any;

2
src/cli/src/utils/cwd.ts Normal file
View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type getCwd = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type logForDebugging = any;

View File

@ -0,0 +1,3 @@
// Auto-generated type stub — replace with real implementation
export type logForDiagnosticsNoPII = any;
export type withDiagnosticsTiming = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type getDoctorDiagnostic = any;

View File

@ -0,0 +1,5 @@
// Auto-generated type stub — replace with real implementation
export type modelSupportsEffort = any;
export type modelSupportsMaxEffort = any;
export type EFFORT_LEVELS = any;
export type resolveAppliedEffort = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type AbortError = any;

View File

@ -0,0 +1,5 @@
// Auto-generated type stub — replace with real implementation
export type isFastModeAvailable = any;
export type isFastModeEnabled = any;
export type isFastModeSupportedByModel = any;
export type getFastModeState = any;

View File

@ -0,0 +1,5 @@
// Auto-generated type stub — replace with real implementation
export type fileHistoryRewind = any;
export type fileHistoryCanRestore = any;
export type fileHistoryEnabled = any;
export type fileHistoryGetDiffStats = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type executeFilePersistence = any;

View File

@ -0,0 +1,4 @@
// Auto-generated type stub — replace with real implementation
export type createFileStateCacheWithSizeLimit = any;
export type mergeFileStateCaches = any;
export type READ_FILE_STATE_CACHE_SIZE = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type getLastCacheSafeParams = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type fromArray = any;

View File

@ -0,0 +1,4 @@
// Auto-generated type stub — replace with real implementation
export type gracefulShutdown = any;
export type gracefulShutdownSync = any;
export type isShuttingDown = any;

View File

@ -0,0 +1,4 @@
// Auto-generated type stub — replace with real implementation
export type headlessProfilerStartTurn = any;
export type headlessProfilerCheckpoint = any;
export type logHeadlessProfilerTurn = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type executeNotificationHooks = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type finalizePendingAsyncHooks = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type registerHookEventHandler = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type createIdleTimeoutManager = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type safeParseJSON = any;

View File

@ -0,0 +1,3 @@
// Auto-generated type stub — replace with real implementation
export type installOrUpdateClaudePackage = any;
export type localInstallationExists = any;

4
src/cli/src/utils/log.ts Normal file
View File

@ -0,0 +1,4 @@
// Auto-generated type stub — replace with real implementation
export type getInMemoryErrors = any;
export type logError = any;
export type logMCPDebug = any;

View File

@ -0,0 +1,8 @@
// Auto-generated type stub — replace with real implementation
export type dequeue = any;
export type dequeueAllMatching = any;
export type enqueue = any;
export type hasCommandsInQueue = any;
export type peek = any;
export type subscribeToCommandQueue = any;
export type getCommandsByMaxPriority = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type createModelSwitchBreadcrumbs = any;

View File

@ -0,0 +1,3 @@
// Auto-generated type stub — replace with real implementation
export type toInternalMessages = any;
export type toSDKRateLimitInfo = any;

View File

@ -0,0 +1,5 @@
// Auto-generated type stub — replace with real implementation
export type getDefaultMainLoopModel = any;
export type getMainLoopModel = any;
export type modelDisplayString = any;
export type parseUserSpecifiedModel = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type getModelOptions = any;

View File

@ -0,0 +1,2 @@
// Auto-generated type stub — replace with real implementation
export type ensureModelStringsInitialized = any;

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