feat(round2+round3): 完整实现 A/B/C/D 主线 + round3-F/H 修复
Round2 主线:
- A: 事件落库地基 (RuntimeApp EventStore 单例 + 14 repo wiring)
- B: 执行体对齐 (read-before-edit, verification-before-completion)
- C: 界面对齐 (@opentui/solid, 删除 runtime 依赖)
- D: 经验闭环 (ExperienceMiner, DebuggerRole, CompactorRole)
Round2 补充修复:
- fail-on-missing 反作弊门禁
- projection-store-apply.test.ts 补写
- 3个空壳测试转行为 (evidence-store, recovery-impl, knowledge-store)
- ask 项目根支持 AIRCODING_PROJECT_ROOT
- Worker 事件契约修复 (task.attempt.started → checkpoint)
Round3-F: cpp 工具切换
- 删除 BuiltInToolRegistrar cpp.* 闭包
- 接入 toolchain-cpp 真实 CppToolRegistrar
- canonical envelope {status/output/metadata}
- ExecutorRole system prompt 对齐新工具名
Round3-H: Doctor 5 类报告
- toolchain (cmake/ninja/cppcheck/clangd/g++)
- display (X11/Wayland + ImageMagick)
- network (internet connectivity)
- provider (api_key/base_url/model/connectivity)
Secret 脱敏:
- 状态交接.md: sk- → \${OPENAI_API_KEY}
- .gitignore: 添加 .air/ .claude/
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -132,20 +132,6 @@ export class BuiltInToolRegistrar {
|
||||
'project.profile.write': def('project.profile.write', 'project', 'Write language profile/toolchain configuration',
|
||||
{ language: { type: 'string', description: 'Language (cpp/c/rust/python)' }, profile_json: { type: 'object', description: 'Profile configuration' } }, ['language', 'profile_json'],
|
||||
{ read: false, write: true, network: false }),
|
||||
// cpp toolchain
|
||||
'cpp.detect': def('cpp.detect', 'debug', 'Detect C++ project structure, toolchain, and source files',
|
||||
{ project_root: { type: 'string', description: 'Project root path' } }, []),
|
||||
'cpp.cmake.configure': def('cpp.cmake.configure', 'build', 'Configure C++ build with CMake (Ninja preferred, Make fallback)',
|
||||
{ generator: { type: 'string', description: 'Generator (Ninja/Unix Makefiles)' }, build_type: { type: 'string', description: 'Debug/Release/RelWithDebInfo' } }, [],
|
||||
{ read: true, write: true, network: false }),
|
||||
'cpp.build': def('cpp.build', 'build', 'Build C++ project via CMake',
|
||||
{ target: { type: 'string', description: 'Build target' }, config: { type: 'string', description: 'Debug/Release' } }, []),
|
||||
'cpp.test': def('cpp.test', 'test', 'Run C++ tests via ctest',
|
||||
{ filter: { type: 'string', description: 'Test filter pattern' } }, []),
|
||||
'cpp.static.cppcheck': def('cpp.static.cppcheck', 'static_analysis', 'Run cppcheck static analysis on C++ code',
|
||||
{ path: { type: 'string', description: 'Path to analyze' }, severity: { type: 'string', description: 'Minimum severity' } }, []),
|
||||
'cpp.clangd.query': def('cpp.clangd.query', 'static_analysis', 'Query clangd LSP for symbol definition or diagnostics',
|
||||
{ file: { type: 'string', description: 'Source file path' }, line: { type: 'number', description: 'Line number' }, column: { type: 'number', description: 'Column number' } }, ['file']),
|
||||
// debug
|
||||
'debug.run': def('debug.run', 'debug', 'Run debugger on a target process or binary',
|
||||
{ target: { type: 'string', description: 'Binary or process to debug' }, breakpoints: { type: 'array', items: { type: 'string' } } }, ['target']),
|
||||
@@ -257,88 +243,6 @@ export class BuiltInToolRegistrar {
|
||||
}
|
||||
},
|
||||
|
||||
'cpp.detect': async (call: any) => {
|
||||
try {
|
||||
const root = (call.arguments as any)?.project_root || project_root
|
||||
const cmake = existsSync(join(root, 'CMakeLists.txt'))
|
||||
const makefile = existsSync(join(root, 'Makefile'))
|
||||
return { status: "ok", call_id: call.call_id, tool_name, type: 'text',
|
||||
output: { has_cmake: cmake, has_makefile: makefile, build_system: cmake ? 'cmake' : makefile ? 'make' : 'none' },
|
||||
metadata: { timestamp: new Date().toISOString(), call_id: call.call_id, tool_name, type: 'ok' } }
|
||||
} catch (e: any) {
|
||||
return { status: 'error', error: { error_id: call.call_id, kind: 'tool_error', severity: 'error', message: e.message, retryability: 'not_retryable', semantic_signature: tool_name },
|
||||
metadata: { timestamp: new Date().toISOString(), call_id: call.call_id, tool_name, type: 'error' } }
|
||||
}
|
||||
},
|
||||
|
||||
'cpp.cmake.configure': async (call: any) => {
|
||||
try {
|
||||
const { generator = 'Ninja', build_type = 'Debug' } = (call.arguments || {}) as any
|
||||
const buildDir = join(project_root, 'build')
|
||||
if (!existsSync(buildDir)) mkdirSync(buildDir, { recursive: true })
|
||||
execFileSync('cmake', ['-G', generator, '-DCMAKE_BUILD_TYPE=' + build_type, '..'], { cwd: buildDir, stdio: 'pipe' })
|
||||
return { status: "ok", call_id: call.call_id, tool_name, type: 'text', output: { generator, build_type, configured: true },
|
||||
metadata: { timestamp: new Date().toISOString(), call_id: call.call_id, tool_name, type: 'ok' } }
|
||||
} catch (e: any) {
|
||||
return { status: 'error', error: { error_id: call.call_id, kind: 'tool_error', severity: 'error', message: e.message, retryability: 'not_retryable', semantic_signature: tool_name },
|
||||
metadata: { timestamp: new Date().toISOString(), call_id: call.call_id, tool_name, type: 'error' } }
|
||||
}
|
||||
},
|
||||
|
||||
'cpp.build': async (call: any) => {
|
||||
try {
|
||||
const { target, config = 'Debug' } = (call.arguments || {}) as any
|
||||
const args = target ? ['--build', '.', '--config', config, '--target', target] : ['--build', '.', '--config', config]
|
||||
const out = execFileSync('cmake', args, { cwd: join(project_root, 'build'), stdio: 'pipe', timeout: 300000 })
|
||||
return { status: "ok", call_id: call.call_id, tool_name, type: 'text',
|
||||
output: { built: true, output: out.toString().slice(-500) },
|
||||
metadata: { timestamp: new Date().toISOString(), call_id: call.call_id, tool_name, type: 'ok' } }
|
||||
} catch (e: any) {
|
||||
return { status: 'error', error: { error_id: call.call_id, kind: 'tool_error', severity: 'error', message: e.message, retryability: 'not_retryable', semantic_signature: tool_name },
|
||||
metadata: { timestamp: new Date().toISOString(), call_id: call.call_id, tool_name, type: 'error' } }
|
||||
}
|
||||
},
|
||||
|
||||
'cpp.test': async (call: any) => {
|
||||
try {
|
||||
const { filter } = (call.arguments || {}) as any
|
||||
const args = filter ? ['--output-on-failure', '-R', filter] : ['--output-on-failure']
|
||||
const out = execFileSync('ctest', args, { cwd: join(project_root, 'build'), stdio: 'pipe', timeout: 300000 })
|
||||
return { status: "ok", call_id: call.call_id, tool_name, type: 'text',
|
||||
output: { passed: true, output: out.toString().slice(-1000) },
|
||||
metadata: { timestamp: new Date().toISOString(), call_id: call.call_id, tool_name, type: 'ok' } }
|
||||
} catch (e: any) {
|
||||
return { status: 'error', error: { error_id: call.call_id, kind: 'tool_error', severity: 'error', message: e.message, retryability: 'not_retryable', semantic_signature: tool_name },
|
||||
metadata: { timestamp: new Date().toISOString(), call_id: call.call_id, tool_name, type: 'error' } }
|
||||
}
|
||||
},
|
||||
|
||||
'cpp.static.cppcheck': async (call: any) => {
|
||||
try {
|
||||
const { path = 'src' } = (call.arguments || {}) as any
|
||||
const out = execFileSync('cppcheck', ['--enable=all', '--quiet', path], { cwd: project_root, stdio: 'pipe', encoding: 'utf-8', timeout: 120000 })
|
||||
return { status: "ok", call_id: call.call_id, tool_name, type: 'text',
|
||||
output: { output: out.toString().slice(-500), issues_found: 0 },
|
||||
metadata: { timestamp: new Date().toISOString(), call_id: call.call_id, tool_name, type: 'ok' } }
|
||||
} catch (e: any) {
|
||||
return { status: 'error', error: { error_id: call.call_id, kind: 'tool_error', severity: 'error', message: e.message, retryability: 'not_retryable', semantic_signature: tool_name },
|
||||
metadata: { timestamp: new Date().toISOString(), call_id: call.call_id, tool_name, type: 'error' } }
|
||||
}
|
||||
},
|
||||
|
||||
'cpp.clangd.query': async (call: any) => {
|
||||
try {
|
||||
const { file, line = 0, column = 0 } = (call.arguments || {}) as any
|
||||
const out = execFileSync('clangd', ['--check=' + file], { cwd: project_root, stdio: 'pipe', encoding: 'utf-8', timeout: 30000 })
|
||||
return { status: "ok", call_id: call.call_id, tool_name, type: 'text',
|
||||
output: { file, line, column, diagnostics: out.toString().slice(-1000) },
|
||||
metadata: { timestamp: new Date().toISOString(), call_id: call.call_id, tool_name, type: 'ok' } }
|
||||
} catch (e: any) {
|
||||
return { status: 'error', error: { error_id: call.call_id, kind: 'tool_error', severity: 'error', message: e.message, retryability: 'not_retryable', semantic_signature: tool_name },
|
||||
metadata: { timestamp: new Date().toISOString(), call_id: call.call_id, tool_name, type: 'error' } }
|
||||
}
|
||||
},
|
||||
|
||||
'debug.run': async (call: any) => {
|
||||
try {
|
||||
const { target } = (call.arguments || {}) as any
|
||||
|
||||
Reference in New Issue
Block a user