@kodrunhq/opencode-autopilot 1.5.0 → 1.6.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.
@@ -0,0 +1,164 @@
1
+ /**
2
+ * oc_memory_status tool — inspect memory system state.
3
+ *
4
+ * Shows observation counts, storage size, recent observations,
5
+ * preferences, and per-type breakdowns. Follows the *Core + tool()
6
+ * pattern from create-agent.ts.
7
+ *
8
+ * @module
9
+ */
10
+
11
+ import { Database } from "bun:sqlite";
12
+ import { statSync } from "node:fs";
13
+ import { join } from "node:path";
14
+ import { tool } from "@opencode-ai/plugin";
15
+ import { DB_FILE, MEMORY_DIR, OBSERVATION_TYPES } from "../memory/constants";
16
+ import { getMemoryDb } from "../memory/database";
17
+ import { getAllPreferences } from "../memory/repository";
18
+ import { getGlobalConfigDir } from "../utils/paths";
19
+
20
+ interface MemoryStatusResult {
21
+ readonly stats: {
22
+ readonly totalObservations: number;
23
+ readonly totalProjects: number;
24
+ readonly totalPreferences: number;
25
+ readonly storageSizeKb: number;
26
+ readonly observationsByType: Record<string, number>;
27
+ } | null;
28
+ readonly recentObservations: readonly {
29
+ readonly type: string;
30
+ readonly summary: string;
31
+ readonly createdAt: string;
32
+ readonly confidence: number;
33
+ }[];
34
+ readonly preferences: readonly {
35
+ readonly key: string;
36
+ readonly value: string;
37
+ readonly confidence: number;
38
+ }[];
39
+ readonly error?: string;
40
+ }
41
+
42
+ /**
43
+ * Core function for memory status inspection.
44
+ * Accepts a Database instance for testability (or uses the singleton).
45
+ */
46
+ export function memoryStatusCore(
47
+ _args: { readonly detail?: "summary" | "full" },
48
+ dbOrPath?: Database | string,
49
+ ): MemoryStatusResult {
50
+ let ownedDb: Database | null = null;
51
+ try {
52
+ if (typeof dbOrPath === "string") {
53
+ ownedDb = new Database(dbOrPath);
54
+ }
55
+ const db = dbOrPath instanceof Database ? dbOrPath : (ownedDb ?? getMemoryDb());
56
+
57
+ // Count observations
58
+ const obsCountRow = db.query("SELECT COUNT(*) as cnt FROM observations").get() as {
59
+ cnt: number;
60
+ };
61
+ const totalObservations = obsCountRow.cnt;
62
+
63
+ // Count by type
64
+ const typeRows = db
65
+ .query("SELECT type, COUNT(*) as cnt FROM observations GROUP BY type")
66
+ .all() as Array<{ type: string; cnt: number }>;
67
+
68
+ const observationsByType: Record<string, number> = {};
69
+ for (const t of OBSERVATION_TYPES) {
70
+ observationsByType[t] = 0;
71
+ }
72
+ for (const row of typeRows) {
73
+ observationsByType[row.type] = row.cnt;
74
+ }
75
+
76
+ // Count projects
77
+ const projCountRow = db.query("SELECT COUNT(*) as cnt FROM projects").get() as {
78
+ cnt: number;
79
+ };
80
+ const totalProjects = projCountRow.cnt;
81
+
82
+ // Count preferences
83
+ const prefCountRow = db.query("SELECT COUNT(*) as cnt FROM preferences").get() as {
84
+ cnt: number;
85
+ };
86
+ const totalPreferences = prefCountRow.cnt;
87
+
88
+ // Storage size — derive from actual DB path, not always the global default
89
+ let storageSizeKb = 0;
90
+ try {
91
+ const statPath =
92
+ typeof dbOrPath === "string" && dbOrPath !== ":memory:"
93
+ ? dbOrPath
94
+ : join(getGlobalConfigDir(), MEMORY_DIR, DB_FILE);
95
+ const stat = statSync(statPath);
96
+ storageSizeKb = Math.round(stat.size / 1024);
97
+ } catch {
98
+ // DB might be in-memory or path doesn't exist
99
+ }
100
+
101
+ // Recent observations (last 10)
102
+ const recentRows = db
103
+ .query(
104
+ "SELECT type, summary, created_at, confidence FROM observations ORDER BY created_at DESC LIMIT 10",
105
+ )
106
+ .all() as Array<{
107
+ type: string;
108
+ summary: string;
109
+ created_at: string;
110
+ confidence: number;
111
+ }>;
112
+
113
+ const recentObservations = recentRows.map((row) => ({
114
+ type: row.type,
115
+ summary: row.summary,
116
+ createdAt: row.created_at,
117
+ confidence: row.confidence,
118
+ }));
119
+
120
+ // All preferences
121
+ const allPrefs = getAllPreferences(db);
122
+ const preferences = allPrefs.map((p) => ({
123
+ key: p.key,
124
+ value: p.value,
125
+ confidence: p.confidence,
126
+ }));
127
+
128
+ return {
129
+ stats: {
130
+ totalObservations,
131
+ totalProjects,
132
+ totalPreferences,
133
+ storageSizeKb,
134
+ observationsByType,
135
+ },
136
+ recentObservations,
137
+ preferences,
138
+ };
139
+ } catch (err) {
140
+ const detail = err instanceof Error ? err.message : String(err);
141
+ return {
142
+ stats: null,
143
+ recentObservations: [],
144
+ preferences: [],
145
+ error: `Memory system error: ${detail}`,
146
+ };
147
+ } finally {
148
+ ownedDb?.close();
149
+ }
150
+ }
151
+
152
+ export const ocMemoryStatus = tool({
153
+ description:
154
+ "Show memory system status: observation counts, recent memories, preferences, and storage size.",
155
+ args: {
156
+ detail: tool.schema
157
+ .enum(["summary", "full"])
158
+ .default("summary")
159
+ .describe("Level of detail to show"),
160
+ },
161
+ async execute(args) {
162
+ return JSON.stringify(memoryStatusCore(args), null, 2);
163
+ },
164
+ });