P0-P8: Full V1.0.0 Alpha implementation + audit reports

Implements 123 tasks across 9 phases (T-001..T-809) totaling 146 source files.

Monorepo (P0):
- 7-package Bun + Turborepo + TypeScript monorepo
- dependency-cruiser enforcing 7 forbidden edges + 5 deep-import rules

Contracts (P0):
- 16 type files (ids/error/event/runtime/ipc/task/worker-result/tool/artifact/evidence/project/provider/permission/ui/capability/platform)

Storage & Events (P1):
- DatabaseManager + MigrationRunner (19 tables, 22 indexes, 5 schema_meta seeds)
- 16 repositories (Repository<T,I,U> pattern, INV-1 status columns via EventStore.project only)
- EventSchemaRegistry (54 durable + 7 ephemeral), EventStore, EventBus, EventIngestor
- Project/Session/Artifact/Evidence stores + 8-step Recovery

Tools & Permission (P2):
- PathClassifier (8 categories), CommandRiskAnalyzer (10 categories), SecretRedactor
- PermissionEngine 6-layer evaluation (capability→profile→task_scope→risk→credential→user_prompt)
- ToolRegistry with 20+ tools across fs/shell/git/project/artifact/context/permission/doctor
- CapabilityManifestValidator + CapabilityRegistry

LLM & Context (P3):
- ModelConfigLoader, CapabilityMatrix, AnthropicCanonicalConverter
- AnthropicAdapter + OpenAICompatibleAdapter
- ProviderManager facade
- PromptLayerLoader (L0/L1/L3/L5), CompactionPolicy, ContextAssembler

Worker IPC & Scheduler (P4):
- WorkerProtocol (NDJSON), WorkerProcess (exit codes 0-5), WorkerManager (spawn/handshake)
- WorkerRuntime (INV-3: IPC only, no direct fs/shell/SQLite)
- 5 worker roles (Executor/Reviewer/Debugger/Compactor/ExperienceMiner)
- TaskGraph, WavePlanner, RetryPlanner, AgentMonitor, WorkspaceManager
- Scheduler (state machine), 8-step Recovery

C++ Toolchain (P5):
- DiagnosticParser, CppProjectDetector, CMakeConfigurator, CppBuilder
- CppTestRunner, CppcheckRunner, ClangdClient
- CppToolRegistrar + capability manifest

Projection & TUI (P6):
- ProjectionStore (hydrate/apply/snapshot/subscribe)
- TuiApp + 8 components (Session/Task/Agent/Tool/Diff/Evidence/Permission/Blocker/Hud)
- ProjectionClient in-process ref

Agents & Knowledge (P7):
- MainAgent, ArchitectureDesigner
- DebugKnowledgeStore + LearnedMemoryStore (single-writer, outbox model)
- Role integration wiring

CLI & Doctor & Release (P8):
- Logger + DeveloperLogEncryptor (AES-256-GCM)
- DoctorService (self_bootstrap first)
- RuntimeApp + ServiceRegistry
- 11 CLI commands: run/init/doctor/provider/resume/compact/history/session/restore/e2e/release
- CliEntrypoint + air<TODO>

Audit (in AirPlan/docs/):
- Deepseek开发阶段审计.md (97 findings)
- Opus开发阶段审计.md (140+ findings, 18 P0 blockers)
- MiniMaxM3开发阶段审计.md (18 P0 blockers, focuses on executability)
- AirPlan/TODO.md (technical debt + 42 TODOs by phase)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
AirCoding
2026-06-02 19:19:55 +08:00
parent 071283df8f
commit a773bac28c
179 changed files with 21855 additions and 0 deletions

View File

@@ -0,0 +1,212 @@
/**
* ContextAssembler - Assembles prompt layers into Anthropic-canonical context
*
* Implements contracts §16; DD §10.1 + §10.2 layer-assembly table.
*
* @module packages/runtime/src/context/ContextAssembler
*/
import type {
AgentType, PromptLayer, BudgetFitResult,
SessionID, ProjectID, AgentID, TaskID, ArtifactID, ISOTimeString
} from '@aircoding/contracts'
import { PromptLayerLoader, createPromptLayerLoader } from './PromptLayerLoader.js'
import { CompactionPolicy, createCompactionPolicy } from './CompactionPolicy.js'
export interface AssembledContext {
messages: AssembledMessage[]
metadata: AssemblyMetadata
}
export interface AssembledMessage {
role: 'system' | 'user' | 'assistant'
content: string
layer?: string
}
export interface AssemblyMetadata {
total_tokens: number
fitted_layers: string[]
omitted_layers: string[]
compaction_requested: boolean
layers_compacted: boolean
omissions: string[]
messages_artifact_id?: string
assembled_at: ISOTimeString
}
export interface AssemblyContext {
session_id: SessionID
project_id: ProjectID
project_root: string
agent_id: AgentID
agent_type: AgentType
task_id?: TaskID
token_budget?: number
additional_layers?: PromptLayer[]
}
export class ContextAssembler {
private loader: PromptLayerLoader
private policy: CompactionPolicy
constructor(loader?: PromptLayerLoader, policy?: CompactionPolicy) {
this.loader = loader || createPromptLayerLoader()
this.policy = policy || createCompactionPolicy()
}
/**
* Assemble context from all layers.
* Returns Anthropic-canonical AssembledContext.
*/
assemble(context: AssemblyContext): AssembledContext {
const token_budget = context.token_budget || 200000
const warnings: string[] = []
// Collect all layers
const layers = this.collect_layers(context)
// Fit into budget
const fit_result = this.policy.fit_to_budget(layers, token_budget)
if (fit_result.omissions.length > 0) {
warnings.push(...fit_result.omissions)
}
// Build messages from fitted layers
const messages = this.build_messages(fit_result.fitted, context)
// Check if compaction is needed
const compaction_check = this.policy.should_compact(layers, fit_result.total_tokens)
return {
messages,
metadata: {
total_tokens: fit_result.total_tokens,
fitted_layers: fit_result.fitted.map(l => l.level),
omitted_layers: fit_result.omitted.map(l => l.level),
compaction_requested: compaction_check.should_compact,
layers_compacted: false,
omissions: fit_result.omissions,
assembled_at: new Date().toISOString() as ISOTimeString
}
}
}
/**
* Collect all layers in order L0-L9.
*/
private collect_layers(context: AssemblyContext): PromptLayer[] {
const layers: PromptLayer[] = []
// L0: Runtime invariants (ALWAYS FIRST, never omitted)
const l0 = this.loader.load_runtime_invariant()
layers.push(l0)
// L1: Role (worker AgentType)
const l1 = this.loader.load_role(context.agent_type)
layers.push(l1)
// L2: Safety - built-in
layers.push({
level: 'safety' as any,
priority: 2,
content: '# Safety Rules\n- Never execute destructive commands\n- Always validate inputs\n- Report errors immediately',
token_estimate: 50
})
// L3: Project rules
const project_rules = this.loader.load_project_rules({
project_id: context.project_id,
project_root: context.project_root
})
layers.push(...project_rules)
// L4: Architecture (if available)
if (context.additional_layers) {
const arch_layers = context.additional_layers.filter(l => l.level === 'architecture')
layers.push(...arch_layers)
}
// L5: Task spec (if task_id provided)
if (context.task_id) {
const task_layers = this.loader.load_task_context(
{
id: context.task_id,
type: 'execute',
title: 'Current Task',
description: 'Task from session context',
acceptance_criteria: ['Task completed successfully']
},
{}
)
layers.push(...task_layers)
}
// TODO(P3): L6 Evidence - load from EvidenceStore (read-only)
// TODO(P3): L7 Conversation - load from SessionStore message history
// TODO(P3): L8 Tool output - load recent tool results from SessionStore
// TODO(P3): L9 User override - load user directives/additional layers
// Add any additional layers
if (context.additional_layers) {
const others = context.additional_layers.filter(l => l.level !== 'architecture')
layers.push(...others)
}
return layers
}
/**
* Build assembled messages from fitted layers.
*/
private build_messages(layers: PromptLayer[], context: AssemblyContext): AssembledMessage[] {
const messages: AssembledMessage[] = []
// System message: L0 + L1 + L2 + L3
const system_content = layers
.filter(l => ['runtime_invariant', 'role', 'safety', 'project_rules'].includes(l.level))
.map(l => l.content)
.join('\n\n---\n\n')
if (system_content) {
messages.push({ role: 'system', content: system_content, layer: 'system' })
}
// Architecture context
const arch_layers = layers.filter(l => l.level === 'architecture')
for (const l of arch_layers) {
messages.push({ role: 'user', content: String(l.content), layer: 'architecture' })
}
// Task spec
const task_layers = layers.filter(l => l.level === 'task_spec')
for (const l of task_layers) {
messages.push({ role: 'user', content: String(l.content), layer: 'task_spec' })
}
// Evidence
const evidence_layers = layers.filter(l => l.level === 'evidence')
for (const l of evidence_layers) {
messages.push({ role: 'user', content: String(l.content), layer: 'evidence' })
}
// Conversation (L7)
const conv_layers = layers.filter(l => l.level === 'conversation')
for (const l of conv_layers) {
messages.push({ role: 'assistant', content: String(l.content), layer: 'conversation' })
}
// Tool output (L8)
const tool_layers = layers.filter(l => l.level === 'tool_output')
for (const l of tool_layers) {
messages.push({ role: 'user', content: `[Tool Output]\n${l.content}`, layer: 'tool_output' })
}
return messages
}
}
export function createContextAssembler(loader?: PromptLayerLoader, policy?: CompactionPolicy): ContextAssembler {
return new ContextAssembler(loader, policy)
}