@alexandrgreen/anchorclaw 0.0.3
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/LICENSE +21 -0
- package/NOTICE +9 -0
- package/README.md +252 -0
- package/dist/api.d.ts +3 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +3 -0
- package/dist/api.js.map +1 -0
- package/dist/config.d.ts +46 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +309 -0
- package/dist/config.js.map +1 -0
- package/dist/config.test.d.ts +2 -0
- package/dist/config.test.d.ts.map +1 -0
- package/dist/config.test.js +100 -0
- package/dist/config.test.js.map +1 -0
- package/dist/identity-policy.d.ts +3 -0
- package/dist/identity-policy.d.ts.map +1 -0
- package/dist/identity-policy.js +7 -0
- package/dist/identity-policy.js.map +1 -0
- package/dist/identity-policy.test.d.ts +2 -0
- package/dist/identity-policy.test.d.ts.map +1 -0
- package/dist/identity-policy.test.js +23 -0
- package/dist/identity-policy.test.js.map +1 -0
- package/dist/identity.d.ts +22 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +113 -0
- package/dist/identity.js.map +1 -0
- package/dist/identity.test.d.ts +2 -0
- package/dist/identity.test.d.ts.map +1 -0
- package/dist/identity.test.js +22 -0
- package/dist/identity.test.js.map +1 -0
- package/dist/importer.d.ts +12 -0
- package/dist/importer.d.ts.map +1 -0
- package/dist/importer.js +297 -0
- package/dist/importer.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +92 -0
- package/dist/index.js.map +1 -0
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/index.test.js +770 -0
- package/dist/index.test.js.map +1 -0
- package/dist/memory/forget.d.ts +22 -0
- package/dist/memory/forget.d.ts.map +1 -0
- package/dist/memory/forget.js +84 -0
- package/dist/memory/forget.js.map +1 -0
- package/dist/memory/get.d.ts +36 -0
- package/dist/memory/get.d.ts.map +1 -0
- package/dist/memory/get.js +282 -0
- package/dist/memory/get.js.map +1 -0
- package/dist/memory/get.test.d.ts +2 -0
- package/dist/memory/get.test.d.ts.map +1 -0
- package/dist/memory/get.test.js +180 -0
- package/dist/memory/get.test.js.map +1 -0
- package/dist/memory/limits.d.ts +10 -0
- package/dist/memory/limits.d.ts.map +1 -0
- package/dist/memory/limits.js +18 -0
- package/dist/memory/limits.js.map +1 -0
- package/dist/memory/manager.d.ts +93 -0
- package/dist/memory/manager.d.ts.map +1 -0
- package/dist/memory/manager.js +344 -0
- package/dist/memory/manager.js.map +1 -0
- package/dist/memory/manager.test.d.ts +2 -0
- package/dist/memory/manager.test.d.ts.map +1 -0
- package/dist/memory/manager.test.js +201 -0
- package/dist/memory/manager.test.js.map +1 -0
- package/dist/memory/paths.d.ts +12 -0
- package/dist/memory/paths.d.ts.map +1 -0
- package/dist/memory/paths.js +31 -0
- package/dist/memory/paths.js.map +1 -0
- package/dist/memory/paths.test.d.ts +2 -0
- package/dist/memory/paths.test.d.ts.map +1 -0
- package/dist/memory/paths.test.js +35 -0
- package/dist/memory/paths.test.js.map +1 -0
- package/dist/memory/prompt.d.ts +37 -0
- package/dist/memory/prompt.d.ts.map +1 -0
- package/dist/memory/prompt.js +152 -0
- package/dist/memory/prompt.js.map +1 -0
- package/dist/memory/prompt.test.d.ts +2 -0
- package/dist/memory/prompt.test.d.ts.map +1 -0
- package/dist/memory/prompt.test.js +47 -0
- package/dist/memory/prompt.test.js.map +1 -0
- package/dist/memory/read-file-shared.d.ts +17 -0
- package/dist/memory/read-file-shared.d.ts.map +1 -0
- package/dist/memory/read-file-shared.js +53 -0
- package/dist/memory/read-file-shared.js.map +1 -0
- package/dist/memory/read-file-shared.test.d.ts +2 -0
- package/dist/memory/read-file-shared.test.d.ts.map +1 -0
- package/dist/memory/read-file-shared.test.js +82 -0
- package/dist/memory/read-file-shared.test.js.map +1 -0
- package/dist/memory/recall.d.ts +22 -0
- package/dist/memory/recall.d.ts.map +1 -0
- package/dist/memory/recall.js +58 -0
- package/dist/memory/recall.js.map +1 -0
- package/dist/memory/search.d.ts +30 -0
- package/dist/memory/search.d.ts.map +1 -0
- package/dist/memory/search.js +110 -0
- package/dist/memory/search.js.map +1 -0
- package/dist/memory/search.test.d.ts +2 -0
- package/dist/memory/search.test.d.ts.map +1 -0
- package/dist/memory/search.test.js +103 -0
- package/dist/memory/search.test.js.map +1 -0
- package/dist/memory/sessions-index-sync.d.ts +28 -0
- package/dist/memory/sessions-index-sync.d.ts.map +1 -0
- package/dist/memory/sessions-index-sync.js +253 -0
- package/dist/memory/sessions-index-sync.js.map +1 -0
- package/dist/memory/sessions-index-sync.test.d.ts +2 -0
- package/dist/memory/sessions-index-sync.test.d.ts.map +1 -0
- package/dist/memory/sessions-index-sync.test.js +280 -0
- package/dist/memory/sessions-index-sync.test.js.map +1 -0
- package/dist/memory/sessions-index.d.ts +30 -0
- package/dist/memory/sessions-index.d.ts.map +1 -0
- package/dist/memory/sessions-index.js +238 -0
- package/dist/memory/sessions-index.js.map +1 -0
- package/dist/memory/sessions-index.test.d.ts +2 -0
- package/dist/memory/sessions-index.test.d.ts.map +1 -0
- package/dist/memory/sessions-index.test.js +266 -0
- package/dist/memory/sessions-index.test.js.map +1 -0
- package/dist/memory/sessions-visibility.d.ts +18 -0
- package/dist/memory/sessions-visibility.d.ts.map +1 -0
- package/dist/memory/sessions-visibility.js +110 -0
- package/dist/memory/sessions-visibility.js.map +1 -0
- package/dist/memory/sessions-visibility.test.d.ts +2 -0
- package/dist/memory/sessions-visibility.test.d.ts.map +1 -0
- package/dist/memory/sessions-visibility.test.js +137 -0
- package/dist/memory/sessions-visibility.test.js.map +1 -0
- package/dist/memory/sessions.d.ts +26 -0
- package/dist/memory/sessions.d.ts.map +1 -0
- package/dist/memory/sessions.js +250 -0
- package/dist/memory/sessions.js.map +1 -0
- package/dist/memory/sessions.test.d.ts +2 -0
- package/dist/memory/sessions.test.d.ts.map +1 -0
- package/dist/memory/sessions.test.js +257 -0
- package/dist/memory/sessions.test.js.map +1 -0
- package/dist/memory/store.d.ts +25 -0
- package/dist/memory/store.d.ts.map +1 -0
- package/dist/memory/store.js +176 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/migrations-fs.d.ts +5 -0
- package/dist/migrations-fs.d.ts.map +1 -0
- package/dist/migrations-fs.js +19 -0
- package/dist/migrations-fs.js.map +1 -0
- package/dist/migrations.d.ts +17 -0
- package/dist/migrations.d.ts.map +1 -0
- package/dist/migrations.js +44 -0
- package/dist/migrations.js.map +1 -0
- package/dist/migrations.test.d.ts +2 -0
- package/dist/migrations.test.d.ts.map +1 -0
- package/dist/migrations.test.js +66 -0
- package/dist/migrations.test.js.map +1 -0
- package/dist/plugin/capability.d.ts +7 -0
- package/dist/plugin/capability.d.ts.map +1 -0
- package/dist/plugin/capability.js +92 -0
- package/dist/plugin/capability.js.map +1 -0
- package/dist/plugin/capability.test.d.ts +2 -0
- package/dist/plugin/capability.test.d.ts.map +1 -0
- package/dist/plugin/capability.test.js +75 -0
- package/dist/plugin/capability.test.js.map +1 -0
- package/dist/plugin/lifecycle.d.ts +6 -0
- package/dist/plugin/lifecycle.d.ts.map +1 -0
- package/dist/plugin/lifecycle.js +31 -0
- package/dist/plugin/lifecycle.js.map +1 -0
- package/dist/plugin/prompt-cache.d.ts +10 -0
- package/dist/plugin/prompt-cache.d.ts.map +1 -0
- package/dist/plugin/prompt-cache.js +58 -0
- package/dist/plugin/prompt-cache.js.map +1 -0
- package/dist/plugin/runtime-context.d.ts +27 -0
- package/dist/plugin/runtime-context.d.ts.map +1 -0
- package/dist/plugin/runtime-context.js +91 -0
- package/dist/plugin/runtime-context.js.map +1 -0
- package/dist/plugin/runtime-helpers.d.ts +3 -0
- package/dist/plugin/runtime-helpers.d.ts.map +1 -0
- package/dist/plugin/runtime-helpers.js +12 -0
- package/dist/plugin/runtime-helpers.js.map +1 -0
- package/dist/plugin/session-delta-helpers.d.ts +11 -0
- package/dist/plugin/session-delta-helpers.d.ts.map +1 -0
- package/dist/plugin/session-delta-helpers.js +62 -0
- package/dist/plugin/session-delta-helpers.js.map +1 -0
- package/dist/plugin/session-delta.d.ts +12 -0
- package/dist/plugin/session-delta.d.ts.map +1 -0
- package/dist/plugin/session-delta.js +307 -0
- package/dist/plugin/session-delta.js.map +1 -0
- package/dist/plugin/tools/common.d.ts +7 -0
- package/dist/plugin/tools/common.d.ts.map +1 -0
- package/dist/plugin/tools/common.js +2 -0
- package/dist/plugin/tools/common.js.map +1 -0
- package/dist/plugin/tools/index.d.ts +3 -0
- package/dist/plugin/tools/index.d.ts.map +1 -0
- package/dist/plugin/tools/index.js +16 -0
- package/dist/plugin/tools/index.js.map +1 -0
- package/dist/plugin/tools/memory-forget.d.ts +3 -0
- package/dist/plugin/tools/memory-forget.d.ts.map +1 -0
- package/dist/plugin/tools/memory-forget.js +80 -0
- package/dist/plugin/tools/memory-forget.js.map +1 -0
- package/dist/plugin/tools/memory-forget.test.d.ts +2 -0
- package/dist/plugin/tools/memory-forget.test.d.ts.map +1 -0
- package/dist/plugin/tools/memory-forget.test.js +58 -0
- package/dist/plugin/tools/memory-forget.test.js.map +1 -0
- package/dist/plugin/tools/memory-get.d.ts +3 -0
- package/dist/plugin/tools/memory-get.d.ts.map +1 -0
- package/dist/plugin/tools/memory-get.js +136 -0
- package/dist/plugin/tools/memory-get.js.map +1 -0
- package/dist/plugin/tools/memory-recall.d.ts +3 -0
- package/dist/plugin/tools/memory-recall.d.ts.map +1 -0
- package/dist/plugin/tools/memory-recall.js +176 -0
- package/dist/plugin/tools/memory-recall.js.map +1 -0
- package/dist/plugin/tools/memory-recall.test.d.ts +2 -0
- package/dist/plugin/tools/memory-recall.test.d.ts.map +1 -0
- package/dist/plugin/tools/memory-recall.test.js +169 -0
- package/dist/plugin/tools/memory-recall.test.js.map +1 -0
- package/dist/plugin/tools/memory-search.d.ts +3 -0
- package/dist/plugin/tools/memory-search.d.ts.map +1 -0
- package/dist/plugin/tools/memory-search.js +332 -0
- package/dist/plugin/tools/memory-search.js.map +1 -0
- package/dist/plugin/tools/memory-search.test.d.ts +2 -0
- package/dist/plugin/tools/memory-search.test.d.ts.map +1 -0
- package/dist/plugin/tools/memory-search.test.js +205 -0
- package/dist/plugin/tools/memory-search.test.js.map +1 -0
- package/dist/plugin/tools/memory-status.d.ts +3 -0
- package/dist/plugin/tools/memory-status.d.ts.map +1 -0
- package/dist/plugin/tools/memory-status.js +134 -0
- package/dist/plugin/tools/memory-status.js.map +1 -0
- package/dist/plugin/tools/memory-store.d.ts +3 -0
- package/dist/plugin/tools/memory-store.d.ts.map +1 -0
- package/dist/plugin/tools/memory-store.js +88 -0
- package/dist/plugin/tools/memory-store.js.map +1 -0
- package/dist/plugin/tools/memory-store.test.d.ts +2 -0
- package/dist/plugin/tools/memory-store.test.d.ts.map +1 -0
- package/dist/plugin/tools/memory-store.test.js +64 -0
- package/dist/plugin/tools/memory-store.test.js.map +1 -0
- package/dist/plugin/tools/memory-visible-output.d.ts +20 -0
- package/dist/plugin/tools/memory-visible-output.d.ts.map +1 -0
- package/dist/plugin/tools/memory-visible-output.js +61 -0
- package/dist/plugin/tools/memory-visible-output.js.map +1 -0
- package/dist/plugin/types.d.ts +61 -0
- package/dist/plugin/types.d.ts.map +1 -0
- package/dist/plugin/types.js +2 -0
- package/dist/plugin/types.js.map +1 -0
- package/dist/postgres.d.ts +7 -0
- package/dist/postgres.d.ts.map +1 -0
- package/dist/postgres.js +55 -0
- package/dist/postgres.js.map +1 -0
- package/migrations/0001_init.sql +228 -0
- package/migrations/0002_session_index.sql +71 -0
- package/openclaw.plugin.json +314 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alexander Green
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/NOTICE
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="./assets/logo.png" alt="AnchorClaw logo" width="800" height="600" style="display:block;margin:0 auto" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# AnchorClaw — Postgres Memory Plugin (OpenClaw)
|
|
6
|
+
|
|
7
|
+
> Alpha preview. API may change before stable release.
|
|
8
|
+
|
|
9
|
+
**AnchorClaw** is created and maintained by Alexander Green.
|
|
10
|
+
The canonical repository is https://github.com/Alexander-Green/anchorClaw.
|
|
11
|
+
|
|
12
|
+
**AnchorClaw** is an OpenClaw memory plugin that replaces file-based durable memory (`MEMORY.md`) with a Postgres-backed, SQL-first durable store while keeping OpenClaw’s memory tooling and CLI/doctor/status flows compatible.
|
|
13
|
+
|
|
14
|
+
## Why We Built This
|
|
15
|
+
|
|
16
|
+
OpenClaw’s default memory model is excellent for transparency (plain files) but it becomes harder to:
|
|
17
|
+
|
|
18
|
+
- do deterministic retrieval and updates (avoid duplicates, enforce stable ordering)
|
|
19
|
+
- support multi-user/workspace isolation cleanly
|
|
20
|
+
- evolve toward advanced features (semantic recall, personas, episodes, knowledge graphs) without turning memory into an opaque blob
|
|
21
|
+
|
|
22
|
+
AnchorClaw makes **Postgres the source of truth** for durable memory while preserving OpenClaw’s UX expectations (tools, corpuses, `MEMORY.md` compatibility).
|
|
23
|
+
|
|
24
|
+
## What Works Today (MVP)
|
|
25
|
+
|
|
26
|
+
- **Durable memory in Postgres** (`memory_items`):
|
|
27
|
+
- `memory_store` (canonical upsert via `canonicalKey`)
|
|
28
|
+
- `memory_search` (`corpus="memory"`) via Postgres FTS (deterministic ordering)
|
|
29
|
+
- `memory_get` reads synthetic paths (`db-memory/items/<uuid>.md`) with bounded excerpts
|
|
30
|
+
- `memory_forget` soft-deletes items (+ audit trail in DB)
|
|
31
|
+
- `memory_recall` shortcut (query → search; empty query → top items)
|
|
32
|
+
- **OpenClaw compatibility**
|
|
33
|
+
- `registerMemoryCapability` + a `MemorySearchManager` adapter so `status/doctor/CLI` can work
|
|
34
|
+
- `memory_get` accepts both parameter styles:
|
|
35
|
+
- AnchorClaw-native: `{ lookup, fromLine, lineCount }`
|
|
36
|
+
- OpenClaw aliases: `{ path, from, lines }`
|
|
37
|
+
- Reading `MEMORY.md` via `memory_get`/runtime returns a **virtual snapshot generated from Postgres** (keeps legacy flows compatible while DB stays source-of-truth)
|
|
38
|
+
- **Sessions corpus (Phase 1 + Phase 2 live-pass complete)**
|
|
39
|
+
- `memory_search(corpus="sessions")` uses Postgres-backed sessions index (`session_index_files` + `session_index_chunks`) with FTS ranking
|
|
40
|
+
- `memory_get(path="sessions/<agentId>/<file>")` is DB-first; file fallback is used only on `index_miss`
|
|
41
|
+
- `sessions.visibility` modes: `off | current | visible` (default: `current`)
|
|
42
|
+
- `sessions.sync.deltaBytes` / `sessions.sync.deltaMessages` control delta reindex thresholds (defaults: `100000` / `50`)
|
|
43
|
+
- state/session path resolution follows OpenClaw-compatible order: `OPENCLAW_STATE_DIR` -> `OPENCLAW_HOME/.openclaw` (or `HOME/.openclaw`) -> legacy `HOME/.clawdbot`
|
|
44
|
+
- Phase 2 live/delta indexing is enabled (`onSessionTranscriptUpdate` + debounce + targeted sync)
|
|
45
|
+
- visibility behavior is runtime-verified:
|
|
46
|
+
- `current`: cross-agent delta updates are ignored
|
|
47
|
+
- `visible`: cross-agent delta updates are accepted and indexed
|
|
48
|
+
- `off`: sessions delta listener is disabled
|
|
49
|
+
- **Migration support**
|
|
50
|
+
- One-time idempotent import of legacy `MEMORY.md` into Postgres (by file hash)
|
|
51
|
+
- Optional (default on) cleanup of `MEMORY.md` after import to avoid duplicate prompt injection
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 🛠 Prerequisites
|
|
56
|
+
|
|
57
|
+
- OpenClaw host that supports memory plugin slots (see `package.json` → `openclaw.install.minHostVersion`)
|
|
58
|
+
- Node.js (plugin runtime)
|
|
59
|
+
- PostgreSQL (no embeddings required for MVP)
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 🚀 Quick Start
|
|
64
|
+
|
|
65
|
+
### 1) Install
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
openclaw plugins install @anchorclaw/anchorclaw
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 2) Configure
|
|
72
|
+
|
|
73
|
+
Select the memory slot and configure Postgres:
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"plugins": {
|
|
78
|
+
"slots": { "memory": "anchorclaw" },
|
|
79
|
+
"entries": {
|
|
80
|
+
"anchorclaw": {
|
|
81
|
+
"enabled": true,
|
|
82
|
+
"config": {
|
|
83
|
+
"sessions": {
|
|
84
|
+
"visibility": "current",
|
|
85
|
+
"sync": {
|
|
86
|
+
"deltaBytes": 100000,
|
|
87
|
+
"deltaMessages": 50
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"identity": {
|
|
91
|
+
"externalId": "family-main-01"
|
|
92
|
+
},
|
|
93
|
+
"postgres": {
|
|
94
|
+
"host": "localhost",
|
|
95
|
+
"database": "anchorclaw",
|
|
96
|
+
"user": "postgres",
|
|
97
|
+
"password": "${ANCHORCLAW_DB_PASSWORD}"
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 3) Restart
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
openclaw gateway restart
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Memory Tooling (MVP)
|
|
115
|
+
|
|
116
|
+
AnchorClaw exposes both “native” and compatibility surfaces via OpenClaw tool contracts:
|
|
117
|
+
|
|
118
|
+
- `memory_store({ content, canonicalKey?, type? })` where `type` is `fact|note` (MVP)
|
|
119
|
+
- `memory_search({ query, corpus?, maxResults?, minScore? })`
|
|
120
|
+
- `corpus="memory"` (default): Postgres durable memory
|
|
121
|
+
- `corpus="sessions"`: Postgres sessions index (DB-first)
|
|
122
|
+
- `corpus="all"`: deterministic merge of `memory + sessions`
|
|
123
|
+
- `corpus="wiki"`: stub for now (use `wiki_search/wiki_get` from `memory-wiki`)
|
|
124
|
+
- `memory_get({ lookup|path, fromLine|from?, lineCount|lines? })`
|
|
125
|
+
- `MEMORY.md` is a virtual DB snapshot (source-of-truth is Postgres)
|
|
126
|
+
- `memory_forget({ lookup|path? , id? })`
|
|
127
|
+
- `memory_recall({ query? })`
|
|
128
|
+
- `memory_status({ check? })`
|
|
129
|
+
- default (`check` omitted / `false`): cached runtime degraded-state report
|
|
130
|
+
- active mode (`check: true`): lightweight healthcheck for DB connectivity/schema + sessions dir accessibility (`exists` + explicit `readable` check)
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Importing `MEMORY.md` and Avoiding Duplicate Prompt Memory
|
|
135
|
+
|
|
136
|
+
OpenClaw core injects `MEMORY.md` as a bootstrap file. AnchorClaw also injects Postgres-backed durable memory via its memory capability.
|
|
137
|
+
|
|
138
|
+
To avoid duplicated prompt memory, AnchorClaw **cleans up `MEMORY.md` after a successful import by default**:
|
|
139
|
+
|
|
140
|
+
- backup: `.openclaw-repair/anchorclaw/MEMORY.md.anchorclaw-backup.<timestamp>.md`
|
|
141
|
+
- replacement: `MEMORY.md` becomes an HTML-comment-only stub
|
|
142
|
+
|
|
143
|
+
To disable cleanup:
|
|
144
|
+
|
|
145
|
+
```json
|
|
146
|
+
{ "import": { "cleanupMemoryMdAfterImport": false } }
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Defaults
|
|
152
|
+
|
|
153
|
+
- `postgres.port`: `5432`
|
|
154
|
+
- `postgres.pool.max`: `10`
|
|
155
|
+
- `postgres.pool.connectionTimeoutMs`: `5000`
|
|
156
|
+
- `postgres.pool.idleTimeoutMs`: `30000`
|
|
157
|
+
- `sessions.sync.deltaBytes`: `100000` (OpenClaw-compatible default)
|
|
158
|
+
- `sessions.sync.deltaMessages`: `50` (OpenClaw-compatible default)
|
|
159
|
+
- Import cleanup: `import.cleanupMemoryMdAfterImport = true`
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Identity & Workspace Scoping (MVP)
|
|
164
|
+
|
|
165
|
+
AnchorClaw scopes all reads/writes by `(user_id, workspace_id)` derived from the current runtime identity.
|
|
166
|
+
|
|
167
|
+
- Preferred identity (Docker/production): set `identity.externalId` (max 20 chars). This becomes the stable `user_identities` key (`channel=anchorclaw-config`).
|
|
168
|
+
- Fallback identity (dev convenience): if `identity.externalId` is not set, identity is derived from OS username (`external_id = sha256(normalized username)`, `channel=openclaw-cli`).
|
|
169
|
+
- If multiple people share the same OS user account, they will share the same AnchorClaw `user_id`.
|
|
170
|
+
- AnchorClaw logs a startup warning on every start when fallback mode is active.
|
|
171
|
+
- Workspace identity: workspaces are isolated per user and per workspace directory (`workspace name = dir:<sha256(resolved workspaceDir)>`).
|
|
172
|
+
|
|
173
|
+
Recommended for Docker/production:
|
|
174
|
+
|
|
175
|
+
```json
|
|
176
|
+
{
|
|
177
|
+
"plugins": {
|
|
178
|
+
"entries": {
|
|
179
|
+
"anchorclaw": {
|
|
180
|
+
"config": {
|
|
181
|
+
"identity": { "externalId": "family-main-01" }
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Postgres SSL
|
|
192
|
+
|
|
193
|
+
AnchorClaw supports two mutually exclusive SSL configuration styles:
|
|
194
|
+
|
|
195
|
+
- Simple flag: `postgres.ssl: true|false`
|
|
196
|
+
- Explicit mode: `postgres.sslMode: "disable"|"require"|"verify-full"` (+ optional `postgres.sslCa`)
|
|
197
|
+
|
|
198
|
+
If you need strict certificate verification (recommended for production), use:
|
|
199
|
+
|
|
200
|
+
```json
|
|
201
|
+
{
|
|
202
|
+
"postgres": {
|
|
203
|
+
"host": "db.example.com",
|
|
204
|
+
"port": "${PGPORT}",
|
|
205
|
+
"database": "anchorclaw",
|
|
206
|
+
"user": "anchorclaw",
|
|
207
|
+
"password": "${ANCHORCLAW_DB_PASSWORD}",
|
|
208
|
+
"sslMode": "verify-full",
|
|
209
|
+
"sslCa": "${ANCHORCLAW_DB_SSL_CA_PEM}"
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
`postgres.ssl` and `postgres.sslMode` cannot be set at the same time.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Postgres Pool
|
|
219
|
+
|
|
220
|
+
Optional pool tuning:
|
|
221
|
+
|
|
222
|
+
```json
|
|
223
|
+
{
|
|
224
|
+
"postgres": {
|
|
225
|
+
"host": "localhost",
|
|
226
|
+
"database": "anchorclaw",
|
|
227
|
+
"user": "postgres",
|
|
228
|
+
"pool": {
|
|
229
|
+
"max": 10,
|
|
230
|
+
"connectionTimeoutMs": 5000,
|
|
231
|
+
"idleTimeoutMs": 30000
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Roadmap (Planned)
|
|
240
|
+
|
|
241
|
+
AnchorClaw intentionally starts with deterministic SQL-first durability. Next layers are planned to reach PostClaw parity and beyond:
|
|
242
|
+
|
|
243
|
+
- **Semantic layer**: embeddings + semantic search (hybrid retrieval: lexical + vector; optional and non-breaking)
|
|
244
|
+
- **Persona context in DB**: dynamic persona/profile retrieval and injection into the system prompt (separate budgets/policy)
|
|
245
|
+
- **Knowledge graph**: `entity_edges`-style relationships and multi-hop retrieval to pull secondary context automatically
|
|
246
|
+
- **Wiki integration / AnchorClaw-native wiki**: either integrate OpenClaw supplements (`memory-wiki`) or build a DB-native wiki layer
|
|
247
|
+
|
|
248
|
+
## Current Status
|
|
249
|
+
|
|
250
|
+
- Durable memory MVP: implemented and green in repo tests.
|
|
251
|
+
- Sessions Phase 1 and Phase 2: implemented, reviewed, and runtime-verified on VPS `server-166`.
|
|
252
|
+
- Session delta indexing parity path is active in runtime (listener + debounce + targeted sync + lifecycle cleanup compatibility fallback).
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAC7F,OAAO,EAAE,wBAAwB,EAAE,MAAM,mDAAmD,CAAC"}
|
package/dist/api.js
ADDED
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAA0B,MAAM,kCAAkC,CAAC;AAC7F,OAAO,EAAE,wBAAwB,EAAE,MAAM,mDAAmD,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export type AnchorClawConfig = {
|
|
2
|
+
sessions?: {
|
|
3
|
+
visibility?: "current" | "off" | "visible";
|
|
4
|
+
sync?: {
|
|
5
|
+
deltaBytes?: number;
|
|
6
|
+
deltaMessages?: number;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
identity?: {
|
|
10
|
+
externalId?: string;
|
|
11
|
+
};
|
|
12
|
+
postgres: {
|
|
13
|
+
host: string;
|
|
14
|
+
port?: number;
|
|
15
|
+
database: string;
|
|
16
|
+
schema?: string;
|
|
17
|
+
user: string;
|
|
18
|
+
password?: string;
|
|
19
|
+
ssl?: boolean;
|
|
20
|
+
sslMode?: "disable" | "require" | "verify-full";
|
|
21
|
+
sslCa?: string;
|
|
22
|
+
pool?: {
|
|
23
|
+
max?: number;
|
|
24
|
+
connectionTimeoutMs?: number;
|
|
25
|
+
idleTimeoutMs?: number;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
import?: {
|
|
29
|
+
/**
|
|
30
|
+
* After successfully importing `MEMORY.md` into Postgres, overwrite `MEMORY.md` with an empty stub
|
|
31
|
+
* (to prevent duplicate prompt injection from OpenClaw bootstrap + AnchorClaw DB injection).
|
|
32
|
+
*/
|
|
33
|
+
cleanupMemoryMdAfterImport?: boolean;
|
|
34
|
+
};
|
|
35
|
+
limits?: {
|
|
36
|
+
maxResults?: number;
|
|
37
|
+
getMaxChars?: number;
|
|
38
|
+
getDefaultLines?: number;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
export declare const DEFAULT_SESSION_DELTA_BYTES = 100000;
|
|
42
|
+
export declare const DEFAULT_SESSION_DELTA_MESSAGES = 50;
|
|
43
|
+
export declare const anchorClawConfigSchema: {
|
|
44
|
+
parse(value: unknown): AnchorClawConfig;
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,EAAE;QACT,UAAU,CAAC,EAAE,SAAS,GAAG,KAAK,GAAG,SAAS,CAAC;QAC3C,IAAI,CAAC,EAAE;YACL,UAAU,CAAC,EAAE,MAAM,CAAC;YACpB,aAAa,CAAC,EAAE,MAAM,CAAC;SACxB,CAAC;KACH,CAAC;IACF,QAAQ,CAAC,EAAE;QACT,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,GAAG,CAAC,EAAE,OAAO,CAAC;QACd,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,aAAa,CAAC;QAChD,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE;YACL,GAAG,CAAC,EAAE,MAAM,CAAC;YACb,mBAAmB,CAAC,EAAE,MAAM,CAAC;YAC7B,aAAa,CAAC,EAAE,MAAM,CAAC;SACxB,CAAC;KACH,CAAC;IACF,MAAM,CAAC,EAAE;QACP;;;WAGG;QACH,0BAA0B,CAAC,EAAE,OAAO,CAAC;KACtC,CAAC;IACF,MAAM,CAAC,EAAE;QACP,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH,CAAC;AAEF,eAAO,MAAM,2BAA2B,SAAU,CAAC;AACnD,eAAO,MAAM,8BAA8B,KAAK,CAAC;AAuHjD,eAAO,MAAM,sBAAsB;iBACpB,OAAO,GAAG,gBAAgB;CA0NxC,CAAC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
export const DEFAULT_SESSION_DELTA_BYTES = 100_000;
|
|
2
|
+
export const DEFAULT_SESSION_DELTA_MESSAGES = 50;
|
|
3
|
+
function asRecord(value) {
|
|
4
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
5
|
+
? value
|
|
6
|
+
: undefined;
|
|
7
|
+
}
|
|
8
|
+
function assertAllowedKeys(value, allowed, label) {
|
|
9
|
+
const unknown = Object.keys(value).filter((key) => !allowed.includes(key));
|
|
10
|
+
if (unknown.length === 0) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
throw new Error(`${label} has unknown keys: ${unknown.join(", ")}`);
|
|
14
|
+
}
|
|
15
|
+
function resolveEnvVars(value) {
|
|
16
|
+
return value.replace(/\$\{([^}]+)\}/g, (_, envVar) => {
|
|
17
|
+
const envValue = process.env[envVar];
|
|
18
|
+
if (!envValue) {
|
|
19
|
+
throw new Error(`Environment variable ${envVar} is not set`);
|
|
20
|
+
}
|
|
21
|
+
return envValue;
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function readOptionalString(value, label) {
|
|
25
|
+
if (value === undefined || value === null) {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
if (typeof value !== "string") {
|
|
29
|
+
throw new Error(`${label} must be a string`);
|
|
30
|
+
}
|
|
31
|
+
const trimmed = value.trim();
|
|
32
|
+
if (!trimmed) {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
return resolveEnvVars(trimmed);
|
|
36
|
+
}
|
|
37
|
+
function readOptionalNonEmptyString(value, label) {
|
|
38
|
+
if (value === undefined || value === null) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
if (typeof value !== "string") {
|
|
42
|
+
throw new Error(`${label} must be a string`);
|
|
43
|
+
}
|
|
44
|
+
const trimmed = value.trim();
|
|
45
|
+
if (!trimmed) {
|
|
46
|
+
throw new Error(`${label} must be non-empty`);
|
|
47
|
+
}
|
|
48
|
+
return resolveEnvVars(trimmed);
|
|
49
|
+
}
|
|
50
|
+
function readRequiredString(value, label) {
|
|
51
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
52
|
+
throw new Error(`${label} required`);
|
|
53
|
+
}
|
|
54
|
+
return resolveEnvVars(value.trim());
|
|
55
|
+
}
|
|
56
|
+
function readOptionalPort(value, label) {
|
|
57
|
+
if (value === undefined || value === null) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
const resolved = typeof value === "string" ? resolveEnvVars(value.trim()) : value;
|
|
61
|
+
if (typeof resolved === "string") {
|
|
62
|
+
if (!resolved) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
const parsed = Number(resolved);
|
|
66
|
+
if (!Number.isInteger(parsed)) {
|
|
67
|
+
throw new Error(`${label} must be an integer`);
|
|
68
|
+
}
|
|
69
|
+
value = parsed;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
value = resolved;
|
|
73
|
+
}
|
|
74
|
+
if (typeof value !== "number" || !Number.isInteger(value)) {
|
|
75
|
+
throw new Error(`${label} must be an integer`);
|
|
76
|
+
}
|
|
77
|
+
if (value < 1 || value > 65535) {
|
|
78
|
+
throw new Error(`${label} must be between 1 and 65535`);
|
|
79
|
+
}
|
|
80
|
+
return value;
|
|
81
|
+
}
|
|
82
|
+
function readOptionalBoolean(value, label) {
|
|
83
|
+
if (value === undefined || value === null) {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
if (typeof value !== "boolean") {
|
|
87
|
+
throw new Error(`${label} must be a boolean`);
|
|
88
|
+
}
|
|
89
|
+
return value;
|
|
90
|
+
}
|
|
91
|
+
function readOptionalIntegerInRange(params) {
|
|
92
|
+
if (params.value === undefined || params.value === null) {
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
if (typeof params.value !== "number" || !Number.isInteger(params.value)) {
|
|
96
|
+
throw new Error(`${params.label} must be an integer`);
|
|
97
|
+
}
|
|
98
|
+
if (params.value < params.min || params.value > params.max) {
|
|
99
|
+
throw new Error(`${params.label} must be between ${params.min} and ${params.max}`);
|
|
100
|
+
}
|
|
101
|
+
return params.value;
|
|
102
|
+
}
|
|
103
|
+
export const anchorClawConfigSchema = {
|
|
104
|
+
parse(value) {
|
|
105
|
+
const obj = asRecord(value);
|
|
106
|
+
if (!obj) {
|
|
107
|
+
throw new Error("anchorclaw config required");
|
|
108
|
+
}
|
|
109
|
+
assertAllowedKeys(obj, ["sessions", "identity", "postgres", "import", "limits"], "anchorclaw config");
|
|
110
|
+
const sessionsObj = asRecord(obj.sessions);
|
|
111
|
+
if (obj.sessions !== undefined && !sessionsObj) {
|
|
112
|
+
throw new Error("sessions must be an object");
|
|
113
|
+
}
|
|
114
|
+
if (sessionsObj) {
|
|
115
|
+
assertAllowedKeys(sessionsObj, ["visibility", "sync"], "sessions");
|
|
116
|
+
}
|
|
117
|
+
const visibilityRaw = sessionsObj
|
|
118
|
+
? readOptionalString(sessionsObj.visibility, "sessions.visibility")
|
|
119
|
+
: undefined;
|
|
120
|
+
const sessionsVisibility = visibilityRaw
|
|
121
|
+
? visibilityRaw === "current" || visibilityRaw === "off" || visibilityRaw === "visible"
|
|
122
|
+
? visibilityRaw
|
|
123
|
+
: (() => {
|
|
124
|
+
throw new Error("sessions.visibility must be one of: current, off, visible");
|
|
125
|
+
})()
|
|
126
|
+
: "current";
|
|
127
|
+
const sessionsSyncObj = sessionsObj ? asRecord(sessionsObj.sync) : undefined;
|
|
128
|
+
if (sessionsObj?.sync !== undefined && !sessionsSyncObj) {
|
|
129
|
+
throw new Error("sessions.sync must be an object");
|
|
130
|
+
}
|
|
131
|
+
if (sessionsSyncObj) {
|
|
132
|
+
assertAllowedKeys(sessionsSyncObj, ["deltaBytes", "deltaMessages"], "sessions.sync");
|
|
133
|
+
}
|
|
134
|
+
const sessionsDeltaBytes = sessionsSyncObj
|
|
135
|
+
? readOptionalIntegerInRange({
|
|
136
|
+
value: sessionsSyncObj.deltaBytes,
|
|
137
|
+
label: "sessions.sync.deltaBytes",
|
|
138
|
+
min: 0,
|
|
139
|
+
max: Number.MAX_SAFE_INTEGER,
|
|
140
|
+
})
|
|
141
|
+
: undefined;
|
|
142
|
+
const sessionsDeltaMessages = sessionsSyncObj
|
|
143
|
+
? readOptionalIntegerInRange({
|
|
144
|
+
value: sessionsSyncObj.deltaMessages,
|
|
145
|
+
label: "sessions.sync.deltaMessages",
|
|
146
|
+
min: 0,
|
|
147
|
+
max: Number.MAX_SAFE_INTEGER,
|
|
148
|
+
})
|
|
149
|
+
: undefined;
|
|
150
|
+
const identityObj = asRecord(obj.identity);
|
|
151
|
+
if (obj.identity !== undefined && !identityObj) {
|
|
152
|
+
throw new Error("identity must be an object");
|
|
153
|
+
}
|
|
154
|
+
if (identityObj) {
|
|
155
|
+
assertAllowedKeys(identityObj, ["externalId"], "identity");
|
|
156
|
+
}
|
|
157
|
+
const identityExternalId = identityObj
|
|
158
|
+
? readOptionalNonEmptyString(identityObj.externalId, "identity.externalId")
|
|
159
|
+
: undefined;
|
|
160
|
+
if (identityExternalId && identityExternalId.length > 20) {
|
|
161
|
+
throw new Error("identity.externalId must be at most 20 characters");
|
|
162
|
+
}
|
|
163
|
+
const postgresObj = asRecord(obj.postgres);
|
|
164
|
+
if (!postgresObj) {
|
|
165
|
+
throw new Error("postgres config required");
|
|
166
|
+
}
|
|
167
|
+
assertAllowedKeys(postgresObj, ["host", "port", "database", "schema", "user", "password", "ssl", "sslMode", "sslCa", "pool"], "postgres config");
|
|
168
|
+
const host = readRequiredString(postgresObj.host, "postgres.host");
|
|
169
|
+
const database = readRequiredString(postgresObj.database, "postgres.database");
|
|
170
|
+
const schema = readOptionalString(postgresObj.schema, "postgres.schema");
|
|
171
|
+
const user = readRequiredString(postgresObj.user, "postgres.user");
|
|
172
|
+
const password = readOptionalString(postgresObj.password, "postgres.password");
|
|
173
|
+
const port = readOptionalPort(postgresObj.port, "postgres.port");
|
|
174
|
+
const ssl = readOptionalBoolean(postgresObj.ssl, "postgres.ssl");
|
|
175
|
+
const sslModeRaw = readOptionalString(postgresObj.sslMode, "postgres.sslMode");
|
|
176
|
+
const sslCa = readOptionalString(postgresObj.sslCa, "postgres.sslCa");
|
|
177
|
+
const poolObj = asRecord(postgresObj.pool);
|
|
178
|
+
if (postgresObj.pool !== undefined && !poolObj) {
|
|
179
|
+
throw new Error("postgres.pool must be an object");
|
|
180
|
+
}
|
|
181
|
+
if (poolObj) {
|
|
182
|
+
assertAllowedKeys(poolObj, ["max", "connectionTimeoutMs", "idleTimeoutMs"], "postgres.pool");
|
|
183
|
+
}
|
|
184
|
+
const sslMode = sslModeRaw
|
|
185
|
+
? sslModeRaw === "disable" || sslModeRaw === "require" || sslModeRaw === "verify-full"
|
|
186
|
+
? sslModeRaw
|
|
187
|
+
: (() => {
|
|
188
|
+
throw new Error("postgres.sslMode must be one of: disable, require, verify-full");
|
|
189
|
+
})()
|
|
190
|
+
: undefined;
|
|
191
|
+
if (typeof ssl === "boolean" && sslMode) {
|
|
192
|
+
throw new Error("postgres.ssl and postgres.sslMode are mutually exclusive; use only sslMode");
|
|
193
|
+
}
|
|
194
|
+
if (sslCa && !sslMode) {
|
|
195
|
+
throw new Error("postgres.sslCa requires postgres.sslMode=verify-full");
|
|
196
|
+
}
|
|
197
|
+
if (sslMode && sslMode !== "verify-full" && sslCa) {
|
|
198
|
+
throw new Error("postgres.sslCa is only valid with postgres.sslMode=verify-full");
|
|
199
|
+
}
|
|
200
|
+
const poolMax = poolObj
|
|
201
|
+
? readOptionalIntegerInRange({
|
|
202
|
+
value: poolObj.max,
|
|
203
|
+
label: "postgres.pool.max",
|
|
204
|
+
min: 1,
|
|
205
|
+
max: 100,
|
|
206
|
+
})
|
|
207
|
+
: undefined;
|
|
208
|
+
const poolConnectionTimeoutMs = poolObj
|
|
209
|
+
? readOptionalIntegerInRange({
|
|
210
|
+
value: poolObj.connectionTimeoutMs,
|
|
211
|
+
label: "postgres.pool.connectionTimeoutMs",
|
|
212
|
+
min: 100,
|
|
213
|
+
max: 600_000,
|
|
214
|
+
})
|
|
215
|
+
: undefined;
|
|
216
|
+
const poolIdleTimeoutMs = poolObj
|
|
217
|
+
? readOptionalIntegerInRange({
|
|
218
|
+
value: poolObj.idleTimeoutMs,
|
|
219
|
+
label: "postgres.pool.idleTimeoutMs",
|
|
220
|
+
min: 100,
|
|
221
|
+
max: 3_600_000,
|
|
222
|
+
})
|
|
223
|
+
: undefined;
|
|
224
|
+
const importObj = asRecord(obj.import);
|
|
225
|
+
if (obj.import !== undefined && !importObj) {
|
|
226
|
+
throw new Error("import must be an object");
|
|
227
|
+
}
|
|
228
|
+
if (importObj) {
|
|
229
|
+
assertAllowedKeys(importObj, ["cleanupMemoryMdAfterImport"], "import");
|
|
230
|
+
}
|
|
231
|
+
const cleanupMemoryMdAfterImport = importObj
|
|
232
|
+
? readOptionalBoolean(importObj.cleanupMemoryMdAfterImport, "import.cleanupMemoryMdAfterImport")
|
|
233
|
+
: undefined;
|
|
234
|
+
const limitsObj = asRecord(obj.limits);
|
|
235
|
+
if (obj.limits !== undefined && !limitsObj) {
|
|
236
|
+
throw new Error("limits must be an object");
|
|
237
|
+
}
|
|
238
|
+
if (limitsObj) {
|
|
239
|
+
assertAllowedKeys(limitsObj, ["maxResults", "getMaxChars", "getDefaultLines"], "limits");
|
|
240
|
+
}
|
|
241
|
+
const limitMaxResults = limitsObj
|
|
242
|
+
? readOptionalIntegerInRange({
|
|
243
|
+
value: limitsObj.maxResults,
|
|
244
|
+
label: "limits.maxResults",
|
|
245
|
+
min: 1,
|
|
246
|
+
max: 10,
|
|
247
|
+
})
|
|
248
|
+
: undefined;
|
|
249
|
+
const limitGetMaxChars = limitsObj
|
|
250
|
+
? readOptionalIntegerInRange({
|
|
251
|
+
value: limitsObj.getMaxChars,
|
|
252
|
+
label: "limits.getMaxChars",
|
|
253
|
+
min: 1000,
|
|
254
|
+
max: 12_000,
|
|
255
|
+
})
|
|
256
|
+
: undefined;
|
|
257
|
+
const limitGetDefaultLines = limitsObj
|
|
258
|
+
? readOptionalIntegerInRange({
|
|
259
|
+
value: limitsObj.getDefaultLines,
|
|
260
|
+
label: "limits.getDefaultLines",
|
|
261
|
+
min: 10,
|
|
262
|
+
max: 120,
|
|
263
|
+
})
|
|
264
|
+
: undefined;
|
|
265
|
+
return {
|
|
266
|
+
sessions: {
|
|
267
|
+
visibility: sessionsVisibility,
|
|
268
|
+
sync: {
|
|
269
|
+
deltaBytes: sessionsDeltaBytes ?? DEFAULT_SESSION_DELTA_BYTES,
|
|
270
|
+
deltaMessages: sessionsDeltaMessages ?? DEFAULT_SESSION_DELTA_MESSAGES,
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
...(identityExternalId ? { identity: { externalId: identityExternalId } } : {}),
|
|
274
|
+
postgres: {
|
|
275
|
+
host,
|
|
276
|
+
...(typeof port === "number" ? { port } : {}),
|
|
277
|
+
database,
|
|
278
|
+
...(schema ? { schema } : {}),
|
|
279
|
+
user,
|
|
280
|
+
...(password ? { password } : {}),
|
|
281
|
+
...(typeof ssl === "boolean" ? { ssl } : {}),
|
|
282
|
+
...(sslMode ? { sslMode } : {}),
|
|
283
|
+
...(sslCa ? { sslCa } : {}),
|
|
284
|
+
...(poolMax || poolConnectionTimeoutMs || poolIdleTimeoutMs
|
|
285
|
+
? {
|
|
286
|
+
pool: {
|
|
287
|
+
...(poolMax ? { max: poolMax } : {}),
|
|
288
|
+
...(poolConnectionTimeoutMs
|
|
289
|
+
? { connectionTimeoutMs: poolConnectionTimeoutMs }
|
|
290
|
+
: {}),
|
|
291
|
+
...(poolIdleTimeoutMs ? { idleTimeoutMs: poolIdleTimeoutMs } : {}),
|
|
292
|
+
},
|
|
293
|
+
}
|
|
294
|
+
: {}),
|
|
295
|
+
},
|
|
296
|
+
import: { cleanupMemoryMdAfterImport: cleanupMemoryMdAfterImport ?? true },
|
|
297
|
+
...(limitMaxResults || limitGetMaxChars || limitGetDefaultLines
|
|
298
|
+
? {
|
|
299
|
+
limits: {
|
|
300
|
+
...(limitMaxResults ? { maxResults: limitMaxResults } : {}),
|
|
301
|
+
...(limitGetMaxChars ? { getMaxChars: limitGetMaxChars } : {}),
|
|
302
|
+
...(limitGetDefaultLines ? { getDefaultLines: limitGetDefaultLines } : {}),
|
|
303
|
+
},
|
|
304
|
+
}
|
|
305
|
+
: {}),
|
|
306
|
+
};
|
|
307
|
+
},
|
|
308
|
+
};
|
|
309
|
+
//# sourceMappingURL=config.js.map
|