Files
AirCoding/AirPlan/docs/architecture/c4/code-view.md
AirCoding 33a76a1ebc Move project from external drive to local NVMe
迁移路径: /run/media/airlongdian/EasyU/AirCoding -> /home/airlongdian/DataDevices/AirWorkSpace/AirCoding

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 09:51:49 +08:00

859 lines
20 KiB
Markdown
Executable File

# C4 Code View and UML Class Model
Date: 2026-05-27
Status: Formal V1 code-view design for AirCoding V1.0.0 Alpha skeleton
This document refines `AirPlan/docs/architecture/c4/module.md` from container/module view into package-level code structure, class/service responsibilities, UML class diagrams, and implementation boundaries.
Canonical TypeScript interface contracts are defined in `AirPlan/docs/architecture/interface-contracts-v1.md`.
## 1. Code View Scope
The V1.0.0 Alpha code view covers these packages:
```text
packages/contracts
packages/cli
packages/runtime
packages/llm
packages/toolchain-cpp
packages/tui
```
The code view is implementation-facing but remains architecture-only. It defines expected classes/interfaces and relationships; exact file names may be adjusted during implementation if contracts and dependencies remain stable.
## 2. Package Dependency Diagram
```plantuml
@startuml
skinparam componentStyle rectangle
package "packages/contracts" as contracts
package "packages/cli" as cli
package "packages/runtime" as runtime
package "packages/llm" as llm
package "packages/toolchain-cpp" as cpp
package "packages/tui" as tui
cli --> runtime
cli --> tui
cli --> llm
cli --> cpp
runtime --> contracts
runtime --> llm : adapter interfaces
runtime ..> cpp : capability registration boundary
llm --> contracts
cpp --> contracts
tui --> contracts
runtime --> llm : ProviderManager facade/API
@enduml
```
Rules:
1. `contracts` must have no implementation-package dependencies.
2. `runtime` must not import `tui`.
3. `tui` must depend only on `contracts` and a narrow `ProjectionClient`/UI API boundary; it must not import runtime private services, query SQLite, or subscribe to EventBus directly.
4. `toolchain-cpp` exposes tools through capability registration, not direct runtime coupling.
5. `llm` owns provider adapters, model config, provider conversion, and ProviderManager implementation; `runtime` owns prompt assembly and calls LLM through the provider facade/API.
## 3. Contracts Package Code View
Expected directory:
```text
packages/contracts/src/
index.ts
ids.ts
runtime.ts
event.ts
ipc.ts
task.ts
worker-result.ts
tool.ts
artifact.ts
evidence.ts
project.ts
provider.ts
permission.ts
ui.ts
error.ts
capability.ts
platform.ts
```
### UML
```plantuml
@startuml
interface RuntimeEvent<T> {
id: UUID
type: string
version: number
timestamp: ISOTimeString
session_id: SessionID
project_id?: ProjectID
source: EventSource
route: string[]
payload: T
}
interface TaskSpec {
id: TaskID
type: TaskType
title: string
description: string
acceptance_criteria: string[]
scope: TaskScope
dependencies: TaskDependencySpec[]
verification: VerificationPolicy
constraints: TaskConstraints
context_refs: TaskContextRefs
output_contract: WorkerOutputContract
}
interface WorkerResult<T> {
task_id: TaskID
agent_id: AgentID
agent_type: AgentType
status: WorkerStatus
summary: string
changed_files: string[]
artifacts: ArtifactRef[]
verification: VerificationResult[]
risks: Risk[]
follow_up_tasks: FollowUpTask[]
evidence_refs: EvidenceRef[]
result: T
}
interface ToolDefinition<I, O> {
name: string
version: number
description: string
input_schema: JsonSchema<I>
output_schema: JsonSchema<O>
category: ToolCategory
permissions: ToolPermissionSpec
streaming: boolean
}
interface ProviderCapabilityMatrix
interface AirError
interface ArtifactRef
interface EvidenceRef
interface PermissionDecision
interface ProjectionSnapshot
interface CapabilityManifestV1
RuntimeEvent --> EventSource
TaskSpec --> WorkerResult : output contract
WorkerResult --> ArtifactRef
WorkerResult --> EvidenceRef
ToolDefinition --> PermissionDecision
AirError --> EvidenceRef
@enduml
```
### Contract Ownership
| Contract | File | Primary consumers |
|---|---|---|
| IDs and aliases | `ids.ts` | all packages |
| RuntimeEvent/EventSource | `event.ts` | EventStore, EventBus, IPC, ProjectionStore |
| TaskSpec | `task.ts` | Scheduler, workers, ContextAssembler |
| WorkerResult | `worker-result.ts` | workers, Scheduler, Main Agent |
| ToolDefinition/ToolResult | `tool.ts` | ToolRegistry, capabilities, workers |
| ArtifactRef/EvidenceRef | `artifact.ts`, `evidence.ts` | ArtifactStore, EvidenceStore, reports |
| ProviderCapabilityMatrix | `provider.ts` | ProviderManager, Scheduler, Doctor |
| AirError/ErrorKind | `error.ts` | tools, Scheduler, agents, UI |
| IpcMessage/ControlMessage | `ipc.ts` | WorkerManager, child workers |
| PermissionDecision | `permission.ts` | PermissionEngine, ToolRegistry, UI |
| ProjectionSnapshot | `ui.ts` | ProjectionStore, TUI/HUD |
| CapabilityManifestV1 | `capability.ts` | CapabilityRegistry, Doctor |
## 4. Runtime Package Code View
Expected directory:
```text
packages/runtime/src/
index.ts
app/
RuntimeApp.ts
ServiceRegistry.ts
config/
ConfigLoader.ts
ResourceLoader.ts
project/
ProjectLocator.ts
ProjectInitializer.ts
ProjectStore.ts
storage/
DatabaseManager.ts
MigrationRunner.ts
repositories/
events/
EventBus.ts
EventStore.ts
EventIngestor.ts
EventSchemaRegistry.ts
sessions/
SessionManager.ts
SessionStore.ts
scheduler/
Scheduler.ts
TaskGraph.ts
WavePlanner.ts
RetryPlanner.ts
WorkspaceManager.ts
AgentMonitor.ts
workers/
WorkerManager.ts
WorkerProcess.ts
WorkerProtocol.ts
roles/
tools/
ToolRegistry.ts
BuiltInToolRegistrar.ts
fs/
shell/
git/
project/
artifact/
context/
permission/
doctor/
security/
PermissionEngine.ts
PathClassifier.ts
CommandRiskAnalyzer.ts
SecretRedactor.ts
capabilities/
CapabilityRegistry.ts
CapabilityManifestValidator.ts
context/
ContextAssembler.ts
PromptLayerLoader.ts
CompactionPolicy.ts
artifacts/
ArtifactStore.ts
EvidenceStore.ts
knowledge/
DebugKnowledgeStore.ts
LearnedMemoryStore.ts
projection/
ProjectionStore.ts
projections/
doctor/
DoctorService.ts
checks/
logging/
Logger.ts
DeveloperLogEncryptor.ts
agents/
main/
architecture/
```
### Runtime Service UML
```plantuml
@startuml
class RuntimeApp {
+start(options): Promise<void>
+shutdown(): Promise<void>
}
class ServiceRegistry {
+get<T>(token): T
+register(token, service): void
}
class ProjectStore {
+open(root): Promise<ProjectContext>
+initialize(root): Promise<ProjectContext>
}
class SessionManager {
+openSession(project, options): Promise<SessionContext>
+closeSession(sessionId): Promise<void>
}
class DatabaseManager {
+open(path): DatabaseHandle
+transaction(fn): Promise<T>
}
class MigrationRunner {
+migrate(db): Promise<void>
}
class EventStore {
+append(event): Promise<void>
+query(filter): Promise<RuntimeEvent[]>
}
class EventIngestor {
+ingest(event): Promise<void>
+ingest_ephemeral(event): Promise<void>
}
class EventBus {
+publish(event): void
+subscribe(filter, handler): Subscription
}
class ProjectionStore {
+hydrate(sessionId): Promise<void>
+apply(event): void
+snapshot(): ProjectionSnapshot
}
RuntimeApp --> ServiceRegistry
RuntimeApp --> ProjectStore
RuntimeApp --> SessionManager
SessionManager --> DatabaseManager
DatabaseManager --> MigrationRunner
EventIngestor --> EventStore : durable events
EventIngestor --> EventBus : ephemeral events
EventStore --> DatabaseManager
EventStore --> EventBus : publishes after commit
ProjectionStore --> SessionStore : hydrate via repositories
ProjectionStore --> EventBus : subscribes to live events
@enduml
```
### Scheduler UML
```plantuml
@startuml
class Scheduler {
+create_tasks(session_id, specs): Promise<void>
+add_dependency(session_id, task_id, dependency): Promise<void>
+load_graph(session_id): Promise<TaskGraph>
+run_until_idle(session_id): Promise<SchedulerRunResult>
+cancel_task(task_id, reason): Promise<void>
-plan_wave(graph): SchedulerWavePlan
-dispatch(wave): Promise<void>
-collect_results(): Promise<void>
}
class TaskGraph {
+tasks: Map<TaskID, TaskNode>
+dependencies: TaskDependencyRecord[]
+getRunnableTasks(): TaskNode[]
+markTerminal(taskId, status): void
}
class WavePlanner {
+plan(graph, resources): SchedulerWavePlan
}
class RetryPlanner {
+decide(task, attempts, error): RetryDecision
}
class WorkspaceManager {
+createWorkspace(plan): Promise<WorkspaceRef>
+mergeWorkspace(workspaceId): Promise<MergeResult>
+cleanupWorkspace(workspaceId): Promise<void>
}
class AgentMonitor {
+recordHeartbeat(event): void
+detectLostAgents(): Promise<AgentLost[]>
+enforceTimeouts(): Promise<void>
}
class WorkerManager {
+spawn(taskSpec, contextPack): Promise<WorkerProcess>
+cancel(agentId, reason): Promise<void>
}
class WorkerProcess {
+agent_id: AgentID
+pid?: number
+send(envelope): void
+on_message(handler): void
}
Scheduler --> TaskGraph
Scheduler --> WavePlanner
Scheduler --> RetryPlanner
Scheduler --> WorkspaceManager
Scheduler --> AgentMonitor
Scheduler --> WorkerManager
Scheduler --> EventStore
Scheduler --> ContextAssembler
WorkerManager --> WorkerProcess
@enduml
```
### Tool/Permission UML
```plantuml
@startuml
class ToolRegistry {
+register(definition, executor): void
+call(name, input, context): Promise<ToolResultEnvelope>
+list(): ToolDefinition[]
}
class PermissionEngine {
+evaluate(request): Promise<PermissionDecision>
+record(decision, context): Promise<void>
}
class PathClassifier {
+classify(path, projectRoot): PathRiskClassification
}
class CommandRiskAnalyzer {
+analyze(command, cwd): CommandRiskAnalysis
}
class CapabilityRegistry {
+discover(): Promise<CapabilityManifestV1[]>
+validate(manifest): Promise<ValidationResult>
+enable(capability_id): Promise<void>
+disable(capability_id): Promise<void>
+register_tools(tool_registry): Promise<void>
}
class DoctorService {
+run(input): Promise<DoctorRunOutput>
+checkCapability(capability): Promise<DoctorIssue[]>
}
ToolRegistry --> PermissionEngine
ToolRegistry --> EventIngestor
ToolRegistry --> ArtifactStore
PermissionEngine --> PathClassifier
PermissionEngine --> CommandRiskAnalyzer
PermissionEngine --> EventIngestor
CapabilityRegistry --> ToolRegistry : registers enabled tools
DoctorService --> CapabilityRegistry : reads manifests/checks dependencies
@enduml
```
### Context/Agent UML
```plantuml
@startuml
class ContextAssembler {
+assemble(input): Promise<AssembledContext>
-loadLayers(profile): Promise<PromptLayer[]>
-fitBudget(context): BudgetFitResult
}
class PromptLayerLoader {
+loadRuntimeInvariant(): PromptLayer
+loadRole(role): PromptLayer
+loadProjectRules(project): PromptLayer[]
}
class MainAgent {
+handleUserMessage(message): Promise<void>
+presentProgress(): Promise<void>
+presentBlocker(blocker): Promise<void>
}
class ArchitectureDesigner {
+assessImpact(change): Promise<ArchitectureImpact>
+updateArchitectureDocs(update): Promise<DocumentUpdate>
}
interface ProviderManager {
+select_model(requirement): Promise<ModelAssignment>
+complete(request): AsyncIterable<ProviderStreamEvent>
}
ContextAssembler --> PromptLayerLoader
MainAgent --> ContextAssembler
MainAgent --> ProviderManager : LLM facade from packages/llm
MainAgent --> Scheduler
ArchitectureDesigner --> ContextAssembler
ArchitectureDesigner --> ProviderManager : LLM facade from packages/llm
ArchitectureDesigner --> EventIngestor
class DebugKnowledgeStore {
+insert(record): Promise<void>
+lookup_by_signature(sig): Promise<DebugRecord[]>
+lookup_by_task(task_id): Promise<DebugRecord[]>
+update(id, patch): Promise<void>
}
class LearnedMemoryStore {
+insert(memory): Promise<void>
+lookup_by_type(type): Promise<LearnedMemory[]>
+update_status(id, status): Promise<void>
+scan_stale(): Promise<LearnedMemory[]>
}
class CompactionPolicy {
+should_compact(messages, budget): boolean
+compact(messages, target): Promise<CompactionResult>
}
ExperienceMinerRole --> LearnedMemoryStore
DebuggerRole --> DebugKnowledgeStore
ContextAssembler --> CompactionPolicy
@enduml
```
## 5. LLM Package Code View
Expected directory:
```text
packages/llm/src/
index.ts
ProviderManager.ts
ModelConfigLoader.ts
CapabilityMatrix.ts
ConversionReport.ts
adapters/
AnthropicAdapter.ts
OpenAICompatibleAdapter.ts
canonical/
AnthropicCanonical.ts
ToolUseConverter.ts
StreamNormalizer.ts
```
### UML
```plantuml
@startuml
interface ProviderAdapter {
+provider_id: string
+list_models(): Promise<ProviderCapabilityMatrix[]>
+validate_model(model_id): Promise<ProviderCapabilityMatrix>
+complete(input): AsyncIterable<ProviderStreamEvent>
+count_tokens?(input): Promise<number>
}
class ProviderManager {
+load_config(): Promise<void>
+select_model(requirement): Promise<ModelAssignment>
+complete(input): AsyncIterable<ProviderStreamEvent>
}
class ModelConfigLoader
class CapabilityMatrixRegistry
class AnthropicAdapter
class OpenAICompatibleAdapter
class AnthropicCanonicalConverter
class StreamNormalizer
ProviderManager --> ProviderAdapter
ProviderManager --> ModelConfigLoader
ProviderManager --> CapabilityMatrixRegistry
AnthropicAdapter ..|> ProviderAdapter
OpenAICompatibleAdapter ..|> ProviderAdapter
OpenAICompatibleAdapter --> AnthropicCanonicalConverter
ProviderAdapter --> StreamNormalizer
@enduml
```
## 6. Toolchain C++ Package Code View
Expected directory:
```text
packages/toolchain-cpp/src/
index.ts
capability.ts
CppToolRegistrar.ts
detect/
CppProjectDetector.ts
build/
CMakeConfigurator.ts
CppBuilder.ts
test/
CppTestRunner.ts
analysis/
CppcheckRunner.ts
ClangdClient.ts
DiagnosticParser.ts
```
### UML
```plantuml
@startuml
class CppToolRegistrar {
+register(toolRegistry): void
}
class CppProjectDetector {
+detect(projectRoot): Promise<CppDetectOutput>
}
class CMakeConfigurator {
+configure(input): Promise<CppCmakeConfigureOutput>
}
class CppBuilder {
+build(input): Promise<CppBuildOutput>
}
class CppTestRunner {
+runTests(input): Promise<CppTestOutput>
}
class CppcheckRunner {
+run(input): Promise<CppcheckOutput>
}
class ClangdClient {
+query(input): Promise<ClangdQueryOutput>
}
class DiagnosticParser {
+parse_compiler_output(output): Diagnostic[]
+semantic_signature(diagnostic): string
}
CppToolRegistrar --> CppProjectDetector
CppToolRegistrar --> CMakeConfigurator
CppToolRegistrar --> CppBuilder
CppToolRegistrar --> CppTestRunner
CppToolRegistrar --> CppcheckRunner
CppToolRegistrar --> ClangdClient
CMakeConfigurator --> DiagnosticParser
CppBuilder --> DiagnosticParser
CppTestRunner --> DiagnosticParser
CppcheckRunner --> DiagnosticParser
@enduml
```
## 7. TUI Package Code View
Expected directory:
```text
packages/tui/src/
index.ts
TuiApp.tsx
ProjectionClient.ts
components/
SessionView.tsx
TaskListView.tsx
AgentStatusView.tsx
ToolRunView.tsx
DiffView.tsx
EvidenceView.tsx
PermissionPrompt.tsx
BlockerReport.tsx
HudView.tsx
theme/
theme.ts
keymap/
keymap.ts
```
### UML
```plantuml
@startuml
class TuiApp {
+start(): void
+stop(): void
}
class ProjectionClient {
+subscribe(handler): Subscription
+snapshot(): ProjectionSnapshot
}
class SessionView
class TaskListView
class AgentStatusView
class ToolRunView
class EvidenceView
class PermissionPrompt
class BlockerReport
class HudView
TuiApp --> ProjectionClient
TuiApp --> SessionView
TuiApp --> TaskListView
TuiApp --> AgentStatusView
TuiApp --> ToolRunView
TuiApp --> EvidenceView
TuiApp --> PermissionPrompt
TuiApp --> BlockerReport
TuiApp --> HudView
@enduml
```
Rules:
1. UI components render projections only.
2. Permission prompts emit user decisions through the narrow runtime UI command API, not private runtime services.
3. UI never mutates domain tables directly.
4. UI never imports `packages/runtime/src/*` private implementation modules.
5. Diff/evidence views must link back to artifact/evidence refs.
## 8. CLI Package Code View
Expected directory:
```text
packages/cli/src/
index.ts
commands/
run.ts
init.ts
doctor.ts
provider.ts
e2e.ts
release.ts
bootstrap/
createRuntime.ts
loadConfig.ts
```
### UML
```plantuml
@startuml
class CliEntrypoint {
+main(argv): Promise<number>
}
class RunCommand
class InitCommand
class DoctorCommand
class ProviderCommand
class E2ECommand
class ReleaseCommand
class RuntimeFactory {
+create(options): Promise<RuntimeApp>
}
CliEntrypoint --> RunCommand
CliEntrypoint --> InitCommand
CliEntrypoint --> DoctorCommand
CliEntrypoint --> ProviderCommand
CliEntrypoint --> E2ECommand
CliEntrypoint --> ReleaseCommand
RunCommand --> RuntimeFactory
InitCommand --> RuntimeFactory
DoctorCommand --> RuntimeFactory
@enduml
```
## 9. Repository Interface Code View
Domain repositories live under `packages/runtime/src/storage/repositories/`.
```plantuml
@startuml
interface SessionRepository
interface MessageRepository
interface EventRepository
interface TaskRepository
interface AgentRepository
interface ToolRunRepository
interface CommandRunRepository
interface ArtifactRepository
interface DiagnosticRepository
interface EvidenceRepository
interface WorkspaceRepository
interface SummaryRepository
interface UiStateRepository
class SessionStore {
+sessions: SessionRepository
+messages: MessageRepository
+events: EventRepository
+tasks: TaskRepository
+agents: AgentRepository
+toolRuns: ToolRunRepository
+commandRuns: CommandRunRepository
+artifacts: ArtifactRepository
+diagnostics: DiagnosticRepository
+evidence: EvidenceRepository
+workspaces: WorkspaceRepository
+summaries: SummaryRepository
+uiState: UiStateRepository
}
@enduml
```
Repositories must be thin persistence adapters. Scheduling, permission, and projection logic must not be hidden inside repositories.
## 10. Worker Role Code View
```plantuml
@startuml
interface WorkerRole {
+run(taskSpec, contextPack, runtime): Promise<WorkerResult>
}
class WorkerRuntime {
+emit(event): void
+callTool(name, input): Promise<ToolResultEnvelope>
+checkpoint(data): Promise<void>
}
class ExecutorRole
class ReviewerRole
class DebuggerRole
class CompactorRole
class ExperienceMinerRole
ExecutorRole ..|> WorkerRole
ReviewerRole ..|> WorkerRole
DebuggerRole ..|> WorkerRole
CompactorRole ..|> WorkerRole
ExperienceMinerRole ..|> WorkerRole
WorkerRole --> WorkerRuntime
@enduml
```
Role constraints:
| Role | Write access | Required output |
|---|---|---|
| Executor | scoped project writes | ExecutorResult in WorkerResult |
| Reviewer | read-only | ReviewerResult |
| Debugger | scoped writes only when assigned | DebuggerResult |
| Compactor | summaries/artifacts only | CompactorResult |
| ExperienceMiner | candidates/rules/skills only when assigned | ExperienceMinerResult |
## 11. State Ownership Rules
| State | Owner | Access rule |
|---|---|---|
| session DB | SessionStore/EventStore | runtime services only |
| live events | EventBus | runtime services publish/subscribe |
| UI projections | ProjectionStore | TUI read only |
| artifacts | ArtifactStore | tools/workers via runtime API |
| evidence refs | EvidenceStore | reports/reviews/debug via runtime API |
| tasks/agents | Scheduler | repositories are storage only |
| permission decisions | PermissionEngine | ToolRegistry requests decisions |
| model config | ProviderManager | runtime/Doctor read through API |
| project rules | ContextAssembler/ProjectStore | workers receive context excerpts |
## 12. Implementation Cut Lines
V1.0.0 Alpha implementation must create public interfaces matching `interface-contracts-v1.md`. Classes may be implemented as functions/modules where idiomatic TypeScript is simpler, but module ownership, dependency direction, and service boundaries must remain intact.
Do not implement:
```text
TUI direct DB access
worker direct SQLite writes
capability direct dependency install
provider adapter changing prompt semantics silently
tool execution without PermissionEngine
repositories containing scheduling policy
```