Files
AirCoding/packages/toolchain-cpp/src/CppToolRegistrar.ts
AirCoding 5e282a39b4 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>
2026-06-09 16:13:16 +08:00

118 lines
6.6 KiB
TypeScript
Executable File

/**
* CppToolRegistrar - Registers cpp.* tools through CapabilityRegistry
* DD §15. INV-4: registered via capability boundary, not direct runtime import.
*
* @module packages/toolchain-cpp/src/CppToolRegistrar
*/
import { CPP_TOOLCHAIN_CAPABILITY } from './capability.js'
import { CppProjectDetector } from './detect/CppProjectDetector.js'
import { CMakeConfigurator } from './build/CMakeConfigurator.js'
import { CppBuilder } from './build/CppBuilder.js'
import { CppTestRunner } from './test/CppTestRunner.js'
import { CppcheckRunner } from './analysis/CppcheckRunner.js'
import { ClangdClient } from './analysis/ClangdClient.js'
export class CppToolRegistrar {
manifest = CPP_TOOLCHAIN_CAPABILITY
/**
* Register all cpp.* tools with the provided registry.
* INV-4: This is called through CapabilityRegistry boundary, never via direct runtime import.
*/
register(registry: { register(name: string, definition: any, executor: (call: any) => Promise<any>): void }, project_root: string): void {
const detector = new CppProjectDetector(project_root)
const configurator = new CMakeConfigurator()
const builder = new CppBuilder()
const tester = new CppTestRunner()
const cppcheck = new CppcheckRunner()
const clangd = new ClangdClient()
// cpp.detect
registry.register('cpp.detect', {
name: 'cpp.detect', category: 'toolchain',
description: 'Detect C++ project structure and toolchain',
input_schema: CPP_TOOLCHAIN_CAPABILITY.tools[0].input_schema,
permissions: { read: true, write: false, network: false }, streaming: false
}, async (call) => {
const result = detector.detect()
return { status: 'ok', call_id: call.call_id, tool_name: 'cpp.detect', output: result, metadata: { timestamp: new Date().toISOString() } }
})
// cpp.configure
registry.register('cpp.configure', {
name: 'cpp.configure', category: 'toolchain',
description: 'Configure C++ build with CMake',
input_schema: CPP_TOOLCHAIN_CAPABILITY.tools[1].input_schema,
permissions: { read: true, write: true, network: false }, streaming: false
}, async (call) => {
const result = configurator.configure({ project_root, generator: call.arguments?.generator as any, build_type: call.arguments?.build_type as any })
if (result.ok) {
return { status: 'ok', call_id: call.call_id, tool_name: 'cpp.configure', output: result, metadata: { timestamp: new Date().toISOString() } }
} else {
return { status: 'error', call_id: call.call_id, tool_name: 'cpp.configure', error: { error_id: call.call_id, kind: 'tool_error', severity: 'error', message: result.error || 'configure failed', retryability: 'not_retryable', semantic_signature: 'cpp.configure' }, metadata: { timestamp: new Date().toISOString() } }
}
})
// cpp.build
registry.register('cpp.build', {
name: 'cpp.build', category: 'toolchain',
description: 'Build C++ project',
input_schema: CPP_TOOLCHAIN_CAPABILITY.tools[2].input_schema,
permissions: { read: true, write: true, network: false }, streaming: false
}, async (call) => {
const result = builder.build(project_root + '/build', call.arguments?.target as string)
if (result.ok) {
return { status: 'ok', call_id: call.call_id, tool_name: 'cpp.build', output: { built: true, output: result.output, diagnostics: result.diagnostics, elapsed_ms: result.elapsed_ms }, metadata: { timestamp: new Date().toISOString() } }
} else {
return { status: 'error', call_id: call.call_id, tool_name: 'cpp.build', error: { error_id: call.call_id, kind: 'tool_error', severity: 'error', message: result.output || 'build failed', retryability: 'not_retryable', semantic_signature: 'cpp.build' }, metadata: { timestamp: new Date().toISOString() } }
}
})
// cpp.test
registry.register('cpp.test', {
name: 'cpp.test', category: 'toolchain',
description: 'Run C++ tests',
input_schema: CPP_TOOLCHAIN_CAPABILITY.tools[3].input_schema,
permissions: { read: true, write: false, network: false }, streaming: false
}, async (call) => {
const result = tester.run_tests(project_root + '/build')
if (result.ok) {
return { status: 'ok', call_id: call.call_id, tool_name: 'cpp.test', output: result, metadata: { timestamp: new Date().toISOString() } }
} else {
return { status: 'error', call_id: call.call_id, tool_name: 'cpp.test', error: { error_id: call.call_id, kind: 'tool_error', severity: 'error', message: result.output || 'test failed', retryability: 'not_retryable', semantic_signature: 'cpp.test' }, metadata: { timestamp: new Date().toISOString() } }
}
})
// cpp.cppcheck
registry.register('cpp.cppcheck', {
name: 'cpp.cppcheck', category: 'toolchain',
description: 'Run cppcheck static analysis',
input_schema: CPP_TOOLCHAIN_CAPABILITY.tools[4].input_schema,
permissions: { read: true, write: false, network: false }, streaming: false
}, async (call) => {
const result = cppcheck.run(project_root, { enable_all: call.arguments?.enable_all as boolean, check_config: call.arguments?.check_config as boolean })
if (result.ok) {
return { status: 'ok', call_id: call.call_id, tool_name: 'cpp.cppcheck', output: result, metadata: { timestamp: new Date().toISOString() } }
} else {
return { status: 'error', call_id: call.call_id, tool_name: 'cpp.cppcheck', error: { error_id: call.call_id, kind: 'tool_error', severity: 'error', message: result.output || 'cppcheck failed', retryability: 'not_retryable', semantic_signature: 'cpp.cppcheck' }, metadata: { timestamp: new Date().toISOString() } }
}
})
// cpp.clangd
registry.register('cpp.clangd', {
name: 'cpp.clangd', category: 'toolchain',
description: 'Query clangd for symbol info',
input_schema: CPP_TOOLCHAIN_CAPABILITY.tools[5].input_schema,
permissions: { read: true, write: false, network: false }, streaming: false
}, async (call) => {
const result = await clangd.query_symbol(call.arguments?.file as string, call.arguments?.line as number, call.arguments?.column as number)
if (result.ok) {
return { status: 'ok', call_id: call.call_id, tool_name: 'cpp.clangd', output: result, metadata: { timestamp: new Date().toISOString() } }
} else {
return { status: 'error', call_id: call.call_id, tool_name: 'cpp.clangd', error: { error_id: call.call_id, kind: 'tool_error', severity: 'error', message: result.error || 'clangd query failed', retryability: 'not_retryable', semantic_signature: 'cpp.clangd' }, metadata: { timestamp: new Date().toISOString() } }
}
})
}
}