opencode-memsearch 0.3.0 → 0.5.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/README.md +12 -6
- package/package.json +2 -2
- package/scripts/cli.ts +117 -0
- package/scripts/lib.ts +75 -0
- package/scripts/reindex.ts +135 -0
- package/scripts/seed-memories.ts +14 -72
package/README.md
CHANGED
|
@@ -97,21 +97,27 @@ your-project/
|
|
|
97
97
|
|
|
98
98
|
You should add `.memsearch/` to your `.gitignore`.
|
|
99
99
|
|
|
100
|
-
##
|
|
100
|
+
## CLI
|
|
101
101
|
|
|
102
|
-
The package includes a
|
|
102
|
+
The package includes a CLI for utility tasks. It requires [Bun](https://bun.sh/) to run.
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
```bash
|
|
105
|
+
bunx opencode-memsearch --help
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Seed
|
|
109
|
+
|
|
110
|
+
Backfill memory from existing OpenCode sessions. This is useful when first installing the plugin on a project you've already been working on.
|
|
105
111
|
|
|
106
112
|
```bash
|
|
107
113
|
# Seed from the last 14 days of sessions (default)
|
|
108
|
-
|
|
114
|
+
bunx opencode-memsearch seed
|
|
109
115
|
|
|
110
116
|
# Seed from the last 30 days
|
|
111
|
-
|
|
117
|
+
bunx opencode-memsearch seed --days 30
|
|
112
118
|
```
|
|
113
119
|
|
|
114
|
-
|
|
120
|
+
The command reads directly from the OpenCode SQLite database, processes all sessions across all projects, summarizes each conversation turn, and writes the results to each project's `.memsearch/memory/` directory. It can be run from anywhere. The seed command respects the same [configuration](#configuration) as the plugin (config file and environment variables).
|
|
115
121
|
|
|
116
122
|
## Configuration
|
|
117
123
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-memsearch",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Persistent cross-session memory for OpenCode, powered by memsearch",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
14
|
"bin": {
|
|
15
|
-
"opencode-memsearch
|
|
15
|
+
"opencode-memsearch": "scripts/cli.ts"
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
18
|
"dist",
|
package/scripts/cli.ts
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* opencode-memsearch CLI — utilities for the opencode-memsearch plugin.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* bunx opencode-memsearch <command> [options]
|
|
7
|
+
*
|
|
8
|
+
* Requires Bun (https://bun.sh/) to run.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { seed } from "./seed-memories"
|
|
12
|
+
import { reindex } from "./reindex"
|
|
13
|
+
|
|
14
|
+
const HELP = `opencode-memsearch — CLI utilities for the opencode-memsearch plugin
|
|
15
|
+
|
|
16
|
+
Usage:
|
|
17
|
+
opencode-memsearch <command> [options]
|
|
18
|
+
|
|
19
|
+
Commands:
|
|
20
|
+
seed Backfill memory from existing OpenCode sessions
|
|
21
|
+
reindex Reset and rebuild vector index from existing memory files
|
|
22
|
+
|
|
23
|
+
Options:
|
|
24
|
+
--help, -h Show this help message
|
|
25
|
+
|
|
26
|
+
Run 'opencode-memsearch <command> --help' for command-specific help.`
|
|
27
|
+
|
|
28
|
+
const SEED_HELP = `Seed memsearch memory files from recent OpenCode sessions.
|
|
29
|
+
|
|
30
|
+
Reads all sessions from the OpenCode SQLite database, summarizes each
|
|
31
|
+
conversation turn via an LLM, and writes the results to each project's
|
|
32
|
+
.memsearch/memory/ directory. Processes all projects; can be run from anywhere.
|
|
33
|
+
|
|
34
|
+
Usage:
|
|
35
|
+
opencode-memsearch seed [--days <n>]
|
|
36
|
+
|
|
37
|
+
Options:
|
|
38
|
+
--days <n> Number of days of history to process (default: 14)
|
|
39
|
+
--help, -h Show this help message`
|
|
40
|
+
|
|
41
|
+
const REINDEX_HELP = `Reset and rebuild the vector index from existing memory files.
|
|
42
|
+
|
|
43
|
+
Discovers all project directories from the OpenCode session database,
|
|
44
|
+
resets each memsearch collection, and re-indexes the .memsearch/memory/
|
|
45
|
+
markdown files using the currently configured embedding provider.
|
|
46
|
+
|
|
47
|
+
This is useful after switching embedding providers (e.g. memsearch[local]
|
|
48
|
+
to memsearch[onnx]) — it rebuilds the vector index without re-running the
|
|
49
|
+
expensive LLM summarization from 'seed'.
|
|
50
|
+
|
|
51
|
+
Usage:
|
|
52
|
+
opencode-memsearch reindex [--dry-run]
|
|
53
|
+
|
|
54
|
+
Options:
|
|
55
|
+
--dry-run Preview what would be reset/reindexed without making changes
|
|
56
|
+
--help, -h Show this help message`
|
|
57
|
+
|
|
58
|
+
function parseSeedArgs(args: string[]): { days: number } {
|
|
59
|
+
let days = 14
|
|
60
|
+
for (let i = 0; i < args.length; i++) {
|
|
61
|
+
if (args[i] === "--days" && args[i + 1]) {
|
|
62
|
+
days = parseInt(args[i + 1], 10)
|
|
63
|
+
if (isNaN(days) || days < 1) {
|
|
64
|
+
console.error("Invalid --days value, using default 14")
|
|
65
|
+
days = 14
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return { days }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function parseReindexArgs(args: string[]): { dryRun: boolean } {
|
|
73
|
+
return { dryRun: args.includes("--dry-run") }
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async function main() {
|
|
77
|
+
const args = process.argv.slice(2)
|
|
78
|
+
const command = args[0]
|
|
79
|
+
|
|
80
|
+
if (!command || command === "--help" || command === "-h") {
|
|
81
|
+
console.log(HELP)
|
|
82
|
+
process.exit(0)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
switch (command) {
|
|
86
|
+
case "seed": {
|
|
87
|
+
const subArgs = args.slice(1)
|
|
88
|
+
if (subArgs.includes("--help") || subArgs.includes("-h")) {
|
|
89
|
+
console.log(SEED_HELP)
|
|
90
|
+
process.exit(0)
|
|
91
|
+
}
|
|
92
|
+
const { days } = parseSeedArgs(subArgs)
|
|
93
|
+
await seed({ days })
|
|
94
|
+
break
|
|
95
|
+
}
|
|
96
|
+
case "reindex": {
|
|
97
|
+
const subArgs = args.slice(1)
|
|
98
|
+
if (subArgs.includes("--help") || subArgs.includes("-h")) {
|
|
99
|
+
console.log(REINDEX_HELP)
|
|
100
|
+
process.exit(0)
|
|
101
|
+
}
|
|
102
|
+
const { dryRun } = parseReindexArgs(subArgs)
|
|
103
|
+
await reindex({ dryRun })
|
|
104
|
+
break
|
|
105
|
+
}
|
|
106
|
+
default:
|
|
107
|
+
console.error(`Unknown command: ${command}`)
|
|
108
|
+
console.error()
|
|
109
|
+
console.log(HELP)
|
|
110
|
+
process.exit(1)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
main().catch((err) => {
|
|
115
|
+
console.error("Fatal error:", err)
|
|
116
|
+
process.exit(1)
|
|
117
|
+
})
|
package/scripts/lib.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib.ts — Shared utilities for opencode-memsearch CLI scripts.
|
|
3
|
+
*
|
|
4
|
+
* Contains helpers used by both the seed and reindex commands:
|
|
5
|
+
* database access, collection name derivation, memsearch detection, etc.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Database } from "bun:sqlite"
|
|
9
|
+
import { createHash } from "crypto"
|
|
10
|
+
import { basename, join, resolve } from "path"
|
|
11
|
+
import { homedir } from "os"
|
|
12
|
+
import { $ } from "bun"
|
|
13
|
+
|
|
14
|
+
// --- Constants ---
|
|
15
|
+
|
|
16
|
+
export const DB_PATH = join(homedir(), ".local", "share", "opencode", "opencode.db")
|
|
17
|
+
|
|
18
|
+
// --- Database types ---
|
|
19
|
+
|
|
20
|
+
export interface DbSession {
|
|
21
|
+
id: string
|
|
22
|
+
directory: string
|
|
23
|
+
title: string
|
|
24
|
+
parent_id: string | null
|
|
25
|
+
time_created: number
|
|
26
|
+
time_updated: number
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// --- Helpers ---
|
|
30
|
+
|
|
31
|
+
export function deriveCollectionName(directory: string): string {
|
|
32
|
+
const abs = resolve(directory)
|
|
33
|
+
const sanitized = basename(abs)
|
|
34
|
+
.toLowerCase()
|
|
35
|
+
.replace(/[^a-z0-9]/g, "_")
|
|
36
|
+
.replace(/_+/g, "_")
|
|
37
|
+
.replace(/^_|_$/g, "")
|
|
38
|
+
.slice(0, 40)
|
|
39
|
+
const hash = createHash("sha256").update(abs).digest("hex").slice(0, 8)
|
|
40
|
+
return `ms_${sanitized}_${hash}`
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// --- Database access ---
|
|
44
|
+
|
|
45
|
+
export function listSessionsFromDb(db: Database, cutoffMs: number): DbSession[] {
|
|
46
|
+
return db.query<DbSession, [number]>(`
|
|
47
|
+
SELECT id, directory, title, parent_id, time_created, time_updated
|
|
48
|
+
FROM session
|
|
49
|
+
WHERE time_created >= ?
|
|
50
|
+
AND parent_id IS NULL
|
|
51
|
+
ORDER BY time_created ASC
|
|
52
|
+
`).all(cutoffMs)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function listDistinctDirectories(db: Database): string[] {
|
|
56
|
+
const rows = db.query<{ directory: string }, []>(`
|
|
57
|
+
SELECT DISTINCT directory
|
|
58
|
+
FROM session
|
|
59
|
+
WHERE parent_id IS NULL
|
|
60
|
+
ORDER BY directory ASC
|
|
61
|
+
`).all()
|
|
62
|
+
return rows.map((r) => r.directory)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// --- Memsearch detection ---
|
|
66
|
+
|
|
67
|
+
export async function detectMemsearch(): Promise<string[]> {
|
|
68
|
+
try {
|
|
69
|
+
await $`which memsearch`.quiet()
|
|
70
|
+
return ["memsearch"]
|
|
71
|
+
} catch {}
|
|
72
|
+
throw new Error(
|
|
73
|
+
"memsearch is not installed. Install it by running: uv tool install 'memsearch[onnx]' — or with pip: pip install 'memsearch[onnx]'. See https://github.com/jdormit/opencode-memsearch for details."
|
|
74
|
+
)
|
|
75
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* reindex.ts — Re-index all memsearch memory files from scratch.
|
|
3
|
+
*
|
|
4
|
+
* This module exports a `reindex` function used by the CLI (cli.ts).
|
|
5
|
+
*
|
|
6
|
+
* Useful when switching embedding providers (e.g. memsearch[local] -> memsearch[onnx])
|
|
7
|
+
* without needing to re-run the expensive LLM-based seed process. The memory markdown
|
|
8
|
+
* files are the source of truth; this command just rebuilds the vector index from them.
|
|
9
|
+
*
|
|
10
|
+
* What it does:
|
|
11
|
+
* 1. Discovers all project directories from the OpenCode SQLite database
|
|
12
|
+
* 2. For each project with existing .memsearch/memory/ files:
|
|
13
|
+
* a. Resets the memsearch collection (drops the old vector data)
|
|
14
|
+
* b. Re-indexes the memory markdown files with the current embedding provider
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { Database } from "bun:sqlite"
|
|
18
|
+
import { readdir } from "fs/promises"
|
|
19
|
+
import { join } from "path"
|
|
20
|
+
import { $ } from "bun"
|
|
21
|
+
|
|
22
|
+
import {
|
|
23
|
+
DB_PATH,
|
|
24
|
+
deriveCollectionName,
|
|
25
|
+
detectMemsearch,
|
|
26
|
+
listDistinctDirectories,
|
|
27
|
+
} from "./lib"
|
|
28
|
+
|
|
29
|
+
// --- Helpers ---
|
|
30
|
+
|
|
31
|
+
async function hasMemoryFiles(memoryDir: string): Promise<boolean> {
|
|
32
|
+
try {
|
|
33
|
+
const files = await readdir(memoryDir)
|
|
34
|
+
return files.some((f) => f.endsWith(".md"))
|
|
35
|
+
} catch {
|
|
36
|
+
return false
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// --- Main ---
|
|
41
|
+
|
|
42
|
+
export async function reindex(opts: { dryRun: boolean }) {
|
|
43
|
+
const { dryRun } = opts
|
|
44
|
+
|
|
45
|
+
if (dryRun) {
|
|
46
|
+
console.log("DRY RUN — no changes will be made.\n")
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Setup
|
|
50
|
+
const memsearchCmd = await detectMemsearch()
|
|
51
|
+
console.log(`Using memsearch: ${memsearchCmd.join(" ")}`)
|
|
52
|
+
|
|
53
|
+
// Open database (read-only)
|
|
54
|
+
const db = new Database(DB_PATH, { readonly: true })
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
// Discover all project directories
|
|
58
|
+
const allDirs = listDistinctDirectories(db)
|
|
59
|
+
console.log(`Found ${allDirs.length} project directories in the OpenCode database.`)
|
|
60
|
+
console.log()
|
|
61
|
+
|
|
62
|
+
// Filter to directories that have memory files
|
|
63
|
+
const targets: { directory: string; memoryDir: string; collectionName: string }[] = []
|
|
64
|
+
|
|
65
|
+
for (const dir of allDirs) {
|
|
66
|
+
const memoryDir = join(dir, ".memsearch", "memory")
|
|
67
|
+
if (await hasMemoryFiles(memoryDir)) {
|
|
68
|
+
targets.push({
|
|
69
|
+
directory: dir,
|
|
70
|
+
memoryDir,
|
|
71
|
+
collectionName: deriveCollectionName(dir),
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (targets.length === 0) {
|
|
77
|
+
console.log("No projects with memory files found. Nothing to reindex.")
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
console.log(`Projects with memory files (${targets.length}):`)
|
|
82
|
+
for (const t of targets) {
|
|
83
|
+
console.log(` ${t.directory}`)
|
|
84
|
+
console.log(` collection: ${t.collectionName}`)
|
|
85
|
+
console.log(` memory dir: ${t.memoryDir}`)
|
|
86
|
+
}
|
|
87
|
+
console.log()
|
|
88
|
+
|
|
89
|
+
if (dryRun) {
|
|
90
|
+
console.log("DRY RUN — would reset and reindex the above collections.")
|
|
91
|
+
return
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Reset and reindex each collection
|
|
95
|
+
let succeeded = 0
|
|
96
|
+
let failed = 0
|
|
97
|
+
|
|
98
|
+
for (let i = 0; i < targets.length; i++) {
|
|
99
|
+
const t = targets[i]
|
|
100
|
+
const label = `[${i + 1}/${targets.length}]`
|
|
101
|
+
|
|
102
|
+
console.log(`${label} ${t.directory}`)
|
|
103
|
+
|
|
104
|
+
// Reset the collection
|
|
105
|
+
console.log(`${label} Resetting collection ${t.collectionName}...`)
|
|
106
|
+
try {
|
|
107
|
+
const resetArgs = [...memsearchCmd, "reset", "--collection", t.collectionName, "--yes"]
|
|
108
|
+
await $`${resetArgs}`.nothrow().quiet()
|
|
109
|
+
} catch (err) {
|
|
110
|
+
console.error(`${label} Failed to reset: ${err}`)
|
|
111
|
+
failed++
|
|
112
|
+
continue
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Re-index the memory files
|
|
116
|
+
console.log(`${label} Indexing ${t.memoryDir}...`)
|
|
117
|
+
try {
|
|
118
|
+
const indexArgs = [...memsearchCmd, "index", t.memoryDir, "--collection", t.collectionName, "--force"]
|
|
119
|
+
const output = await $`${indexArgs}`.nothrow().quiet().text()
|
|
120
|
+
if (output.trim()) {
|
|
121
|
+
console.log(`${label} ${output.trim()}`)
|
|
122
|
+
}
|
|
123
|
+
succeeded++
|
|
124
|
+
} catch (err) {
|
|
125
|
+
console.error(`${label} Failed to index: ${err}`)
|
|
126
|
+
failed++
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
console.log()
|
|
131
|
+
console.log(`Reindex complete: ${succeeded} succeeded, ${failed} failed.`)
|
|
132
|
+
} finally {
|
|
133
|
+
db.close()
|
|
134
|
+
}
|
|
135
|
+
}
|
package/scripts/seed-memories.ts
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
1
|
/**
|
|
3
2
|
* seed-memories.ts — Seed memsearch memory files from recent OpenCode sessions.
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
* npx opencode-memsearch-seed [--days 14]
|
|
4
|
+
* This module exports a `seed` function used by the CLI (cli.ts).
|
|
7
5
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* This script:
|
|
6
|
+
* What it does:
|
|
11
7
|
* 1. Reads session + message data directly from the OpenCode SQLite database
|
|
12
8
|
* 2. For each session, formats each conversation turn as a transcript
|
|
13
9
|
* 3. Summarizes each turn via `opencode run` (model is configurable, see README)
|
|
@@ -16,12 +12,19 @@
|
|
|
16
12
|
*/
|
|
17
13
|
|
|
18
14
|
import { Database } from "bun:sqlite"
|
|
19
|
-
import { createHash } from "crypto"
|
|
20
15
|
import { appendFile, mkdir, readFile, writeFile, unlink } from "fs/promises"
|
|
21
|
-
import { join
|
|
16
|
+
import { join } from "path"
|
|
22
17
|
import { homedir, tmpdir } from "os"
|
|
23
18
|
import { $ } from "bun"
|
|
24
19
|
|
|
20
|
+
import {
|
|
21
|
+
DB_PATH,
|
|
22
|
+
DbSession,
|
|
23
|
+
deriveCollectionName,
|
|
24
|
+
detectMemsearch,
|
|
25
|
+
listSessionsFromDb,
|
|
26
|
+
} from "./lib"
|
|
27
|
+
|
|
25
28
|
// --- Configuration ---
|
|
26
29
|
|
|
27
30
|
interface PluginConfig {
|
|
@@ -77,23 +80,10 @@ Rules:
|
|
|
77
80
|
- Do NOT ask follow-up questions
|
|
78
81
|
- STOP immediately after the last bullet point`
|
|
79
82
|
|
|
80
|
-
const DB_PATH = join(homedir(), ".local", "share", "opencode", "opencode.db")
|
|
81
83
|
const TEMP_DIR = join(tmpdir(), "memsearch-seed")
|
|
82
84
|
|
|
83
85
|
// --- Helpers ---
|
|
84
86
|
|
|
85
|
-
function deriveCollectionName(directory: string): string {
|
|
86
|
-
const abs = resolve(directory)
|
|
87
|
-
const sanitized = basename(abs)
|
|
88
|
-
.toLowerCase()
|
|
89
|
-
.replace(/[^a-z0-9]/g, "_")
|
|
90
|
-
.replace(/_+/g, "_")
|
|
91
|
-
.replace(/^_|_$/g, "")
|
|
92
|
-
.slice(0, 40)
|
|
93
|
-
const hash = createHash("sha256").update(abs).digest("hex").slice(0, 8)
|
|
94
|
-
return `ms_${sanitized}_${hash}`
|
|
95
|
-
}
|
|
96
|
-
|
|
97
87
|
function formatDate(epochMs: number): string {
|
|
98
88
|
const d = new Date(epochMs)
|
|
99
89
|
const yyyy = d.getFullYear()
|
|
@@ -107,32 +97,8 @@ function formatTime(epochMs: number): string {
|
|
|
107
97
|
return `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}`
|
|
108
98
|
}
|
|
109
99
|
|
|
110
|
-
function parseArgs(): { days: number } {
|
|
111
|
-
const args = process.argv.slice(2)
|
|
112
|
-
let days = 14
|
|
113
|
-
for (let i = 0; i < args.length; i++) {
|
|
114
|
-
if (args[i] === "--days" && args[i + 1]) {
|
|
115
|
-
days = parseInt(args[i + 1], 10)
|
|
116
|
-
if (isNaN(days) || days < 1) {
|
|
117
|
-
console.error("Invalid --days value, using default 14")
|
|
118
|
-
days = 14
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
return { days }
|
|
123
|
-
}
|
|
124
|
-
|
|
125
100
|
// --- Database types ---
|
|
126
101
|
|
|
127
|
-
interface DbSession {
|
|
128
|
-
id: string
|
|
129
|
-
directory: string
|
|
130
|
-
title: string
|
|
131
|
-
parent_id: string | null
|
|
132
|
-
time_created: number
|
|
133
|
-
time_updated: number
|
|
134
|
-
}
|
|
135
|
-
|
|
136
102
|
interface DbMessage {
|
|
137
103
|
id: string
|
|
138
104
|
session_id: string
|
|
@@ -149,16 +115,6 @@ interface DbPart {
|
|
|
149
115
|
|
|
150
116
|
// --- Database access ---
|
|
151
117
|
|
|
152
|
-
function listSessionsFromDb(db: Database, cutoffMs: number): DbSession[] {
|
|
153
|
-
return db.query<DbSession, [number]>(`
|
|
154
|
-
SELECT id, directory, title, parent_id, time_created, time_updated
|
|
155
|
-
FROM session
|
|
156
|
-
WHERE time_created >= ?
|
|
157
|
-
AND parent_id IS NULL
|
|
158
|
-
ORDER BY time_created ASC
|
|
159
|
-
`).all(cutoffMs)
|
|
160
|
-
}
|
|
161
|
-
|
|
162
118
|
function getSessionMessages(
|
|
163
119
|
db: Database,
|
|
164
120
|
sessionId: string,
|
|
@@ -309,17 +265,6 @@ function getUserText(turn: { info: any; parts: any[] }[]): string {
|
|
|
309
265
|
return ""
|
|
310
266
|
}
|
|
311
267
|
|
|
312
|
-
// Detect memsearch command
|
|
313
|
-
async function detectMemsearch(): Promise<string[]> {
|
|
314
|
-
try {
|
|
315
|
-
await $`which memsearch`.quiet()
|
|
316
|
-
return ["memsearch"]
|
|
317
|
-
} catch {}
|
|
318
|
-
throw new Error(
|
|
319
|
-
"memsearch is not installed. Install it by running: uv tool install 'memsearch[onnx]' — or with pip: pip install 'memsearch[onnx]'. See https://github.com/jdormit/opencode-memsearch for details."
|
|
320
|
-
)
|
|
321
|
-
}
|
|
322
|
-
|
|
323
268
|
// Summarize a transcript via `opencode run`
|
|
324
269
|
async function summarizeWithOpencode(transcript: string, tempFile: string, model: string): Promise<string> {
|
|
325
270
|
// Write transcript to temp file
|
|
@@ -354,8 +299,8 @@ async function summarizeWithOpencode(transcript: string, tempFile: string, model
|
|
|
354
299
|
|
|
355
300
|
// --- Main ---
|
|
356
301
|
|
|
357
|
-
async function
|
|
358
|
-
const { days } =
|
|
302
|
+
export async function seed(opts: { days: number }) {
|
|
303
|
+
const { days } = opts
|
|
359
304
|
const cutoff = Date.now() - days * 24 * 60 * 60 * 1000
|
|
360
305
|
|
|
361
306
|
console.log(`Seeding memories from the last ${days} days...`)
|
|
@@ -514,7 +459,4 @@ async function main() {
|
|
|
514
459
|
}
|
|
515
460
|
}
|
|
516
461
|
|
|
517
|
-
|
|
518
|
-
console.error("Fatal error:", err)
|
|
519
|
-
process.exit(1)
|
|
520
|
-
})
|
|
462
|
+
|