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:
158
packages/contracts/src/artifact.ts
Executable file
158
packages/contracts/src/artifact.ts
Executable 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[]>
|
||||
}
|
||||
70
packages/contracts/src/capability.ts
Executable file
70
packages/contracts/src/capability.ts
Executable 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
65
packages/contracts/src/error.ts
Executable 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
56
packages/contracts/src/event.ts
Executable 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
|
||||
}
|
||||
66
packages/contracts/src/evidence.ts
Executable file
66
packages/contracts/src/evidence.ts
Executable 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
47
packages/contracts/src/ids.ts
Executable 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
30
packages/contracts/src/index.ts
Executable 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
203
packages/contracts/src/ipc.ts
Executable 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>
|
||||
}
|
||||
124
packages/contracts/src/permission.ts
Executable file
124
packages/contracts/src/permission.ts
Executable 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>
|
||||
}
|
||||
224
packages/contracts/src/platform.ts
Executable file
224
packages/contracts/src/platform.ts
Executable 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
|
||||
}
|
||||
52
packages/contracts/src/project.ts
Executable file
52
packages/contracts/src/project.ts
Executable 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>
|
||||
}
|
||||
290
packages/contracts/src/provider.ts
Executable file
290
packages/contracts/src/provider.ts
Executable 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
105
packages/contracts/src/runtime.ts
Executable 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
302
packages/contracts/src/task.ts
Executable 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
121
packages/contracts/src/tool.ts
Executable 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
214
packages/contracts/src/ui.ts
Executable 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>
|
||||
}
|
||||
167
packages/contracts/src/worker-result.ts
Executable file
167
packages/contracts/src/worker-result.ts
Executable 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[]
|
||||
}
|
||||
Reference in New Issue
Block a user