@agentmemory/agentmemory 0.7.3 → 0.7.5

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.md CHANGED
@@ -105,9 +105,9 @@ Hook scripts in `src/hooks/` are standalone Node.js scripts (no iii-sdk import).
105
105
 
106
106
  ## Current Stats (v0.7.0)
107
107
 
108
- - 41 MCP tools (7 visible by default, `AGENTMEMORY_TOOLS=all` for all)
109
- - 100 REST endpoints
108
+ - 43 MCP tools (8 visible by default, `AGENTMEMORY_TOOLS=all` for all)
109
+ - 103 REST endpoints
110
110
  - 6 MCP resources, 3 MCP prompts
111
111
  - 12 hooks, 4 skills
112
112
  - 50+ iii functions
113
- - 614 tests
113
+ - 627 tests
package/README.md CHANGED
@@ -26,7 +26,7 @@
26
26
 
27
27
  ---
28
28
 
29
- Every AI coding agent has the same blind spot. Session ends, memory vanishes. You re-explain architecture. You re-discover bugs. You re-teach preferences. Built-in memory files like CLAUDE.md and .cursorrules are 200-line sticky notes that overflow and go stale. agentmemory replaces that with a searchable, versioned, cross-agent database — 41 MCP tools, triple-stream retrieval (BM25 + vector + knowledge graph), 4-tier memory consolidation, provenance-tracked citations, and cascading staleness so retired facts never pollute your context again. One instance serves Claude Code, Cursor, Codex, Windsurf, and any MCP client simultaneously. 614 tests. Zero external DB dependencies.
29
+ Every AI coding agent has the same blind spot. Session ends, memory vanishes. You re-explain architecture. You re-discover bugs. You re-teach preferences. Built-in memory files like CLAUDE.md and .cursorrules are 200-line sticky notes that overflow and go stale. agentmemory replaces that with a searchable, versioned, cross-agent database — 43 MCP tools, triple-stream retrieval (BM25 + vector + knowledge graph), 4-tier memory consolidation, provenance-tracked citations, and cascading staleness so retired facts never pollute your context again. One instance serves Claude Code, Cursor, Codex, Windsurf, and any MCP client simultaneously. 627 tests. Zero external DB dependencies.
30
30
 
31
31
  The result is measurable. On 240 real observations across 30 sessions, agentmemory hits 64% Recall@10 and perfect MRR while using 92% fewer tokens than dumping everything into context. When an agent searches "database performance optimization," it finds the N+1 fix you made three weeks ago — something keyword grep literally cannot do. Memories version automatically, supersede each other, propagate staleness to related graph nodes, and sync across agent instances via P2P mesh. Your agents stop repeating mistakes. Your context stays clean. Your sessions start fast.
32
32
 
@@ -131,7 +131,7 @@ These agents support hooks natively. agentmemory captures tool usage automatical
131
131
 
132
132
  ### MCP support (any MCP-compatible agent)
133
133
 
134
- Any agent that connects to MCP servers can use agentmemory's 41 tools, 6 resources, and 3 prompts. The agent actively queries and saves memory through MCP calls.
134
+ Any agent that connects to MCP servers can use agentmemory's 43 tools, 6 resources, and 3 prompts. The agent actively queries and saves memory through MCP calls.
135
135
 
136
136
  | Agent | How to connect |
137
137
  |---|---|
@@ -143,7 +143,7 @@ Any agent that connects to MCP servers can use agentmemory's 41 tools, 6 resourc
143
143
 
144
144
  ### REST API (any agent, any language)
145
145
 
146
- Agents without hooks or MCP can integrate via 100 REST endpoints directly. This works with any agent, language, or framework.
146
+ Agents without hooks or MCP can integrate via 103 REST endpoints directly. This works with any agent, language, or framework.
147
147
 
148
148
  ```bash
149
149
  POST /agentmemory/observe # Capture what the agent did
@@ -161,7 +161,7 @@ GET /agentmemory/profile # Get project intelligence
161
161
  | Claude Code user | Plugin install (hooks + MCP + skills) |
162
162
  | Building a custom agent with Claude SDK | AgentSDKProvider (zero config) |
163
163
  | Using Cursor, Windsurf, or any MCP client | MCP server (41 tools + 6 resources + 3 prompts) |
164
- | Building your own agent framework | REST API (100 endpoints) |
164
+ | Building your own agent framework | REST API (103 endpoints) |
165
165
  | Sharing memory across multiple agents | All agents point to the same iii-engine instance |
166
166
 
167
167
  ## Quick Start
@@ -190,7 +190,7 @@ git clone https://github.com/rohitg00/agentmemory.git && cd agentmemory
190
190
  npm install && npm run build && npm start
191
191
  ```
192
192
 
193
- ### 4. Verify
193
+ ### 3. Verify
194
194
 
195
195
  ```bash
196
196
  curl http://localhost:3111/agentmemory/health
@@ -203,7 +203,7 @@ open http://localhost:3113
203
203
  {
204
204
  "status": "healthy",
205
205
  "service": "agentmemory",
206
- "version": "0.7.1",
206
+ "version": "0.7.4",
207
207
  "health": {
208
208
  "memory": { "heapUsed": 42000000, "heapTotal": 67000000 },
209
209
  "cpu": { "percent": 2.1 },
@@ -632,7 +632,7 @@ ANTHROPIC_API_KEY=sk-ant-...
632
632
 
633
633
  ## API
634
634
 
635
- 106 endpoints on port `3111` (100 core + 6 MCP protocol). Protected endpoints require `Authorization: Bearer <secret>` when `AGENTMEMORY_SECRET` is set. The table below shows a representative subset; see `src/triggers/api.ts` for the full endpoint list.
635
+ 109 endpoints on port `3111` (103 core + 6 MCP protocol). Protected endpoints require `Authorization: Bearer <secret>` when `AGENTMEMORY_SECRET` is set. The table below shows a representative subset; see `src/triggers/api.ts` for the full endpoint list.
636
636
 
637
637
  | Method | Path | Description |
638
638
  |--------|------|-------------|
@@ -700,7 +700,7 @@ ANTHROPIC_API_KEY=sk-ant-...
700
700
  /plugin install agentmemory
701
701
  ```
702
702
 
703
- Restart Claude Code. All 12 hooks, 4 skills, and 41 MCP tools are registered automatically.
703
+ Restart Claude Code. All 12 hooks, 4 skills, and 43 MCP tools are registered automatically.
704
704
 
705
705
  ### Plugin Commands
706
706
 
@@ -724,7 +724,7 @@ agentmemory is built on iii-engine's three primitives:
724
724
  | Prometheus / Grafana | iii OTEL + built-in health monitor |
725
725
  | Redis (circuit breaker) | In-process circuit breaker + fallback chain |
726
726
 
727
- **113 source files. ~20,000 LOC. 614 tests. Zero external DB dependencies.**
727
+ **113 source files. ~20,000 LOC. 627 tests. Zero external DB dependencies.**
728
728
 
729
729
  ### Functions (89 mem:: functions)
730
730
 
@@ -808,7 +808,7 @@ agentmemory is built on iii-engine's three primitives:
808
808
  ```bash
809
809
  npm run dev # Hot reload
810
810
  npm run build # Production build (~425KB)
811
- npm test # Unit tests (614 tests, ~1.5s)
811
+ npm test # Unit tests (627 tests, ~1.5s)
812
812
  npm run test:integration # API tests (requires running services)
813
813
  ```
814
814
 
package/dist/cli.mjs CHANGED
@@ -42,7 +42,8 @@ function getRestPort() {
42
42
  }
43
43
  async function isEngineRunning() {
44
44
  try {
45
- return (await fetch(`http://localhost:${getRestPort()}/agentmemory/livez`, { signal: AbortSignal.timeout(2e3) })).ok;
45
+ await fetch(`http://localhost:${getRestPort()}/`, { signal: AbortSignal.timeout(2e3) });
46
+ return true;
46
47
  } catch {
47
48
  return false;
48
49
  }
@@ -159,12 +160,12 @@ async function main() {
159
160
  p.intro("agentmemory");
160
161
  if (skipEngine) {
161
162
  p.log.info("Skipping engine check (--no-engine)");
162
- await import("./src-sYZDDbiA.mjs");
163
+ await import("./src-Dflj3k63.mjs");
163
164
  return;
164
165
  }
165
166
  if (await isEngineRunning()) {
166
167
  p.log.success("iii-engine is running");
167
- await import("./src-sYZDDbiA.mjs");
168
+ await import("./src-Dflj3k63.mjs");
168
169
  return;
169
170
  }
170
171
  if (!await startEngine()) {
@@ -192,7 +193,7 @@ async function main() {
192
193
  process.exit(1);
193
194
  }
194
195
  s.stop("iii-engine is ready");
195
- await import("./src-sYZDDbiA.mjs");
196
+ await import("./src-Dflj3k63.mjs");
196
197
  }
197
198
  main().catch((err) => {
198
199
  p.log.error(err instanceof Error ? err.message : String(err));
package/dist/cli.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { spawn, execFileSync, execSync } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as p from \"@clack/prompts\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst args = process.argv.slice(2);\n\nif (args.includes(\"--help\") || args.includes(\"-h\")) {\n console.log(`\nagentmemory — persistent memory for AI coding agents\n\nUsage: agentmemory [options]\n\nOptions:\n --help, -h Show this help\n --tools all|core Tool visibility (default: core = 7 tools)\n --no-engine Skip auto-starting iii-engine\n --port <N> Override REST port (default: 3111)\n\nEnvironment:\n AGENTMEMORY_TOOLS=all Expose all 41 MCP tools\n AGENTMEMORY_SECRET=xxx Auth secret for REST/MCP\n CONSOLIDATION_ENABLED=true Enable auto-consolidation (off by default)\n OBSIDIAN_AUTO_EXPORT=true Auto-export on consolidation\n\nQuick start:\n npx @agentmemory/agentmemory # installs iii if missing, starts everything\n npx agentmemory-mcp # standalone MCP server (no engine needed)\n`);\n process.exit(0);\n}\n\nconst toolsIdx = args.indexOf(\"--tools\");\nif (toolsIdx !== -1 && args[toolsIdx + 1]) {\n process.env[\"AGENTMEMORY_TOOLS\"] = args[toolsIdx + 1];\n}\n\nconst portIdx = args.indexOf(\"--port\");\nif (portIdx !== -1 && args[portIdx + 1]) {\n process.env[\"III_REST_PORT\"] = args[portIdx + 1];\n}\n\nconst skipEngine = args.includes(\"--no-engine\");\n\nfunction getRestPort(): number {\n return parseInt(process.env[\"III_REST_PORT\"] || \"3111\", 10) || 3111;\n}\n\nasync function isEngineRunning(): Promise<boolean> {\n try {\n const res = await fetch(`http://localhost:${getRestPort()}/agentmemory/livez`, {\n signal: AbortSignal.timeout(2000),\n });\n return res.ok;\n } catch {\n return false;\n }\n}\n\nfunction findIiiConfig(): string {\n const candidates = [\n join(__dirname, \"iii-config.yaml\"),\n join(__dirname, \"..\", \"iii-config.yaml\"),\n join(process.cwd(), \"iii-config.yaml\"),\n ];\n for (const c of candidates) {\n if (existsSync(c)) return c;\n }\n return \"\";\n}\n\nfunction whichBinary(name: string): string | null {\n const cmd = process.platform === \"win32\" ? \"where\" : \"which\";\n try {\n return execFileSync(cmd, [name], { encoding: \"utf-8\" }).trim().split(\"\\n\")[0];\n } catch {\n return null;\n }\n}\n\nasync function installIii(): Promise<boolean> {\n if (process.platform === \"win32\") {\n p.log.warn(\"Automatic iii-engine install is not supported on Windows.\");\n p.log.info(\"Install manually: https://iii.dev/docs\");\n return false;\n }\n\n const curlBin = whichBinary(\"curl\");\n if (!curlBin) {\n p.log.warn(\"curl not found — cannot auto-install iii-engine.\");\n return false;\n }\n\n const shouldInstall = await p.confirm({\n message: \"iii-engine is not installed. Install it now?\",\n initialValue: true,\n });\n\n if (p.isCancel(shouldInstall) || !shouldInstall) {\n return false;\n }\n\n const s = p.spinner();\n s.start(\"Installing iii-engine...\");\n\n try {\n execSync(\"curl -fsSL https://install.iii.dev/iii/main/install.sh | sh\", {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n timeout: 120000,\n });\n\n const installed = whichBinary(\"iii\");\n if (installed) {\n s.stop(\"iii-engine installed successfully\");\n return true;\n }\n\n s.stop(\"Installation completed but iii not found in PATH\");\n p.log.warn(\"You may need to restart your shell or add iii to your PATH.\");\n\n const iiiPaths = [\n join(process.env[\"HOME\"] || \"\", \".local\", \"bin\", \"iii\"),\n \"/usr/local/bin/iii\",\n ];\n for (const iiiPath of iiiPaths) {\n if (existsSync(iiiPath)) {\n p.log.info(`Found iii at: ${iiiPath}`);\n process.env[\"PATH\"] = `${dirname(iiiPath)}:${process.env[\"PATH\"]}`;\n return true;\n }\n }\n\n return false;\n } catch (err) {\n s.stop(\"Failed to install iii-engine\");\n p.log.error(err instanceof Error ? err.message : String(err));\n return false;\n }\n}\n\nasync function startEngine(): Promise<boolean> {\n const configPath = findIiiConfig();\n let iiiBin = whichBinary(\"iii\");\n\n if (!iiiBin) {\n const installed = await installIii();\n if (installed) {\n iiiBin = whichBinary(\"iii\");\n }\n }\n\n if (iiiBin && configPath) {\n const s = p.spinner();\n s.start(`Starting iii-engine: ${iiiBin}`);\n const child = spawn(iiiBin, [\"--config\", configPath], {\n detached: true,\n stdio: \"ignore\",\n });\n child.unref();\n s.stop(\"iii-engine process started\");\n return true;\n }\n\n const dockerBin = whichBinary(\"docker\");\n const dockerCompose = join(__dirname, \"..\", \"docker-compose.yml\");\n const dcExists = existsSync(dockerCompose) || existsSync(join(process.cwd(), \"docker-compose.yml\"));\n\n if (dockerBin && dcExists) {\n const composeFile = existsSync(dockerCompose) ? dockerCompose : join(process.cwd(), \"docker-compose.yml\");\n const s = p.spinner();\n s.start(\"Starting iii-engine via Docker...\");\n const child = spawn(dockerBin, [\"compose\", \"-f\", composeFile, \"up\", \"-d\"], {\n detached: true,\n stdio: \"ignore\",\n });\n child.unref();\n s.stop(\"Docker compose started\");\n return true;\n }\n\n return false;\n}\n\nasync function waitForEngine(timeoutMs: number): Promise<boolean> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n if (await isEngineRunning()) return true;\n await new Promise((r) => setTimeout(r, 500));\n }\n return false;\n}\n\nasync function main() {\n p.intro(\"agentmemory\");\n\n if (skipEngine) {\n p.log.info(\"Skipping engine check (--no-engine)\");\n await import(\"./index.js\");\n return;\n }\n\n if (await isEngineRunning()) {\n p.log.success(\"iii-engine is running\");\n await import(\"./index.js\");\n return;\n }\n\n const started = await startEngine();\n if (!started) {\n p.log.error(\"Could not start iii-engine.\");\n p.note(\n [\n \"Install iii-engine (pick one):\",\n \" curl -fsSL https://install.iii.dev/iii/main/install.sh | sh\",\n \" cargo install iii-engine\",\n \"\",\n \"Or use Docker:\",\n \" docker pull iiidev/iii:latest\",\n \"\",\n \"Docs: https://iii.dev/docs\",\n \"\",\n \"Or skip with: agentmemory --no-engine\",\n ].join(\"\\n\"),\n \"Setup required\",\n );\n process.exit(1);\n }\n\n const s = p.spinner();\n s.start(\"Waiting for iii-engine to be ready...\");\n\n const ready = await waitForEngine(15000);\n if (!ready) {\n const port = getRestPort();\n s.stop(\"iii-engine did not become ready within 15s\");\n p.log.error(`Check that ports ${port}, ${port + 1}, 49134 are available.`);\n process.exit(1);\n }\n\n s.stop(\"iii-engine is ready\");\n await import(\"./index.js\");\n}\n\nmain().catch((err) => {\n p.log.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { spawn, execFileSync, execSync } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as p from \"@clack/prompts\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst args = process.argv.slice(2);\n\nif (args.includes(\"--help\") || args.includes(\"-h\")) {\n console.log(`\nagentmemory — persistent memory for AI coding agents\n\nUsage: agentmemory [options]\n\nOptions:\n --help, -h Show this help\n --tools all|core Tool visibility (default: core = 7 tools)\n --no-engine Skip auto-starting iii-engine\n --port <N> Override REST port (default: 3111)\n\nEnvironment:\n AGENTMEMORY_TOOLS=all Expose all 41 MCP tools\n AGENTMEMORY_SECRET=xxx Auth secret for REST/MCP\n CONSOLIDATION_ENABLED=true Enable auto-consolidation (off by default)\n OBSIDIAN_AUTO_EXPORT=true Auto-export on consolidation\n\nQuick start:\n npx @agentmemory/agentmemory # installs iii if missing, starts everything\n npx agentmemory-mcp # standalone MCP server (no engine needed)\n`);\n process.exit(0);\n}\n\nconst toolsIdx = args.indexOf(\"--tools\");\nif (toolsIdx !== -1 && args[toolsIdx + 1]) {\n process.env[\"AGENTMEMORY_TOOLS\"] = args[toolsIdx + 1];\n}\n\nconst portIdx = args.indexOf(\"--port\");\nif (portIdx !== -1 && args[portIdx + 1]) {\n process.env[\"III_REST_PORT\"] = args[portIdx + 1];\n}\n\nconst skipEngine = args.includes(\"--no-engine\");\n\nfunction getRestPort(): number {\n return parseInt(process.env[\"III_REST_PORT\"] || \"3111\", 10) || 3111;\n}\n\nasync function isEngineRunning(): Promise<boolean> {\n try {\n await fetch(`http://localhost:${getRestPort()}/`, {\n signal: AbortSignal.timeout(2000),\n });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction findIiiConfig(): string {\n const candidates = [\n join(__dirname, \"iii-config.yaml\"),\n join(__dirname, \"..\", \"iii-config.yaml\"),\n join(process.cwd(), \"iii-config.yaml\"),\n ];\n for (const c of candidates) {\n if (existsSync(c)) return c;\n }\n return \"\";\n}\n\nfunction whichBinary(name: string): string | null {\n const cmd = process.platform === \"win32\" ? \"where\" : \"which\";\n try {\n return execFileSync(cmd, [name], { encoding: \"utf-8\" }).trim().split(\"\\n\")[0];\n } catch {\n return null;\n }\n}\n\nasync function installIii(): Promise<boolean> {\n if (process.platform === \"win32\") {\n p.log.warn(\"Automatic iii-engine install is not supported on Windows.\");\n p.log.info(\"Install manually: https://iii.dev/docs\");\n return false;\n }\n\n const curlBin = whichBinary(\"curl\");\n if (!curlBin) {\n p.log.warn(\"curl not found — cannot auto-install iii-engine.\");\n return false;\n }\n\n const shouldInstall = await p.confirm({\n message: \"iii-engine is not installed. Install it now?\",\n initialValue: true,\n });\n\n if (p.isCancel(shouldInstall) || !shouldInstall) {\n return false;\n }\n\n const s = p.spinner();\n s.start(\"Installing iii-engine...\");\n\n try {\n execSync(\"curl -fsSL https://install.iii.dev/iii/main/install.sh | sh\", {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n timeout: 120000,\n });\n\n const installed = whichBinary(\"iii\");\n if (installed) {\n s.stop(\"iii-engine installed successfully\");\n return true;\n }\n\n s.stop(\"Installation completed but iii not found in PATH\");\n p.log.warn(\"You may need to restart your shell or add iii to your PATH.\");\n\n const iiiPaths = [\n join(process.env[\"HOME\"] || \"\", \".local\", \"bin\", \"iii\"),\n \"/usr/local/bin/iii\",\n ];\n for (const iiiPath of iiiPaths) {\n if (existsSync(iiiPath)) {\n p.log.info(`Found iii at: ${iiiPath}`);\n process.env[\"PATH\"] = `${dirname(iiiPath)}:${process.env[\"PATH\"]}`;\n return true;\n }\n }\n\n return false;\n } catch (err) {\n s.stop(\"Failed to install iii-engine\");\n p.log.error(err instanceof Error ? err.message : String(err));\n return false;\n }\n}\n\nasync function startEngine(): Promise<boolean> {\n const configPath = findIiiConfig();\n let iiiBin = whichBinary(\"iii\");\n\n if (!iiiBin) {\n const installed = await installIii();\n if (installed) {\n iiiBin = whichBinary(\"iii\");\n }\n }\n\n if (iiiBin && configPath) {\n const s = p.spinner();\n s.start(`Starting iii-engine: ${iiiBin}`);\n const child = spawn(iiiBin, [\"--config\", configPath], {\n detached: true,\n stdio: \"ignore\",\n });\n child.unref();\n s.stop(\"iii-engine process started\");\n return true;\n }\n\n const dockerBin = whichBinary(\"docker\");\n const dockerCompose = join(__dirname, \"..\", \"docker-compose.yml\");\n const dcExists = existsSync(dockerCompose) || existsSync(join(process.cwd(), \"docker-compose.yml\"));\n\n if (dockerBin && dcExists) {\n const composeFile = existsSync(dockerCompose) ? dockerCompose : join(process.cwd(), \"docker-compose.yml\");\n const s = p.spinner();\n s.start(\"Starting iii-engine via Docker...\");\n const child = spawn(dockerBin, [\"compose\", \"-f\", composeFile, \"up\", \"-d\"], {\n detached: true,\n stdio: \"ignore\",\n });\n child.unref();\n s.stop(\"Docker compose started\");\n return true;\n }\n\n return false;\n}\n\nasync function waitForEngine(timeoutMs: number): Promise<boolean> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n if (await isEngineRunning()) return true;\n await new Promise((r) => setTimeout(r, 500));\n }\n return false;\n}\n\nasync function main() {\n p.intro(\"agentmemory\");\n\n if (skipEngine) {\n p.log.info(\"Skipping engine check (--no-engine)\");\n await import(\"./index.js\");\n return;\n }\n\n if (await isEngineRunning()) {\n p.log.success(\"iii-engine is running\");\n await import(\"./index.js\");\n return;\n }\n\n const started = await startEngine();\n if (!started) {\n p.log.error(\"Could not start iii-engine.\");\n p.note(\n [\n \"Install iii-engine (pick one):\",\n \" curl -fsSL https://install.iii.dev/iii/main/install.sh | sh\",\n \" cargo install iii-engine\",\n \"\",\n \"Or use Docker:\",\n \" docker pull iiidev/iii:latest\",\n \"\",\n \"Docs: https://iii.dev/docs\",\n \"\",\n \"Or skip with: agentmemory --no-engine\",\n ].join(\"\\n\"),\n \"Setup required\",\n );\n process.exit(1);\n }\n\n const s = p.spinner();\n s.start(\"Waiting for iii-engine to be ready...\");\n\n const ready = await waitForEngine(15000);\n if (!ready) {\n const port = getRestPort();\n s.stop(\"iii-engine did not become ready within 15s\");\n p.log.error(`Check that ports ${port}, ${port + 1}, 49134 are available.`);\n process.exit(1);\n }\n\n s.stop(\"iii-engine is ready\");\n await import(\"./index.js\");\n}\n\nmain().catch((err) => {\n p.log.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n});\n"],"mappings":"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"}
@@ -8,6 +8,7 @@ services:
8
8
  - "9464:9464"
9
9
  volumes:
10
10
  - iii-data:/data
11
+ - ./iii-config.yaml:/app/config.yaml:ro
11
12
  restart: unless-stopped
12
13
 
13
14
  volumes:
@@ -10,7 +10,7 @@ modules:
10
10
  - class: modules::api::RestApiModule
11
11
  config:
12
12
  port: 3111
13
- host: 127.0.0.1
13
+ host: 0.0.0.0
14
14
  default_timeout: 180000
15
15
  cors:
16
16
  allowed_origins: ["http://localhost:3111", "http://localhost:3113", "http://127.0.0.1:3111", "http://127.0.0.1:3113"]
@@ -34,7 +34,7 @@ modules:
34
34
  - class: modules::stream::StreamModule
35
35
  config:
36
36
  port: 3112
37
- host: 127.0.0.1
37
+ host: 0.0.0.0
38
38
 
39
39
  - class: modules::observability::OtelModule
40
40
  config: