@kodrunhq/opencode-autopilot 1.15.2 → 1.16.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/cli.ts +5 -0
- package/bin/inspect.ts +337 -0
- package/package.json +1 -1
- package/src/agents/autopilot.ts +7 -15
- package/src/health/checks.ts +29 -4
- package/src/index.ts +103 -11
- package/src/inspect/formatters.ts +225 -0
- package/src/inspect/repository.ts +882 -0
- package/src/kernel/database.ts +45 -0
- package/src/kernel/migrations.ts +62 -0
- package/src/kernel/repository.ts +571 -0
- package/src/kernel/schema.ts +122 -0
- package/src/kernel/types.ts +66 -0
- package/src/memory/capture.ts +221 -25
- package/src/memory/database.ts +74 -12
- package/src/memory/index.ts +17 -1
- package/src/memory/project-key.ts +6 -0
- package/src/memory/repository.ts +833 -42
- package/src/memory/retrieval.ts +83 -169
- package/src/memory/schemas.ts +39 -7
- package/src/memory/types.ts +4 -0
- package/src/observability/event-handlers.ts +28 -17
- package/src/observability/event-store.ts +29 -1
- package/src/observability/forensic-log.ts +159 -0
- package/src/observability/forensic-schemas.ts +69 -0
- package/src/observability/forensic-types.ts +10 -0
- package/src/observability/index.ts +21 -27
- package/src/observability/log-reader.ts +142 -111
- package/src/observability/log-writer.ts +41 -83
- package/src/observability/retention.ts +2 -2
- package/src/observability/session-logger.ts +36 -57
- package/src/observability/summary-generator.ts +31 -19
- package/src/observability/types.ts +12 -24
- package/src/orchestrator/contracts/invariants.ts +14 -0
- package/src/orchestrator/contracts/legacy-result-adapter.ts +8 -20
- package/src/orchestrator/fallback/event-handler.ts +47 -3
- package/src/orchestrator/handlers/architect.ts +2 -1
- package/src/orchestrator/handlers/build.ts +55 -97
- package/src/orchestrator/handlers/retrospective.ts +2 -1
- package/src/orchestrator/handlers/types.ts +0 -1
- package/src/orchestrator/lesson-memory.ts +29 -9
- package/src/orchestrator/orchestration-logger.ts +37 -23
- package/src/orchestrator/phase.ts +8 -4
- package/src/orchestrator/state.ts +79 -17
- package/src/projects/database.ts +47 -0
- package/src/projects/repository.ts +264 -0
- package/src/projects/resolve.ts +301 -0
- package/src/projects/schemas.ts +30 -0
- package/src/projects/types.ts +12 -0
- package/src/review/memory.ts +29 -9
- package/src/tools/doctor.ts +26 -2
- package/src/tools/forensics.ts +7 -12
- package/src/tools/logs.ts +6 -5
- package/src/tools/memory-preferences.ts +157 -0
- package/src/tools/memory-status.ts +17 -96
- package/src/tools/orchestrate.ts +97 -81
- package/src/tools/pipeline-report.ts +3 -2
- package/src/tools/quick.ts +2 -2
- package/src/tools/review.ts +39 -6
- package/src/tools/session-stats.ts +3 -2
- package/src/utils/paths.ts +20 -1
package/src/tools/doctor.ts
CHANGED
|
@@ -39,9 +39,33 @@ async function detectContractHealth(projectRoot?: string): Promise<ContractHealt
|
|
|
39
39
|
const artifactDir = getProjectArtifactDir(projectRoot);
|
|
40
40
|
const logPath = join(artifactDir, "orchestration.jsonl");
|
|
41
41
|
const content = await readFile(logPath, "utf-8");
|
|
42
|
+
const entries = content
|
|
43
|
+
.split("\n")
|
|
44
|
+
.map((line) => line.trim())
|
|
45
|
+
.filter(Boolean)
|
|
46
|
+
.map((line) => {
|
|
47
|
+
try {
|
|
48
|
+
return JSON.parse(line) as Record<string, unknown>;
|
|
49
|
+
} catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
.filter((entry): entry is Record<string, unknown> => entry !== null);
|
|
54
|
+
const legacyTasksFallbackSeen =
|
|
55
|
+
entries.some(
|
|
56
|
+
(entry) =>
|
|
57
|
+
typeof entry.message === "string" &&
|
|
58
|
+
entry.message.includes("PLAN fallback: parsed legacy tasks.md"),
|
|
59
|
+
) || content.includes("PLAN fallback: parsed legacy tasks.md");
|
|
60
|
+
const legacyResultParserSeen =
|
|
61
|
+
entries.some(
|
|
62
|
+
(entry) =>
|
|
63
|
+
typeof entry.message === "string" &&
|
|
64
|
+
entry.message.includes("Legacy result parser path used"),
|
|
65
|
+
) || content.includes("Legacy result parser path used");
|
|
42
66
|
return {
|
|
43
|
-
legacyTasksFallbackSeen
|
|
44
|
-
legacyResultParserSeen
|
|
67
|
+
legacyTasksFallbackSeen,
|
|
68
|
+
legacyResultParserSeen,
|
|
45
69
|
};
|
|
46
70
|
} catch {
|
|
47
71
|
return {
|
package/src/tools/forensics.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
2
|
-
import { join } from "node:path";
|
|
3
1
|
import { tool } from "@opencode-ai/plugin";
|
|
2
|
+
import { readForensicEvents } from "../observability/forensic-log";
|
|
4
3
|
import { loadState } from "../orchestrator/state";
|
|
5
4
|
import { getProjectArtifactDir } from "../utils/paths";
|
|
6
5
|
|
|
@@ -23,16 +22,12 @@ function getSuggestedAction(failedPhase: string, recoverable: boolean): "resume"
|
|
|
23
22
|
return "resume";
|
|
24
23
|
}
|
|
25
24
|
|
|
26
|
-
async function readRecentContractEvents(
|
|
25
|
+
async function readRecentContractEvents(projectRoot: string): Promise<readonly string[]> {
|
|
27
26
|
try {
|
|
28
|
-
const
|
|
29
|
-
const lines = raw
|
|
30
|
-
.split("\n")
|
|
31
|
-
.map((line) => line.trim())
|
|
32
|
-
.filter(Boolean)
|
|
33
|
-
.slice(-120);
|
|
27
|
+
const events = (await readForensicEvents(projectRoot)).slice(-120);
|
|
34
28
|
const codes = new Set<string>();
|
|
35
|
-
for (const
|
|
29
|
+
for (const event of events) {
|
|
30
|
+
const searchable = `${String(event.code ?? "")} ${String(event.message ?? "")} ${JSON.stringify(event.payload ?? {})}`;
|
|
36
31
|
for (const code of [
|
|
37
32
|
"E_INVALID_RESULT",
|
|
38
33
|
"E_STALE_RESULT",
|
|
@@ -42,7 +37,7 @@ async function readRecentContractEvents(artifactDir: string): Promise<readonly s
|
|
|
42
37
|
"E_BUILD_TASK_ID_REQUIRED",
|
|
43
38
|
"E_BUILD_UNKNOWN_TASK",
|
|
44
39
|
]) {
|
|
45
|
-
if (
|
|
40
|
+
if (searchable.includes(code)) {
|
|
46
41
|
codes.add(code);
|
|
47
42
|
}
|
|
48
43
|
}
|
|
@@ -98,7 +93,7 @@ export async function forensicsCore(
|
|
|
98
93
|
const recoverable = isRecoverable(failureContext.failedPhase);
|
|
99
94
|
const suggestedAction = getSuggestedAction(failureContext.failedPhase, recoverable);
|
|
100
95
|
const phasesCompleted = state.phases.filter((p) => p.status === "DONE").map((p) => p.name);
|
|
101
|
-
const deterministicErrorCodes = await readRecentContractEvents(
|
|
96
|
+
const deterministicErrorCodes = await readRecentContractEvents(projectRoot);
|
|
102
97
|
|
|
103
98
|
return JSON.stringify({
|
|
104
99
|
failedPhase: failureContext.failedPhase,
|
package/src/tools/logs.ts
CHANGED
|
@@ -79,9 +79,10 @@ export async function logsCore(
|
|
|
79
79
|
options?: LogsOptions,
|
|
80
80
|
logsDir?: string,
|
|
81
81
|
): Promise<string> {
|
|
82
|
+
const logsRoot = logsDir ?? process.cwd();
|
|
82
83
|
switch (mode) {
|
|
83
84
|
case "list": {
|
|
84
|
-
const sessions = await listSessionLogs(
|
|
85
|
+
const sessions = await listSessionLogs(logsRoot);
|
|
85
86
|
|
|
86
87
|
return JSON.stringify({
|
|
87
88
|
action: "logs_list",
|
|
@@ -92,8 +93,8 @@ export async function logsCore(
|
|
|
92
93
|
|
|
93
94
|
case "detail": {
|
|
94
95
|
const log = options?.sessionID
|
|
95
|
-
? await readSessionLog(options.sessionID,
|
|
96
|
-
: await readLatestSessionLog(
|
|
96
|
+
? await readSessionLog(options.sessionID, logsRoot)
|
|
97
|
+
: await readLatestSessionLog(logsRoot);
|
|
97
98
|
|
|
98
99
|
if (!log) {
|
|
99
100
|
const target = options?.sessionID
|
|
@@ -117,8 +118,8 @@ export async function logsCore(
|
|
|
117
118
|
|
|
118
119
|
case "search": {
|
|
119
120
|
const log = options?.sessionID
|
|
120
|
-
? await readSessionLog(options.sessionID,
|
|
121
|
-
: await readLatestSessionLog(
|
|
121
|
+
? await readSessionLog(options.sessionID, logsRoot)
|
|
122
|
+
: await readLatestSessionLog(logsRoot);
|
|
122
123
|
|
|
123
124
|
if (!log) {
|
|
124
125
|
const target = options?.sessionID
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import type { Database } from "bun:sqlite";
|
|
2
|
+
import { tool } from "@opencode-ai/plugin";
|
|
3
|
+
import {
|
|
4
|
+
deletePreferenceRecord,
|
|
5
|
+
deletePreferencesByKey,
|
|
6
|
+
getMemoryDb,
|
|
7
|
+
prunePreferenceEvidence,
|
|
8
|
+
prunePreferences,
|
|
9
|
+
} from "../memory";
|
|
10
|
+
import { resolveProjectIdentitySync } from "../projects/resolve";
|
|
11
|
+
|
|
12
|
+
type PreferenceScopeArg = "global" | "project";
|
|
13
|
+
type PreferenceStatusArg = "candidate" | "confirmed" | "rejected" | "unconfirmed" | "any";
|
|
14
|
+
|
|
15
|
+
interface MemoryPreferencesArgs {
|
|
16
|
+
readonly subcommand: "delete" | "prune" | "prune-evidence";
|
|
17
|
+
readonly id?: string;
|
|
18
|
+
readonly key?: string;
|
|
19
|
+
readonly scope?: PreferenceScopeArg;
|
|
20
|
+
readonly olderThanDays?: number;
|
|
21
|
+
readonly status?: PreferenceStatusArg;
|
|
22
|
+
readonly keepLatestPerPreference?: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function resolveProjectId(projectRoot: string, db: Database): string | null {
|
|
26
|
+
const resolved = resolveProjectIdentitySync(projectRoot, {
|
|
27
|
+
db,
|
|
28
|
+
allowCreate: false,
|
|
29
|
+
});
|
|
30
|
+
return resolved.id.startsWith("project:") ? null : resolved.id;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function memoryPreferencesCore(
|
|
34
|
+
args: MemoryPreferencesArgs,
|
|
35
|
+
projectRoot: string,
|
|
36
|
+
db?: Database,
|
|
37
|
+
): string {
|
|
38
|
+
try {
|
|
39
|
+
const resolvedDb = db ?? getMemoryDb();
|
|
40
|
+
const scope = args.scope ?? "global";
|
|
41
|
+
const projectId = scope === "project" ? resolveProjectId(projectRoot, resolvedDb) : null;
|
|
42
|
+
|
|
43
|
+
if (scope === "project" && projectId === null) {
|
|
44
|
+
return JSON.stringify({
|
|
45
|
+
error: "no_project_preferences",
|
|
46
|
+
message: "No known project identity for current directory.",
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
switch (args.subcommand) {
|
|
51
|
+
case "delete": {
|
|
52
|
+
if (typeof args.id === "string" && args.id.trim().length > 0) {
|
|
53
|
+
return JSON.stringify({
|
|
54
|
+
ok: true,
|
|
55
|
+
subcommand: "delete",
|
|
56
|
+
result: deletePreferenceRecord(args.id, resolvedDb),
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
if (typeof args.key === "string" && args.key.trim().length > 0) {
|
|
60
|
+
return JSON.stringify({
|
|
61
|
+
ok: true,
|
|
62
|
+
subcommand: "delete",
|
|
63
|
+
result: deletePreferencesByKey(args.key, { scope, projectId }, resolvedDb),
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return JSON.stringify({
|
|
67
|
+
error: "id_or_key_required",
|
|
68
|
+
message: "delete requires either id or key.",
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
case "prune": {
|
|
73
|
+
if (typeof args.olderThanDays !== "number" || args.olderThanDays <= 0) {
|
|
74
|
+
return JSON.stringify({
|
|
75
|
+
error: "older_than_days_required",
|
|
76
|
+
message: "prune requires olderThanDays > 0.",
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return JSON.stringify({
|
|
80
|
+
ok: true,
|
|
81
|
+
subcommand: "prune",
|
|
82
|
+
result: prunePreferences(
|
|
83
|
+
{
|
|
84
|
+
olderThanDays: args.olderThanDays,
|
|
85
|
+
scope,
|
|
86
|
+
projectId,
|
|
87
|
+
status: args.status ?? "unconfirmed",
|
|
88
|
+
},
|
|
89
|
+
resolvedDb,
|
|
90
|
+
),
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
case "prune-evidence": {
|
|
95
|
+
if (typeof args.olderThanDays !== "number" || args.olderThanDays <= 0) {
|
|
96
|
+
return JSON.stringify({
|
|
97
|
+
error: "older_than_days_required",
|
|
98
|
+
message: "prune-evidence requires olderThanDays > 0.",
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
return JSON.stringify({
|
|
102
|
+
ok: true,
|
|
103
|
+
subcommand: "prune-evidence",
|
|
104
|
+
result: prunePreferenceEvidence(
|
|
105
|
+
{
|
|
106
|
+
olderThanDays: args.olderThanDays,
|
|
107
|
+
keepLatestPerPreference: args.keepLatestPerPreference,
|
|
108
|
+
scope,
|
|
109
|
+
projectId,
|
|
110
|
+
status: args.status ?? "any",
|
|
111
|
+
},
|
|
112
|
+
resolvedDb,
|
|
113
|
+
),
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
} catch (error: unknown) {
|
|
118
|
+
return JSON.stringify({
|
|
119
|
+
error: error instanceof Error ? error.message : String(error),
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export const ocMemoryPreferences = tool({
|
|
125
|
+
description:
|
|
126
|
+
"Manage learned preferences. Supports delete by id/key and pruning stale preference records or evidence.",
|
|
127
|
+
args: {
|
|
128
|
+
subcommand: tool.schema
|
|
129
|
+
.enum(["delete", "prune", "prune-evidence"])
|
|
130
|
+
.describe("Preference maintenance operation"),
|
|
131
|
+
id: tool.schema.string().optional().describe("Preference record id for delete"),
|
|
132
|
+
key: tool.schema.string().optional().describe("Preference key for delete"),
|
|
133
|
+
scope: tool.schema
|
|
134
|
+
.enum(["global", "project"])
|
|
135
|
+
.default("global")
|
|
136
|
+
.describe("Preference scope filter"),
|
|
137
|
+
olderThanDays: tool.schema
|
|
138
|
+
.number()
|
|
139
|
+
.int()
|
|
140
|
+
.positive()
|
|
141
|
+
.optional()
|
|
142
|
+
.describe("Delete records/evidence older than this many days"),
|
|
143
|
+
status: tool.schema
|
|
144
|
+
.enum(["candidate", "confirmed", "rejected", "unconfirmed", "any"])
|
|
145
|
+
.optional()
|
|
146
|
+
.describe("Preference status filter for prune operations"),
|
|
147
|
+
keepLatestPerPreference: tool.schema
|
|
148
|
+
.number()
|
|
149
|
+
.int()
|
|
150
|
+
.min(0)
|
|
151
|
+
.optional()
|
|
152
|
+
.describe("For prune-evidence, keep this many newest evidence rows per preference"),
|
|
153
|
+
},
|
|
154
|
+
async execute(args) {
|
|
155
|
+
return memoryPreferencesCore(args, process.cwd());
|
|
156
|
+
},
|
|
157
|
+
});
|
|
@@ -2,20 +2,15 @@
|
|
|
2
2
|
* oc_memory_status tool — inspect memory system state.
|
|
3
3
|
*
|
|
4
4
|
* Shows observation counts, storage size, recent observations,
|
|
5
|
-
* preferences, and per-type breakdowns
|
|
6
|
-
*
|
|
5
|
+
* preferences, and per-type breakdowns through the shared inspection
|
|
6
|
+
* query layer.
|
|
7
7
|
*
|
|
8
8
|
* @module
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { Database } from "bun:sqlite";
|
|
12
|
-
import { statSync } from "node:fs";
|
|
13
|
-
import { join } from "node:path";
|
|
11
|
+
import type { Database } from "bun:sqlite";
|
|
14
12
|
import { tool } from "@opencode-ai/plugin";
|
|
15
|
-
import {
|
|
16
|
-
import { getMemoryDb } from "../memory/database";
|
|
17
|
-
import { getAllPreferences } from "../memory/repository";
|
|
18
|
-
import { getGlobalConfigDir } from "../utils/paths";
|
|
13
|
+
import { getMemoryOverview } from "../inspect/repository";
|
|
19
14
|
|
|
20
15
|
interface MemoryStatusResult {
|
|
21
16
|
readonly stats: {
|
|
@@ -47,94 +42,22 @@ export function memoryStatusCore(
|
|
|
47
42
|
_args: { readonly detail?: "summary" | "full" },
|
|
48
43
|
dbOrPath?: Database | string,
|
|
49
44
|
): MemoryStatusResult {
|
|
50
|
-
let ownedDb: Database | null = null;
|
|
51
45
|
try {
|
|
52
|
-
|
|
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
|
-
}));
|
|
46
|
+
const overview = getMemoryOverview(dbOrPath);
|
|
127
47
|
|
|
128
48
|
return {
|
|
129
|
-
stats:
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
},
|
|
136
|
-
|
|
137
|
-
|
|
49
|
+
stats: overview.stats,
|
|
50
|
+
recentObservations: overview.recentObservations.map((row) => ({
|
|
51
|
+
type: row.type,
|
|
52
|
+
summary: row.summary,
|
|
53
|
+
createdAt: row.createdAt,
|
|
54
|
+
confidence: row.confidence,
|
|
55
|
+
})),
|
|
56
|
+
preferences: overview.preferences.map((row) => ({
|
|
57
|
+
key: row.key,
|
|
58
|
+
value: row.value,
|
|
59
|
+
confidence: row.confidence,
|
|
60
|
+
})),
|
|
138
61
|
};
|
|
139
62
|
} catch (err) {
|
|
140
63
|
const detail = err instanceof Error ? err.message : String(err);
|
|
@@ -144,8 +67,6 @@ export function memoryStatusCore(
|
|
|
144
67
|
preferences: [],
|
|
145
68
|
error: `Memory system error: ${detail}`,
|
|
146
69
|
};
|
|
147
|
-
} finally {
|
|
148
|
-
ownedDb?.close();
|
|
149
70
|
}
|
|
150
71
|
}
|
|
151
72
|
|