@bcmyguest/openmem 0.6.3 → 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.
Files changed (102) hide show
  1. package/{skills → .agents/skills}/openmem/SKILL.md +5 -0
  2. package/README.md +80 -76
  3. package/cli/coding-agent/capabilities.mjs +14 -3
  4. package/cli/coding-agent/context-store.mjs +81 -0
  5. package/cli/coding-agent/context-trim.mjs +897 -0
  6. package/cli/coding-agent/file-io.mjs +72 -0
  7. package/cli/coding-agent/hook-harnesses.mjs +2 -1
  8. package/cli/coding-agent/hook-runner.mjs +28 -4
  9. package/cli/coding-agent/install-access.mjs +43 -17
  10. package/cli/coding-agent/install-context-proxy.mjs +333 -0
  11. package/cli/coding-agent/install-rtk.mjs +60 -0
  12. package/cli/coding-agent/install-shim.mjs +119 -15
  13. package/cli/coding-agent/opencode-config.mjs +21 -5
  14. package/cli/coding-agent/opencode-plugin.mjs +39 -3
  15. package/cli/coding-agent/opencode2-plugin/index.js +299 -0
  16. package/cli/coding-agent/recall-frame.mjs +29 -0
  17. package/cli/coding-agent/remove-upstream-access.mjs +122 -0
  18. package/cli/coding-agent/runtime.mjs +2 -1
  19. package/cli/coding-agent/session-db.mjs +626 -0
  20. package/cli/coding-agent/session-facade.mjs +30 -6
  21. package/cli/coding-agent/toml-edit.mjs +161 -0
  22. package/cli/context-management.mjs +254 -0
  23. package/cli/feed-sync.mjs +18 -2
  24. package/cli/install-coding-agent.mjs +173 -40
  25. package/cli/mcp/context-sql-runner.mjs +58 -0
  26. package/cli/mcp/context-store.mjs +670 -0
  27. package/cli/mcp/knowledge.mjs +333 -0
  28. package/cli/mcp/memory-facade.mjs +99 -33
  29. package/cli/openmem-mcp.mjs +3 -0
  30. package/cli/openmem.mjs +18 -1
  31. package/cli/schedule.mjs +176 -0
  32. package/cli/stack.mjs +2 -0
  33. package/cli/switch-memory-provider.mjs +1 -1
  34. package/compose.yaml +67 -4
  35. package/config/hindsight.env.example +2 -0
  36. package/config/openmem.toml.example +64 -2
  37. package/docs/architecture.md +35 -9
  38. package/docs/coding-agent-hooks.md +26 -2
  39. package/docs/coding-agents.md +27 -7
  40. package/docs/compatibility.md +80 -0
  41. package/docs/concepts.md +30 -7
  42. package/docs/context-management.md +255 -0
  43. package/docs/context-proxy.md +115 -0
  44. package/docs/context-research.md +215 -0
  45. package/docs/context-store.md +277 -0
  46. package/docs/hindsight.md +5 -2
  47. package/docs/mcp-setup.md +5 -2
  48. package/docs/mem0.md +39 -1
  49. package/docs/memory-providers.md +2 -2
  50. package/docs/meridian-litellm.md +198 -0
  51. package/docs/model-configuration.md +22 -0
  52. package/docs/npx-install.md +6 -4
  53. package/docs/openmem-config.md +2 -2
  54. package/docs/quickstart.md +12 -6
  55. package/docs/setup-wizard.md +5 -4
  56. package/docs/sources-feeds.md +9 -22
  57. package/package.json +5 -4
  58. package/providers/cognee/OPERATOR.md +2 -2
  59. package/providers/hindsight/lib/clack.mjs +122 -20
  60. package/providers/hindsight/lib/coding-agent.mjs +1 -1
  61. package/providers/hindsight/lib/config.mjs +6 -0
  62. package/providers/hindsight/lib/env-setup.mjs +2 -1
  63. package/providers/hindsight/lib/litellm-routes.mjs +21 -12
  64. package/providers/hindsight/lib/meridian.mjs +307 -0
  65. package/providers/hindsight/lib/model-backend.mjs +38 -9
  66. package/providers/hindsight/lib/probe.mjs +21 -0
  67. package/providers/hindsight/lib/stack-env.mjs +5 -12
  68. package/providers/hindsight/lib/state.mjs +6 -1
  69. package/providers/hindsight/lib/summary.mjs +16 -2
  70. package/providers/hindsight/lib/validate.mjs +6 -0
  71. package/providers/hindsight/wizard.mjs +3 -2
  72. package/providers/mem0/OPERATOR.md +21 -2
  73. package/providers/mem0/compose.yaml +24 -2
  74. package/providers/mem0/lib/coding-agent.mjs +1 -1
  75. package/providers/mem0/lib/configure.mjs +66 -0
  76. package/providers/mem0/lib/litellm.mjs +457 -0
  77. package/providers/mem0/lib/stack-env.mjs +40 -1
  78. package/providers/mem0/lib/summary.mjs +30 -2
  79. package/providers/mem0/manifest.json +1 -1
  80. package/providers/mem0/wizard.mjs +15 -2
  81. package/proxy/config.yaml +33 -0
  82. package/proxy/openmem_context/__init__.py +6 -0
  83. package/proxy/openmem_context/adapters.py +504 -0
  84. package/proxy/openmem_context/compress.py +53 -0
  85. package/proxy/openmem_context/core.py +606 -0
  86. package/proxy/openmem_context/embed.py +212 -0
  87. package/proxy/openmem_context/recall.py +49 -0
  88. package/proxy/openmem_context/session.py +70 -0
  89. package/proxy/openmem_context/sessiondb.py +276 -0
  90. package/proxy/openmem_context/settings.py +134 -0
  91. package/proxy/openmem_context/store.py +129 -0
  92. package/proxy/openmem_context/tokens.py +123 -0
  93. package/proxy/openmem_context/ttl.py +78 -0
  94. package/proxy/openmem_context_hook.py +34 -0
  95. package/scripts/check-pack.mjs +2 -1
  96. package/scripts/setup.mjs +14 -1
  97. package/server.json +2 -2
  98. package/wizard/lib/context-step.mjs +140 -0
  99. package/wizard/lib/litellm-env.mjs +55 -0
  100. package/wizard/lib/pm-config.mjs +212 -4
  101. package/wizard/lib/prompts.mjs +28 -0
  102. package/wizard/lib/run-wizard.mjs +26 -31
@@ -1,16 +1,23 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * Install coding-agent session memory for Claude Code, Codex, OpenCode, Cursor CLI.
4
- * All providers: unified MCP + in-repo session hooks.
5
- * Optional: --hindsight-plugin also runs @vectorize-io/hindsight-coding-agents (Hindsight stacks only).
4
+ * All providers: unified MCP. Session hooks come from OpenMem ([agents] integration =
5
+ * "openmem", default) or the provider's own plugin ("provider", Hindsight only); never both.
6
+ * Optional: rtk command rewriting when rtk is on PATH, and the local context proxy.
6
7
  */
7
8
  import { spawnSync } from "node:child_process";
9
+ import fs from "node:fs";
8
10
  import path from "node:path";
9
11
  import { fileURLToPath } from "node:url";
10
12
  import { CODING_AGENTS, DEFAULT_AGENT_IDS } from "./coding-agent/agents.mjs";
11
13
  import { AGENT_IDS, PROVIDER_CAPABILITIES } from "./coding-agent/capabilities.mjs";
12
- import { installSessionShim } from "./coding-agent/install-shim.mjs";
14
+ import { installSessionShim, removeSessionShim, removeUpstreamHooks } from "./coding-agent/install-shim.mjs";
13
15
  import { installAgentAccess } from "./coding-agent/install-access.mjs";
16
+ import { contextProxyStartCommand, installContextProxy, probeContextProxy } from "./coding-agent/install-context-proxy.mjs";
17
+ import { upsertEnvFile } from "./coding-agent/file-io.mjs";
18
+ import { installRtk } from "./coding-agent/install-rtk.mjs";
19
+ import { removeUpstreamAccess } from "./coding-agent/remove-upstream-access.mjs";
20
+ import { opencodeMajorVersion } from "./coding-agent/opencode-config.mjs";
14
21
  import { prepareAgentRuntime } from "./coding-agent/runtime.mjs";
15
22
  import { SHIM_AGENT_IDS } from "./coding-agent/hook-harnesses.mjs";
16
23
  import { resolveMemoryProvider } from "./install-memory-mcp.mjs";
@@ -18,20 +25,44 @@ import { isMainModule } from "./is-main.mjs";
18
25
  import { resolveHindsightApiUrl } from "./mcp/context.mjs";
19
26
  import { resolveStackRoot } from "./stack.mjs";
20
27
  import { runInstallMemoryMcp } from "./install-memory-mcp.mjs";
28
+ import { ensureContextProxyService, proxyServiceNeeded } from "./context-management.mjs";
29
+ import {
30
+ agentIntegrationFromPmConfig,
31
+ contextAgentsFromPmConfig,
32
+ contextProxyFromPmConfig,
33
+ contextProxyStackEnvFromPmConfig,
34
+ loadPmConfig,
35
+ updatePmConfigTable,
36
+ } from "../wizard/lib/pm-config.mjs";
21
37
 
22
38
  const PKG_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
23
39
  const BIN = "openmem-install-coding-agent";
40
+ /** Providers that ship their own coding-agent plugin. */
41
+ const PROVIDER_PLUGINS = ["hindsight"];
24
42
 
25
43
  const HELP = `${BIN}: wire session memory for coding agents
26
44
 
27
45
  Usage:
28
- npx openmem install-coding-agent [--yes] [--dry-run] [--agents a,b] [--hindsight-plugin]
46
+ npx openmem install-coding-agent [--yes] [--dry-run] [--agents a,b]
47
+ [--provider-plugin | --no-provider-plugin] [--no-rtk]
48
+ [--context-proxy | --no-context-proxy]
29
49
 
30
50
  Default agents: ${DEFAULT_AGENT_IDS.join(", ")}
31
51
  All known agents: ${CODING_AGENTS.map((a) => a.id).join(", ")}
32
52
 
33
- Every provider gets install-mcp + openmem session hooks (SessionStart / prompt / Stop).
34
- With --hindsight-plugin and MEMORY_PROVIDER=hindsight, also runs hindsight-coding-agents install.
53
+ Every provider gets install-mcp. Session hooks are exclusive:
54
+ default openmem hooks (SessionStart / prompt / Stop); removes upstream Hindsight
55
+ hooks, its "hindsight" MCP server and its hindsight-coding-agent skill
56
+ --provider-plugin the provider's own plugin (Hindsight: hindsight-coding-agents); removes openmem hooks
57
+ --no-provider-plugin switch back to openmem hooks
58
+ The choice is saved as [agents] integration in ~/.config/personal-memory/config.toml.
59
+ --hindsight-plugin was renamed to --provider-plugin.
60
+
61
+ rtk on PATH: runs rtk init for each supported agent (skip with --no-rtk).
62
+ Context proxy: without a flag, [context_proxy.agents] claude-code / opencode1 / codex (missing keys follow
63
+ [context_proxy] enabled) choose which agents go through the local context proxy. With a stack root,
64
+ the installer starts the context-proxy service when one of them is on and stops it when none is.
65
+ --context-proxy / --no-context-proxy override every agent for this run and save [context_proxy] enabled.
35
66
  `;
36
67
 
37
68
  function parseArgs(argv) {
@@ -39,7 +70,9 @@ function parseArgs(argv) {
39
70
  yes: false,
40
71
  dry: false,
41
72
  help: false,
42
- hindsightPlugin: false,
73
+ providerPlugin: undefined,
74
+ rtk: true,
75
+ contextProxy: undefined,
43
76
  agents: [...DEFAULT_AGENT_IDS],
44
77
  unknown: [],
45
78
  };
@@ -48,7 +81,11 @@ function parseArgs(argv) {
48
81
  if (a === "--yes" || a === "-y") flags.yes = true;
49
82
  else if (a === "--dry-run") flags.dry = true;
50
83
  else if (a === "--help" || a === "-h") flags.help = true;
51
- else if (a === "--hindsight-plugin") flags.hindsightPlugin = true;
84
+ else if (a === "--provider-plugin") flags.providerPlugin = true;
85
+ else if (a === "--no-provider-plugin") flags.providerPlugin = false;
86
+ else if (a === "--no-rtk") flags.rtk = false;
87
+ else if (a === "--context-proxy") flags.contextProxy = true;
88
+ else if (a === "--no-context-proxy") flags.contextProxy = false;
52
89
  else if (a === "--agents") flags.agents = String(argv[++i] || "").split(",").map((s) => s.trim()).filter(Boolean);
53
90
  else flags.unknown.push(a);
54
91
  }
@@ -63,38 +100,111 @@ function h() {
63
100
  };
64
101
  }
65
102
 
103
+ /** Resolve integration and proxy settings from flags, then config; persist flag choices. */
104
+ function resolveSettings({ home, stackRoot, flags, write, log }) {
105
+ const cfg = loadPmConfig(home, stackRoot || home).merged;
106
+ const providerFlag = flags.providerPlugin;
107
+ const integration = providerFlag === undefined ? agentIntegrationFromPmConfig(cfg) : providerFlag ? "provider" : "openmem";
108
+ const proxy = contextProxyFromPmConfig(cfg);
109
+ const contextAgents = contextAgentsFromPmConfig(cfg).agents;
110
+ if (flags.contextProxy !== undefined) {
111
+ proxy.enabled = flags.contextProxy;
112
+ for (const k of Object.keys(contextAgents)) contextAgents[k] = flags.contextProxy;
113
+ }
114
+ if (providerFlag !== undefined) {
115
+ const r = updatePmConfigTable(home, "agents", { integration }, { dry: !write });
116
+ log.info(`${r === "dry-run" ? "dry-run: would save" : "saved"} [agents] integration = "${integration}"`);
117
+ }
118
+ if (flags.contextProxy !== undefined) {
119
+ const r = updatePmConfigTable(home, "context_proxy", { enabled: proxy.enabled }, { dry: !write });
120
+ log.info(`${r === "dry-run" ? "dry-run: would save" : "saved"} [context_proxy] enabled = ${proxy.enabled}`);
121
+ }
122
+ return { integration, proxy, contextAgents, cfg };
123
+ }
124
+
125
+ /** Copy config.toml's proxy settings into the stack .env compose reads, when that file exists. */
126
+ function syncProxyStackEnv({ stackRoot, cfg, log }) {
127
+ const entries = contextProxyStackEnvFromPmConfig(cfg);
128
+ const file = stackRoot ? path.join(stackRoot, ".env") : "";
129
+ if (!file || !Object.keys(entries).length || !fs.existsSync(file)) return;
130
+ upsertEnvFile(file, entries);
131
+ log.ok(`context proxy settings → ${file} (${Object.keys(entries).join(", ")})`);
132
+ }
133
+
134
+ /** Warn loudly when the proxy is not answering: Claude Code fails every request until it runs. */
135
+ async function warnIfProxyDown({ port, startCommand, log, fetch }) {
136
+ if (await probeContextProxy(port, { fetch })) {
137
+ log.ok(`context proxy is up on http://127.0.0.1:${port}`);
138
+ return true;
139
+ }
140
+ const bar = "!".repeat(72);
141
+ log.warn([
142
+ bar,
143
+ `! Context proxy is NOT running on http://127.0.0.1:${port}.`,
144
+ "! Claude Code (and OpenCode 1) now send every request there and will fail until it runs.",
145
+ `! Start it: ${startCommand}`,
146
+ "! Or disable: npx openmem install-coding-agent --yes --no-context-proxy",
147
+ bar,
148
+ ].join("\n"));
149
+ return false;
150
+ }
151
+
66
152
  export async function runInstallCodingAgent(opts) {
67
153
  const home = opts.home;
68
154
  const env = opts.env || process.env;
69
155
  const flags = opts.flags;
156
+ const log = opts.h || h();
70
157
  for (const agentId of flags.agents) {
71
158
  if (!AGENT_IDS.includes(agentId)) {
72
- opts.h?.warn(`Unknown agent "${agentId}" (known: ${AGENT_IDS.join(", ")})`);
159
+ log.warn(`Unknown agent "${agentId}" (known: ${AGENT_IDS.join(", ")})`);
73
160
  }
74
161
  }
75
162
  const provider = resolveMemoryProvider(home, env);
76
163
  const caps = PROVIDER_CAPABILITIES[provider] || {};
77
- opts.h?.info(`Provider ${provider}: capabilities ${JSON.stringify(caps)}`);
164
+ log.info(`Provider ${provider}: capabilities ${JSON.stringify(caps)}`);
78
165
 
166
+ const dry = flags.dry || !flags.yes;
167
+ const { integration, proxy, contextAgents, cfg } = resolveSettings({ home, stackRoot: opts.stackRoot, flags, write: !dry, log });
168
+ const project = env.PM_PROJECT || String(cfg.stack?.project || "") || "openmem";
169
+ const startCommand = contextProxyStartCommand({ stackRoot: opts.stackRoot, project });
170
+ // OpenCode 2 never uses the proxy; its plugin reads [context_proxy.agents] opencode2 itself.
171
+ const agentEnabled = { "claude-code": contextAgents["claude-code"], opencode: contextAgents.opencode1, codex: contextAgents.codex };
172
+ const serviceOn = proxyServiceNeeded(contextAgents);
173
+ const service = (dryRun) => ensureContextProxyService({
174
+ home, stackRoot: opts.stackRoot, project, on: serviceOn, dry: dryRun, env, spawn: opts.docker, log,
175
+ });
176
+ const useProviderPlugin = integration === "provider" && PROVIDER_PLUGINS.includes(provider);
177
+ if (integration === "provider" && !useProviderPlugin) {
178
+ log.warn(`Provider ${provider} has no coding-agent plugin; installing openmem hooks instead`);
179
+ }
79
180
  const shimAgents = flags.agents.filter((id) => SHIM_AGENT_IDS.includes(id) || id === "opencode");
181
+ const opencodeMajor = flags.agents.includes("opencode") ? opencodeMajorVersion({ env }) : 1;
80
182
  const runtimeRoot = prepareAgentRuntime({
81
- home, repoRoot: opts.repoRoot, stackRoot: opts.stackRoot, dry: flags.dry || !flags.yes, h: opts.h || h(),
183
+ home, repoRoot: opts.repoRoot, stackRoot: opts.stackRoot, dry, h: log,
82
184
  });
185
+ const upstreamCmd = () => {
186
+ const apiUrl = resolveHindsightApiUrl({ home, stackRoot: opts.stackRoot, env });
187
+ return ["npx", "-y", "@vectorize-io/hindsight-coding-agents", "install", ...flags.agents, "--server", "self-hosted", "--api-url", apiUrl];
188
+ };
83
189
  if (flags.dry) {
84
- opts.h?.info("dry-run: would run install-mcp --yes");
85
- installSessionShim({ home, repoRoot: runtimeRoot, agents: shimAgents, dry: true, h: opts.h || h() });
86
- installAgentAccess({ home, runtimeRoot, stackRoot: opts.stackRoot, agents: flags.agents, dry: true, h: opts.h || h() });
87
- if (flags.hindsightPlugin && provider === "hindsight") {
88
- const apiUrl = resolveHindsightApiUrl({ home, stackRoot: opts.stackRoot, env });
89
- opts.h?.info(
90
- `dry-run: would also run npx @vectorize-io/hindsight-coding-agents install ${flags.agents.join(" ")} --server self-hosted --api-url ${apiUrl}`,
91
- );
190
+ log.info("dry-run: would run install-mcp --yes");
191
+ if (useProviderPlugin) {
192
+ removeSessionShim({ home, agents: shimAgents, dry: true, h: log });
193
+ } else {
194
+ installSessionShim({ home, repoRoot: runtimeRoot, agents: shimAgents, dry: true, h: log, opencodeMajor });
195
+ removeUpstreamHooks({ home, agents: shimAgents, dry: true, h: log });
196
+ removeUpstreamAccess({ home, agents: flags.agents, dry: true, h: log });
92
197
  }
93
- return { provider, ran: false };
198
+ installAgentAccess({ home, runtimeRoot, stackRoot: opts.stackRoot, agents: flags.agents, dry: true, h: log });
199
+ if (flags.rtk) installRtk({ agents: flags.agents, env, dry: true, h: log, opencodeMajor });
200
+ installContextProxy({ home, agents: flags.agents, enabled: proxy.enabled, agentEnabled, port: proxy.port, dry: true, h: log, opencodeMajor });
201
+ service(true);
202
+ if (useProviderPlugin) log.info(`dry-run: would also run ${upstreamCmd().join(" ")}`);
203
+ return { provider, integration, ran: false };
94
204
  }
95
205
  if (!flags.yes) {
96
- opts.h?.warn("Re-run with --yes to install MCP + session hooks");
97
- return { provider, ran: false };
206
+ log.warn("Re-run with --yes to install MCP + session hooks");
207
+ return { provider, integration, ran: false };
98
208
  }
99
209
 
100
210
  await runInstallMemoryMcp({
@@ -103,40 +213,63 @@ export async function runInstallCodingAgent(opts) {
103
213
  stackRoot: opts.stackRoot,
104
214
  flags: { yes: true, dry: false, notebooklm: false, notebooklmOnly: false, providerOnly: false, noUnifiedMcp: false, help: false, unknown: [] },
105
215
  env,
106
- h: opts.h || h(),
107
- });
108
- installSessionShim({
109
- home,
110
- repoRoot: runtimeRoot,
111
- agents: shimAgents,
112
- dry: false,
113
- h: opts.h || h(),
216
+ h: log,
114
217
  });
218
+ if (useProviderPlugin) {
219
+ removeSessionShim({ home, agents: shimAgents, h: log });
220
+ } else {
221
+ installSessionShim({ home, repoRoot: runtimeRoot, agents: shimAgents, dry: false, h: log, opencodeMajor });
222
+ removeUpstreamHooks({ home, agents: shimAgents, h: log });
223
+ removeUpstreamAccess({ home, agents: flags.agents, h: log });
224
+ }
115
225
  installAgentAccess({
116
- home, runtimeRoot, stackRoot: opts.stackRoot, agents: flags.agents, dry: false, h: opts.h || h(),
226
+ home, runtimeRoot, stackRoot: opts.stackRoot, agents: flags.agents, dry: false, h: log,
117
227
  });
228
+ const rtk = flags.rtk ? installRtk({ agents: flags.agents, env, h: log, spawn: opts.spawn, opencodeMajor }) : { rtk: null, ran: [] };
229
+ // On: start the service before agents point at it. Off: stop it after they are unwired.
230
+ if (serviceOn) service(false);
231
+ const proxyOut = installContextProxy({ home, agents: flags.agents, enabled: proxy.enabled, agentEnabled, port: proxy.port, h: log, opencodeMajor });
232
+ if (!serviceOn) service(false);
233
+ const proxyUsed = flags.agents.some((id) => id in agentEnabled && agentEnabled[id] && !proxyOut.pluginTrimmed.includes(id));
234
+ if (proxyUsed) {
235
+ syncProxyStackEnv({ stackRoot: opts.stackRoot, cfg, log });
236
+ await warnIfProxyDown({ port: proxy.port, startCommand, log, fetch: opts.fetch });
237
+ }
118
238
 
119
- if (flags.hindsightPlugin && provider === "hindsight") {
120
- const apiUrl = resolveHindsightApiUrl({ home, stackRoot: opts.stackRoot, env });
121
- const cmd = ["npx", "-y", "@vectorize-io/hindsight-coding-agents", "install", ...flags.agents, "--server", "self-hosted", "--api-url", apiUrl];
122
- opts.h?.info(`Also installing upstream Hindsight plugin: ${cmd.join(" ")}`);
123
- const r = spawnSync(cmd[0], cmd.slice(1), { stdio: "inherit", env });
124
- return { provider, ran: true, status: r.status ?? 1 };
239
+ let status = 0;
240
+ if (useProviderPlugin) {
241
+ const cmd = upstreamCmd();
242
+ log.info(`Installing upstream Hindsight plugin: ${cmd.join(" ")}`);
243
+ const r = (opts.spawn || spawnSync)(cmd[0], cmd.slice(1), { stdio: "inherit", env });
244
+ status = r.status ?? 1;
125
245
  }
126
246
 
127
247
  for (const agentId of flags.agents) {
128
248
  if (shimAgents.includes(agentId)) {
129
- opts.h?.info(` ${agentId}: openmem session hooks + unified MCP`);
249
+ const hooks = useProviderPlugin ? "upstream Hindsight hooks" : "openmem session hooks";
250
+ const extras = [
251
+ rtk.ran.includes(agentId) ? "rtk" : "",
252
+ proxyOut.changed.includes(agentId) && agentEnabled[agentId] ? "context proxy" : "",
253
+ !useProviderPlugin && proxyOut.pluginTrimmed.includes(agentId) ? "native context trimming (OpenCode 2; context proxy not used)" : "",
254
+ ].filter(Boolean);
255
+ log.info(` ${agentId}: ${hooks} + unified MCP${extras.length ? ` + ${extras.join(" + ")}` : ""}`);
130
256
  } else {
131
257
  const row = CODING_AGENTS.find((a) => a.id === agentId);
132
- opts.h?.info(` ${agentId}: ${row?.sessionPath || "unified MCP memory_*"}`);
258
+ log.info(` ${agentId}: ${row?.sessionPath || "unified MCP memory_*"}`);
133
259
  }
134
260
  }
135
- return { provider, ran: true, status: 0 };
261
+ if (agentEnabled["claude-code"] && flags.agents.includes("claude-code")) {
262
+ log.info(`Context proxy enabled: Claude Code now sends every request to http://127.0.0.1:${proxy.port}; start the proxy before using Claude Code: ${startCommand}`);
263
+ }
264
+ return { provider, integration, ran: true, status };
136
265
  }
137
266
 
138
267
  async function main() {
139
268
  const flags = parseArgs(process.argv.slice(2));
269
+ if (flags.unknown.includes("--hindsight-plugin")) {
270
+ console.error("install-coding-agent: --hindsight-plugin was renamed to --provider-plugin");
271
+ process.exit(2);
272
+ }
140
273
  if (flags.help || flags.unknown.length) {
141
274
  console.log(HELP);
142
275
  process.exit(flags.unknown.length ? 2 : 0);
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Child process for smart_compact_sql (cli/mcp/context-store.mjs): reads {file, sql, cap, cellMax} as JSON on
3
+ * stdin, runs the statement on a read-only connection and prints {columns, rows, truncated} or {error}. The parent
4
+ * kills it after its time limit, which also stops a long-running SQLite step.
5
+ */
6
+ import fs from "node:fs";
7
+
8
+ const SQLITE_OK = 0;
9
+ const SQLITE_DENY = 1;
10
+ // sqlite3_set_authorizer action codes allowed for a query: SELECT, READ, FUNCTION, RECURSIVE.
11
+ const ALLOWED_ACTIONS = new Set([21, 20, 31, 33]);
12
+ // SQLITE_PRAGMA; FTS5 reads `PRAGMA data_version` internally on a MATCH. User SQL never reaches here with a
13
+ // PRAGMA (the parent's statement check rejects it), and an assignment carries a value in arg2.
14
+ const SQLITE_PRAGMA = 19;
15
+ const READ_PRAGMAS = new Set(["data_version"]);
16
+
17
+ function cell(value, cellMax) {
18
+ if (value instanceof Uint8Array) return `<blob ${value.byteLength} bytes>`;
19
+ if (typeof value === "bigint") return Number.isSafeInteger(Number(value)) ? Number(value) : String(value);
20
+ if (typeof value === "string" && value.length > cellMax) return `${value.slice(0, cellMax)}…`;
21
+ return value;
22
+ }
23
+
24
+ function run({ file, sql, cap, cellMax }) {
25
+ const { DatabaseSync } = process.getBuiltinModule("node:sqlite");
26
+ const db = new DatabaseSync(file, { readOnly: true });
27
+ try {
28
+ db.exec("PRAGMA busy_timeout = 1000");
29
+ // Node >= 24.10 (setAuthorizer): deny every action a query does not need, on top of the read-only
30
+ // connection and the parent's statement check.
31
+ if (typeof db.setAuthorizer === "function") {
32
+ db.setAuthorizer((action, arg1, arg2) => (ALLOWED_ACTIONS.has(action)
33
+ || (action === SQLITE_PRAGMA && READ_PRAGMAS.has(String(arg1).toLowerCase()) && arg2 === null) ? SQLITE_OK : SQLITE_DENY));
34
+ }
35
+ const rows = [];
36
+ let truncated = false;
37
+ let columns = [];
38
+ for (const row of db.prepare(sql).iterate()) {
39
+ if (rows.length === cap) {
40
+ truncated = true;
41
+ break;
42
+ }
43
+ if (!columns.length) columns = Object.keys(row);
44
+ rows.push(Object.fromEntries(Object.entries(row).map(([k, v]) => [k, cell(v, cellMax)])));
45
+ }
46
+ return { columns, rows, truncated };
47
+ } finally {
48
+ db.close();
49
+ }
50
+ }
51
+
52
+ let out;
53
+ try {
54
+ out = run(JSON.parse(fs.readFileSync(0, "utf8")));
55
+ } catch (err) {
56
+ out = { error: err instanceof Error ? err.message : String(err) };
57
+ }
58
+ process.stdout.write(JSON.stringify(out));