Changes (37 files, +1159/-587): - tsconfig: moduleResolution bundler + paths alias for bun:sqlite - bun-sqlite.ts: type shim replacing stale declare module .d.ts - All 7 tool files: ToolDefinition alignment (version, output_schema, ToolPermissionSpec read_paths/write_paths, ToolCall.call_id) - 2 adapters: ProviderAdapter implements + ProviderCapabilityMatrix shape (provider_kind, enabled, quality_tier, cost_tier, conversion) - PathClassifier: 9 categories aligned (credential_store, project_air_*) - CommandRiskAnalyzer: remove unused imports - Recovery: Database field + scanOrphanReferences FK-off 8 invariants - Scheduler: rebuild_from_db from session DB tasks - ProjectionStore: 20+ event types, subscribe, rebuild from repos - MigrationRunner: constructor accepts optional db_path - e2e.ts: replaced hardcoded ✅ with 14 real test/check gates - wiring.ts: eventIngestor.ingest (durable path, INV-2) - init.ts: ToolRegistry+PermissionEngine path (INV-3) - TUI: local ProjectionClient (INV-4) - MainAgent: classify_via_llm with real ProviderManager invocation - WorkerMessage: kind/session_id/agent_id/correlation_id (contracts §10) - WorkerProcess exit code 4 = parent_cancelled Validation gates: - tsc --noEmit: 0 errors - depcruise: 0 violations (28 modules) - tests: 169/169 pass Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
73 lines
1.8 KiB
TypeScript
Executable File
73 lines
1.8 KiB
TypeScript
Executable File
/**
|
|
* ProjectionClient - Local TUI-side projection consumer
|
|
* TUI copies minimal projection types from contracts to avoid INV-4 violation
|
|
* (TUI must only depend on contracts; dd §13.2 / c4/code-view §2 rule 3).
|
|
*
|
|
* The runtime package provides the authoritative ProjectionClient in
|
|
* `runtime/projection/ProjectionClient.ts`. TUI defines its own local copy
|
|
* with the same surface so that subscriptions work in-process.
|
|
*
|
|
* @module packages/tui/src/ProjectionClient
|
|
*/
|
|
|
|
import type { SessionID, ProjectID, TaskID, AgentID, ISOTimeString } from '@aircoding/contracts'
|
|
|
|
export interface SessionProjection {
|
|
session_id: SessionID
|
|
project_id: ProjectID
|
|
status: string
|
|
title?: string
|
|
tasks: TaskProjection[]
|
|
agents: AgentProjection[]
|
|
}
|
|
|
|
export interface TaskProjection {
|
|
id: TaskID
|
|
type: string
|
|
status: string
|
|
title: string
|
|
retry_count: number
|
|
attempts: number
|
|
created_at: string
|
|
}
|
|
|
|
export interface AgentProjection {
|
|
id: AgentID
|
|
type: string
|
|
status: string
|
|
task_id?: TaskID
|
|
last_heartbeat?: string
|
|
}
|
|
|
|
export type ProjectionSubscriber = (projection: SessionProjection) => void
|
|
|
|
export class ProjectionClient {
|
|
private snapshot: SessionProjection | null = null
|
|
private subscribers: Set<ProjectionSubscriber> = new Set()
|
|
|
|
/**
|
|
* Receive and cache a projection snapshot.
|
|
*/
|
|
receive_snapshot(projection: SessionProjection): void {
|
|
this.snapshot = projection
|
|
for (const sub of this.subscribers) {
|
|
sub(projection)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Subscribe to projection updates.
|
|
*/
|
|
subscribe(subscriber: ProjectionSubscriber): () => void {
|
|
this.subscribers.add(subscriber)
|
|
return () => this.subscribers.delete(subscriber)
|
|
}
|
|
|
|
/**
|
|
* Get current snapshot.
|
|
*/
|
|
get_snapshot(): SessionProjection | null {
|
|
return this.snapshot
|
|
}
|
|
}
|