@bcmyguest/openmem 0.0.0-stage → 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/.agents/skills/openmem/SKILL.md +34 -0
- package/LICENSE +190 -0
- package/README.md +140 -2
- package/bin/hindsight-project-index +530 -0
- package/cli/coding-agent/access-policy.mjs +38 -0
- package/cli/coding-agent/agents.mjs +34 -0
- package/cli/coding-agent/bank-from-cwd.mjs +140 -0
- package/cli/coding-agent/capabilities.mjs +34 -0
- package/cli/coding-agent/context-store.mjs +81 -0
- package/cli/coding-agent/context-trim.mjs +897 -0
- package/cli/coding-agent/file-io.mjs +72 -0
- package/cli/coding-agent/hook-harnesses.mjs +88 -0
- package/cli/coding-agent/hook-runner.mjs +284 -0
- package/cli/coding-agent/install-access.mjs +119 -0
- package/cli/coding-agent/install-context-proxy.mjs +333 -0
- package/cli/coding-agent/install-rtk.mjs +60 -0
- package/cli/coding-agent/install-shim.mjs +201 -0
- package/cli/coding-agent/opencode-config.mjs +107 -0
- package/cli/coding-agent/opencode-plugin.mjs +132 -0
- package/cli/coding-agent/opencode2-plugin/index.js +299 -0
- package/cli/coding-agent/recall-frame.mjs +29 -0
- package/cli/coding-agent/remove-upstream-access.mjs +122 -0
- package/cli/coding-agent/runtime.mjs +40 -0
- package/cli/coding-agent/session-db.mjs +626 -0
- package/cli/coding-agent/session-facade.mjs +86 -0
- package/cli/coding-agent/toml-edit.mjs +161 -0
- package/cli/cognee-mcp.mjs +260 -0
- package/cli/context-management.mjs +254 -0
- package/cli/feed-sync.mjs +27 -0
- package/cli/install-coding-agent.mjs +298 -0
- package/cli/install-memory-mcp.mjs +426 -0
- package/cli/is-main.mjs +18 -0
- package/cli/mcp/context-sql-runner.mjs +58 -0
- package/cli/mcp/context-store.mjs +670 -0
- package/cli/mcp/context.mjs +61 -0
- package/cli/mcp/export/cognee-dataset-name.mjs +12 -0
- package/cli/mcp/export/cognee.mjs +119 -0
- package/cli/mcp/export/hindsight.mjs +48 -0
- package/cli/mcp/export/index.mjs +26 -0
- package/cli/mcp/export/mem0.mjs +31 -0
- package/cli/mcp/knowledge.mjs +333 -0
- package/cli/mcp/llm-synthesize.mjs +50 -0
- package/cli/mcp/mem0-scope-id.mjs +22 -0
- package/cli/mcp/memory-facade.mjs +521 -0
- package/cli/mcp/memory-reflect-consolidate.mjs +120 -0
- package/cli/mcp/notebooklm-banks.mjs +21 -0
- package/cli/mcp/notebooklm-hindsight-rest.mjs +45 -0
- package/cli/mcp/notebooklm-provider.mjs +225 -0
- package/cli/mcp/pmm-records.mjs +23 -0
- package/cli/mcp/portability.mjs +158 -0
- package/cli/mcp/stdio.mjs +65 -0
- package/cli/mcp/unified-mcp-install.mjs +65 -0
- package/cli/mem0-mcp.mjs +108 -0
- package/cli/notebooklm-mcp.mjs +236 -0
- package/cli/openmem-mcp.mjs +38 -0
- package/cli/openmem.mjs +222 -0
- package/cli/roots.mjs +85 -0
- package/cli/schedule.mjs +176 -0
- package/cli/stack.mjs +438 -0
- package/cli/switch-memory-provider.mjs +358 -0
- package/cli/wiring-report.mjs +125 -0
- package/compose.bench.yaml +12 -0
- package/compose.yaml +227 -0
- package/config/coding-agent.json +13 -0
- package/config/hindsight.env.example +26 -0
- package/config/index.yml +54 -0
- package/config/litellm.lemond.yaml +40 -0
- package/config/litellm.ollama.yaml +33 -0
- package/config/notebooklm.yml +33 -0
- package/config/openmem.toml.example +124 -0
- package/docs/OPENMEM.md +23 -0
- package/docs/architecture.md +245 -0
- package/docs/assets/README.md +10 -0
- package/docs/assets/setup-demo.gif +0 -0
- package/docs/coding-agent-hooks.md +75 -0
- package/docs/coding-agent-scopes.md +22 -0
- package/docs/coding-agents.md +71 -0
- package/docs/cognee.md +37 -0
- package/docs/compatibility.md +80 -0
- package/docs/concepts.md +135 -0
- package/docs/context-management.md +255 -0
- package/docs/context-proxy.md +115 -0
- package/docs/context-research.md +215 -0
- package/docs/context-store.md +277 -0
- package/docs/hindsight.md +77 -0
- package/docs/index-sources-roadmap.md +38 -0
- package/docs/index-sources.md +39 -0
- package/docs/indexer-sinks.md +122 -0
- package/docs/indexing.md +57 -0
- package/docs/manual-stack-setup.md +74 -0
- package/docs/mcp-install-guide.md +4 -0
- package/docs/mcp-setup.md +104 -0
- package/docs/mem0.md +141 -0
- package/docs/memory-portability.md +73 -0
- package/docs/memory-providers.md +246 -0
- package/docs/meridian-litellm.md +198 -0
- package/docs/model-configuration.md +106 -0
- package/docs/notebooklm.md +83 -0
- package/docs/npx-install.md +172 -0
- package/docs/openmem-config.md +194 -0
- package/docs/provider-wizard-hooks.md +222 -0
- package/docs/quickstart.md +107 -0
- package/docs/setup-wizard.md +117 -0
- package/docs/sources-feeds.md +39 -0
- package/docs/sources-readwise.md +23 -0
- package/docs/sources-zotero.md +22 -0
- package/glama.json +4 -0
- package/indexer/Dockerfile +38 -0
- package/indexer/code_outline.py +146 -0
- package/indexer/feed_sync.py +107 -0
- package/indexer/index_config.py +290 -0
- package/indexer/pytest.ini +5 -0
- package/indexer/sinks/__init__.py +148 -0
- package/indexer/sinks/_http.py +44 -0
- package/indexer/sinks/cognee.py +329 -0
- package/indexer/sinks/hindsight.py +107 -0
- package/indexer/sinks/mem0.py +247 -0
- package/indexer/watch.py +240 -0
- package/package.json +96 -4
- package/providers/_template/compose.yaml +52 -0
- package/providers/cognee/OPERATOR.md +82 -0
- package/providers/cognee/compose.yaml +89 -0
- package/providers/cognee/lib/clack.mjs +157 -0
- package/providers/cognee/lib/coding-agent.mjs +26 -0
- package/providers/cognee/lib/cognee-mcp-install.mjs +153 -0
- package/providers/cognee/lib/config.mjs +98 -0
- package/providers/cognee/lib/env-file.mjs +194 -0
- package/providers/cognee/lib/env-setup.mjs +83 -0
- package/providers/cognee/lib/llm-env.mjs +382 -0
- package/providers/cognee/lib/ports.mjs +25 -0
- package/providers/cognee/lib/smoke.mjs +246 -0
- package/providers/cognee/lib/stack-env.mjs +134 -0
- package/providers/cognee/lib/state.mjs +101 -0
- package/providers/cognee/lib/summary.mjs +56 -0
- package/providers/cognee/lib/validate.mjs +97 -0
- package/providers/cognee/manifest.json +56 -0
- package/providers/cognee/wizard.mjs +134 -0
- package/providers/graphiti/manifest.json +15 -0
- package/providers/hindsight/lib/clack.mjs +347 -0
- package/providers/hindsight/lib/coding-agent.mjs +204 -0
- package/providers/hindsight/lib/config.mjs +79 -0
- package/providers/hindsight/lib/env-setup.mjs +72 -0
- package/providers/hindsight/lib/litellm-routes.mjs +196 -0
- package/providers/hindsight/lib/meridian.mjs +307 -0
- package/providers/hindsight/lib/model-backend.mjs +243 -0
- package/providers/hindsight/lib/notebooklm-mcp-install.mjs +127 -0
- package/providers/hindsight/lib/ollama-compose.mjs +51 -0
- package/providers/hindsight/lib/ports.mjs +30 -0
- package/providers/hindsight/lib/probe.mjs +54 -0
- package/providers/hindsight/lib/stack-env.mjs +125 -0
- package/providers/hindsight/lib/state.mjs +80 -0
- package/providers/hindsight/lib/summary.mjs +57 -0
- package/providers/hindsight/lib/validate.mjs +81 -0
- package/providers/hindsight/manifest.json +58 -0
- package/providers/hindsight/wizard.mjs +150 -0
- package/providers/letta/manifest.json +29 -0
- package/providers/mem0/OPERATOR.md +143 -0
- package/providers/mem0/compose.yaml +79 -0
- package/providers/mem0/lib/coding-agent.mjs +58 -0
- package/providers/mem0/lib/config.mjs +45 -0
- package/providers/mem0/lib/configure.mjs +201 -0
- package/providers/mem0/lib/dotenv.mjs +71 -0
- package/providers/mem0/lib/env-file.mjs +110 -0
- package/providers/mem0/lib/http.mjs +69 -0
- package/providers/mem0/lib/litellm.mjs +457 -0
- package/providers/mem0/lib/mcp-install.mjs +165 -0
- package/providers/mem0/lib/secret.mjs +30 -0
- package/providers/mem0/lib/smoke.mjs +179 -0
- package/providers/mem0/lib/stack-env.mjs +255 -0
- package/providers/mem0/lib/state.mjs +67 -0
- package/providers/mem0/lib/summary.mjs +88 -0
- package/providers/mem0/lib/url.mjs +106 -0
- package/providers/mem0/lib/validate.mjs +158 -0
- package/providers/mem0/manifest.json +47 -0
- package/providers/mem0/wizard.mjs +146 -0
- package/providers/zep/manifest.json +29 -0
- package/proxy/config.yaml +33 -0
- package/proxy/openmem_context/__init__.py +6 -0
- package/proxy/openmem_context/adapters.py +504 -0
- package/proxy/openmem_context/compress.py +53 -0
- package/proxy/openmem_context/core.py +606 -0
- package/proxy/openmem_context/embed.py +212 -0
- package/proxy/openmem_context/recall.py +49 -0
- package/proxy/openmem_context/session.py +70 -0
- package/proxy/openmem_context/sessiondb.py +276 -0
- package/proxy/openmem_context/settings.py +134 -0
- package/proxy/openmem_context/store.py +129 -0
- package/proxy/openmem_context/tokens.py +123 -0
- package/proxy/openmem_context/ttl.py +78 -0
- package/proxy/openmem_context_hook.py +34 -0
- package/scripts/check-pack.mjs +219 -0
- package/scripts/gen-masks.mjs +83 -0
- package/scripts/gen-masks.sh +4 -0
- package/scripts/promotion-provider-smoke.mjs +34 -0
- package/scripts/run-setup.sh +30 -0
- package/scripts/setup.mjs +107 -0
- package/scripts/setup.sh +5 -0
- package/scripts/spin-up.sh +45 -0
- package/scripts/wizard.sh +5 -0
- package/server.json +34 -0
- package/sync/Dockerfile +27 -0
- package/sync/memory_backend.py +87 -0
- package/sync/notebooklm_sync.py +664 -0
- package/wizard/bin/pm.mjs +97 -0
- package/wizard/bin/setup.mjs +33 -0
- package/wizard/lib/compose-version.mjs +32 -0
- package/wizard/lib/compose.mjs +70 -0
- package/wizard/lib/context-step.mjs +140 -0
- package/wizard/lib/curl.mjs +103 -0
- package/wizard/lib/docker-build.mjs +148 -0
- package/wizard/lib/exec.mjs +41 -0
- package/wizard/lib/indexer.mjs +6 -0
- package/wizard/lib/litellm-env.mjs +55 -0
- package/wizard/lib/load-machine-env.mjs +4 -0
- package/wizard/lib/log.mjs +32 -0
- package/wizard/lib/notebooklm-agent-access.mjs +92 -0
- package/wizard/lib/notebooklm.mjs +214 -0
- package/wizard/lib/parse-args.mjs +87 -0
- package/wizard/lib/paths.mjs +39 -0
- package/wizard/lib/pm-config.mjs +371 -0
- package/wizard/lib/ports.mjs +94 -0
- package/wizard/lib/prompts.mjs +85 -0
- package/wizard/lib/provider-wizard/helpers.mjs +98 -0
- package/wizard/lib/provider-wizard/run-steps.mjs +129 -0
- package/wizard/lib/providers/registry.mjs +262 -0
- package/wizard/lib/run-clack.mjs +108 -0
- package/wizard/lib/run-wizard.mjs +750 -0
- package/wizard/lib/validate-setup.mjs +62 -0
- package/wizard/lib/wizard-action.mjs +34 -0
- package/wizard/lib/wizard-conf.mjs +71 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Pack-content gate: what `npm publish` would ship must contain the runtime files and
|
|
4
|
+
* nothing machine-specific. Used by CI (`npm run pack:check`) and by test_cli_package.mjs.
|
|
5
|
+
*
|
|
6
|
+
* node scripts/check-pack.mjs inspect `npm pack --dry-run`
|
|
7
|
+
* node scripts/check-pack.mjs --tarball X.tgz inspect a packed tarball (extracted to a tmp dir)
|
|
8
|
+
* node scripts/check-pack.mjs --json machine-readable result
|
|
9
|
+
*
|
|
10
|
+
* Exit 1 when any problem is found. Leak findings are reported, never silently allowed;
|
|
11
|
+
* the only allowlist is ALLOWED_PATH_MENTIONS below.
|
|
12
|
+
*/
|
|
13
|
+
import { spawnSync } from "node:child_process";
|
|
14
|
+
import fs from "node:fs";
|
|
15
|
+
import os from "node:os";
|
|
16
|
+
import path from "node:path";
|
|
17
|
+
import { fileURLToPath } from "node:url";
|
|
18
|
+
import { listShippedFiles } from "../cli/stack.mjs";
|
|
19
|
+
|
|
20
|
+
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
21
|
+
|
|
22
|
+
/** Files the installed package cannot run without. */
|
|
23
|
+
export const REQUIRED = [
|
|
24
|
+
"package.json",
|
|
25
|
+
"README.md",
|
|
26
|
+
"cli/openmem.mjs",
|
|
27
|
+
"cli/notebooklm-mcp.mjs",
|
|
28
|
+
"cli/cognee-mcp.mjs",
|
|
29
|
+
"cli/mem0-mcp.mjs",
|
|
30
|
+
"cli/install-memory-mcp.mjs",
|
|
31
|
+
"cli/switch-memory-provider.mjs",
|
|
32
|
+
"cli/stack.mjs",
|
|
33
|
+
"cli/roots.mjs",
|
|
34
|
+
".agents/skills/openmem/SKILL.md",
|
|
35
|
+
"wizard/bin/setup.mjs",
|
|
36
|
+
"wizard/bin/pm.mjs",
|
|
37
|
+
"wizard/lib/run-wizard.mjs",
|
|
38
|
+
"wizard/lib/parse-args.mjs",
|
|
39
|
+
"providers/hindsight/manifest.json",
|
|
40
|
+
"providers/hindsight/wizard.mjs",
|
|
41
|
+
"compose.yaml",
|
|
42
|
+
"compose.bench.yaml",
|
|
43
|
+
"indexer/Dockerfile",
|
|
44
|
+
"indexer/watch.py",
|
|
45
|
+
"bin/hindsight-project-index",
|
|
46
|
+
"sync/Dockerfile",
|
|
47
|
+
"config/index.yml",
|
|
48
|
+
"config/notebooklm.yml",
|
|
49
|
+
"config/hindsight.env.example",
|
|
50
|
+
"config/litellm.lemond.yaml",
|
|
51
|
+
"config/openmem.toml.example",
|
|
52
|
+
"scripts/setup.mjs",
|
|
53
|
+
"scripts/gen-masks.mjs",
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
/** Paths that must never be packed. Tested against the posix path inside the package. */
|
|
57
|
+
export const FORBIDDEN = [
|
|
58
|
+
[/(^|\/)\.env$/, ".env"],
|
|
59
|
+
[/(^|\/)\.env\.(?!example$)/, ".env.*"],
|
|
60
|
+
[/(^|\/)machine\.env$/, "machine.env"],
|
|
61
|
+
[/(^|\/)hindsight\.env$/, "hindsight.env"],
|
|
62
|
+
[/(^|\/)litellm\.env$/, "litellm.env"],
|
|
63
|
+
[/(^|\/)compose\.override\.ya?ml$/, "compose.override.yaml"],
|
|
64
|
+
[/(^|\/)\.build-hash$/, ".build-hash"],
|
|
65
|
+
[/(^|\/)\.pm-stack-manifest\.json$/, "stack manifest"],
|
|
66
|
+
[/\.pyc$/, "*.pyc"],
|
|
67
|
+
[/(^|\/)__pycache__(\/|$)/, "__pycache__"],
|
|
68
|
+
[/(^|\/)node_modules(\/|$)/, "node_modules"],
|
|
69
|
+
[/(^|\/)\.codegraph(\/|$)/, ".codegraph"],
|
|
70
|
+
[/(^|\/)\.git(\/|$)/, ".git"],
|
|
71
|
+
[/(^|\/)\.agents\/(?!skills\/openmem\/)/, ".agents except openmem skill"],
|
|
72
|
+
[/^site(\/|$)/, "site/"],
|
|
73
|
+
[/ROADMAP/, "ROADMAP*"],
|
|
74
|
+
[/WAVE2/, "WAVE2*"],
|
|
75
|
+
[/\.(tgz|tar|log)$/, "archives/logs"],
|
|
76
|
+
];
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Operator path markers. Container-internal home of the Hindsight image is not a leak.
|
|
80
|
+
*/
|
|
81
|
+
const LEAK_RE = /\/(?:home|Users)\/[A-Za-z0-9._-]*/g;
|
|
82
|
+
export const ALLOWED_PATH_MENTIONS = [/^\/home\/hindsight$/];
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @param {string} cwd
|
|
86
|
+
* @param {string[]} args
|
|
87
|
+
*/
|
|
88
|
+
function npm(cwd, args) {
|
|
89
|
+
const r = spawnSync("npm", args, { cwd, encoding: "utf8", maxBuffer: 64 * 1024 * 1024 });
|
|
90
|
+
if (r.status !== 0) throw new Error(`npm ${args.join(" ")} failed: ${r.stderr || r.stdout}`);
|
|
91
|
+
return r.stdout;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @param {string} root
|
|
96
|
+
* @returns {{ files: string[], dir: string, cleanup: () => void }}
|
|
97
|
+
*/
|
|
98
|
+
function listFromDryRun(root) {
|
|
99
|
+
const out = npm(root, ["pack", "--dry-run", "--json", "--ignore-scripts"]);
|
|
100
|
+
const j = JSON.parse(out);
|
|
101
|
+
return { files: j[0].files.map((/** @type {{path: string}} */ f) => f.path), dir: root, cleanup() {} };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* @param {string} tgz
|
|
106
|
+
* @returns {{ files: string[], dir: string, cleanup: () => void }}
|
|
107
|
+
*/
|
|
108
|
+
function listFromTarball(tgz) {
|
|
109
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "pm-pack-"));
|
|
110
|
+
const r = spawnSync("tar", ["-xzf", path.resolve(tgz), "-C", tmp], { encoding: "utf8" });
|
|
111
|
+
if (r.status !== 0) throw new Error(`tar failed: ${r.stderr}`);
|
|
112
|
+
const dir = path.join(tmp, "package");
|
|
113
|
+
/** @type {string[]} */
|
|
114
|
+
const files = [];
|
|
115
|
+
const walk = (/** @type {string} */ rel) => {
|
|
116
|
+
for (const e of fs.readdirSync(path.join(dir, rel), { withFileTypes: true })) {
|
|
117
|
+
const child = rel ? `${rel}/${e.name}` : e.name;
|
|
118
|
+
if (e.isDirectory()) walk(child);
|
|
119
|
+
else files.push(child);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
walk("");
|
|
123
|
+
return { files: files.sort(), dir, cleanup: () => fs.rmSync(tmp, { recursive: true, force: true }) };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** @param {Buffer} buf */
|
|
127
|
+
function isText(buf) {
|
|
128
|
+
return !buf.subarray(0, 8000).includes(0);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @typedef {{ ok: boolean, count: number, topLevel: Record<string, number>, problems: string[], files: string[] }} PackResult
|
|
133
|
+
*/
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Check a list of packed files against the gate.
|
|
137
|
+
*
|
|
138
|
+
* @param {{ files: string[], dir: string, license?: string, root?: string }} input
|
|
139
|
+
* @returns {PackResult}
|
|
140
|
+
*/
|
|
141
|
+
export function evaluatePack({ files, dir, license, root = ROOT }) {
|
|
142
|
+
/** @type {string[]} */
|
|
143
|
+
const problems = [];
|
|
144
|
+
const set = new Set(files);
|
|
145
|
+
|
|
146
|
+
for (const req of REQUIRED) {
|
|
147
|
+
if (!set.has(req)) problems.push(`missing required file: ${req}`);
|
|
148
|
+
}
|
|
149
|
+
if (license && license !== "UNLICENSED" && !set.has("LICENSE")) {
|
|
150
|
+
problems.push(`package.json license is ${license} but LICENSE is not packed`);
|
|
151
|
+
}
|
|
152
|
+
// Everything the stack materializer copies must be in the package.
|
|
153
|
+
for (const rel of listShippedFiles(root)) {
|
|
154
|
+
if (!set.has(rel)) problems.push(`stack asset is not packed (update package.json "files"): ${rel}`);
|
|
155
|
+
}
|
|
156
|
+
for (const f of files) {
|
|
157
|
+
for (const [re, label] of FORBIDDEN) {
|
|
158
|
+
if (re.test(f)) problems.push(`forbidden file packed (${label}): ${f}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
for (const f of files) {
|
|
162
|
+
const abs = path.join(dir, f);
|
|
163
|
+
let buf;
|
|
164
|
+
try {
|
|
165
|
+
buf = fs.readFileSync(abs);
|
|
166
|
+
} catch {
|
|
167
|
+
problems.push(`cannot read packed file: ${f}`);
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
if (!isText(buf)) continue;
|
|
171
|
+
const lines = buf.toString("utf8").split("\n");
|
|
172
|
+
lines.forEach((line, i) => {
|
|
173
|
+
for (const m of line.matchAll(LEAK_RE)) {
|
|
174
|
+
if (ALLOWED_PATH_MENTIONS.some((re) => re.test(m[0]))) continue;
|
|
175
|
+
problems.push(`machine path "${m[0]}" in ${f}:${i + 1}`);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** @type {Record<string, number>} */
|
|
181
|
+
const topLevel = {};
|
|
182
|
+
for (const f of files) {
|
|
183
|
+
const top = f.includes("/") ? `${f.split("/")[0]}/` : f;
|
|
184
|
+
topLevel[top] = (topLevel[top] || 0) + 1;
|
|
185
|
+
}
|
|
186
|
+
return { ok: problems.length === 0, count: files.length, topLevel, problems, files };
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* @param {{ root?: string, tarball?: string }} [opts]
|
|
191
|
+
* @returns {PackResult}
|
|
192
|
+
*/
|
|
193
|
+
export function checkPack({ root = ROOT, tarball } = {}) {
|
|
194
|
+
const listing = tarball ? listFromTarball(tarball) : listFromDryRun(root);
|
|
195
|
+
try {
|
|
196
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8"));
|
|
197
|
+
return evaluatePack({ files: listing.files, dir: listing.dir, license: pkg.license, root });
|
|
198
|
+
} finally {
|
|
199
|
+
listing.cleanup();
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
204
|
+
const argv = process.argv.slice(2);
|
|
205
|
+
const ti = argv.indexOf("--tarball");
|
|
206
|
+
const tarball = ti >= 0 ? argv[ti + 1] : undefined;
|
|
207
|
+
const result = checkPack({ tarball });
|
|
208
|
+
if (argv.includes("--json")) {
|
|
209
|
+
console.log(JSON.stringify(result, null, 2));
|
|
210
|
+
} else {
|
|
211
|
+
const dirs = Object.entries(result.topLevel)
|
|
212
|
+
.map(([k, v]) => `${k} ${v}`)
|
|
213
|
+
.join(", ");
|
|
214
|
+
console.log(`pack: ${result.count} files (${dirs})`);
|
|
215
|
+
for (const p of result.problems) console.log(`FAIL ${p}`);
|
|
216
|
+
if (result.ok) console.log("pack check passed");
|
|
217
|
+
}
|
|
218
|
+
process.exit(result.ok ? 0 : 1);
|
|
219
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
|
|
7
|
+
// compose.override.yaml belongs to the mutable stack root (PM_STACK_ROOT), not the code root.
|
|
8
|
+
const repo = path.resolve(
|
|
9
|
+
process.env.PM_STACK_ROOT || path.join(path.dirname(fileURLToPath(import.meta.url)), ".."),
|
|
10
|
+
);
|
|
11
|
+
const home = process.env.HOME || os.homedir();
|
|
12
|
+
const out = path.join(repo, "compose.override.yaml");
|
|
13
|
+
|
|
14
|
+
const dirs = [
|
|
15
|
+
".ssh",
|
|
16
|
+
".gnupg",
|
|
17
|
+
".config/hindsight",
|
|
18
|
+
// Provider env files with API keys (mem0.env, ...). The indexer never reads it.
|
|
19
|
+
".config/personal-memory",
|
|
20
|
+
".config/notebooklm",
|
|
21
|
+
".notebooklm",
|
|
22
|
+
".aws",
|
|
23
|
+
".config/gcloud",
|
|
24
|
+
".config/gh",
|
|
25
|
+
".config/glab-cli",
|
|
26
|
+
".kube",
|
|
27
|
+
".docker",
|
|
28
|
+
".mozilla",
|
|
29
|
+
".config/google-chrome",
|
|
30
|
+
".config/chromium",
|
|
31
|
+
".password-store",
|
|
32
|
+
".local/share/keyrings",
|
|
33
|
+
".config/fnox",
|
|
34
|
+
".local/share/fnox",
|
|
35
|
+
".secrets",
|
|
36
|
+
];
|
|
37
|
+
const files = [
|
|
38
|
+
".codex/auth.json",
|
|
39
|
+
".claude/.credentials.json",
|
|
40
|
+
".claude.json",
|
|
41
|
+
".netrc",
|
|
42
|
+
".git-credentials",
|
|
43
|
+
".npmrc",
|
|
44
|
+
".pypirc",
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
const tmpfsLines = [];
|
|
48
|
+
for (const d of dirs) {
|
|
49
|
+
if (fs.existsSync(path.join(home, d)) && fs.statSync(path.join(home, d)).isDirectory()) {
|
|
50
|
+
tmpfsLines.push(` - "${path.join(home, d)}"`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const volumeLines = [];
|
|
54
|
+
for (const f of files) {
|
|
55
|
+
if (fs.existsSync(path.join(home, f)) && fs.statSync(path.join(home, f)).isFile()) {
|
|
56
|
+
volumeLines.push(` - "/dev/null:${path.join(home, f)}:ro"`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const userIndex = path.join(home, ".config/hindsight/index.yml");
|
|
60
|
+
const envLines = [];
|
|
61
|
+
if (fs.existsSync(userIndex)) {
|
|
62
|
+
volumeLines.push(` - "${userIndex}:/etc/hindsight/index.yml:ro"`);
|
|
63
|
+
envLines.push(" HINDSIGHT_INDEX_CONFIG: /etc/hindsight/index.yml");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const parts = [
|
|
67
|
+
"# Generated by scripts/gen-masks.mjs for this host. Do not commit.",
|
|
68
|
+
"services:",
|
|
69
|
+
" indexer:",
|
|
70
|
+
];
|
|
71
|
+
if (tmpfsLines.length) {
|
|
72
|
+
parts.push(" tmpfs:", ...tmpfsLines);
|
|
73
|
+
}
|
|
74
|
+
if (volumeLines.length) {
|
|
75
|
+
parts.push(" volumes:", ...volumeLines);
|
|
76
|
+
}
|
|
77
|
+
if (envLines.length) {
|
|
78
|
+
parts.push(" environment:", ...envLines);
|
|
79
|
+
}
|
|
80
|
+
parts.push("");
|
|
81
|
+
|
|
82
|
+
fs.writeFileSync(out, parts.join("\n"));
|
|
83
|
+
console.log(`wrote ${out}`);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Promotion bar for experimental → supported: run contract tests; optional live Docker stacks.
|
|
4
|
+
* CI runs the Node tests only. Maintainers: MEM0_PROMOTION=1 COGNEE_PROMOTION=1 with stacks up.
|
|
5
|
+
*/
|
|
6
|
+
import { spawnSync } from "node:child_process";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
|
|
10
|
+
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
11
|
+
const tests = [
|
|
12
|
+
"scripts/tests/test_memory_facade.mjs",
|
|
13
|
+
"scripts/tests/test_memory_portability.mjs",
|
|
14
|
+
"scripts/tests/test_compose_profiles.mjs",
|
|
15
|
+
"scripts/tests/test_coding_agents.mjs",
|
|
16
|
+
"scripts/tests/test_wiring_report.mjs",
|
|
17
|
+
"scripts/tests/test_install_coding_agent.mjs",
|
|
18
|
+
"scripts/tests/test_session_shim.mjs",
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
let failed = 0;
|
|
22
|
+
for (const t of tests) {
|
|
23
|
+
const r = spawnSync(process.execPath, [path.join(root, t)], { stdio: "inherit" });
|
|
24
|
+
if (r.status !== 0) failed++;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (process.env.MEM0_PROMOTION === "1") {
|
|
28
|
+
console.log("MEM0_PROMOTION=1: run live mem0 stack + wizard smoke manually (see providers/mem0/OPERATOR.md)");
|
|
29
|
+
}
|
|
30
|
+
if (process.env.COGNEE_PROMOTION === "1") {
|
|
31
|
+
console.log("COGNEE_PROMOTION=1: run live Cognee cognify+search manually (see docs/cognee.md)");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
process.exit(failed ? 1 : 0);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Non-interactive checkout bootstrap (CI, remote shells without a TTY).
|
|
3
|
+
# Prefer: npx openmem or cd checkout && npx . setup
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
6
|
+
cd "${REPO}"
|
|
7
|
+
|
|
8
|
+
npm install --no-fund --no-audit
|
|
9
|
+
|
|
10
|
+
if [ -f "${HOME}/.config/hindsight/wizard.conf" ]; then
|
|
11
|
+
exec npx . setup --yes --no-smoke "$@"
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
if [ -t 0 ] && [ -t 1 ]; then
|
|
15
|
+
exec npx . setup --no-smoke "$@"
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
cat <<EOF
|
|
19
|
+
openmem checkout: ${REPO}
|
|
20
|
+
|
|
21
|
+
Run the wizard on a terminal (Docker, provider, indexing):
|
|
22
|
+
|
|
23
|
+
cd ${REPO}
|
|
24
|
+
mkdir -p ~/.config/personal-memory
|
|
25
|
+
cp config/openmem.toml.example ~/.config/personal-memory/config.toml
|
|
26
|
+
npx . setup
|
|
27
|
+
|
|
28
|
+
Or from npm (no clone): npx openmem
|
|
29
|
+
EOF
|
|
30
|
+
exit 0
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Write the stack .env (HOST_UID, HOST_GID and provider entries) and compose.override.yaml.
|
|
4
|
+
*
|
|
5
|
+
* PM_STACK_ROOT (default: this checkout) is the mutable stack directory; the provider
|
|
6
|
+
* comes from MEMORY_PROVIDER (default: hindsight) and is loaded from the read-only code
|
|
7
|
+
* root (PM_PACKAGE_ROOT, else this checkout). A provider contributes through optional
|
|
8
|
+
* exports of providers/<id>/wizard.mjs:
|
|
9
|
+
* prepareStackEnv({ repo, home, env }) -> { entries, drop, report }
|
|
10
|
+
* migrateEnv({ repo, home, env }) (for --migrate-env)
|
|
11
|
+
* setupNotices({ repo, home, env }) -> string[]
|
|
12
|
+
*/
|
|
13
|
+
import fs from "node:fs";
|
|
14
|
+
import os from "node:os";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
import { spawnSync } from "node:child_process";
|
|
17
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
18
|
+
import {
|
|
19
|
+
DEFAULT_PROVIDER_ID,
|
|
20
|
+
loadManifest,
|
|
21
|
+
} from "../wizard/lib/providers/registry.mjs";
|
|
22
|
+
import { wizardModulePath } from "../wizard/lib/provider-wizard/run-steps.mjs";
|
|
23
|
+
|
|
24
|
+
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
|
|
25
|
+
const packageRoot = path.resolve(process.env.PM_PACKAGE_ROOT || path.join(scriptDir, ".."));
|
|
26
|
+
const repo = path.resolve(process.env.PM_STACK_ROOT || packageRoot);
|
|
27
|
+
const home = process.env.HOME || os.homedir();
|
|
28
|
+
const envFile = path.join(repo, ".env");
|
|
29
|
+
const tmp = `${envFile}.tmp`;
|
|
30
|
+
const migrate = process.argv.includes("--migrate-env");
|
|
31
|
+
process.env.PM_PACKAGE_ROOT = packageRoot;
|
|
32
|
+
|
|
33
|
+
const providerId = process.env.MEMORY_PROVIDER || DEFAULT_PROVIDER_ID;
|
|
34
|
+
const manifest = loadManifest(providerId);
|
|
35
|
+
if (!manifest) {
|
|
36
|
+
console.error(`unknown memory provider '${providerId}' (see providers/*/manifest.json)`);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
const modFile = wizardModulePath(manifest);
|
|
40
|
+
const provider = modFile && fs.existsSync(modFile) ? await import(pathToFileURL(modFile).href) : {};
|
|
41
|
+
const opts = { repo, home, env: process.env };
|
|
42
|
+
|
|
43
|
+
/** @type {{ entries: [string, string][], drop: string[], report: string[] }} */
|
|
44
|
+
let spec = { entries: [], drop: [], report: [] };
|
|
45
|
+
try {
|
|
46
|
+
fs.mkdirSync(path.join(home, ".config/hindsight"), { recursive: true, mode: 0o700 });
|
|
47
|
+
if (typeof provider.prepareStackEnv === "function") {
|
|
48
|
+
spec = { ...spec, ...(await provider.prepareStackEnv(opts)) };
|
|
49
|
+
}
|
|
50
|
+
} catch (e) {
|
|
51
|
+
console.error(/** @type {Error} */ (e).message);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Context-proxy settings from config.toml ([context_proxy], [compaction]) for compose; keys the
|
|
56
|
+
// config leaves unset keep any hand-written .env line. Shell env still overrides at `compose up`.
|
|
57
|
+
/** @type {Record<string, string>} */
|
|
58
|
+
let proxyEnv = {};
|
|
59
|
+
try {
|
|
60
|
+
// Imported here: pm-config needs npm dependencies, and setup.mjs also runs from bare checkouts.
|
|
61
|
+
const { contextProxyStackEnvFromPmConfig, loadPmConfig } = await import("../wizard/lib/pm-config.mjs");
|
|
62
|
+
proxyEnv = contextProxyStackEnvFromPmConfig(loadPmConfig(home, repo).merged);
|
|
63
|
+
} catch (e) {
|
|
64
|
+
console.warn(`skipped context-proxy settings: ${/** @type {Error} */ (e).message}`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const dropRe = new RegExp(`^(${["HOST_UID", "HOST_GID", ...spec.drop, ...Object.keys(proxyEnv)].join("|")})=`);
|
|
68
|
+
|
|
69
|
+
const kept = [];
|
|
70
|
+
if (fs.existsSync(envFile)) {
|
|
71
|
+
for (const line of fs.readFileSync(envFile, "utf8").split("\n")) {
|
|
72
|
+
if (line && !dropRe.test(line)) kept.push(line);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const uid = os.userInfo().uid;
|
|
76
|
+
const gid = os.userInfo().gid;
|
|
77
|
+
kept.push(`HOST_UID=${uid}`, `HOST_GID=${gid}`);
|
|
78
|
+
for (const [key, value] of spec.entries) kept.push(`${key}=${value}`);
|
|
79
|
+
for (const [key, value] of Object.entries(proxyEnv)) kept.push(`${key}=${value}`);
|
|
80
|
+
fs.mkdirSync(repo, { recursive: true });
|
|
81
|
+
fs.writeFileSync(tmp, `${kept.filter(Boolean).join("\n")}\n`, { mode: 0o644 });
|
|
82
|
+
fs.renameSync(tmp, envFile);
|
|
83
|
+
console.log(`wrote ${envFile}: ${[`HOST_UID=${uid}`, `HOST_GID=${gid}`, ...spec.report].join(" ")}`);
|
|
84
|
+
|
|
85
|
+
const gen = spawnSync(process.execPath, [path.join(scriptDir, "gen-masks.mjs")], {
|
|
86
|
+
stdio: "inherit",
|
|
87
|
+
env: { ...process.env, PM_STACK_ROOT: repo },
|
|
88
|
+
});
|
|
89
|
+
if (gen.status !== 0) process.exit(gen.status ?? 1);
|
|
90
|
+
|
|
91
|
+
if (migrate) {
|
|
92
|
+
if (typeof provider.migrateEnv !== "function") {
|
|
93
|
+
console.error(`provider ${providerId} has no --migrate-env step`);
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
await provider.migrateEnv(opts);
|
|
98
|
+
} catch (e) {
|
|
99
|
+
console.error(/** @type {Error} */ (e).message);
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
process.exit(0);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (typeof provider.setupNotices === "function") {
|
|
106
|
+
for (const line of await provider.setupNotices(opts)) console.log(line);
|
|
107
|
+
}
|
package/scripts/setup.sh
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# openmem: test pack/install and optional GitHub release (clean subshell).
|
|
3
|
+
set -eu
|
|
4
|
+
ROOT=$(cd "$(dirname "$0")/.." && pwd)
|
|
5
|
+
LOG="${RUN_LOG:-/tmp/openmem-spin-$(date +%Y%m%d-%H%M%S).log}"
|
|
6
|
+
|
|
7
|
+
usage() {
|
|
8
|
+
cat <<EOF
|
|
9
|
+
Usage: sh scripts/spin-up.sh <target>
|
|
10
|
+
|
|
11
|
+
test npm test (pack + install + coding-agent wiring)
|
|
12
|
+
release merge wip/revamp -> main if needed, run Prepare release workflow
|
|
13
|
+
help
|
|
14
|
+
|
|
15
|
+
Log: \$RUN_LOG ($LOG)
|
|
16
|
+
EOF
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
run() {
|
|
20
|
+
(cd "$ROOT" && "$@") 2>&1 | tee "$LOG"
|
|
21
|
+
echo "log: $LOG"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
target=${1:-help}
|
|
25
|
+
case $target in
|
|
26
|
+
help|-h|--help) usage; exit 0 ;;
|
|
27
|
+
test) run npm test ;;
|
|
28
|
+
release)
|
|
29
|
+
run git fetch origin main wip/revamp
|
|
30
|
+
branch=$(git -C "$ROOT" rev-parse --abbrev-ref HEAD)
|
|
31
|
+
if [ "$branch" != main ]; then
|
|
32
|
+
git -C "$ROOT" checkout main
|
|
33
|
+
git -C "$ROOT" pull origin main
|
|
34
|
+
git -C "$ROOT" merge --no-edit origin/wip/revamp
|
|
35
|
+
git -C "$ROOT" push origin main
|
|
36
|
+
fi
|
|
37
|
+
gh workflow run "Prepare release" --repo bcmyguest/openmem -f dry_run=false
|
|
38
|
+
echo "Prepare release dispatched; watch: gh run list --repo bcmyguest/openmem --workflow Release"
|
|
39
|
+
;;
|
|
40
|
+
*)
|
|
41
|
+
echo "unknown: $target" >&2
|
|
42
|
+
usage >&2
|
|
43
|
+
exit 2
|
|
44
|
+
;;
|
|
45
|
+
esac
|
package/server.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
|
+
"name": "io.github.bcmyguest/openmem",
|
|
4
|
+
"title": "OpenMem",
|
|
5
|
+
"description": "Memory interface for coding agents \u2014 stable memory_* tools over Hindsight, mem0, or Cognee.",
|
|
6
|
+
"version": "0.6.4",
|
|
7
|
+
"packages": [
|
|
8
|
+
{
|
|
9
|
+
"registryType": "npm",
|
|
10
|
+
"identifier": "@bcmyguest/openmem",
|
|
11
|
+
"version": "0.6.4",
|
|
12
|
+
"transport": {
|
|
13
|
+
"type": "stdio"
|
|
14
|
+
},
|
|
15
|
+
"packageArguments": [],
|
|
16
|
+
"environmentVariables": [
|
|
17
|
+
{
|
|
18
|
+
"name": "MEMORY_PROVIDER",
|
|
19
|
+
"description": "Active backend: hindsight (default), mem0, or cognee",
|
|
20
|
+
"isRequired": false
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"name": "PM_STACK_ROOT",
|
|
24
|
+
"description": "OpenMem stack directory (compose project, .env)",
|
|
25
|
+
"isRequired": false
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"repository": {
|
|
31
|
+
"url": "https://github.com/bcmyguest/openmem",
|
|
32
|
+
"source": "github"
|
|
33
|
+
}
|
|
34
|
+
}
|
package/sync/Dockerfile
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# NotebookLM -> Hindsight sync (opt-in compose profile "notebooklm"). No browser: login runs on the host.
|
|
2
|
+
FROM python:3.12-slim
|
|
3
|
+
|
|
4
|
+
# Pinned: the unofficial notebooklm-py client changes without notice. google-auth and requests serve the optional
|
|
5
|
+
# enterprise backend only.
|
|
6
|
+
# [markdown] pulls markdownify — sources.get_fulltext(..., output_format="markdown") needs it.
|
|
7
|
+
RUN pip install --no-cache-dir 'notebooklm-py[markdown]==0.8.5' pyyaml==6.0.3 google-auth==2.62.0 requests==2.34.2
|
|
8
|
+
|
|
9
|
+
COPY sync/notebooklm_sync.py sync/memory_backend.py /opt/notebooklm/
|
|
10
|
+
COPY indexer/sinks/ /opt/indexer/sinks/
|
|
11
|
+
# Shipped default config. The per-machine override is mounted at /etc/notebooklm/override.yml by compose.
|
|
12
|
+
COPY config/notebooklm.yml /opt/config/notebooklm.yml
|
|
13
|
+
RUN chmod 0755 /opt/notebooklm/notebooklm_sync.py
|
|
14
|
+
|
|
15
|
+
# The compose user is the host's UID/GID, which has no passwd entry here. HOME must be writable and must not be the
|
|
16
|
+
# host's home. The state directory is 0777 so a fresh named volume (which copies the image's mode) is writable.
|
|
17
|
+
RUN mkdir -p /data/state /data/notebooklm /tmp/nlm-home && chmod 0777 /data/state /data/notebooklm /tmp/nlm-home
|
|
18
|
+
ENV PYTHONUNBUFFERED=1 \
|
|
19
|
+
PYTHONNOUSERSITE=1 \
|
|
20
|
+
PYTHONPATH=/opt/indexer \
|
|
21
|
+
HOME=/tmp/nlm-home \
|
|
22
|
+
NOTEBOOKLM_HOME=/data/notebooklm \
|
|
23
|
+
NOTEBOOKLM_STATE=/data/state/state.json \
|
|
24
|
+
HINDSIGHT_URL=http://hindsight:8888 \
|
|
25
|
+
MEMORY_SINK=hindsight
|
|
26
|
+
|
|
27
|
+
CMD ["python3", "/opt/notebooklm/notebooklm_sync.py"]
|