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

19
packages/contracts/package.json Executable file
View File

@@ -0,0 +1,19 @@
{
"name": "@aircoding/contracts",
"version": "1.0.0-alpha.0",
"private": true,
"type": "module",
"main": "./src/index.ts",
"types": "./src/index.ts",
"exports": {
".": "./src/index.ts"
},
"scripts": {
"typecheck": "tsc --noEmit",
"build": "tsc --build",
"clean": "rm -rf dist tsconfig.tsbuildinfo"
},
"devDependencies": {
"typescript": "^5.8.0"
}
}

View File

@@ -0,0 +1,158 @@
/**
* AirCoding Artifact Contracts
*
* Implements ArtifactRef, ArtifactCreateInput, ArtifactContext, ArtifactReadResult,
* ArtifactStore, DebugKnowledgeStore, LearnedMemoryStore, DebugRecord, LearnedMemory
* per interface-contracts-v1.md §14, §20 and system-detailed-design.md §3.
*/
// Re-export IDs and types needed for these contracts
import type {
ArtifactID,
UUID,
ISOTimeString,
JsonObject,
SessionID,
TaskID,
AgentID,
ToolRunID,
CommandRunID,
} from './ids.js'
export type {
ArtifactID,
UUID,
ISOTimeString,
JsonObject,
SessionID,
TaskID,
AgentID,
ToolRunID,
CommandRunID,
}
// Re-export EntityRef for DebugKnowledgeStore and LearnedMemoryStore
import type { EntityRef } from './event.js'
export type { EntityRef }
// Re-export EvidenceRef for DebugRecord
import type { EvidenceRef } from './evidence.js'
/**
* Reference to a stored artifact.
*/
export interface ArtifactRef {
artifact_id: ArtifactID
uri: string
path: string
type: string
sha256?: string
size_bytes?: number
}
/**
* Input for creating a new artifact.
*/
export interface ArtifactCreateInput {
type: string
original_name?: string
content?: string
source_path?: string
associated_entity_type?: string
associated_entity_id?: string
metadata?: JsonObject
}
/**
* Context information for artifact operations.
*/
export interface ArtifactContext {
session_id: SessionID
task_id?: TaskID
agent_id?: AgentID
tool_run_id?: ToolRunID
command_run_id?: CommandRunID
}
/**
* Result of reading an artifact, including optional content.
*/
export interface ArtifactReadResult {
artifact: ArtifactRef
content?: string | Uint8Array
content_type?: string
}
/**
* Storage interface for artifacts.
*/
export interface ArtifactStore {
create(input: ArtifactCreateInput, context: ArtifactContext): Promise<ArtifactRef>
get(artifact_id: ArtifactID): Promise<ArtifactRef | undefined>
read(artifact_id: ArtifactID): Promise<ArtifactReadResult>
}
// =============================================================================
// Knowledge Store Contracts (merged from knowledge.ts per DD §3)
// =============================================================================
/**
* A debug record capturing failure diagnosis and resolution.
*/
export interface DebugRecord {
debug_record_id: UUID
task_id?: TaskID
failure_signature: string
summary: string
root_cause?: string
fix_ref?: string
evidence_refs?: EvidenceRef[]
verification_refs?: EvidenceRef[]
created_at: ISOTimeString
updated_at: ISOTimeString
metadata_json?: JsonObject
}
/**
* Storage interface for debug knowledge records.
*/
export interface DebugKnowledgeStore {
insert(record: DebugRecord): Promise<void>
lookup_by_signature(failure_signature: string): Promise<DebugRecord[]>
lookup_by_task(task_id: TaskID): Promise<DebugRecord[]>
update(debug_record_id: UUID, patch: Partial<DebugRecord>): Promise<void>
}
/**
* Types of learned memory.
*/
export type LearnedMemoryType = 'project_rule' | 'toolchain_rule' | 'skill_update' | 'debug_experience'
/**
* Status of learned memory.
*/
export type LearnedMemoryStatus = 'candidate' | 'promoted' | 'archived' | 'rejected'
/**
* A learned memory entry capturing project knowledge.
*/
export interface LearnedMemory {
memory_id: UUID
memory_type: LearnedMemoryType
summary: string
content?: string
source_ref?: EntityRef
status: LearnedMemoryStatus
created_at: ISOTimeString
updated_at: ISOTimeString
metadata_json?: JsonObject
}
/**
* Storage interface for learned memory.
*/
export interface LearnedMemoryStore {
insert(memory: LearnedMemory): Promise<void>
lookup_by_type(memory_type: LearnedMemoryType): Promise<LearnedMemory[]>
update_status(memory_id: UUID, status: LearnedMemoryStatus): Promise<void>
scan_stale(): Promise<LearnedMemory[]>
}

View File

@@ -0,0 +1,70 @@
// contracts §18 — Capability Contracts
// File: capability.ts — CapabilityManifestV1, ValidationResult, CapabilityRegistry, trust levels
// Implements: interface-contracts-v1.md §18
import type { CapabilityID, JsonSchema, JsonObject } from "./ids.js"
import type { ToolCategory } from "./tool.js"
import type { ToolPermissionSpec } from "./permission.js"
import type { ToolRegistry } from "./tool.js"
// =============================================================================
// contracts §18 — Capability Contracts
// =============================================================================
/**
* Trust levels for capabilities, ordered from most trusted to least trusted.
* Trust affects default enablement/prompt posture but never bypasses
* ToolRegistry or PermissionEngine.
*/
export type CapabilityTrustLevel =
| "built_in" // Core AirCoding capabilities, always trusted
| "project_local" // Project-scoped capabilities, trusted within project
| "user_installed" // User-installed capabilities, moderate trust
| "verified_publisher" // Third-party from verified publishers
| "untrusted" // Unverified third-party capabilities
export interface CapabilityToolSpec {
name: string
version: number
category: ToolCategory
description: string
input_schema: JsonSchema
output_schema: JsonSchema
streaming?: boolean
permissions: ToolPermissionSpec
}
export interface CapabilityManifestV1 {
schema_version: 1 // Must be exactly 1 per DoD
capability_id: CapabilityID
display_name: string
version: string
description: string
publisher?: string
source: JsonObject
trust_level: CapabilityTrustLevel
tools: CapabilityToolSpec[]
dependencies?: JsonObject[]
permissions: JsonObject
events?: {
produced?: string[]
consumed?: string[]
}
artifact_types?: string[]
config_schema?: JsonSchema
entrypoint?: JsonObject
}
export interface ValidationResult {
ok: boolean
errors: string[]
warnings: string[]
}
export interface CapabilityRegistry {
discover(): Promise<CapabilityManifestV1[]>
validate(manifest: CapabilityManifestV1): Promise<ValidationResult>
enable(capability_id: CapabilityID): Promise<void>
disable(capability_id: CapabilityID): Promise<void>
register_tools(tool_registry: ToolRegistry): Promise<void>
}

65
packages/contracts/src/error.ts Executable file
View File

@@ -0,0 +1,65 @@
// contracts §3 — Error Contracts
// File: error.ts — ErrorKind, ErrorSeverity, Retryability, AirError
import type { UUID, JsonObject } from "./ids.js"
import type { EntityRef } from "./event.js"
export type ErrorKind =
| "user_error"
| "project_error"
| "env_error"
| "dependency_error"
| "permission_error"
| "tool_error"
| "command_error"
| "build_error"
| "test_error"
| "static_analysis_error"
| "debug_error"
| "provider_error"
| "model_capability_error"
| "context_error"
| "agent_error"
| "scheduler_error"
| "workspace_error"
| "merge_error"
| "architecture_error"
| "policy_error"
| "system_error"
| "unknown_error"
export type ErrorSeverity = "info" | "warning" | "error" | "fatal"
export type Retryability = "retryable" | "retryable_after_change" | "not_retryable" | "unknown"
export interface AirError {
error_id: UUID
kind: ErrorKind
severity: ErrorSeverity
message: string
detail?: string
retryability: Retryability
semantic_signature: string
cause_ref?: EntityRef
cause_refs?: EntityRef[]
user_action?: string
metadata?: JsonObject
}
/**
* Pure type-guard for AirError. Dependency-free: only checks structural shape.
* Returns true when the value looks like an AirError (has all required fields
* with the expected types).
*/
export function is_air_error(value: unknown): value is AirError {
if (typeof value !== "object" || value === null) return false
const obj = value as Record<string, unknown>
return (
typeof obj["error_id"] === "string" &&
typeof obj["kind"] === "string" &&
typeof obj["severity"] === "string" &&
typeof obj["message"] === "string" &&
typeof obj["retryability"] === "string" &&
typeof obj["semantic_signature"] === "string"
)
}

56
packages/contracts/src/event.ts Executable file
View File

@@ -0,0 +1,56 @@
// contracts §5 — Runtime Event Contracts
import type { ISOTimeString, UUID, SessionID, ProjectID, TaskID, AgentID, ToolRunID, CommandRunID } from './ids.js'
import type { AgentType } from './runtime.js'
// EntityType and EntityRef (contracts §4)
export type EntityType =
| "session"
| "message"
| "task"
| "agent"
| "tool_run"
| "command_run"
| "artifact"
| "diagnostic"
| "workspace"
| "summary"
| "capability"
| "provider"
export interface EntityRef {
type: EntityType
id: string
}
// EventSource (contracts §5)
export interface EventSource {
kind: "main" | "architecture_designer" | "scheduler" | "agent" | "tool" | "system"
id?: string
agent_type?: AgentType
}
// RuntimeEvent (contracts §5)
export interface RuntimeEvent<TPayload = unknown> {
id: UUID
type: string
version: number
timestamp: ISOTimeString
session_id: SessionID
project_id?: ProjectID
source: EventSource
route: string[]
payload: TPayload
}
// EventFilter (contracts §5)
export interface EventFilter {
session_id?: SessionID
types?: string[]
task_id?: TaskID
agent_id?: AgentID
tool_run_id?: ToolRunID
command_run_id?: CommandRunID
route_prefix?: string[]
since?: ISOTimeString
}

View File

@@ -0,0 +1,66 @@
/**
* AirCoding Evidence Contracts
*
* Implements EvidenceRef, EvidenceCreateInput, EvidenceStore
* per interface-contracts-v1.md §14 and system-detailed-design.md §3.
*/
// Re-export IDs and types needed for these contracts
import type {
EvidenceRefID,
UUID,
ISOTimeString,
JsonObject,
TaskID,
AgentID,
ToolRunID,
CommandRunID,
ArtifactID,
} from './ids.js'
export type {
EvidenceRefID,
UUID,
ISOTimeString,
JsonObject,
TaskID,
AgentID,
ToolRunID,
CommandRunID,
ArtifactID,
}
/**
* Reference to evidence supporting a claim or result.
*/
export interface EvidenceRef {
evidence_ref_id: EvidenceRefID
kind: string
ref: string
claim: string
location_json?: unknown
}
/**
* Input for creating new evidence.
*/
export interface EvidenceCreateInput {
kind: string
ref: string
claim: string
location_json?: unknown
task_id?: TaskID
agent_id?: AgentID
tool_run_id?: ToolRunID
command_run_id?: CommandRunID
artifact_id?: ArtifactID
diagnostic_id?: string
message_id?: string
}
/**
* Storage interface for evidence references.
*/
export interface EvidenceStore {
create(input: EvidenceCreateInput): Promise<EvidenceRef>
list_for_entity(entity_type: string, entity_id: string): Promise<EvidenceRef[]>
}

47
packages/contracts/src/ids.ts Executable file
View File

@@ -0,0 +1,47 @@
// contracts §2 — Core Primitive Types
// File: ids.ts — primitive ID aliases, Clock, IdGenerator
export type ISOTimeString = string
export type UUID = string
export type ProjectID = string
export type SessionID = string
export type MessageID = string
export type TaskID = string
export type AgentID = string
export type ToolRunID = string
export type CommandRunID = string
export type ArtifactID = string
export type EvidenceRefID = string
export type WorkspaceID = string
export type SummaryID = string
export type CapabilityID = string
export type ProviderID = string
export type ModelID = string
export type WaveID = string
export type JsonObject = Record<string, unknown>
export type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue }
// JsonSchema<T> is nominal-only: T provides no compile-time runtime check,
// but documents the expected shape for tool schema consumers.
// The T parameter is retained for documentation purposes but is not used at runtime.
export type JsonSchema<_T = unknown> = JsonObject
export interface Clock {
now(): ISOTimeString
}
export interface IdGenerator {
uuid(): UUID
project_id(): ProjectID
session_id(): SessionID
message_id(): MessageID
task_id(): TaskID
agent_id(): AgentID
tool_run_id(): ToolRunID
command_run_id(): CommandRunID
artifact_id(): ArtifactID
evidence_ref_id(): EvidenceRefID
workspace_id(): WorkspaceID
summary_id(): SummaryID
}

30
packages/contracts/src/index.ts Executable file
View File

@@ -0,0 +1,30 @@
// contracts index - barrel export of all contract modules
// Each module corresponds to a section of interface-contracts-v1.md
export * from './ids' // §2 Core Primitive Types
export * from './error' // §3 Error Contracts
export * from './event' // §5 Runtime Event Contracts
export * from './runtime' // §10 Worker/IPC Contracts (runtime context)
export * from './ipc' // §10 Worker/IPC Contracts
export * from './task' // §9 Task and Scheduler Contracts
export * from './worker-result' // §11 WorkerResult Contracts
export * from './tool' // §12 Tool Contracts + §21 Diagnostic Contracts
export * from './permission' // §13 Permission Contracts
export * from './artifact' // §14 Artifact Contracts
export * from './evidence' // §14 Evidence Contracts
export * from './project' // §8 Project and Session Contracts
// Provider exports - re-export with disambiguation for duplicate names
export type {
ProviderCapabilityMatrix,
ProviderCompletionInput,
ProviderStreamEvent,
ProviderAdapter,
ProviderManager,
ModelRequirement as ProviderModelRequirement,
ModelAssignment as ProviderModelAssignment,
ModelAssignmentMode,
} from './provider'
export * from './ui' // §17 Projection/UI Contracts
export * from './capability' // §18 Capability Contracts
export * from './platform' // §19 Doctor/Logging Contracts + Cross-Platform Matrix

203
packages/contracts/src/ipc.ts Executable file
View File

@@ -0,0 +1,203 @@
// AirCoding V1.0.0 Alpha - IPC Contracts
// Implements: contracts §10 IPC — IpcDirection, IpcEnvelope, IpcKind, IpcMessage, ControlMessage, payloads
// Merges: workers.ts symbols per system-detailed-design.md §3, §8.2
import type {
UUID,
ISOTimeString,
SessionID,
AgentID,
} from './ids.js'
import type { RuntimeEvent } from './event.js'
import type { AirError } from './error.js'
import type { AgentRuntimeContext, ContextPack } from './runtime.js'
// Stub imports for types referenced from contracts §10 that don't exist yet
// These will be replaced with actual imports when the corresponding files are created
import type { TaskSpec } from './task.js'
import type { WorkerResult } from './worker-result.js'
import type { ToolResultEnvelope, ToolEvent, ToolExecutionContext } from './tool.js'
// §10.1 IPC Direction Types
export type IpcDirection = 'parent_to_worker' | 'worker_to_parent'
// §10.2 IPC Envelope
export interface IpcEnvelope<TPayload = unknown> {
id: UUID
direction: IpcDirection
kind: IpcKind
timestamp: ISOTimeString
session_id: SessionID
agent_id: AgentID
correlation_id?: UUID
protocol_version: number
payload: TPayload
}
// §10.3 IPC Message Kinds
export type IpcKind =
| 'control'
| 'event'
| 'log'
| 'tool.call'
| 'tool.result'
| 'tool.stream'
| 'worker.result'
| 'worker.checkpoint'
| 'protocol.error'
// §10.4 IPC Message Union
export type IpcMessage =
| IpcEnvelope<ControlMessage>
| IpcEnvelope<RuntimeEvent>
| IpcEnvelope<LogPayload>
| IpcEnvelope<ToolCallRequest>
| IpcEnvelope<ToolCallResponse>
| IpcEnvelope<ToolStreamPayload>
| IpcEnvelope<WorkerResult>
| IpcEnvelope<WorkerCheckpointPayload>
| IpcEnvelope<ProtocolErrorPayload>
// §10.5 Direction-Typed Messages (per contracts §10)
// ParentToWorkerMessage covers: control, tool.result, tool.stream
export type ParentToWorkerMessage =
| IpcEnvelope<ControlMessage>
| IpcEnvelope<ToolCallResponse>
| IpcEnvelope<ToolStreamPayload>
// WorkerToParentMessage covers: event, log, tool.call, worker.result, worker.checkpoint, protocol.error
export type WorkerToParentMessage =
| IpcEnvelope<RuntimeEvent>
| IpcEnvelope<LogPayload>
| IpcEnvelope<ToolCallRequest>
| IpcEnvelope<WorkerResult>
| IpcEnvelope<WorkerCheckpointPayload>
| IpcEnvelope<ProtocolErrorPayload>
// §10.6 Log Payload
export interface LogPayload {
level: 'debug' | 'info' | 'warn' | 'error'
message: string
data?: unknown
}
// §10.7 Control Messages
export type ControlMessage =
| AgentStartControlMessage
| AgentCancelControlMessage
| AgentPauseControlMessage
| AgentResumeControlMessage
| AgentExtendTimeoutControlMessage
| WorkerReadyControlMessage
export interface AgentStartControlMessage {
type: 'agent.start'
version: 1
task_spec: TaskSpec
context_pack: ContextPack
runtime: AgentRuntimeContext
}
export interface AgentCancelControlMessage {
type: 'agent.cancel'
reason: string
}
export interface AgentPauseControlMessage {
type: 'agent.pause'
reason: string
}
export interface AgentResumeControlMessage {
type: 'agent.resume'
}
export interface AgentExtendTimeoutControlMessage {
type: 'agent.extend_timeout'
extra_ms: number
reason: string
}
export interface WorkerReadyControlMessage {
type: 'worker.ready'
protocol_version: number
worker_version: string
}
// §10.8 Tool Call Request (worker → parent)
export interface ToolCallRequest {
tool_call_id: UUID
tool_name: string
input: unknown
context: ToolExecutionContext
}
// §10.9 Tool Call Response (parent → worker)
export interface ToolCallResponse {
tool_call_id: UUID
result: ToolResultEnvelope
}
// §10.10 Tool Stream Payload
export interface ToolStreamPayload {
tool_call_id: UUID
event: ToolEvent
}
// §10.11 Worker Checkpoint Payload
export interface WorkerCheckpointPayload {
checkpoint_id: UUID
task_id: string // TaskID - using string to avoid import cycle
data: unknown
}
// §10.12 Protocol Error Payload
export interface ProtocolErrorPayload {
error: AirError
received_message_id?: UUID
}
// ===== workers.ts symbols merged per system-detailed-design.md §3, §8.2 =====
/**
* Worker role interface - implemented by worker child processes.
* Each role (ExecutorRole, ReviewerRole, etc.) implements this interface.
* The TResult type parameter specifies the result type for this role.
*/
export interface WorkerRole<TResult = unknown> {
run(
task_spec: TaskSpec,
context_pack: ContextPack,
runtime: WorkerRuntime
): Promise<WorkerResult<TResult>>
}
/**
* Worker runtime - the IPC surface exposed to worker agents.
* Workers use this to communicate with the parent process.
* All filesystem/shell/network access goes through this interface.
*/
export interface WorkerRuntime {
/**
* Emit a runtime event to be ingested by the parent process.
* Events flow through IPC → parent EventIngestor → EventStore/EventBus.
*/
emit(event: RuntimeEvent): Promise<void>
/**
* Call a tool through the parent process.
* The parent handles permission checking, execution, and event emission.
* Returns the tool result envelope with status, output, and any errors.
*/
call_tool<I, O>(
name: string,
input: I
): Promise<ToolResultEnvelope<O>>
/**
* Create a checkpoint with arbitrary data.
* Useful for long-running tasks to save progress.
* Emits a worker.checkpoint IPC message to the parent.
*/
checkpoint(data: unknown): Promise<void>
}

View File

@@ -0,0 +1,124 @@
// contracts §13 — Permission Contracts
// File: permission.ts — PathPolicy, PermissionRequestContext, PermissionAction,
// PermissionGrantScope, PermissionDecision, PermissionRecordResult, PermissionEngine
import type { SessionID, TaskID, AgentID, EvidenceRefID } from './ids.js'
import type { AirError } from './error.js'
// Re-export PathPolicy and ToolPermissionSpec from tool.ts so they are also
// available from this module per the DD §3 file map (PathPolicy canonical
// assignment: permission.ts) and downstream import expectations.
export type { PathPolicy, ToolPermissionSpec } from './tool.js'
// =============================================================================
// §13 — Permission Contracts
// =============================================================================
/**
* Context provided when the ToolRegistry requests a permission evaluation.
* Constructed from ToolExecutionContext + ToolDefinition.permissions + input
* paths/commands per DD §9.1.
*/
export interface PermissionRequestContext {
session_id: SessionID
task_id?: TaskID
agent_id?: AgentID
tool_name?: string
command?: string
paths?: string[]
network?: boolean
requested_action: string
reason: string
}
/**
* Actions the PermissionEngine can return.
* ToolRegistry.call branches on these per DD §9.3:
*
* allow — execute; create backup first if backup_required
* announce_then_run — emit visible notice, then execute unless interrupted;
* bounded by grant_scope
* ask_user — suspend; emit permission.prompt.requested;
* resume on permission.prompt.resolved
* deny — do not execute; return ToolResultEnvelope{status:"error"};
* caller may pick safe path
* block — return blocked outcome → task.blocked upstream
* refuse — return AirError{kind:"policy_error"}; no execution
*/
export type PermissionAction =
| 'allow'
| 'announce_then_run'
| 'ask_user'
| 'deny'
| 'block'
| 'refuse'
/**
* Scope of a permission grant. Determines how long the granted action
* remains valid before re-evaluation is required.
*
* none — no grant (decision is informational only)
* once — valid for this single invocation
* session — valid for the remainder of the session
* project — valid across sessions for this project
* global — valid across all projects for this user
*/
export type PermissionGrantScope =
| 'none'
| 'once'
| 'session'
| 'project'
| 'global'
/**
* Risk levels assigned by the PermissionEngine during evaluation.
* Used by downstream branching logic and UI presentation.
*/
export type PermissionRiskLevel = 'low' | 'medium' | 'high' | 'critical'
/**
* Decision returned by PermissionEngine.evaluate.
* Matches DD §22.1 specification and DD §9.3 branching table.
*
* Layered evaluation order (contracts §13, runtime-semantics §8, overview §12):
* 1. tool capability declaration
* 2. permission profile (permission_template)
* 3. TaskSpec scope allowed/denied paths
* 4. path/command/network risk classification (PathClassifier + CommandRiskAnalyzer)
* 5. credential/system-sensitive override
* 6. user prompt workflow if required
*/
export interface PermissionDecision {
action: PermissionAction
grant_scope: PermissionGrantScope
risk_level: PermissionRiskLevel
reason: string
required_confirmation?: boolean
backup_required?: boolean
evidence_ref_ids?: EvidenceRefID[]
}
/**
* Result of recording a permission decision.
* PermissionEngine.record writes a permission.decision.recorded durable event
* and returns this result; on write failure it returns {ok:false, error}.
*/
export interface PermissionRecordResult {
ok: boolean
error?: AirError
}
/**
* Core permission evaluation engine interface.
* Implements contracts §13, referenced by ToolRegistry (DD §9.1, §9.3).
*
* Invariants (DD §9.2):
* - project-level allow never overrides task scope
* - credential/system-sensitive overrides broad allows
* - paths normalized via realpath before prefix checks
* - .git/ internals protected
*/
export interface PermissionEngine {
evaluate(context: PermissionRequestContext): Promise<PermissionDecision>
record(decision: PermissionDecision, context: PermissionRequestContext): Promise<PermissionRecordResult>
}

View File

@@ -0,0 +1,224 @@
// contracts §19 + cross-platform matrix — Platform Contracts
// File: platform.ts — DoctorService, DoctorRunInput/Output, DoctorIssue, cross-platform tier enums
// Implements: interface-contracts-v1.md §19, cross-platform-matrix-v1.md
// Merged: doctor.ts symbols per DD §3
import type { CapabilityID, ArtifactID } from "./ids.js"
// =============================================================================
// contracts §19 — Doctor Contracts
// =============================================================================
/**
* Doctor run mode determines what actions the doctor service can perform.
*/
export type DoctorRunMode = "read_only" | "fix"
/**
* Doctor run scope determines which capabilities/subsystems to check.
*/
export type DoctorRunScope = "startup" | "project" | "toolchain" | "release_gate"
export interface DoctorRunInput {
mode: DoctorRunMode
scope?: DoctorRunScope
capabilities?: CapabilityID[]
bundle?: boolean
}
export interface DoctorRunOutput {
run_id: string
status: "passed" | "issues_found" | "fixed" | "failed"
issue_count: number
blocking_issue_count: number
report_artifact_id?: ArtifactID
bundle_artifact_id?: ArtifactID
}
/**
* Severity level for doctor issues.
*/
export type DoctorIssueSeverity = "blocking" | "warning" | "info"
/**
* Category for doctor issues, mapping to different subsystems.
*/
export type DoctorIssueCategory =
| "runtime" // Bun runtime, SQLite, basic shell
| "project" // Project initialization, .air directory
| "toolchain" // C++ toolchain (CMake, Ninja, gcc/clang, etc.)
| "permission" // Permission engine, path policy
| "provider" // LLM provider configuration
| "workspace" // Workspace management, git worktree
| "capability" // Capability registry, tool registration
/**
* A single issue discovered by the doctor service.
*/
export interface DoctorIssue {
id: string
severity: DoctorIssueSeverity
category: DoctorIssueCategory
title: string
description: string
fix_suggestion?: string
evidence_refs?: string[]
}
/**
* DoctorService interface for running diagnostic checks.
*/
export interface DoctorService {
run(input: DoctorRunInput): Promise<DoctorRunOutput>
}
// =============================================================================
// contracts §19 — Logging Contracts
// =============================================================================
export interface Logger {
debug(message: string, data?: unknown): void
info(message: string, data?: unknown): void
warn(message: string, data?: unknown): void
error(message: string, data?: unknown): void
}
export interface DeveloperLogEncryptor {
encrypt_log_chunk(chunk: Uint8Array): Promise<Uint8Array>
}
// =============================================================================
// cross-platform-matrix-v1.md — Platform Tier Enums
// =============================================================================
/**
* Platform support levels from cross-platform-matrix-v1.md §1.
*/
export type PlatformSupportLevel =
| "tier_1" // Release-blocking support; tested before release
| "tier_2" // Intended support; best-effort validation
| "experimental" // May work; no compatibility promise
| "unsupported" // Explicit non-target
/**
* Operating system type for platform detection.
*/
export type PlatformOS = "linux" | "darwin" | "windows" | "unknown"
/**
* CPU architecture type for platform detection.
*/
export type PlatformArch = "x64" | "arm64" | "arm" | "unknown"
/**
* Libc type for platform detection.
*/
export type PlatformLibc = "glibc" | "musl" | "unknown"
/**
* Display backend types for GUI evidence collection.
*/
export interface PlatformDisplayBackend {
wayland?: boolean
x11?: boolean
xvfb?: boolean
wslg?: boolean
}
/**
* Platform information contract from cross-platform-matrix-v1.md §10.
*/
export interface PlatformInfo {
os: PlatformOS
arch: PlatformArch
libc?: PlatformLibc
shell?: string
is_wsl?: boolean
display?: PlatformDisplayBackend
package_managers?: string[]
path_case_sensitive?: boolean
}
/**
* Runtime feature support levels for different platforms.
*/
export type RuntimeFeature =
| "bun_runtime"
| "cli"
| "tui"
| "sqlite_session_db"
| "ndjson_child_processes"
| "tool_registry"
| "permission_engine_path_policy"
| "doctor_read_only"
| "doctor_fix"
/**
* C++ toolchain feature support levels.
*/
export type ToolchainFeature =
| "cmake"
| "ninja"
| "make_fallback"
| "gcc_clang"
| "clangd_cli"
| "cppcheck"
| "ctest_googletest"
| "core_dumps_backtrace"
/**
* Filesystem capability support.
*/
export type FilesystemCapability =
| "posix_paths"
| "symlink_realpath"
| "chmod_exec_bits"
| "case_sensitivity"
| "project_local_air"
| "git_worktree"
| "project_outside_backup_repo"
/**
* Shell behavior support.
*/
export type ShellBehavior =
| "bash_sh_commands"
| "process_signals"
| "sudo"
| "package_manager_commands"
| "timeout_kill"
/**
* GUI/Debug/Network evidence support.
*/
export type EvidenceCapability =
| "screenshots"
| "gui_automation"
| "pcaps"
| "core_dumps"
| "debugger_integration"
/**
* Feature tier mapping for runtime features.
* Maps runtime feature to support level per platform.
*/
export interface RuntimeFeatureTier {
feature: RuntimeFeature
linux_x86_64: PlatformSupportLevel
linux_arm64: PlatformSupportLevel
macOS: PlatformSupportLevel
windows_native: PlatformSupportLevel
wsl2: PlatformSupportLevel
}
/**
* Toolchain feature tier mapping.
*/
export interface ToolchainFeatureTier {
feature: ToolchainFeature
linux_x86_64: PlatformSupportLevel
linux_arm64: PlatformSupportLevel
macOS: PlatformSupportLevel
windows_native: PlatformSupportLevel
wsl2: PlatformSupportLevel
}

View File

@@ -0,0 +1,52 @@
// contracts §8 — Project and Session Contracts
// File: project.ts — ProjectContext, ProjectInitOptions, ProjectStore,
// SessionContext, OpenSessionOptions, SessionManager
import type { ProjectID, SessionID, ProviderID, ModelID } from './ids'
// §8.1 ProjectContext — runtime context for an opened AirCoding project
export interface ProjectContext {
project_id: ProjectID
project_root: string
air_root: string
shared_root: string
local_root: string
schema_version: number
}
// §8.2 ProjectInitOptions — options for initializing a new project
export interface ProjectInitOptions {
force?: boolean
title?: string
default_rules?: boolean
}
// §8.3 ProjectStore — locate, initialize, and open projects
export interface ProjectStore {
locate(start_path: string): Promise<ProjectContext | undefined>
initialize(project_root: string, options?: ProjectInitOptions): Promise<ProjectContext>
open(project_root: string): Promise<ProjectContext>
}
// §8.4 SessionContext — runtime context for an open session
export interface SessionContext {
session_id: SessionID
project_id: ProjectID
project_root: string
db_path: string
artifact_root: string
}
// §8.5 OpenSessionOptions — options for opening a session
export interface OpenSessionOptions {
session_id?: SessionID
title?: string
model_provider_id?: ProviderID
model_id?: ModelID
}
// §8.6 SessionManager — open and close sessions
export interface SessionManager {
open_session(project: ProjectContext, options?: OpenSessionOptions): Promise<SessionContext>
close_session(session_id: SessionID): Promise<void>
}

View File

@@ -0,0 +1,290 @@
/**
* AirCoding Provider Contracts
*
* Implements ProviderCapabilityMatrix, ModelRequirement, ProviderCompletionInput,
* ProviderStreamEvent, ProviderAdapter, and ProviderManager interfaces
* per interface-contracts-v1.md §15 and system-detailed-design.md §22.6.
*/
// Import IDs needed for these types
import type {
ProviderID,
ModelID,
JsonObject,
} from './ids'
// =============================================================================
// §15 — Provider Contracts
// =============================================================================
/**
* Provider kind types supported by the system.
* Matches provider-capability-matrix-v1.md §2.
*/
export type ProviderKind =
| 'anthropic'
| 'openai'
| 'openrouter'
| 'ollama'
| 'anthropic_compatible'
| 'openai_compatible'
| 'custom'
/**
* Quality tier classification for models.
*/
export type QualityTier = 'frontier' | 'strong' | 'standard' | 'cheap' | 'local' | 'unknown'
/**
* Cost tier classification for models.
*/
export type CostTier = 'high' | 'medium' | 'low' | 'free' | 'unknown'
/**
* Provider identity - core provider metadata.
* Matches provider-capability-matrix-v1.md §2.
*/
export interface ProviderIdentity {
provider_id: ProviderID
provider_kind: ProviderKind
display_name: string
base_url?: string
auth_ref?: string
local: boolean
}
/**
* Capability matrix for a specific model on a provider.
* Matches interface-contracts-v1.md §15 and provider-capability-matrix-v1.md §3.
*/
export interface ProviderCapabilityMatrix {
provider_id: ProviderID
provider_kind: ProviderKind
model_id: ModelID
display_name?: string
enabled: boolean
quality_tier: QualityTier
cost_tier: CostTier
context_window_tokens?: number
max_output_tokens?: number
supports: ProviderSupports
conversion: ProviderConversion
limits?: ProviderLimits
default_use?: ProviderDefaultUse
notes?: string[]
}
/**
* Supported capabilities for a model.
* Per provider-capability-matrix-v1.md §3.
*/
export interface ProviderSupports {
text_input: boolean
text_output: boolean
streaming: boolean
tool_use: boolean
parallel_tool_use: boolean
structured_output: boolean
json_mode: boolean
thinking: boolean
prompt_cache: boolean
system_prompt: boolean
image_input: boolean
image_output: boolean
audio_input: boolean
audio_output: boolean
file_input: boolean
computer_use: boolean
long_context: boolean
batch: boolean
}
/**
* Conversion behavior for provider adapter.
* Per provider-capability-matrix-v1.md §3.
*/
export interface ProviderConversion {
from_anthropic_canonical: 'lossless' | 'lossy' | 'unsupported'
tool_schema: 'native' | 'converted' | 'emulated' | 'unsupported'
image_input: 'native' | 'artifact_link' | 'unsupported'
thinking: 'native' | 'stripped' | 'unsupported'
cache_control: 'native' | 'ignored' | 'unsupported'
}
/**
* Rate limits for a model.
* Per provider-capability-matrix-v1.md §3.
*/
export interface ProviderLimits {
requests_per_minute?: number
tokens_per_minute?: number
concurrent_requests?: number
max_tool_schema_bytes?: number
max_image_count?: number
max_file_bytes?: number
}
/**
* Default use cases for a model.
* Per provider-capability-matrix-v1.md §3.
*/
export interface ProviderDefaultUse {
main?: boolean
architecture?: boolean
execute?: boolean
review?: boolean
debug?: boolean
compact?: boolean
mine_experience?: boolean
}
/**
* Model requirement specification for task execution.
* Per interface-contracts-v1.md §15 and provider-capability-matrix-v1.md §5.
*/
export interface ModelRequirement {
required: Partial<ProviderSupports>
preferred?: Partial<ProviderSupports>
min_quality_tier?: 'frontier' | 'strong' | 'standard' | 'cheap' | 'local'
max_cost_tier?: 'high' | 'medium' | 'low' | 'free'
min_context_window_tokens?: number
allow_lossy_conversion?: boolean
}
/**
* Model assignment mode - how the model was selected.
* Per provider-capability-matrix-v1.md §6.
*/
export type ModelAssignmentMode = 'scheduler_forced' | 'agent_select'
/**
* Model assignment - the selected model for a task.
* Per interface-contracts-v1.md §9 and §15, and provider-capability-matrix-v1.md §6.
* Note: This is also defined in task.ts for scheduler use - this re-export ensures
* both modules have access to the same type definition.
*/
export interface ModelAssignment {
mode: ModelAssignmentMode
provider_id?: ProviderID
model_id?: ModelID
allowed_models?: Array<{ provider_id: ProviderID; model_id: ModelID }>
requirement: ModelRequirement
reason: string
}
/**
* Input for a provider completion request.
* Per interface-contracts-v1.md §15 and provider-capability-matrix-v1.md §7.
*/
export interface ProviderCompletionInput {
provider_id: ProviderID
model_id: ModelID
canonical_format: 'anthropic'
messages: unknown[]
tools?: unknown[]
tool_choice?: unknown
system?: unknown
max_output_tokens?: number
temperature?: number
metadata?: JsonObject
}
/**
* Stream event types from provider.
* Per interface-contracts-v1.md §15.
*/
export type ProviderStreamEventType =
| 'message_start'
| 'content_delta'
| 'tool_use'
| 'message_stop'
| 'error'
/**
* A stream event from the provider.
* Per interface-contracts-v1.md §15.
*/
export interface ProviderStreamEvent {
type: ProviderStreamEventType
payload: unknown
}
/**
* Conversion report for provider adaptation.
* Per provider-capability-matrix-v1.md §8.
*/
export interface ProviderConversionReport {
status: 'lossless' | 'lossy' | 'unsupported'
omissions: string[]
warnings: string[]
required_confirmation?: boolean
}
/**
* Provider adapter interface - the contract for all LLM provider implementations.
* Per interface-contracts-v1.md §15 and system-detailed-design.md §22.6.
*
* Adapter responsibilities (per provider-capability-matrix-v1.md §7):
* 1. Convert Anthropic canonical messages to provider format.
* 2. Convert provider output back to Anthropic canonical content blocks or RuntimeEvents.
* 3. Validate tool-call and structured-output compatibility.
* 4. Record conversion omissions/losses.
* 5. Never leak credentials into logs, events, artifacts, or model-visible messages.
*/
export interface ProviderAdapter {
/** Unique identifier for this adapter instance */
provider_id: ProviderID
/**
* List all available models for this provider.
* Returns capability matrix for each model.
*/
list_models(): Promise<ProviderCapabilityMatrix[]>
/**
* Validate and get capability matrix for a specific model.
* @throws Error if model is not available
*/
validate_model(model_id: ModelID): Promise<ProviderCapabilityMatrix>
/**
* Execute a completion request.
* Yields stream events as they arrive from the provider.
*/
complete(input: ProviderCompletionInput): AsyncIterable<ProviderStreamEvent>
/**
* Optional: Count tokens for a given input.
* Useful for context budgeting and cost estimation.
*/
count_tokens?(input: unknown): Promise<number>
}
/**
* Provider manager interface - the orchestration layer for model selection and completion.
* Per interface-contracts-v1.md §15 and system-detailed-design.md §12.1.
*
* The ProviderManager is the runtime facade that:
* - Loads and manages provider configuration
* - Selects appropriate models based on requirements
* - Routes completion requests to the appropriate adapter
*/
export interface ProviderManager {
/**
* Load provider configuration from global and project sources.
* Should be called at startup or when configuration changes.
*/
load_config(): Promise<void>
/**
* Select an appropriate model based on requirements.
* @returns ModelAssignment with the selected provider/model
*/
select_model(requirement: ModelRequirement): Promise<ModelAssignment>
/**
* Execute a completion request.
* Yields normalized stream events.
*/
complete(input: ProviderCompletionInput): AsyncIterable<ProviderStreamEvent>
}

105
packages/contracts/src/runtime.ts Executable file
View File

@@ -0,0 +1,105 @@
/**
* AirCoding Runtime Contracts
*
* Implements AgentType, AgentRuntimeContext, ContextPack, and PromptLayer types
* per interface-contracts-v1.md and system-detailed-design.md §3.
*/
// Re-export IDs needed for these types (imported from ids which has no runtime deps)
// Using type-only re-export to avoid circular issues
import type { SessionID, ProjectID, AgentID, TaskID, ArtifactID } from './ids'
export type { SessionID, ProjectID, AgentID, TaskID, ArtifactID }
/**
* Worker agent types - the 5 worker roles that run as child processes.
* Runtime-resident roles (main, architecture_designer, scheduler) are NOT members.
*/
export type AgentType = 'executor' | 'reviewer' | 'debugger' | 'compactor' | 'experience_miner'
/**
* Runtime context passed to worker agents.
* Provides the execution environment and permission boundaries.
*/
export interface AgentRuntimeContext {
session_id: SessionID
project_id: ProjectID
agent_id: AgentID
worktree_path?: string
permission_template: 'main_direct' | 'executor' | 'reviewer' | 'debugger' | 'system'
}
/**
* Context pack assembled by ContextAssembler and sent to workers.
* Contains references to artifacts, plans, and assembled context.
*/
export interface ContextPack {
refs: {
plan_ref?: string
arc_ref?: string
task_refs?: TaskID[]
artifact_refs?: ArtifactID[]
rule_refs?: string[]
}
assembled_context_ref?: ArtifactID
notes?: string[]
}
/**
* Prompt layer levels following prompt-layering-v1 §2.
* Ordered L0-L9 for hierarchical context assembly.
*/
export type PromptLayerLevel =
| 'runtime_invariant' // L0
| 'role' // L1
| 'safety' // L2
| 'project_rules' // L3
| 'architecture' // L4
| 'task_spec' // L5
| 'evidence' // L6
| 'conversation' // L7
| 'tool_output' // L8
| 'user_override' // L9
| 'system_debug' // applied within L9 when present
/**
* A single prompt layer with level, priority, and content.
* Used by ContextAssembler to build the full context.
*/
export interface PromptLayer {
level: PromptLayerLevel
priority: number
content: unknown
token_estimate?: number
source_ref?: string
immutable?: boolean
}
/**
* Result of fitting prompt layers into a token budget.
*/
export interface BudgetFitResult {
fitted: PromptLayer[]
omitted: PromptLayer[]
omissions: string[]
total_tokens: number
}
/**
* Interface for loading prompt layers from external resources.
* Implemented by ContextAssembler or separate loader.
*/
export interface PromptLayerLoader {
load_runtime_invariant(): PromptLayer
load_role(role: AgentType): PromptLayer
load_project_rules(project: { project_id: string; project_root: string }): PromptLayer[]
load_task_context(
spec: {
id: string
type: string
title: string
description: string
acceptance_criteria: string[]
},
context_refs: { plan_ref?: string; arc_ref?: string; artifacts?: string[] }
): PromptLayer[]
}

302
packages/contracts/src/task.ts Executable file
View File

@@ -0,0 +1,302 @@
/**
* AirCoding Task Contracts
*
* Implements TaskType, TaskScope, TaskDependencySpec, VerificationPolicy,
* TaskConstraints, TaskContextRefs, WorkerOutputContract, TaskSpec, TaskGraph,
* Scheduler interfaces, and storage.ts symbols (TransactionManager, Repository)
* per interface-contracts-v1.md §9 and system-detailed-design.md §3.
*/
// Import IDs needed for these types
import type {
SessionID,
TaskID,
AgentID,
ArtifactID,
ProviderID,
ModelID,
WorkspaceID,
WaveID,
UUID,
ISOTimeString,
} from './ids.js'
// Re-export ModelAssignment from provider.ts (canonical definition per DD §3)
// and make it available to this module for scheduler types
import type { ModelAssignment } from './provider.js'
export type { ModelAssignment } from './provider.js'
// =============================================================================
// §9 — Task and Scheduler Contracts
// =============================================================================
/**
* Task types supported by the scheduler and worker system.
* Maps to specific worker roles per DD §8.3.
*/
export type TaskType = 'execute' | 'review' | 'debug' | 'compact' | 'mine_experience' | 'docs'
/**
* Task status lifecycle states.
*/
export type TaskStatus = 'pending' | 'running' | 'completed' | 'failed' | 'blocked' | 'cancelled' | 'interrupted'
/**
* Task dependency types defining relationship semantics.
*/
export type TaskDependencyType = 'hard' | 'soft' | 'conflict' | 'serialization'
/**
* Specification for a task dependency.
*/
export interface TaskDependencySpec {
depends_on_task_id: TaskID
dependency_type: TaskDependencyType
reason?: string
source?: 'architecture' | 'scheduler' | 'worker' | 'user' | 'system'
}
/**
* Defines the scope boundaries for a task's execution.
*/
export interface TaskScope {
write_area?: string
expected_files?: string[]
allowed_paths?: string[]
denied_paths?: string[]
}
/**
* Verification policy for task completion.
*/
export interface VerificationPolicy {
commands?: string[]
required: boolean
fallback_allowed: boolean
}
/**
* Execution constraints for a task.
*/
export interface TaskConstraints {
max_turns: number
soft_timeout_ms: number
hard_timeout_ms: number
retry_budget: number
model_policy: 'scheduler_forced' | 'agent_select'
model_provider_id?: ProviderID
model_id?: ModelID
}
/**
* References to contextual artifacts and other tasks.
*/
export interface TaskContextRefs {
plan_ref?: string
arc_ref?: string
parent_task_results?: ArtifactID[]
artifacts?: ArtifactID[]
}
/**
* Worker output contract types - the result structure each worker type produces.
*/
export type WorkerOutputContract =
| 'ExecutorResult'
| 'ReviewerResult'
| 'DebuggerResult'
| 'CompactorResult'
| 'ExperienceMinerResult'
/**
* Complete task specification for scheduler and workers.
* Matches DD §22.1 specification.
*/
export 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
}
/**
* A task node within the task graph with runtime state.
*/
export interface TaskNode {
task_id: TaskID
spec: TaskSpec
status: TaskStatus
assigned_agent_id?: AgentID
retry_count: number
workspace_id?: WorkspaceID
}
/**
* Task graph representing all tasks and dependencies for a session.
*/
export interface TaskGraph {
session_id: SessionID
tasks: Map<TaskID, TaskNode>
dependencies: Array<{
id: UUID
task_id: TaskID
depends_on_task_id: TaskID
dependency_type: TaskDependencyType
reason?: string
created_at: ISOTimeString
}>
}
/**
* Workspace creation strategy for task execution.
*/
export interface WorkspacePlan {
strategy: 'main' | 'worktree' | 'isolated_copy'
path?: string
base_ref?: string
branch_name?: string
reason: string
}
/**
* Scheduler wave plan - the planned execution wave for one cycle.
*/
export interface SchedulerWavePlan {
wave_id: WaveID
runnable_task_ids: TaskID[]
serialized_task_ids: TaskID[]
workspace_assignments: Record<TaskID, WorkspacePlan>
model_assignments: Record<TaskID, ModelAssignment>
reason: string
}
/**
* Result of a scheduler run.
*/
export interface SchedulerRunResult {
status: 'completed' | 'blocked' | 'cancelled' | 'idle'
completed_task_ids: TaskID[]
blocked_task_ids: TaskID[]
summary: string
}
/**
* Scheduler interface - the orchestration service for task execution.
* Per DD §7.1, the Scheduler is an orchestration service, not a coding agent.
*/
export interface Scheduler {
create_tasks(session_id: SessionID, specs: TaskSpec[]): Promise<void>
add_dependency(session_id: SessionID, task_id: TaskID, dependency: TaskDependencySpec): Promise<void>
load_graph(session_id: SessionID): Promise<TaskGraph>
run_until_idle(session_id: SessionID): Promise<SchedulerRunResult>
cancel_task(task_id: TaskID, reason: string): Promise<void>
}
// =============================================================================
// §6 — Transaction and Storage Contracts (merged from storage.ts per DD §3)
// =============================================================================
/**
* Handle for an active database transaction.
*/
export interface TransactionHandle {
id: string
}
/**
* Handle for an open database connection.
*/
export interface DatabaseHandle {
path: string
}
/**
* Transaction manager interface for database operations.
*/
export interface TransactionManager {
transaction<T>(fn: (tx: TransactionHandle) => Promise<T>): Promise<T>
}
/**
* Generic repository interface for CRUD operations.
* @template TRecord - The record type for the repository
* @template TInsert - The insert type (typically record without auto-generated fields)
* @template TUpdate - The update patch type
*/
export interface Repository<TRecord, TInsert, TUpdate> {
get(id: string, tx?: TransactionHandle): Promise<TRecord | undefined>
insert(record: TInsert, tx?: TransactionHandle): Promise<void>
update(id: string, patch: TUpdate, tx?: TransactionHandle): Promise<void>
}
/**
* Task record as stored in the database.
* Mirrors db-schema §7 columns.
*/
export interface TaskRecord {
id: TaskID
session_id: SessionID
type: TaskType
status: TaskStatus
title: string
task_spec_json: string
worker_result_json?: string
assigned_agent_id?: AgentID
workspace_id?: WorkspaceID
retry_count: number
created_at: ISOTimeString
started_at?: ISOTimeString
completed_at?: ISOTimeString
heartbeat_at?: ISOTimeString
metadata_json?: string
}
/**
* Task insert type - fields required when creating a new task.
* Omits computed/auto fields.
*/
export type TaskInsert = Omit<
TaskRecord,
'retry_count' | 'started_at' | 'completed_at' | 'heartbeat_at' | 'worker_result_json'
> & {
retry_count?: number
}
/**
* Task update patch type.
*/
export type TaskUpdate = Partial<Omit<TaskRecord, 'id' | 'session_id' | 'created_at'>>
/**
* Extended repository interface for task-specific operations.
*/
export interface TaskRepository extends Repository<TaskRecord, TaskInsert, TaskUpdate> {
/**
* List tasks by status filter.
*/
list_by_status(session_id: SessionID, statuses: TaskStatus[], tx?: TransactionHandle): Promise<TaskRecord[]>
/**
* List runnable task candidates - tasks that have all dependencies satisfied.
*/
list_runnable_candidates(session_id: SessionID, tx?: TransactionHandle): Promise<TaskRecord[]>
}
/**
* Task dependency record as stored in the database.
*/
export interface TaskDependencyRecord {
id: UUID
session_id: SessionID
task_id: TaskID
depends_on_task_id: TaskID
dependency_type: TaskDependencyType
reason?: string
created_at: ISOTimeString
}

121
packages/contracts/src/tool.ts Executable file
View File

@@ -0,0 +1,121 @@
// contracts §12 + §21 — Tool Contracts + Diagnostic Contracts
// File: tool.ts — ToolCategory, ToolDefinition, ToolExecutor, StreamingToolExecutor,
// ToolExecutionContext, ToolResultEnvelope, ToolEvent, ToolRegistry, Diagnostic
// Merged: diagnostics.ts symbols per DD §3
import type { JsonSchema, JsonObject, UUID, ISOTimeString, SessionID, ProjectID, TaskID, AgentID, MessageID, ArtifactID, EvidenceRefID, CommandRunID } from "./ids.js"
import type { AirError } from "./error.js"
// =============================================================================
// contracts §12 — Tool Contracts
// =============================================================================
export type ToolCategory =
| "filesystem"
| "shell"
| "git"
| "project"
| "build"
| "test"
| "debug"
| "static_analysis"
| "gui"
| "network"
| "memory"
| "context"
| "artifact"
| "permission"
| "doctor"
| "internal"
export interface ToolPermissionSpec {
read_paths?: PathPolicy
write_paths?: PathPolicy
execute?: boolean
network?: boolean
system_sensitive?: boolean
credentials?: boolean
}
export interface PathPolicy {
allow?: string[]
deny?: string[]
source?: string
}
export interface ToolDefinition<I = unknown, O = unknown> {
name: string
version: number
description: string
input_schema: JsonSchema<I>
output_schema: JsonSchema<O>
category: ToolCategory
permissions: ToolPermissionSpec
streaming: boolean
}
export interface ToolExecutor<I = unknown, O = unknown> {
execute(input: I, context: ToolExecutionContext): Promise<ToolResultEnvelope<O>>
}
export interface StreamingToolExecutor<I = unknown, O = unknown> {
execute_streaming(input: I, context: ToolExecutionContext): AsyncIterable<ToolEvent>
execute_final(input: I, context: ToolExecutionContext): Promise<ToolResultEnvelope<O>>
}
export interface ToolExecutionContext {
session_id: SessionID
project_id: ProjectID
task_id?: TaskID
agent_id?: AgentID
origin_message_id?: MessageID
permission_template: string
cwd?: string
}
export interface ToolResultEnvelope<T = unknown> {
status: "ok" | "error" | "cancelled"
output?: T
error?: AirError
artifact_ids?: ArtifactID[]
evidence_ref_ids?: EvidenceRefID[]
metadata?: JsonObject
}
export interface ToolEvent {
type: "progress" | "artifact" | "result"
payload: unknown
}
export interface ToolRegistry {
register<I, O>(definition: ToolDefinition<I, O>, executor: ToolExecutor<I, O>): void
register_streaming<I, O>(definition: ToolDefinition<I, O>, executor: StreamingToolExecutor<I, O>): void
call<I, O>(name: string, input: I, context: ToolExecutionContext): Promise<ToolResultEnvelope<O>>
call_streaming<I, O>(name: string, input: I, context: ToolExecutionContext): AsyncIterable<ToolEvent | ToolResultEnvelope<O>>
list(): ToolDefinition[]
}
// =============================================================================
// contracts §21 — Diagnostic Contracts
// =============================================================================
export type DiagnosticSeverity = "error" | "warning" | "info" | "hint"
export interface Diagnostic {
diagnostic_id: UUID
task_id?: TaskID
agent_id?: AgentID
command_run_id?: CommandRunID
artifact_id?: ArtifactID
language?: string
toolchain?: string
severity: DiagnosticSeverity
file?: string
line?: number
column?: number
code?: string
message: string
semantic_signature: string
created_at: ISOTimeString
metadata_json?: JsonObject
}

214
packages/contracts/src/ui.ts Executable file
View File

@@ -0,0 +1,214 @@
// contracts §17 — Projection/UI Contracts
// File: ui.ts — all *Projection types, ProjectionSnapshot, ProjectionStore,
// ProjectionClient, UiCommandChannel; projection.ts symbols merged per DD §3.
import type {
SessionID,
TaskID,
AgentID,
ToolRunID,
CommandRunID,
ArtifactID,
ISOTimeString,
} from './ids.js'
import type { RuntimeEvent } from './event.js'
import type { TaskStatus } from './task.js'
import type { AgentType } from './runtime.js'
// Re-export for external consumers of this module
export type {
SessionID,
TaskID,
AgentID,
ToolRunID,
CommandRunID,
ArtifactID,
ISOTimeString,
}
export type { TaskStatus } from './task.js'
export type { AgentType } from './runtime.js'
export type { RuntimeEvent } from './event.js'
// =============================================================================
// §17 — Projection Types
// =============================================================================
/**
* Derived status for CommandRunProjection.
* Matches DD §4.4 derivation:
* completed_at == null -> "running"
* cancellation metadata present -> "cancelled"
* exit_code === 0 -> "ok"
* exit_code != 0 (non-null) -> "error"
* otherwise -> "unknown"
*/
export type CommandRunStatus = 'running' | 'ok' | 'error' | 'cancelled' | 'unknown'
/**
* Pure derivation function for command run status.
* Implements DD §4.4 logic so that CommandRunProjection.status
* never invents a value outside the defined union.
*/
export function derive_command_status(fields: {
completed_at: ISOTimeString | null | undefined
exit_code: number | null | undefined
cancelled: boolean
}): CommandRunStatus {
if (fields.completed_at == null) return 'running'
if (fields.cancelled) return 'cancelled'
if (fields.exit_code === 0) return 'ok'
if (fields.exit_code != null) return 'error'
return 'unknown'
}
export interface SessionProjection {
session_id: SessionID
title?: string
status: string
}
export interface TaskProjection {
task_id: TaskID
title: string
status: TaskStatus
progress_text?: string
}
export interface AgentProjection {
agent_id: AgentID
agent_type: AgentType
status: string
task_id?: TaskID
progress_text?: string
}
export interface ToolRunProjection {
tool_run_id: ToolRunID
tool_name: string
status: string
task_id?: TaskID
}
export interface CommandRunProjection {
command_run_id: CommandRunID
command: string
status: CommandRunStatus
exit_code?: number
}
export interface ArtifactProjection {
artifact_id: ArtifactID
type: string
uri: string
}
export interface PermissionPromptProjection {
prompt_id: string
subject: string
risk_level: string
reason: string
options: string[]
}
export interface BlockerProjection {
task_id?: TaskID
reason: string
required_decision: string
}
// =============================================================================
// §17 — ProjectionSnapshot
// =============================================================================
export interface ProjectionSnapshot {
session?: SessionProjection
tasks: TaskProjection[]
agents: AgentProjection[]
tool_runs: ToolRunProjection[]
command_runs: CommandRunProjection[]
artifacts: ArtifactProjection[]
permission_prompts: PermissionPromptProjection[]
blockers: BlockerProjection[]
updated_at: ISOTimeString
}
// =============================================================================
// §17 — Subscription (re-declared here for projection consumers)
// =============================================================================
/**
* Subscription handle returned by ProjectionStore.subscribe and
* ProjectionClient.subscribe. Mirrors the EventBus Subscription
* contract (§7) for standalone projection consumers.
*/
export interface Subscription {
unsubscribe(): void
}
// =============================================================================
// §17 — ProjectionStore
// =============================================================================
/**
* ProjectionStore.apply handles all durable events and key ephemeral events
* (agent.heartbeat, task.progress, assistant.message.delta, tool.progress,
* command.stdout.delta, command.stderr.delta). Unknown event types are ignored.
*
* command_runs projection status uses the derivation in DD §4.4
* (derive_command_status). ProjectionStore is never a scheduling/recovery
* source of truth (overview §9.3).
*/
export interface ProjectionStore {
hydrate(session_id: SessionID): Promise<void>
apply(event: RuntimeEvent): void
snapshot(): ProjectionSnapshot
subscribe(handler: (snapshot: ProjectionSnapshot) => void): Subscription
}
// =============================================================================
// §17 — ProjectionClient
// =============================================================================
/**
* Read-only client for the TUI. V1 transport: TUI runs in-process with runtime;
* ProjectionClient is a direct interface reference, not IPC.
* TUI may consume only ProjectionClient or projection contracts, never runtime
* internals, SQLite, or EventBus directly.
*/
export interface ProjectionClient {
snapshot(): ProjectionSnapshot
subscribe(handler: (snapshot: ProjectionSnapshot) => void): Subscription
}
// =============================================================================
// §17 — UiCommandChannel
// =============================================================================
/**
* Narrow interface through which the TUI emits user decisions back to the
* runtime. Covers two V1 command types:
*
* - Permission prompt responses (user selects an option for a
* permission.prompt.requested event; runtime emits
* permission.prompt.resolved).
* - Blocker decisions (user resolves a BlockerProjection; runtime
* processes the decision through the scheduler/task system).
*
* Boundary rule (code-view §7): packages/tui may only import from
* packages/contracts, never from packages/runtime/src/*.
*/
export interface UiCommandChannel {
/**
* Resolve a permission prompt by selecting an option.
* The runtime will emit a permission.prompt.resolved durable event
* and resume the suspended tool call.
*/
resolve_permission_prompt(prompt_id: string, selected_option: string): Promise<void>
/**
* Resolve a blocker by providing the user's decision.
* The runtime processes the decision through the task system
* to unblock the affected task.
*/
resolve_blocker(blocker: BlockerProjection, decision: string): Promise<void>
}

View File

@@ -0,0 +1,167 @@
/**
* AirCoding Worker Result Contracts
*
* Implements WorkerStatus, WorkerResult, ExecutorResult, ReviewerResult,
* DebuggerResult, CompactorResult, ExperienceMinerResult, BlockerReport,
* Risk, FollowUpTask per interface-contracts-v1.md §11 and system-detailed-design.md §3.
*/
// Import types needed for these interfaces
import type {
TaskID,
AgentID,
ArtifactID,
EvidenceRefID,
SummaryID,
MessageID,
UUID,
} from './ids.js'
import type { AgentType } from './runtime.js'
import type { ArtifactRef } from './artifact.js'
import type { EvidenceRef } from './evidence.js'
// Re-export for external consumers
export type {
TaskID,
AgentID,
ArtifactID,
EvidenceRefID,
SummaryID,
MessageID,
UUID,
}
export type { AgentType }
export type { ArtifactRef }
export type { EvidenceRef }
/**
* Status values for worker results.
* Per DD §22.1: status ∈ {completed, failed, blocked, cancelled}
*/
export type WorkerStatus = 'completed' | 'failed' | 'blocked' | 'cancelled'
/**
* Result of a verification check performed by a worker.
*/
export interface VerificationResult {
name: string
status: 'passed' | 'failed' | 'skipped' | 'unknown'
evidence_ref_ids?: EvidenceRefID[]
notes?: string
}
/**
* Risk identified during worker execution.
*/
export interface Risk {
severity: 'low' | 'medium' | 'high'
summary: string
}
/**
* Follow-up task created as a result of worker execution.
*/
export interface FollowUpTask {
title: string
description: string
type?: 'execute' | 'review' | 'debug' | 'compact' | 'mine_experience' | 'docs'
}
/**
* Generic worker result container.
* Per DD §22.1: status ∈ {completed, failed, blocked, cancelled}
*/
export interface WorkerResult<TResult = unknown> {
task_id: TaskID
agent_id: AgentID
agent_type: AgentType
status: WorkerStatus
summary: string
changed_files: string[]
diff_ref?: ArtifactID
artifacts: ArtifactRef[]
verification: VerificationResult[]
risks: Risk[]
follow_up_tasks: FollowUpTask[]
evidence_refs: EvidenceRef[]
result: TResult
}
/**
* Result from an Executor worker.
*/
export interface ExecutorResult {
implementation_summary: string
changed_files: string[]
verification_commands: string[]
}
/**
* A single finding from a reviewer.
*/
export interface ReviewFinding {
severity: 'low' | 'medium' | 'high'
category: 'correctness' | 'security' | 'scope' | 'architecture' | 'test' | 'maintainability'
message: string
file?: string
line?: number
evidence_ref_ids?: EvidenceRefID[]
}
/**
* Result from a Reviewer worker.
*/
export interface ReviewerResult {
verdict: 'approved' | 'changes_requested' | 'blocked'
findings: ReviewFinding[]
}
/**
* Report documenting a blocker that prevented task completion.
*/
export interface BlockerReport {
impact_level: 'implementation' | 'interface' | 'architecture' | 'product' | 'permission' | 'environment' | 'policy'
reason: string
required_decision: string
options?: Array<{ label: string; tradeoff: string }>
evidence_ref_ids?: EvidenceRefID[]
suggested_default?: string
}
/**
* Result from a Debugger worker.
*/
export interface DebuggerResult {
diagnosis: string
root_cause?: string
fixed: boolean
blocker?: BlockerReport
}
/**
* Result from a Compactor worker.
*/
export interface CompactorResult {
summary_id: SummaryID
range_start_message_id?: MessageID
range_end_message_id?: MessageID
token_estimate_before?: number
token_estimate_after?: number
}
/**
* A candidate memory extracted by the experience miner.
*/
export interface MemoryCandidate {
candidate_id: UUID
memory_type: 'project_rule' | 'toolchain_rule' | 'skill_update' | 'debug_experience'
summary: string
evidence_ref_ids?: EvidenceRefID[]
}
/**
* Result from an ExperienceMiner worker.
*/
export interface ExperienceMinerResult {
candidates: MemoryCandidate[]
}

View File

@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src"]
}