import type { CorrectionSampleReviewStatus, CorrectionExportMode, SignalConfirmationInput, SignalConfirmationRow, SignalConfirmationStatus, TrajectoryDataStats, TrajectoryAssistantTurnInput, TrajectoryUserTurnInput, TrajectoryToolCallInput, TrajectoryPainEventInput, TrajectoryGateBlockInput, TrajectoryTrustChangeInput, TrajectoryPrincipleEventInput, TrajectoryTaskOutcomeInput, TrajectorySessionInput, EvolutionTaskRecord, EvolutionEventRecord, EvolutionTaskFilters, AssistantTurnRecord, CorrectionSampleRecord, TrajectoryExportResult, TrajectoryDatabaseOptions, RuleHostContextResult, RuleHostEvidenceRow } from './trajectory-types.js'; export type { CorrectionSampleReviewStatus, CorrectionExportMode, TrajectoryDataStats, TrajectoryAssistantTurnInput, TrajectoryUserTurnInput, TrajectoryToolCallInput, TrajectoryPainEventInput, TrajectoryGateBlockInput, DailyMetricRow, TrajectoryTrustChangeInput, TrajectoryPrincipleEventInput, TrajectoryTaskOutcomeInput, TrajectorySessionInput, TaskKind, TaskPriority, EvolutionTaskInput, EvolutionEventInput, EvolutionTaskRecord, EvolutionEventRecord, EvolutionTaskFilters, AssistantTurnRecord, CorrectionSampleRecord, TrajectoryExportResult, TrajectoryDatabaseOptions, RuleHostContextRow, RuleHostContextResult, RuleHostEvidenceRow, } from './trajectory-types.js'; /** * Initialize trajectory.db schema at the given workspace directory. * * Opens trajectory.db in write mode, applies the full schema (tables + indexes + views + * migrations), then closes the DB. Does NOT run importLegacyArtifacts() or * pruneUnreferencedBlobs() — those are runtime side-effects of TrajectoryDatabase * construction and are not needed for pure initialization. * * Idempotent: safe to call on an existing DB; all CREATE statements use IF NOT EXISTS. * * @returns list of created/verified table names and any warnings */ export declare function initTrajectorySchema(workspaceDir: string): { tables: string[]; warnings: string[]; }; export declare class TrajectoryDatabase { private readonly workspaceDir; private readonly stateDir; private readonly dbPath; private readonly blobDir; private readonly exportDir; private readonly blobInlineThresholdBytes; private readonly orphanBlobGraceMs; private readonly db; constructor(opts: TrajectoryDatabaseOptions); dispose(): void; /** * PRI-647: whether the underlying SQLite connection is still open. * * Plugin service stop() (e.g. OpenClaw config hot-reload) calls * TrajectoryRegistry.dispose() which closes this connection without * invalidating a leaked WorkspaceContext handle. Cached owners must check * this before reuse and reacquire a fresh instance instead of returning a * dead connection (previously threw TypeError: The database connection is * not open on every prompt build). */ get isOpen(): boolean; recordSession(input: TrajectorySessionInput): void; recordAssistantTurn(input: TrajectoryAssistantTurnInput): number; recordUserTurn(input: TrajectoryUserTurnInput): number; /** * PRI-788 G1: Stage2 LLM 确认纠正后的标志位回写。user_turns 的第一个(也是 * 唯一)更新 API:以 recordUserTurn 返回的 rowid 精确寻址(rc-7,不重扫)。 * * @returns 是否实际更新了行。false = rowid 不存在(轮次已被清理),调用方 * 应记 SIGNAL_WRITEBACK_MISS 上浮,不得静默。 */ markUserTurnCorrection(rowid: number, cue: string | null): boolean; recordToolCall(input: TrajectoryToolCallInput): number; recordPainEvent(input: TrajectoryPainEventInput): number; recordGateBlock(input: TrajectoryGateBlockInput): void; recordTrustChange(input: TrajectoryTrustChangeInput): void; recordPrincipleEvent(input: TrajectoryPrincipleEventInput): void; recordTaskOutcome(input: TrajectoryTaskOutcomeInput): void; /** * PRI-770: fresh workspaces no longer create the evolution tables (the * writer path was retired with the evolution worker in PRI-737), while * historical workspaces keep theirs. Readers degrade to empty results on a * missing table instead of throwing — the same contract as the SDK readers' * "DB does not exist → empty array" behaviour. This is an expected, * observable state for new workspaces, not a silent failure. */ private evolutionTableMissing; /** * List evolution tasks with optional filtering. * * Returns: Analytics data aggregated from trajectory database. * Not: Runtime truth or real-time queue state. */ listEvolutionTasks(filters?: EvolutionTaskFilters): EvolutionTaskRecord[]; /** * List evolution events for a trace or globally. * * Returns: Analytics data aggregated from trajectory database. * Not: Runtime truth or real-time queue state. */ listEvolutionEvents(traceId?: string, filters?: { limit?: number; offset?: number; }): EvolutionEventRecord[]; /** * Get evolution task by trace ID. * * Returns: Analytics data aggregated from trajectory database. * Not: Runtime truth or real-time queue state. */ getEvolutionTaskByTraceId(traceId: string): EvolutionTaskRecord | null; /** * Get evolution task statistics. * * Returns: Analytics data aggregated from trajectory database. * Not: Runtime truth or real-time queue state. */ getEvolutionStats(): { total: number; pending: number; inProgress: number; completed: number; failed: number; }; /** * List recent sessions from the trajectory database. * * Returns: Recent session records ordered by most recently updated. * * @param options.limit - Maximum number of sessions to return (default: 20) * @param options.dateFrom - Only return sessions updated after this date * @param options.dateTo - Only return sessions updated before this date */ listRecentSessions(options?: { limit?: number; dateFrom?: string; dateTo?: string; }): { sessionId: string; startedAt: string; updatedAt: string; }[]; /** * List assistant turns for a session. * * Returns: Analytics data aggregated from trajectory database. * Not: Runtime truth or real-time queue state. */ listAssistantTurns(sessionId: string): AssistantTurnRecord[]; /** * List tool calls for a session. * * Returns: Analytics data aggregated from trajectory database. * Not: Runtime truth or real-time queue state. */ listToolCallsForSession(sessionId: string): { id: number; toolName: string; outcome: string; filePath: string | null; durationMs: number | null; exitCode: number | null; errorType: string | null; errorMessage: string | null; gfiBefore: number | null; gfiAfter: number | null; resultPreview: string | null; createdAt: string; }[]; /** * PRI-482 Phase 3: Query tool_calls for RuleContext v2 history assembly. * * Reads limit+1 rows (DESC by id) to compute truncated, then reverses to FIFO. * Returns raw rows — the assembler (rule-context-assembler.ts) validates them. * * Spec: §5.1, §5.2. ERR-026: reuses production schema (no hand-written DDL). */ getRuleHostContextRows(sessionId: string, limit?: number): RuleHostContextResult; /** Resolve one Owner-selected tool call without inferring its desired label. */ getRuleHostEvidenceRow(id: number): RuleHostEvidenceRow | null; /** Return FIFO history strictly before an Owner-selected tool call. */ getRuleHostContextRowsBefore(sessionId: string, beforeId: number, limit?: number): RuleHostContextResult; /** * List pain events for a session. * * Returns: Analytics data aggregated from trajectory database. * Not: Runtime truth or real-time queue state. */ listPainEventsForSession(sessionId: string): { id: number; source: string; score: number; reason: string | null; severity: string | null; origin: string | null; confidence: number | null; createdAt: string; }[]; /** * PRI-484 Phase 5 — Look up a single pain event by canonical_pain_id. * * Used by BehaviorExamplePackAssembler to anchor a pain lineage without * already knowing the session_id. Returns null when not found. * * ERR-001 (rc-1, rc-2): row fields validated as unknown — no `as` bypass. * Uses a type-guard predicate to narrow the DB row structurally. */ getPainEventByCanonicalId(canonicalPainId: string): { id: number; sessionId: string; source: string; score: number; reason: string | null; severity: string | null; origin: string | null; confidence: number | null; text: string | null; canonicalPainId: string; runtimeTaskId: string | null; createdAt: string; } | null; /** * List user turns for a session. * Returns bounded fields — `rawExcerpt` is the stored ≤200-char excerpt * (persisted per user_turn), not the full raw text. */ listUserTurnsForSession(sessionId: string): { id: number; turnIndex: number; rawExcerpt: string; correctionDetected: boolean; correctionCue: string | null; createdAt: string; }[]; /** * PRI-844: the most recent correction-flagged user turn of a session, with * the Owner's verbatim words (full raw_text when it was persisted inline; * falls back to the ≤200-char excerpt when the text was offloaded to a * blob). Used by pain producers that only hold a session id (e.g. the * llm_output hook) to attach first-class correction evidence instead of a * trigger excerpt. `maxAgeMs` bounds staleness — a correction from long * before the pain must not be attributed to it. */ getLatestCorrectionTurn(sessionId: string, opts?: { maxAgeMs?: number; nowMs?: number; }): { turnIndex: number; text: string; referencesAssistantTurnId: number | null; occurredAt: string; } | undefined; /** * PRI-844: fetch one user turn by rowid for correction-evidence recovery on * the async confirmation path (the persisted queue stores only a 400-char * excerpt; the full text stays here). Returns undefined when the row is * gone or carries no recoverable text. */ getCorrectionTurnByRowid(rowid: number): { turnIndex: number; text: string; referencesAssistantTurnId: number | null; occurredAt: string; } | undefined; /** * List correction samples with optional review status filter. * * Returns: Analytics data aggregated from trajectory database. * Not: Runtime truth or real-time queue state. */ listCorrectionSamples(status?: CorrectionSampleReviewStatus): CorrectionSampleRecord[]; /** * List correction samples for a specific session. * Returns minimal fields for nocturnal use — correction cue only. * #268: Wire correction_samples into nocturnal pipeline. */ listCorrectionSamplesForSession(sessionId: string): { correctionCue: string | null; }[]; reviewCorrectionSample(sampleId: string, status: Exclude, note?: string): CorrectionSampleRecord; /** * When a correction sample is rejected, emit a pain event to the trajectory. * This feeds rejected corrections into the nocturnal pipeline as a high-fidelity * violation signal (human-verified, unlike heuristic pain detection). */ private recordCorrectionRejectedPain; /** * 入队一条待确认信号。幂等:UNIQUE(user_turn_rowid) 兜底,重复入队是 no-op * (同一轮消息只会在队列里出现一次)。id 由 (sessionId, rowid) 确定性派生。 */ enqueueSignalConfirmation(input: SignalConfirmationInput): void; /** 按 attempts ASC, created_at ASC 取 pending 队列(最久未确认的优先)。 */ listPendingSignalConfirmations(limit: number): SignalConfirmationRow[]; /** 确认失败一次:attempts++(仍 pending,可重试)。返回累加后的 attempts。 */ bumpSignalConfirmationAttempt(id: string): number; /** * 终态转移(confirmed/rejected/abandoned)。乐观锁守卫:仅当仍为 pending 时 * 生效(照 principle_candidates 模式);返回是否实际转移。 */ markSignalConfirmationResult(id: string, status: Exclude, resolution: string): boolean; /** 经济性:pending 总量(健康度指标 G4 用,O(1) 走索引)。 */ countPendingSignalConfirmations(): number; /** * Export correction samples to JSONL file. * * Returns: Analytics data aggregated from trajectory database. * Not: Runtime truth or real-time queue state. */ exportCorrections(opts: { mode: CorrectionExportMode; approvedOnly: boolean; }): TrajectoryExportResult; /** * Export analytics data to JSON file. * * Returns: Analytics data aggregated from trajectory database. * Not: Runtime truth or real-time queue state. */ exportAnalytics(): TrajectoryExportResult; /** * Get trajectory database statistics. * * Returns: Analytics data aggregated from trajectory database. * Not: Runtime truth or real-time queue state. */ getDataStats(): TrajectoryDataStats; cleanupBlobStorage(): { removedFiles: number; reclaimedBytes: number; }; private initSchema; private importLegacyArtifacts; private migrateSchema; /** * Get daily metrics for analytics. * * Returns: Analytics data aggregated from trajectory database. * Not: Runtime truth or real-time queue state. */ private dailyMetrics; private importLegacySessions; private importLegacyEvents; private importLegacyEvolution; private markImported; private isImported; private maybeCreateCorrectionSample; private recordExportAudit; private storeRawText; private restoreRawText; private computeBlobBytes; private pruneUnreferencedBlobs; private withWrite; } export declare class TrajectoryRegistry { private static readonly instances; static get(workspaceDir: string, opts?: Omit): TrajectoryDatabase; static dispose(workspaceDir: string): void; static clear(): void; static use(workspaceDir: string, fn: (_db: TrajectoryDatabase) => T, opts?: Omit): T; }