@dzhi/ocpg 0.6.2 → 0.8.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 +17 -25
- package/ocpg.ts +13 -34
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,41 +12,33 @@ In `opencode.json`:
|
|
|
12
12
|
```json
|
|
13
13
|
{
|
|
14
14
|
"plugin": [
|
|
15
|
-
|
|
15
|
+
"@dzhi/ocpg"
|
|
16
16
|
]
|
|
17
17
|
}
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
## Connecting to the database
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
Need a Postgres instance? The [`deploy/`](./deploy) directory ships a hardened Docker Compose setup (localhost-only, `memories` schema auto-created on first boot) — see [`deploy/README.md`](./deploy/README.md).
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
{
|
|
26
|
-
"plugin": [
|
|
27
|
-
[
|
|
28
|
-
"@dzhi/ocpg",
|
|
29
|
-
{
|
|
30
|
-
"host": "localhost",
|
|
31
|
-
"port": 5432,
|
|
32
|
-
"user": "pguser",
|
|
33
|
-
"database": "agent-memory"
|
|
34
|
-
}
|
|
35
|
-
]
|
|
36
|
-
]
|
|
37
|
-
}
|
|
38
|
-
```
|
|
24
|
+
Configure the connection via environment variables, e.g. in `~/.zshenv`. Any Postgres user and database name will do — use whatever names fit your setup and mirror them here:
|
|
39
25
|
|
|
40
|
-
|
|
26
|
+
```bash
|
|
27
|
+
export OCPG_HOST="localhost"
|
|
28
|
+
export OCPG_PORT="5432"
|
|
29
|
+
export OCPG_USER="ocpguser"
|
|
30
|
+
export OCPG_PASSWORD="your-postgres-password"
|
|
31
|
+
export OCPG_DB="ocpg"
|
|
32
|
+
```
|
|
41
33
|
|
|
42
|
-
|
|
|
43
|
-
|
|
|
44
|
-
| `
|
|
45
|
-
| `
|
|
46
|
-
| `
|
|
47
|
-
| `
|
|
34
|
+
| Env var | Default |
|
|
35
|
+
| --------------- | ------------ |
|
|
36
|
+
| `OCPG_HOST` | `localhost` |
|
|
37
|
+
| `OCPG_PORT` | `5432` |
|
|
38
|
+
| `OCPG_USER` | `ocpguser` |
|
|
39
|
+
| `OCPG_DB` | `ocpg` |
|
|
48
40
|
|
|
49
|
-
**Password is never set via
|
|
41
|
+
**Password is env-only.** The plugin never reads config files, options, or external secret managers — set `OCPG_PASSWORD` in your shell environment (e.g. via direnv/.envrc, however you source your secrets).
|
|
50
42
|
|
|
51
43
|
## Tools
|
|
52
44
|
|
package/ocpg.ts
CHANGED
|
@@ -2,29 +2,24 @@
|
|
|
2
2
|
import { SQL } from "bun";
|
|
3
3
|
import { Plugin } from "@opencode/plugin";
|
|
4
4
|
|
|
5
|
-
// --- DB config:
|
|
6
|
-
type
|
|
7
|
-
host
|
|
8
|
-
port
|
|
9
|
-
user
|
|
10
|
-
database
|
|
5
|
+
// --- DB config: env > defaults. Plugin options are not read; password is deliberately env-only (never in config).
|
|
6
|
+
type DbConfig = {
|
|
7
|
+
host: string;
|
|
8
|
+
port: number;
|
|
9
|
+
user: string;
|
|
10
|
+
database: string;
|
|
11
11
|
};
|
|
12
|
-
type DbConfig = Required<DbOptions>;
|
|
13
12
|
type RecallArgs = { query?: string; global?: boolean; limit?: number };
|
|
14
13
|
type RememberArgs = { content: string; tags?: string[] };
|
|
15
14
|
|
|
16
|
-
// Defaults resolved ONCE at module init —
|
|
15
|
+
// Defaults resolved ONCE at module init — env-only, no process spawning.
|
|
17
16
|
const defaultConfig: DbConfig = {
|
|
18
17
|
host: process.env.OCPG_HOST || "localhost",
|
|
19
18
|
port: Number(process.env.OCPG_PORT) || 5432,
|
|
20
|
-
user: process.env.OCPG_USER || "
|
|
21
|
-
database: process.env.OCPG_DB || "
|
|
19
|
+
user: process.env.OCPG_USER || "ocpguser",
|
|
20
|
+
database: process.env.OCPG_DB || "ocpg",
|
|
22
21
|
};
|
|
23
|
-
const password =
|
|
24
|
-
process.env.OCPG_PASSWORD ||
|
|
25
|
-
Bun.spawnSync(["pass", "show", "postgres-workstation-password"])
|
|
26
|
-
.stdout.toString()
|
|
27
|
-
.trim();
|
|
22
|
+
const password = process.env.OCPG_PASSWORD || "";
|
|
28
23
|
|
|
29
24
|
// Options-object constructor, not a URL string: Bun's SQL parses string URLs via
|
|
30
25
|
// url.parse(), which emits the DEP0169 DeprecationWarning at plugin load under opencode.
|
|
@@ -41,14 +36,6 @@ function makeSql(cfg: DbConfig): SQL {
|
|
|
41
36
|
|
|
42
37
|
let sql = makeSql(defaultConfig);
|
|
43
38
|
|
|
44
|
-
// Swap the pool when the plugin loads with config options ({ "package": "@dzhi/ocpg", "options": {...} } in opencode.jsonc).
|
|
45
|
-
// No-op without options so the module-level env/default config stands. Pools are lazy — a never-connected pool closes cleanly.
|
|
46
|
-
function reconfigure(options?: DbOptions): void {
|
|
47
|
-
if (!options) return;
|
|
48
|
-
void sql.close().catch(() => {});
|
|
49
|
-
sql = makeSql({ ...defaultConfig, ...options });
|
|
50
|
-
}
|
|
51
|
-
|
|
52
39
|
export interface MemoryRow {
|
|
53
40
|
id: number;
|
|
54
41
|
content: string;
|
|
@@ -150,12 +137,6 @@ async function dispose(): Promise<void> {
|
|
|
150
137
|
|
|
151
138
|
// --- Agent tools: recall + remember with dedup-on-write ---
|
|
152
139
|
|
|
153
|
-
function normalizeTags(tags: string[] | undefined, projectDir: string): string[] {
|
|
154
|
-
const input = tags ?? [];
|
|
155
|
-
const base = projectDir.split('/').pop() ?? projectDir;
|
|
156
|
-
return [...input, `project:${base}`];
|
|
157
|
-
}
|
|
158
|
-
|
|
159
140
|
async function recall(
|
|
160
141
|
args: RecallArgs,
|
|
161
142
|
ctx: { directory: string },
|
|
@@ -207,7 +188,8 @@ async function remember(
|
|
|
207
188
|
return 'ERROR: content must be at least 10 characters.';
|
|
208
189
|
}
|
|
209
190
|
|
|
210
|
-
|
|
191
|
+
// Tags are stored verbatim — project scoping lives in the project column, not tags.
|
|
192
|
+
const tags = args.tags ?? [];
|
|
211
193
|
const basename = ctx.directory.split('/').pop() ?? ctx.directory;
|
|
212
194
|
|
|
213
195
|
// Dedup: project-scoped, common-opening-words AND-match via FTS
|
|
@@ -233,7 +215,7 @@ async function remember(
|
|
|
233
215
|
// the element type hint is required for clean array storage.
|
|
234
216
|
const inserted = await sql`
|
|
235
217
|
INSERT INTO memories (content, tags, session_id, project)
|
|
236
|
-
VALUES (${args.content}, ${sql.array(
|
|
218
|
+
VALUES (${args.content}, ${sql.array(tags, "text")}, ${ctx.sessionID}, ${ctx.directory})
|
|
237
219
|
RETURNING id
|
|
238
220
|
` as { id: number }[];
|
|
239
221
|
|
|
@@ -256,7 +238,6 @@ function invalidateInjection(sessionID: string): void {
|
|
|
256
238
|
const ocpg = Plugin.define({
|
|
257
239
|
id: "ocpg",
|
|
258
240
|
async setup(ctx) {
|
|
259
|
-
reconfigure(ctx.options as DbOptions | undefined);
|
|
260
241
|
const directory = ctx.location.directory;
|
|
261
242
|
|
|
262
243
|
// Inject project memories into every model request's system context.
|
|
@@ -320,11 +301,9 @@ const __internals = {
|
|
|
320
301
|
get sql() {
|
|
321
302
|
return sql;
|
|
322
303
|
},
|
|
323
|
-
reconfigure,
|
|
324
304
|
truncateMemory,
|
|
325
305
|
formatBlock,
|
|
326
306
|
handleTransform,
|
|
327
|
-
normalizeTags,
|
|
328
307
|
recall,
|
|
329
308
|
remember,
|
|
330
309
|
invalidateInjection,
|