@remnic/server 1.0.3 → 1.0.4
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/dist/bin/{chunk-XDNRJ5ON.js → chunk-MKNXEH3P.js} +4 -2
- package/dist/bin/chunk-MKNXEH3P.js.map +1 -0
- package/dist/bin/engram-server.js +1 -1
- package/dist/bin/remnic-server.js +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/package.json +7 -8
- package/dist/bin/chunk-XDNRJ5ON.js.map +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Joshua Warren
|
|
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.
|
|
@@ -72,7 +72,9 @@ async function startServer(options) {
|
|
|
72
72
|
authTokensGetter: () => getAllValidTokensCached(),
|
|
73
73
|
principal: serverConfig.principal,
|
|
74
74
|
maxBodyBytes: serverConfig.maxBodyBytes,
|
|
75
|
-
adminConsoleEnabled: serverConfig.adminConsoleEnabled ?? false
|
|
75
|
+
adminConsoleEnabled: serverConfig.adminConsoleEnabled ?? false,
|
|
76
|
+
citationsEnabled: config.citationsEnabled,
|
|
77
|
+
citationsAutoDetect: config.citationsAutoDetect
|
|
76
78
|
});
|
|
77
79
|
const { host, port } = await httpServer.start();
|
|
78
80
|
return { config, service, httpServer, host, port };
|
|
@@ -147,4 +149,4 @@ if (process.argv[1] && (/remnic-server[\\/](?:dist|src)[\\/]index\.[jt]s$/.test(
|
|
|
147
149
|
export {
|
|
148
150
|
cliMain
|
|
149
151
|
};
|
|
150
|
-
//# sourceMappingURL=chunk-
|
|
152
|
+
//# sourceMappingURL=chunk-MKNXEH3P.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["/**\n * @remnic/server\n *\n * Standalone Remnic memory server.\n *\n * Loads config from `remnic.config.json` (or env vars), creates an Orchestrator,\n * and starts the HTTP access server with MCP endpoint — no OpenClaw required.\n *\n * Usage:\n * npx remnic-server\n * npx remnic-server --config ./my-remnic.json\n * npx remnic-server --port 4320\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { parseConfig, Orchestrator, EngramAccessService, EngramAccessHttpServer, initLogger, log, getAllValidTokens, getAllValidTokensCached, type PluginConfig } from \"@remnic/core\";\n\n// ── Config loading ──────────────────────────────────────────────────────────\n\nexport interface ServerConfig {\n remnic: Record<string, unknown>;\n server: {\n host?: string;\n port?: number;\n authToken?: string;\n principal?: string;\n maxBodyBytes?: number;\n adminConsoleEnabled?: boolean;\n };\n}\n\nfunction readCompatEnv(primary: string, legacy: string): string | undefined {\n return process.env[primary] ?? process.env[legacy];\n}\n\nfunction resolveConfigPath(cliPath?: string): string {\n if (cliPath) return path.resolve(cliPath);\n\n const envPath = readCompatEnv(\"REMNIC_CONFIG_PATH\", \"ENGRAM_CONFIG_PATH\");\n if (envPath) return path.resolve(envPath);\n\n const homeDir = process.env.HOME ?? \"~\";\n const candidates = [\n path.join(process.cwd(), \"remnic.config.json\"),\n path.join(process.cwd(), \"engram.config.json\"),\n path.join(homeDir, \".config\", \"remnic\", \"config.json\"),\n path.join(homeDir, \".config\", \"engram\", \"config.json\"),\n ];\n for (const candidate of candidates) {\n if (fs.existsSync(candidate)) return candidate;\n }\n\n return path.join(homeDir, \".config\", \"remnic\", \"config.json\");\n}\n\nfunction loadConfigFile(configPath: string): ServerConfig {\n const raw = JSON.parse(fs.readFileSync(configPath, \"utf8\"));\n return {\n remnic: raw.remnic ?? raw.engram ?? raw ?? {},\n server: raw.server ?? {},\n };\n}\n\nfunction envOverrides(): Partial<ServerConfig[\"server\"]> & { remnic?: Record<string, unknown> } {\n const overrides: Record<string, unknown> = {};\n const remnic: Record<string, unknown> = {};\n\n const port = readCompatEnv(\"REMNIC_PORT\", \"ENGRAM_PORT\");\n const host = readCompatEnv(\"REMNIC_HOST\", \"ENGRAM_HOST\");\n const authToken = readCompatEnv(\"REMNIC_AUTH_TOKEN\", \"ENGRAM_AUTH_TOKEN\");\n if (port) overrides.port = parseInt(port, 10);\n if (host) overrides.host = host;\n if (authToken) overrides.authToken = authToken;\n\n if (process.env.OPENAI_API_KEY) remnic.openaiApiKey = process.env.OPENAI_API_KEY;\n const memoryDir = readCompatEnv(\"REMNIC_MEMORY_DIR\", \"ENGRAM_MEMORY_DIR\");\n if (memoryDir) remnic.memoryDir = memoryDir;\n\n return { ...overrides, ...(Object.keys(remnic).length > 0 ? { remnic } : {}) };\n}\n\n// ── Server startup ──────────────────────────────────────────────────────────\n\nexport interface ServerResult {\n config: PluginConfig;\n service: EngramAccessService;\n httpServer: EngramAccessHttpServer;\n host: string;\n port: number;\n}\n\nexport async function startServer(options?: {\n configPath?: string;\n host?: string;\n port?: number;\n authToken?: string;\n}): Promise<ServerResult> {\n initLogger();\n\n const configPath = resolveConfigPath(options?.configPath);\n const fileConfig = fs.existsSync(configPath)\n ? loadConfigFile(configPath)\n : { remnic: {}, server: {} };\n\n const env = envOverrides();\n\n // Merge: file < env < cli flags\n const remnicConfig = { ...fileConfig.remnic, ...(env.remnic ?? {}) };\n const serverConfig = {\n ...fileConfig.server,\n ...env,\n ...(options?.host ? { host: options.host } : {}),\n ...(options?.port ? { port: options.port } : {}),\n ...(options?.authToken ? { authToken: options.authToken } : {}),\n };\n\n const config = parseConfig(remnicConfig);\n const orchestrator = new Orchestrator(config);\n const service = new EngramAccessService(orchestrator);\n\n const authToken = serverConfig.authToken ?? readCompatEnv(\"REMNIC_AUTH_TOKEN\", \"ENGRAM_AUTH_TOKEN\") ?? \"\";\n\n // Connector tokens are loaded dynamically per request via authTokensGetter\n // so that token generate/revoke takes effect without server restart\n if (!authToken && getAllValidTokens().length === 0) {\n log.warn(\"No auth token set — server will reject all requests. Set REMNIC_AUTH_TOKEN, server.authToken in config, or generate tokens with 'remnic token generate'.\");\n }\n\n const httpServer = new EngramAccessHttpServer({\n service,\n host: serverConfig.host ?? \"127.0.0.1\",\n port: serverConfig.port ?? 4318,\n authToken: authToken || undefined,\n authTokensGetter: () => getAllValidTokensCached(),\n principal: serverConfig.principal,\n maxBodyBytes: serverConfig.maxBodyBytes,\n adminConsoleEnabled: serverConfig.adminConsoleEnabled ?? false,\n citationsEnabled: config.citationsEnabled,\n citationsAutoDetect: config.citationsAutoDetect,\n });\n\n const { host, port } = await httpServer.start();\n\n return { config, service, httpServer, host, port };\n}\n\n// ── CLI entry point ──────────────────────────────────────────────────────────\n\nfunction parseCliArgs(argv: string[]): Record<string, string | undefined> {\n const args: Record<string, string | undefined> = {};\n for (let i = 0; i < argv.length; i++) {\n const token = argv[i];\n if (token.startsWith(\"--\")) {\n const key = token.slice(2);\n const next = argv[i + 1];\n if (next && !next.startsWith(\"--\")) {\n args[key] = next;\n i++;\n } else {\n args[key] = \"true\";\n }\n }\n }\n return args;\n}\n\nexport async function cliMain(argv: string[] = process.argv.slice(2)): Promise<void> {\n const args = parseCliArgs(argv);\n\n if (args.help) {\n console.log(`\nremnic-server — Standalone Remnic memory server\n\nUsage:\n remnic-server [options]\n\nOptions:\n --config <path> Path to config file (default: remnic.config.json)\n --host <addr> Bind address (default: 127.0.0.1)\n --port <number> Port number (default: 4318)\n --auth-token <tok> Bearer token for auth (or set REMNIC_AUTH_TOKEN)\n --help Show this help\n\nEnvironment:\n REMNIC_CONFIG_PATH Config file path (ENGRAM_CONFIG_PATH also supported)\n REMNIC_PORT Server port (ENGRAM_PORT also supported)\n REMNIC_HOST Bind address (ENGRAM_HOST also supported)\n REMNIC_AUTH_TOKEN Auth bearer token (ENGRAM_AUTH_TOKEN also supported)\n REMNIC_MEMORY_DIR Override memory directory (ENGRAM_MEMORY_DIR also supported)\n OPENAI_API_KEY OpenAI API key for extraction\n`);\n process.exit(0);\n }\n\n const result = await startServer({\n configPath: args.config,\n host: args.host,\n port: args.port ? parseInt(args.port, 10) : undefined,\n authToken: args[\"auth-token\"],\n });\n\n console.log(`Remnic server listening on http://${result.host}:${result.port}`);\n\n // Graceful shutdown\n const shutdown = async (signal: string) => {\n console.log(`\\nReceived ${signal}, shutting down...`);\n await result.httpServer.stop();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", () => shutdown(\"SIGINT\"));\n process.on(\"SIGTERM\", () => shutdown(\"SIGTERM\"));\n}\n\n// Auto-run when executed directly\n// Matches: `node .../remnic-server/dist/index.js`, `node .../remnic-server/src/index.ts`,\n// `npx remnic-server`, `npx engram-server`, but NOT test files under those directories\nif (\n process.argv[1] &&\n (/remnic-server[\\\\/](?:dist|src)[\\\\/]index\\.[jt]s$/.test(process.argv[1]) ||\n /engram-server[\\\\/](?:dist|src)[\\\\/]index\\.[jt]s$/.test(process.argv[1]) ||\n process.argv[1].endsWith(\"remnic-server\") ||\n process.argv[1].endsWith(\"engram-server\"))\n) {\n cliMain().catch((err) => {\n process.stderr.write(`Fatal: ${err instanceof Error ? err.message : String(err)}\\n`);\n process.exit(1);\n });\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -72,7 +72,9 @@ async function startServer(options) {
|
|
|
72
72
|
authTokensGetter: () => getAllValidTokensCached(),
|
|
73
73
|
principal: serverConfig.principal,
|
|
74
74
|
maxBodyBytes: serverConfig.maxBodyBytes,
|
|
75
|
-
adminConsoleEnabled: serverConfig.adminConsoleEnabled ?? false
|
|
75
|
+
adminConsoleEnabled: serverConfig.adminConsoleEnabled ?? false,
|
|
76
|
+
citationsEnabled: config.citationsEnabled,
|
|
77
|
+
citationsAutoDetect: config.citationsAutoDetect
|
|
76
78
|
});
|
|
77
79
|
const { host, port } = await httpServer.start();
|
|
78
80
|
return { config, service, httpServer, host, port };
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @remnic/server\n *\n * Standalone Remnic memory server.\n *\n * Loads config from `remnic.config.json` (or env vars), creates an Orchestrator,\n * and starts the HTTP access server with MCP endpoint — no OpenClaw required.\n *\n * Usage:\n * npx remnic-server\n * npx remnic-server --config ./my-remnic.json\n * npx remnic-server --port 4320\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { parseConfig, Orchestrator, EngramAccessService, EngramAccessHttpServer, initLogger, log, getAllValidTokens, getAllValidTokensCached, type PluginConfig } from \"@remnic/core\";\n\n// ── Config loading ──────────────────────────────────────────────────────────\n\nexport interface ServerConfig {\n remnic: Record<string, unknown>;\n server: {\n host?: string;\n port?: number;\n authToken?: string;\n principal?: string;\n maxBodyBytes?: number;\n adminConsoleEnabled?: boolean;\n };\n}\n\nfunction readCompatEnv(primary: string, legacy: string): string | undefined {\n return process.env[primary] ?? process.env[legacy];\n}\n\nfunction resolveConfigPath(cliPath?: string): string {\n if (cliPath) return path.resolve(cliPath);\n\n const envPath = readCompatEnv(\"REMNIC_CONFIG_PATH\", \"ENGRAM_CONFIG_PATH\");\n if (envPath) return path.resolve(envPath);\n\n const homeDir = process.env.HOME ?? \"~\";\n const candidates = [\n path.join(process.cwd(), \"remnic.config.json\"),\n path.join(process.cwd(), \"engram.config.json\"),\n path.join(homeDir, \".config\", \"remnic\", \"config.json\"),\n path.join(homeDir, \".config\", \"engram\", \"config.json\"),\n ];\n for (const candidate of candidates) {\n if (fs.existsSync(candidate)) return candidate;\n }\n\n return path.join(homeDir, \".config\", \"remnic\", \"config.json\");\n}\n\nfunction loadConfigFile(configPath: string): ServerConfig {\n const raw = JSON.parse(fs.readFileSync(configPath, \"utf8\"));\n return {\n remnic: raw.remnic ?? raw.engram ?? raw ?? {},\n server: raw.server ?? {},\n };\n}\n\nfunction envOverrides(): Partial<ServerConfig[\"server\"]> & { remnic?: Record<string, unknown> } {\n const overrides: Record<string, unknown> = {};\n const remnic: Record<string, unknown> = {};\n\n const port = readCompatEnv(\"REMNIC_PORT\", \"ENGRAM_PORT\");\n const host = readCompatEnv(\"REMNIC_HOST\", \"ENGRAM_HOST\");\n const authToken = readCompatEnv(\"REMNIC_AUTH_TOKEN\", \"ENGRAM_AUTH_TOKEN\");\n if (port) overrides.port = parseInt(port, 10);\n if (host) overrides.host = host;\n if (authToken) overrides.authToken = authToken;\n\n if (process.env.OPENAI_API_KEY) remnic.openaiApiKey = process.env.OPENAI_API_KEY;\n const memoryDir = readCompatEnv(\"REMNIC_MEMORY_DIR\", \"ENGRAM_MEMORY_DIR\");\n if (memoryDir) remnic.memoryDir = memoryDir;\n\n return { ...overrides, ...(Object.keys(remnic).length > 0 ? { remnic } : {}) };\n}\n\n// ── Server startup ──────────────────────────────────────────────────────────\n\nexport interface ServerResult {\n config: PluginConfig;\n service: EngramAccessService;\n httpServer: EngramAccessHttpServer;\n host: string;\n port: number;\n}\n\nexport async function startServer(options?: {\n configPath?: string;\n host?: string;\n port?: number;\n authToken?: string;\n}): Promise<ServerResult> {\n initLogger();\n\n const configPath = resolveConfigPath(options?.configPath);\n const fileConfig = fs.existsSync(configPath)\n ? loadConfigFile(configPath)\n : { remnic: {}, server: {} };\n\n const env = envOverrides();\n\n // Merge: file < env < cli flags\n const remnicConfig = { ...fileConfig.remnic, ...(env.remnic ?? {}) };\n const serverConfig = {\n ...fileConfig.server,\n ...env,\n ...(options?.host ? { host: options.host } : {}),\n ...(options?.port ? { port: options.port } : {}),\n ...(options?.authToken ? { authToken: options.authToken } : {}),\n };\n\n const config = parseConfig(remnicConfig);\n const orchestrator = new Orchestrator(config);\n const service = new EngramAccessService(orchestrator);\n\n const authToken = serverConfig.authToken ?? readCompatEnv(\"REMNIC_AUTH_TOKEN\", \"ENGRAM_AUTH_TOKEN\") ?? \"\";\n\n // Connector tokens are loaded dynamically per request via authTokensGetter\n // so that token generate/revoke takes effect without server restart\n if (!authToken && getAllValidTokens().length === 0) {\n log.warn(\"No auth token set — server will reject all requests. Set REMNIC_AUTH_TOKEN, server.authToken in config, or generate tokens with 'remnic token generate'.\");\n }\n\n const httpServer = new EngramAccessHttpServer({\n service,\n host: serverConfig.host ?? \"127.0.0.1\",\n port: serverConfig.port ?? 4318,\n authToken: authToken || undefined,\n authTokensGetter: () => getAllValidTokensCached(),\n principal: serverConfig.principal,\n maxBodyBytes: serverConfig.maxBodyBytes,\n adminConsoleEnabled: serverConfig.adminConsoleEnabled ?? false,\n });\n\n const { host, port } = await httpServer.start();\n\n return { config, service, httpServer, host, port };\n}\n\n// ── CLI entry point ──────────────────────────────────────────────────────────\n\nfunction parseCliArgs(argv: string[]): Record<string, string | undefined> {\n const args: Record<string, string | undefined> = {};\n for (let i = 0; i < argv.length; i++) {\n const token = argv[i];\n if (token.startsWith(\"--\")) {\n const key = token.slice(2);\n const next = argv[i + 1];\n if (next && !next.startsWith(\"--\")) {\n args[key] = next;\n i++;\n } else {\n args[key] = \"true\";\n }\n }\n }\n return args;\n}\n\nexport async function cliMain(argv: string[] = process.argv.slice(2)): Promise<void> {\n const args = parseCliArgs(argv);\n\n if (args.help) {\n console.log(`\nremnic-server — Standalone Remnic memory server\n\nUsage:\n remnic-server [options]\n\nOptions:\n --config <path> Path to config file (default: remnic.config.json)\n --host <addr> Bind address (default: 127.0.0.1)\n --port <number> Port number (default: 4318)\n --auth-token <tok> Bearer token for auth (or set REMNIC_AUTH_TOKEN)\n --help Show this help\n\nEnvironment:\n REMNIC_CONFIG_PATH Config file path (ENGRAM_CONFIG_PATH also supported)\n REMNIC_PORT Server port (ENGRAM_PORT also supported)\n REMNIC_HOST Bind address (ENGRAM_HOST also supported)\n REMNIC_AUTH_TOKEN Auth bearer token (ENGRAM_AUTH_TOKEN also supported)\n REMNIC_MEMORY_DIR Override memory directory (ENGRAM_MEMORY_DIR also supported)\n OPENAI_API_KEY OpenAI API key for extraction\n`);\n process.exit(0);\n }\n\n const result = await startServer({\n configPath: args.config,\n host: args.host,\n port: args.port ? parseInt(args.port, 10) : undefined,\n authToken: args[\"auth-token\"],\n });\n\n console.log(`Remnic server listening on http://${result.host}:${result.port}`);\n\n // Graceful shutdown\n const shutdown = async (signal: string) => {\n console.log(`\\nReceived ${signal}, shutting down...`);\n await result.httpServer.stop();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", () => shutdown(\"SIGINT\"));\n process.on(\"SIGTERM\", () => shutdown(\"SIGTERM\"));\n}\n\n// Auto-run when executed directly\n// Matches: `node .../remnic-server/dist/index.js`, `node .../remnic-server/src/index.ts`,\n// `npx remnic-server`, `npx engram-server`, but NOT test files under those directories\nif (\n process.argv[1] &&\n (/remnic-server[\\\\/](?:dist|src)[\\\\/]index\\.[jt]s$/.test(process.argv[1]) ||\n /engram-server[\\\\/](?:dist|src)[\\\\/]index\\.[jt]s$/.test(process.argv[1]) ||\n process.argv[1].endsWith(\"remnic-server\") ||\n process.argv[1].endsWith(\"engram-server\"))\n) {\n cliMain().catch((err) => {\n process.stderr.write(`Fatal: ${err instanceof Error ? err.message : String(err)}\\n`);\n process.exit(1);\n });\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @remnic/server\n *\n * Standalone Remnic memory server.\n *\n * Loads config from `remnic.config.json` (or env vars), creates an Orchestrator,\n * and starts the HTTP access server with MCP endpoint — no OpenClaw required.\n *\n * Usage:\n * npx remnic-server\n * npx remnic-server --config ./my-remnic.json\n * npx remnic-server --port 4320\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { parseConfig, Orchestrator, EngramAccessService, EngramAccessHttpServer, initLogger, log, getAllValidTokens, getAllValidTokensCached, type PluginConfig } from \"@remnic/core\";\n\n// ── Config loading ──────────────────────────────────────────────────────────\n\nexport interface ServerConfig {\n remnic: Record<string, unknown>;\n server: {\n host?: string;\n port?: number;\n authToken?: string;\n principal?: string;\n maxBodyBytes?: number;\n adminConsoleEnabled?: boolean;\n };\n}\n\nfunction readCompatEnv(primary: string, legacy: string): string | undefined {\n return process.env[primary] ?? process.env[legacy];\n}\n\nfunction resolveConfigPath(cliPath?: string): string {\n if (cliPath) return path.resolve(cliPath);\n\n const envPath = readCompatEnv(\"REMNIC_CONFIG_PATH\", \"ENGRAM_CONFIG_PATH\");\n if (envPath) return path.resolve(envPath);\n\n const homeDir = process.env.HOME ?? \"~\";\n const candidates = [\n path.join(process.cwd(), \"remnic.config.json\"),\n path.join(process.cwd(), \"engram.config.json\"),\n path.join(homeDir, \".config\", \"remnic\", \"config.json\"),\n path.join(homeDir, \".config\", \"engram\", \"config.json\"),\n ];\n for (const candidate of candidates) {\n if (fs.existsSync(candidate)) return candidate;\n }\n\n return path.join(homeDir, \".config\", \"remnic\", \"config.json\");\n}\n\nfunction loadConfigFile(configPath: string): ServerConfig {\n const raw = JSON.parse(fs.readFileSync(configPath, \"utf8\"));\n return {\n remnic: raw.remnic ?? raw.engram ?? raw ?? {},\n server: raw.server ?? {},\n };\n}\n\nfunction envOverrides(): Partial<ServerConfig[\"server\"]> & { remnic?: Record<string, unknown> } {\n const overrides: Record<string, unknown> = {};\n const remnic: Record<string, unknown> = {};\n\n const port = readCompatEnv(\"REMNIC_PORT\", \"ENGRAM_PORT\");\n const host = readCompatEnv(\"REMNIC_HOST\", \"ENGRAM_HOST\");\n const authToken = readCompatEnv(\"REMNIC_AUTH_TOKEN\", \"ENGRAM_AUTH_TOKEN\");\n if (port) overrides.port = parseInt(port, 10);\n if (host) overrides.host = host;\n if (authToken) overrides.authToken = authToken;\n\n if (process.env.OPENAI_API_KEY) remnic.openaiApiKey = process.env.OPENAI_API_KEY;\n const memoryDir = readCompatEnv(\"REMNIC_MEMORY_DIR\", \"ENGRAM_MEMORY_DIR\");\n if (memoryDir) remnic.memoryDir = memoryDir;\n\n return { ...overrides, ...(Object.keys(remnic).length > 0 ? { remnic } : {}) };\n}\n\n// ── Server startup ──────────────────────────────────────────────────────────\n\nexport interface ServerResult {\n config: PluginConfig;\n service: EngramAccessService;\n httpServer: EngramAccessHttpServer;\n host: string;\n port: number;\n}\n\nexport async function startServer(options?: {\n configPath?: string;\n host?: string;\n port?: number;\n authToken?: string;\n}): Promise<ServerResult> {\n initLogger();\n\n const configPath = resolveConfigPath(options?.configPath);\n const fileConfig = fs.existsSync(configPath)\n ? loadConfigFile(configPath)\n : { remnic: {}, server: {} };\n\n const env = envOverrides();\n\n // Merge: file < env < cli flags\n const remnicConfig = { ...fileConfig.remnic, ...(env.remnic ?? {}) };\n const serverConfig = {\n ...fileConfig.server,\n ...env,\n ...(options?.host ? { host: options.host } : {}),\n ...(options?.port ? { port: options.port } : {}),\n ...(options?.authToken ? { authToken: options.authToken } : {}),\n };\n\n const config = parseConfig(remnicConfig);\n const orchestrator = new Orchestrator(config);\n const service = new EngramAccessService(orchestrator);\n\n const authToken = serverConfig.authToken ?? readCompatEnv(\"REMNIC_AUTH_TOKEN\", \"ENGRAM_AUTH_TOKEN\") ?? \"\";\n\n // Connector tokens are loaded dynamically per request via authTokensGetter\n // so that token generate/revoke takes effect without server restart\n if (!authToken && getAllValidTokens().length === 0) {\n log.warn(\"No auth token set — server will reject all requests. Set REMNIC_AUTH_TOKEN, server.authToken in config, or generate tokens with 'remnic token generate'.\");\n }\n\n const httpServer = new EngramAccessHttpServer({\n service,\n host: serverConfig.host ?? \"127.0.0.1\",\n port: serverConfig.port ?? 4318,\n authToken: authToken || undefined,\n authTokensGetter: () => getAllValidTokensCached(),\n principal: serverConfig.principal,\n maxBodyBytes: serverConfig.maxBodyBytes,\n adminConsoleEnabled: serverConfig.adminConsoleEnabled ?? false,\n citationsEnabled: config.citationsEnabled,\n citationsAutoDetect: config.citationsAutoDetect,\n });\n\n const { host, port } = await httpServer.start();\n\n return { config, service, httpServer, host, port };\n}\n\n// ── CLI entry point ──────────────────────────────────────────────────────────\n\nfunction parseCliArgs(argv: string[]): Record<string, string | undefined> {\n const args: Record<string, string | undefined> = {};\n for (let i = 0; i < argv.length; i++) {\n const token = argv[i];\n if (token.startsWith(\"--\")) {\n const key = token.slice(2);\n const next = argv[i + 1];\n if (next && !next.startsWith(\"--\")) {\n args[key] = next;\n i++;\n } else {\n args[key] = \"true\";\n }\n }\n }\n return args;\n}\n\nexport async function cliMain(argv: string[] = process.argv.slice(2)): Promise<void> {\n const args = parseCliArgs(argv);\n\n if (args.help) {\n console.log(`\nremnic-server — Standalone Remnic memory server\n\nUsage:\n remnic-server [options]\n\nOptions:\n --config <path> Path to config file (default: remnic.config.json)\n --host <addr> Bind address (default: 127.0.0.1)\n --port <number> Port number (default: 4318)\n --auth-token <tok> Bearer token for auth (or set REMNIC_AUTH_TOKEN)\n --help Show this help\n\nEnvironment:\n REMNIC_CONFIG_PATH Config file path (ENGRAM_CONFIG_PATH also supported)\n REMNIC_PORT Server port (ENGRAM_PORT also supported)\n REMNIC_HOST Bind address (ENGRAM_HOST also supported)\n REMNIC_AUTH_TOKEN Auth bearer token (ENGRAM_AUTH_TOKEN also supported)\n REMNIC_MEMORY_DIR Override memory directory (ENGRAM_MEMORY_DIR also supported)\n OPENAI_API_KEY OpenAI API key for extraction\n`);\n process.exit(0);\n }\n\n const result = await startServer({\n configPath: args.config,\n host: args.host,\n port: args.port ? parseInt(args.port, 10) : undefined,\n authToken: args[\"auth-token\"],\n });\n\n console.log(`Remnic server listening on http://${result.host}:${result.port}`);\n\n // Graceful shutdown\n const shutdown = async (signal: string) => {\n console.log(`\\nReceived ${signal}, shutting down...`);\n await result.httpServer.stop();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", () => shutdown(\"SIGINT\"));\n process.on(\"SIGTERM\", () => shutdown(\"SIGTERM\"));\n}\n\n// Auto-run when executed directly\n// Matches: `node .../remnic-server/dist/index.js`, `node .../remnic-server/src/index.ts`,\n// `npx remnic-server`, `npx engram-server`, but NOT test files under those directories\nif (\n process.argv[1] &&\n (/remnic-server[\\\\/](?:dist|src)[\\\\/]index\\.[jt]s$/.test(process.argv[1]) ||\n /engram-server[\\\\/](?:dist|src)[\\\\/]index\\.[jt]s$/.test(process.argv[1]) ||\n process.argv[1].endsWith(\"remnic-server\") ||\n process.argv[1].endsWith(\"engram-server\"))\n) {\n cliMain().catch((err) => {\n process.stderr.write(`Fatal: ${err instanceof Error ? err.message : String(err)}\\n`);\n process.exit(1);\n });\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remnic/server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Standalone Remnic memory server — HTTP + MCP without OpenClaw",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -20,13 +20,8 @@
|
|
|
20
20
|
"access": "public",
|
|
21
21
|
"provenance": true
|
|
22
22
|
},
|
|
23
|
-
"scripts": {
|
|
24
|
-
"build": "tsup src/index.ts --format esm --target es2022 --platform node --outDir dist && tsup bin/remnic-server.ts bin/engram-server.ts --format esm --target es2022 --platform node --outDir dist/bin",
|
|
25
|
-
"check-types": "tsc --noEmit",
|
|
26
|
-
"prepublishOnly": "npm run build"
|
|
27
|
-
},
|
|
28
23
|
"dependencies": {
|
|
29
|
-
"@remnic/core": "
|
|
24
|
+
"@remnic/core": "^1.0.2"
|
|
30
25
|
},
|
|
31
26
|
"devDependencies": {
|
|
32
27
|
"tsup": "^8.5.1",
|
|
@@ -37,5 +32,9 @@
|
|
|
37
32
|
"type": "git",
|
|
38
33
|
"url": "https://github.com/joshuaswarren/remnic.git",
|
|
39
34
|
"directory": "packages/remnic-server"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsup src/index.ts --format esm --target es2022 --platform node --outDir dist && tsup bin/remnic-server.ts bin/engram-server.ts --format esm --target es2022 --platform node --outDir dist/bin",
|
|
38
|
+
"check-types": "tsc --noEmit"
|
|
40
39
|
}
|
|
41
|
-
}
|
|
40
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["/**\n * @remnic/server\n *\n * Standalone Remnic memory server.\n *\n * Loads config from `remnic.config.json` (or env vars), creates an Orchestrator,\n * and starts the HTTP access server with MCP endpoint — no OpenClaw required.\n *\n * Usage:\n * npx remnic-server\n * npx remnic-server --config ./my-remnic.json\n * npx remnic-server --port 4320\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { parseConfig, Orchestrator, EngramAccessService, EngramAccessHttpServer, initLogger, log, getAllValidTokens, getAllValidTokensCached, type PluginConfig } from \"@remnic/core\";\n\n// ── Config loading ──────────────────────────────────────────────────────────\n\nexport interface ServerConfig {\n remnic: Record<string, unknown>;\n server: {\n host?: string;\n port?: number;\n authToken?: string;\n principal?: string;\n maxBodyBytes?: number;\n adminConsoleEnabled?: boolean;\n };\n}\n\nfunction readCompatEnv(primary: string, legacy: string): string | undefined {\n return process.env[primary] ?? process.env[legacy];\n}\n\nfunction resolveConfigPath(cliPath?: string): string {\n if (cliPath) return path.resolve(cliPath);\n\n const envPath = readCompatEnv(\"REMNIC_CONFIG_PATH\", \"ENGRAM_CONFIG_PATH\");\n if (envPath) return path.resolve(envPath);\n\n const homeDir = process.env.HOME ?? \"~\";\n const candidates = [\n path.join(process.cwd(), \"remnic.config.json\"),\n path.join(process.cwd(), \"engram.config.json\"),\n path.join(homeDir, \".config\", \"remnic\", \"config.json\"),\n path.join(homeDir, \".config\", \"engram\", \"config.json\"),\n ];\n for (const candidate of candidates) {\n if (fs.existsSync(candidate)) return candidate;\n }\n\n return path.join(homeDir, \".config\", \"remnic\", \"config.json\");\n}\n\nfunction loadConfigFile(configPath: string): ServerConfig {\n const raw = JSON.parse(fs.readFileSync(configPath, \"utf8\"));\n return {\n remnic: raw.remnic ?? raw.engram ?? raw ?? {},\n server: raw.server ?? {},\n };\n}\n\nfunction envOverrides(): Partial<ServerConfig[\"server\"]> & { remnic?: Record<string, unknown> } {\n const overrides: Record<string, unknown> = {};\n const remnic: Record<string, unknown> = {};\n\n const port = readCompatEnv(\"REMNIC_PORT\", \"ENGRAM_PORT\");\n const host = readCompatEnv(\"REMNIC_HOST\", \"ENGRAM_HOST\");\n const authToken = readCompatEnv(\"REMNIC_AUTH_TOKEN\", \"ENGRAM_AUTH_TOKEN\");\n if (port) overrides.port = parseInt(port, 10);\n if (host) overrides.host = host;\n if (authToken) overrides.authToken = authToken;\n\n if (process.env.OPENAI_API_KEY) remnic.openaiApiKey = process.env.OPENAI_API_KEY;\n const memoryDir = readCompatEnv(\"REMNIC_MEMORY_DIR\", \"ENGRAM_MEMORY_DIR\");\n if (memoryDir) remnic.memoryDir = memoryDir;\n\n return { ...overrides, ...(Object.keys(remnic).length > 0 ? { remnic } : {}) };\n}\n\n// ── Server startup ──────────────────────────────────────────────────────────\n\nexport interface ServerResult {\n config: PluginConfig;\n service: EngramAccessService;\n httpServer: EngramAccessHttpServer;\n host: string;\n port: number;\n}\n\nexport async function startServer(options?: {\n configPath?: string;\n host?: string;\n port?: number;\n authToken?: string;\n}): Promise<ServerResult> {\n initLogger();\n\n const configPath = resolveConfigPath(options?.configPath);\n const fileConfig = fs.existsSync(configPath)\n ? loadConfigFile(configPath)\n : { remnic: {}, server: {} };\n\n const env = envOverrides();\n\n // Merge: file < env < cli flags\n const remnicConfig = { ...fileConfig.remnic, ...(env.remnic ?? {}) };\n const serverConfig = {\n ...fileConfig.server,\n ...env,\n ...(options?.host ? { host: options.host } : {}),\n ...(options?.port ? { port: options.port } : {}),\n ...(options?.authToken ? { authToken: options.authToken } : {}),\n };\n\n const config = parseConfig(remnicConfig);\n const orchestrator = new Orchestrator(config);\n const service = new EngramAccessService(orchestrator);\n\n const authToken = serverConfig.authToken ?? readCompatEnv(\"REMNIC_AUTH_TOKEN\", \"ENGRAM_AUTH_TOKEN\") ?? \"\";\n\n // Connector tokens are loaded dynamically per request via authTokensGetter\n // so that token generate/revoke takes effect without server restart\n if (!authToken && getAllValidTokens().length === 0) {\n log.warn(\"No auth token set — server will reject all requests. Set REMNIC_AUTH_TOKEN, server.authToken in config, or generate tokens with 'remnic token generate'.\");\n }\n\n const httpServer = new EngramAccessHttpServer({\n service,\n host: serverConfig.host ?? \"127.0.0.1\",\n port: serverConfig.port ?? 4318,\n authToken: authToken || undefined,\n authTokensGetter: () => getAllValidTokensCached(),\n principal: serverConfig.principal,\n maxBodyBytes: serverConfig.maxBodyBytes,\n adminConsoleEnabled: serverConfig.adminConsoleEnabled ?? false,\n });\n\n const { host, port } = await httpServer.start();\n\n return { config, service, httpServer, host, port };\n}\n\n// ── CLI entry point ──────────────────────────────────────────────────────────\n\nfunction parseCliArgs(argv: string[]): Record<string, string | undefined> {\n const args: Record<string, string | undefined> = {};\n for (let i = 0; i < argv.length; i++) {\n const token = argv[i];\n if (token.startsWith(\"--\")) {\n const key = token.slice(2);\n const next = argv[i + 1];\n if (next && !next.startsWith(\"--\")) {\n args[key] = next;\n i++;\n } else {\n args[key] = \"true\";\n }\n }\n }\n return args;\n}\n\nexport async function cliMain(argv: string[] = process.argv.slice(2)): Promise<void> {\n const args = parseCliArgs(argv);\n\n if (args.help) {\n console.log(`\nremnic-server — Standalone Remnic memory server\n\nUsage:\n remnic-server [options]\n\nOptions:\n --config <path> Path to config file (default: remnic.config.json)\n --host <addr> Bind address (default: 127.0.0.1)\n --port <number> Port number (default: 4318)\n --auth-token <tok> Bearer token for auth (or set REMNIC_AUTH_TOKEN)\n --help Show this help\n\nEnvironment:\n REMNIC_CONFIG_PATH Config file path (ENGRAM_CONFIG_PATH also supported)\n REMNIC_PORT Server port (ENGRAM_PORT also supported)\n REMNIC_HOST Bind address (ENGRAM_HOST also supported)\n REMNIC_AUTH_TOKEN Auth bearer token (ENGRAM_AUTH_TOKEN also supported)\n REMNIC_MEMORY_DIR Override memory directory (ENGRAM_MEMORY_DIR also supported)\n OPENAI_API_KEY OpenAI API key for extraction\n`);\n process.exit(0);\n }\n\n const result = await startServer({\n configPath: args.config,\n host: args.host,\n port: args.port ? parseInt(args.port, 10) : undefined,\n authToken: args[\"auth-token\"],\n });\n\n console.log(`Remnic server listening on http://${result.host}:${result.port}`);\n\n // Graceful shutdown\n const shutdown = async (signal: string) => {\n console.log(`\\nReceived ${signal}, shutting down...`);\n await result.httpServer.stop();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", () => shutdown(\"SIGINT\"));\n process.on(\"SIGTERM\", () => shutdown(\"SIGTERM\"));\n}\n\n// Auto-run when executed directly\n// Matches: `node .../remnic-server/dist/index.js`, `node .../remnic-server/src/index.ts`,\n// `npx remnic-server`, `npx engram-server`, but NOT test files under those directories\nif (\n process.argv[1] &&\n (/remnic-server[\\\\/](?:dist|src)[\\\\/]index\\.[jt]s$/.test(process.argv[1]) ||\n /engram-server[\\\\/](?:dist|src)[\\\\/]index\\.[jt]s$/.test(process.argv[1]) ||\n process.argv[1].endsWith(\"remnic-server\") ||\n process.argv[1].endsWith(\"engram-server\"))\n) {\n cliMain().catch((err) => {\n process.stderr.write(`Fatal: ${err instanceof Error ? err.message : String(err)}\\n`);\n process.exit(1);\n });\n}\n"],"mappings":"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","names":[]}
|