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>
118 lines
6.6 KiB
TypeScript
Executable File
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() } }
|
|
}
|
|
})
|
|
}
|
|
}
|