@kodrunhq/opencode-autopilot 1.16.0 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/inspect.ts +2 -2
- package/package.json +1 -1
- package/src/config/index.ts +29 -0
- package/src/config/migrations.ts +196 -0
- package/src/config/v7.ts +45 -0
- package/src/config.ts +3 -3
- package/src/health/checks.ts +97 -0
- package/src/health/types.ts +1 -1
- package/src/index.ts +25 -2
- package/src/kernel/transaction.ts +48 -0
- package/src/kernel/types.ts +1 -2
- package/src/logging/domains.ts +39 -0
- package/src/logging/forensic-writer.ts +177 -0
- package/src/logging/index.ts +4 -0
- package/src/logging/logger.ts +44 -0
- package/src/logging/performance.ts +59 -0
- package/src/logging/rotation.ts +261 -0
- package/src/logging/types.ts +33 -0
- package/src/memory/capture-utils.ts +149 -0
- package/src/memory/capture.ts +16 -197
- package/src/memory/decay.ts +11 -2
- package/src/memory/injector.ts +4 -1
- package/src/memory/lessons.ts +85 -0
- package/src/memory/observations.ts +177 -0
- package/src/memory/preferences.ts +718 -0
- package/src/memory/projects.ts +83 -0
- package/src/memory/repository.ts +46 -1001
- package/src/memory/retrieval.ts +5 -1
- package/src/observability/context-display.ts +8 -0
- package/src/observability/event-handlers.ts +44 -6
- package/src/observability/forensic-log.ts +10 -2
- package/src/observability/forensic-schemas.ts +9 -1
- package/src/observability/log-reader.ts +20 -1
- package/src/orchestrator/error-context.ts +24 -0
- package/src/orchestrator/handlers/build-utils.ts +118 -0
- package/src/orchestrator/handlers/build.ts +13 -148
- package/src/orchestrator/handlers/retrospective.ts +0 -1
- package/src/orchestrator/lesson-memory.ts +7 -2
- package/src/orchestrator/orchestration-logger.ts +46 -31
- package/src/orchestrator/progress.ts +63 -0
- package/src/review/memory.ts +11 -3
- package/src/review/parse-findings.ts +116 -0
- package/src/review/pipeline.ts +3 -107
- package/src/review/selection.ts +38 -4
- package/src/scoring/time-provider.ts +23 -0
- package/src/tools/doctor.ts +2 -2
- package/src/tools/logs.ts +32 -6
- package/src/tools/orchestrate.ts +11 -9
- package/src/tools/replay.ts +42 -0
- package/src/tools/review.ts +8 -2
- package/src/tools/summary.ts +43 -0
- package/src/utils/random.ts +33 -0
- package/src/ux/session-summary.ts +56 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observation repository operations.
|
|
3
|
+
*
|
|
4
|
+
* Handles observation CRUD, search, and access tracking.
|
|
5
|
+
* Extracted from repository.ts for better module organization.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { Database } from "bun:sqlite";
|
|
11
|
+
import { withTransaction } from "../kernel/transaction";
|
|
12
|
+
import { OBSERVATION_TYPES } from "./constants";
|
|
13
|
+
import { getMemoryDb } from "./database";
|
|
14
|
+
import { observationSchema } from "./schemas";
|
|
15
|
+
import type { Observation, ObservationType } from "./types";
|
|
16
|
+
|
|
17
|
+
/** Resolve optional db parameter to singleton fallback. */
|
|
18
|
+
function resolveDb(db?: Database): Database {
|
|
19
|
+
return db ?? getMemoryDb();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Validate observation type at runtime. */
|
|
23
|
+
function parseObservationType(value: unknown): ObservationType {
|
|
24
|
+
if (typeof value === "string" && (OBSERVATION_TYPES as readonly string[]).includes(value)) {
|
|
25
|
+
return value as ObservationType;
|
|
26
|
+
}
|
|
27
|
+
return "context";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Map a snake_case DB row to camelCase Observation. */
|
|
31
|
+
function rowToObservation(row: Record<string, unknown>): Observation {
|
|
32
|
+
return {
|
|
33
|
+
id: row.id as number,
|
|
34
|
+
projectId: (row.project_id as string) ?? null,
|
|
35
|
+
sessionId: row.session_id as string,
|
|
36
|
+
type: parseObservationType(row.type),
|
|
37
|
+
content: row.content as string,
|
|
38
|
+
summary: row.summary as string,
|
|
39
|
+
confidence: row.confidence as number,
|
|
40
|
+
accessCount: row.access_count as number,
|
|
41
|
+
createdAt: row.created_at as string,
|
|
42
|
+
lastAccessed: row.last_accessed as string,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Insert an observation. Validates via Zod before writing.
|
|
48
|
+
* Returns the observation with the generated id.
|
|
49
|
+
*/
|
|
50
|
+
export function insertObservation(obs: Omit<Observation, "id">, db?: Database): Observation {
|
|
51
|
+
const validated = observationSchema.omit({ id: true }).parse(obs);
|
|
52
|
+
const d = resolveDb(db);
|
|
53
|
+
|
|
54
|
+
return withTransaction(d, () => {
|
|
55
|
+
const row = d
|
|
56
|
+
.query<
|
|
57
|
+
{ id: number },
|
|
58
|
+
[string | null, string, ObservationType, string, string, number, number, string, string]
|
|
59
|
+
>(
|
|
60
|
+
`INSERT INTO observations (project_id, session_id, type, content, summary, confidence, access_count, created_at, last_accessed)
|
|
61
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING id`,
|
|
62
|
+
)
|
|
63
|
+
.get(
|
|
64
|
+
validated.projectId,
|
|
65
|
+
validated.sessionId,
|
|
66
|
+
validated.type,
|
|
67
|
+
validated.content,
|
|
68
|
+
validated.summary,
|
|
69
|
+
validated.confidence,
|
|
70
|
+
validated.accessCount,
|
|
71
|
+
validated.createdAt,
|
|
72
|
+
validated.lastAccessed,
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
if (!row) {
|
|
76
|
+
throw new Error("Failed to insert observation");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return { ...validated, id: row.id };
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Search observations using FTS5 MATCH with BM25 ranking.
|
|
85
|
+
* Filters by projectId (null for user-level observations).
|
|
86
|
+
*/
|
|
87
|
+
export function searchObservations(
|
|
88
|
+
query: string,
|
|
89
|
+
projectId: string | null,
|
|
90
|
+
limit = 20,
|
|
91
|
+
db?: Database,
|
|
92
|
+
): Array<Observation & { ftsRank: number }> {
|
|
93
|
+
const d = resolveDb(db);
|
|
94
|
+
|
|
95
|
+
const projectFilter = projectId === null ? "AND o.project_id IS NULL" : "AND o.project_id = ?";
|
|
96
|
+
const safeFtsQuery = `"${query.replace(/"/g, '""')}"`;
|
|
97
|
+
const params: Array<string | number> =
|
|
98
|
+
projectId === null ? [safeFtsQuery, limit] : [safeFtsQuery, projectId, limit];
|
|
99
|
+
|
|
100
|
+
const rows = d
|
|
101
|
+
.query(
|
|
102
|
+
`SELECT o.*, bm25(observations_fts) as fts_rank
|
|
103
|
+
FROM observations_fts f
|
|
104
|
+
JOIN observations o ON o.id = f.rowid
|
|
105
|
+
WHERE observations_fts MATCH ?
|
|
106
|
+
${projectFilter}
|
|
107
|
+
ORDER BY fts_rank
|
|
108
|
+
LIMIT ?`,
|
|
109
|
+
)
|
|
110
|
+
.all(...params) as Array<Record<string, unknown>>;
|
|
111
|
+
|
|
112
|
+
return rows.map((row) => ({
|
|
113
|
+
...rowToObservation(row),
|
|
114
|
+
ftsRank: row.fts_rank as number,
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Get observations filtered by project_id, ordered by created_at DESC.
|
|
120
|
+
*/
|
|
121
|
+
export function getObservationsByProject(
|
|
122
|
+
projectId: string | null,
|
|
123
|
+
limit = 50,
|
|
124
|
+
db?: Database,
|
|
125
|
+
): readonly Observation[] {
|
|
126
|
+
const d = resolveDb(db);
|
|
127
|
+
|
|
128
|
+
const whereClause = projectId === null ? "WHERE project_id IS NULL" : "WHERE project_id = ?";
|
|
129
|
+
const params: Array<string | number> = projectId === null ? [limit] : [projectId, limit];
|
|
130
|
+
|
|
131
|
+
const rows = d
|
|
132
|
+
.query(`SELECT * FROM observations ${whereClause} ORDER BY created_at DESC LIMIT ?`)
|
|
133
|
+
.all(...params) as Array<Record<string, unknown>>;
|
|
134
|
+
|
|
135
|
+
return rows.map(rowToObservation);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Get recent failure observations for a project.
|
|
140
|
+
*/
|
|
141
|
+
export function getRecentFailureObservations(
|
|
142
|
+
projectId: string,
|
|
143
|
+
limit = 5,
|
|
144
|
+
db?: Database,
|
|
145
|
+
): readonly Observation[] {
|
|
146
|
+
const d = resolveDb(db);
|
|
147
|
+
const rows = d
|
|
148
|
+
.query(
|
|
149
|
+
`SELECT *
|
|
150
|
+
FROM observations
|
|
151
|
+
WHERE project_id = ?
|
|
152
|
+
AND type = 'error'
|
|
153
|
+
ORDER BY created_at DESC, id DESC
|
|
154
|
+
LIMIT ?`,
|
|
155
|
+
)
|
|
156
|
+
.all(projectId, limit) as Array<Record<string, unknown>>;
|
|
157
|
+
return Object.freeze(rows.map(rowToObservation));
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Delete an observation by id.
|
|
162
|
+
*/
|
|
163
|
+
export function deleteObservation(id: number, db?: Database): void {
|
|
164
|
+
const d = resolveDb(db);
|
|
165
|
+
d.run("DELETE FROM observations WHERE id = ?", [id]);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Increment access_count and update last_accessed for an observation.
|
|
170
|
+
*/
|
|
171
|
+
export function updateAccessCount(id: number, db?: Database): void {
|
|
172
|
+
const d = resolveDb(db);
|
|
173
|
+
d.run("UPDATE observations SET access_count = access_count + 1, last_accessed = ? WHERE id = ?", [
|
|
174
|
+
new Date().toISOString(),
|
|
175
|
+
id,
|
|
176
|
+
]);
|
|
177
|
+
}
|