@agentmemory/agentmemory 0.9.28 → 0.9.29
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/.env.example +15 -6
- package/AGENTS.md +6 -6
- package/README.md +220 -152
- package/dist/.env.example +15 -6
- package/dist/cli.d.mts.map +1 -1
- package/dist/cli.mjs +233 -35
- package/dist/cli.mjs.map +1 -1
- package/dist/{connect-JnsJXc68.mjs → connect-Qaeq15TQ.mjs} +599 -41
- package/dist/connect-Qaeq15TQ.mjs.map +1 -0
- package/dist/docker-compose.yml +2 -2
- package/dist/hooks/antigravity-bridge.d.mts +8 -0
- package/dist/hooks/antigravity-bridge.d.mts.map +1 -0
- package/dist/hooks/antigravity-bridge.mjs +114 -0
- package/dist/hooks/antigravity-bridge.mjs.map +1 -0
- package/dist/hooks/notification.mjs +19 -4
- package/dist/hooks/notification.mjs.map +1 -1
- package/dist/hooks/post-commit.mjs +13 -1
- package/dist/hooks/post-commit.mjs.map +1 -1
- package/dist/hooks/post-tool-failure.mjs +14 -3
- package/dist/hooks/post-tool-failure.mjs.map +1 -1
- package/dist/hooks/post-tool-use.mjs +14 -3
- package/dist/hooks/post-tool-use.mjs.map +1 -1
- package/dist/hooks/pre-compact.mjs +12 -2
- package/dist/hooks/pre-compact.mjs.map +1 -1
- package/dist/hooks/pre-tool-use.mjs +1 -1
- package/dist/hooks/pre-tool-use.mjs.map +1 -1
- package/dist/hooks/prompt-submit.mjs +14 -3
- package/dist/hooks/prompt-submit.mjs.map +1 -1
- package/dist/hooks/session-end.mjs +82 -18
- package/dist/hooks/session-end.mjs.map +1 -1
- package/dist/hooks/session-start.mjs +22 -4
- package/dist/hooks/session-start.mjs.map +1 -1
- package/dist/hooks/stop.mjs +1 -7
- package/dist/hooks/stop.mjs.map +1 -1
- package/dist/hooks/subagent-start.mjs +14 -3
- package/dist/hooks/subagent-start.mjs.map +1 -1
- package/dist/hooks/subagent-stop.mjs +14 -3
- package/dist/hooks/subagent-stop.mjs.map +1 -1
- package/dist/hooks/task-completed.mjs +14 -3
- package/dist/hooks/task-completed.mjs.map +1 -1
- package/dist/{image-refs-C2YU7BIm.mjs → image-refs-CJgZmb9X.mjs} +2 -2
- package/dist/{image-refs-C2YU7BIm.mjs.map → image-refs-CJgZmb9X.mjs.map} +1 -1
- package/dist/index.mjs +1557 -755
- package/dist/index.mjs.map +1 -1
- package/dist/schema-BFZhNTF7.mjs +197 -0
- package/dist/schema-BFZhNTF7.mjs.map +1 -0
- package/dist/{src-CzgoepGU.mjs → src-G7yt8gGm.mjs} +1531 -883
- package/dist/src-G7yt8gGm.mjs.map +1 -0
- package/dist/{standalone-YsZFFQBM.mjs → standalone-BqNJDJ04.mjs} +26 -15
- package/dist/standalone-BqNJDJ04.mjs.map +1 -0
- package/dist/standalone.d.mts.map +1 -1
- package/dist/standalone.mjs +50 -14
- package/dist/standalone.mjs.map +1 -1
- package/dist/{tools-registry-D3NEoe5m.mjs → tools-registry-BV_2bu7z.mjs} +293 -3
- package/dist/tools-registry-BV_2bu7z.mjs.map +1 -0
- package/dist/viewer/favicon.svg +35 -1
- package/dist/viewer/index.html +473 -83
- package/docker-compose.yml +2 -2
- package/integrations/pi/README.md +77 -0
- package/integrations/pi/index.ts +403 -0
- package/integrations/pi/package.json +32 -0
- package/integrations/pi/security.ts +35 -0
- package/package.json +3 -4
- package/plugin/.claude-plugin/plugin.json +2 -2
- package/plugin/.codex-plugin/plugin.json +2 -2
- package/plugin/.devin-plugin/plugin.json +32 -0
- package/plugin/cursor/hooks.json +41 -0
- package/plugin/cursor/mcp.json +12 -0
- package/plugin/hooks/hooks.antigravity.json +43 -0
- package/plugin/hooks/hooks.devin.json +67 -0
- package/plugin/hooks/hooks.droid.json +55 -0
- package/plugin/opencode/README.md +1 -1
- package/plugin/opencode/agentmemory-capture.ts +73 -13
- package/plugin/opencode/plugin.json +1 -1
- package/plugin/plugin.json +2 -2
- package/plugin/scripts/antigravity-bridge.d.mts +8 -0
- package/plugin/scripts/antigravity-bridge.d.mts.map +1 -0
- package/plugin/scripts/antigravity-bridge.mjs +114 -0
- package/plugin/scripts/antigravity-bridge.mjs.map +1 -0
- package/plugin/scripts/notification.mjs +19 -4
- package/plugin/scripts/notification.mjs.map +1 -1
- package/plugin/scripts/post-commit.mjs +13 -1
- package/plugin/scripts/post-commit.mjs.map +1 -1
- package/plugin/scripts/post-tool-failure.mjs +14 -3
- package/plugin/scripts/post-tool-failure.mjs.map +1 -1
- package/plugin/scripts/post-tool-use.mjs +14 -3
- package/plugin/scripts/post-tool-use.mjs.map +1 -1
- package/plugin/scripts/pre-compact.mjs +12 -2
- package/plugin/scripts/pre-compact.mjs.map +1 -1
- package/plugin/scripts/pre-tool-use.mjs +1 -1
- package/plugin/scripts/pre-tool-use.mjs.map +1 -1
- package/plugin/scripts/prompt-submit.mjs +14 -3
- package/plugin/scripts/prompt-submit.mjs.map +1 -1
- package/plugin/scripts/session-end.mjs +82 -18
- package/plugin/scripts/session-end.mjs.map +1 -1
- package/plugin/scripts/session-start.mjs +22 -4
- package/plugin/scripts/session-start.mjs.map +1 -1
- package/plugin/scripts/stop.mjs +1 -7
- package/plugin/scripts/stop.mjs.map +1 -1
- package/plugin/scripts/subagent-start.mjs +14 -3
- package/plugin/scripts/subagent-start.mjs.map +1 -1
- package/plugin/scripts/subagent-stop.mjs +14 -3
- package/plugin/scripts/subagent-stop.mjs.map +1 -1
- package/plugin/scripts/task-completed.mjs +14 -3
- package/plugin/scripts/task-completed.mjs.map +1 -1
- package/plugin/skills/agentmemory-agents/REFERENCE.md +6 -3
- package/plugin/skills/agentmemory-config/REFERENCE.md +4 -1
- package/plugin/skills/agentmemory-mcp-tools/REFERENCE.md +3 -2
- package/plugin/skills/agentmemory-rest-api/REFERENCE.md +14 -1
- package/plugin/skills/forget/SKILL.md +4 -1
- package/plugin/skills/lesson/SKILL.md +64 -0
- package/plugin/skills/memory-discipline/SKILL.md +57 -0
- package/plugin/skills/recall/SKILL.md +4 -1
- package/plugin/skills/remember/SKILL.md +6 -1
- package/dist/config-ChC9EtgV.mjs +0 -259
- package/dist/config-ChC9EtgV.mjs.map +0 -1
- package/dist/connect-JnsJXc68.mjs.map +0 -1
- package/dist/schema-CNiCWzV9.mjs +0 -78
- package/dist/schema-CNiCWzV9.mjs.map +0 -1
- package/dist/src-CzgoepGU.mjs.map +0 -1
- package/dist/standalone-YsZFFQBM.mjs.map +0 -1
- package/dist/tools-registry-D3NEoe5m.mjs.map +0 -1
- package/plugin/scripts/diagnostics.d.mts +0 -17
- package/plugin/scripts/diagnostics.d.mts.map +0 -1
- package/plugin/scripts/diagnostics.mjs.map +0 -1
package/dist/.env.example
CHANGED
|
@@ -26,22 +26,24 @@
|
|
|
26
26
|
# The detection order is OPENAI_API_KEY → MINIMAX_API_KEY → ANTHROPIC_API_KEY
|
|
27
27
|
# → GEMINI_API_KEY → OPENROUTER_API_KEY → noop.
|
|
28
28
|
|
|
29
|
-
# OPENAI_API_KEY=sk-... #
|
|
29
|
+
# OPENAI_API_KEY=sk-... # Activates both the OpenAI-compatible LLM provider (DeepSeek, SiliconFlow, vLLM, LM Studio, Ollama via `/v1`) and OpenAI embeddings. Set OPENAI_API_KEY_FOR_LLM=false to scope it to embeddings only.
|
|
30
30
|
# OPENAI_BASE_URL=https://api.openai.com # Override for OpenAI-compatible providers
|
|
31
|
+
# OPENAI_MODEL=gpt-5.6-luna # Default OpenAI-compatible chat model
|
|
32
|
+
# OPENAI_API_KEY_FOR_LLM=false # Skip OpenAI auto-detection for LLM; key stays active for embeddings
|
|
31
33
|
|
|
32
34
|
# ANTHROPIC_API_KEY=sk-ant-...
|
|
33
|
-
# ANTHROPIC_MODEL=claude-sonnet-
|
|
35
|
+
# ANTHROPIC_MODEL=claude-sonnet-5 # Default Anthropic model
|
|
34
36
|
# ANTHROPIC_BASE_URL=https://api.anthropic.com # Override for Anthropic-compatible proxies / Azure AI Foundry
|
|
35
37
|
|
|
36
38
|
# GEMINI_API_KEY=... # Either env name works; GEMINI_API_KEY takes precedence
|
|
37
39
|
# GOOGLE_API_KEY=... # Alias for GEMINI_API_KEY when set alone (emits a one-time stderr hint)
|
|
38
|
-
# GEMINI_MODEL=gemini-
|
|
40
|
+
# GEMINI_MODEL=gemini-3.7-flash # Default Gemini model (current stable Flash)
|
|
39
41
|
|
|
40
42
|
# OPENROUTER_API_KEY=sk-or-...
|
|
41
|
-
# OPENROUTER_MODEL=anthropic/claude-sonnet-
|
|
43
|
+
# OPENROUTER_MODEL=anthropic/claude-sonnet-5
|
|
42
44
|
|
|
43
45
|
# MINIMAX_API_KEY=...
|
|
44
|
-
# MINIMAX_MODEL=MiniMax-
|
|
46
|
+
# MINIMAX_MODEL=MiniMax-M3
|
|
45
47
|
|
|
46
48
|
# MAX_TOKENS=4096 # Cap LLM completion tokens for compression / summarise calls
|
|
47
49
|
|
|
@@ -111,6 +113,13 @@
|
|
|
111
113
|
# CONSOLIDATION_DECAY_DAYS=30 # Age (days) after which non-reinforced memories decay during consolidation
|
|
112
114
|
# GRAPH_EXTRACTION_ENABLED=true # Extract concept-graph edges on remember; powers the graph-traversal recall path
|
|
113
115
|
# GRAPH_EXTRACTION_BATCH_SIZE=8 # Memories per graph-extraction batch
|
|
116
|
+
|
|
117
|
+
# Local reasoning models only: set to 1 to ask the model to skip its
|
|
118
|
+
# hidden thinking pass during graph extraction. Extraction runs several
|
|
119
|
+
# times faster; relation quality can drop slightly. Leave unset to let
|
|
120
|
+
# the model think (default).
|
|
121
|
+
# AGENTMEMORY_LLM_NOTHINK=1
|
|
122
|
+
|
|
114
123
|
# AGENTMEMORY_REFLECT=true # Periodically auto-synthesize lessons from memories
|
|
115
124
|
# AGENTMEMORY_DROP_STALE_INDEX=true # Drop on-disk BM25 / vector index on startup if dim guard fires (#248). Recovery toggle for stuck-state debugging.
|
|
116
125
|
# AGENTMEMORY_IMAGE_EMBEDDINGS=true # Enable image embeddings when an image provider is present (experimental).
|
|
@@ -119,7 +128,7 @@
|
|
|
119
128
|
# 6. CLI / runtime knobs
|
|
120
129
|
# -----------------------------------------------------------------------------
|
|
121
130
|
|
|
122
|
-
# AGENTMEMORY_TOOLS=
|
|
131
|
+
# AGENTMEMORY_TOOLS=core # all (54 tools, default) | core (8 tools): surface exposed to MCP clients
|
|
123
132
|
# AGENTMEMORY_SLOTS=memory # Comma-separated plugin slot names the CLI should claim
|
|
124
133
|
# AGENTMEMORY_DEBUG=1 # Trace MCP shim probe + standalone fallback decisions to stderr
|
|
125
134
|
# AGENTMEMORY_FORCE_PROXY=1 # Skip the MCP shim livez probe and trust AGENTMEMORY_URL (for sandboxed MCP clients that can't reach localhost)
|
package/dist/cli.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.mts","names":[],"sources":["../src/cli.ts"],"mappings":";
|
|
1
|
+
{"version":3,"file":"cli.d.mts","names":[],"sources":["../src/cli.ts"],"mappings":";iBAoSsB,kBAAA,CAAA,GAAsB,OAAA"}
|
package/dist/cli.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as runAdapter, i as resolveAdapter, r as knownAgents, t as ADAPTERS } from "./connect-
|
|
3
|
-
import { i as generateId } from "./schema-
|
|
2
|
+
import { a as runAdapter, i as resolveAdapter, r as knownAgents, t as ADAPTERS } from "./connect-Qaeq15TQ.mjs";
|
|
3
|
+
import { i as generateId } from "./schema-BFZhNTF7.mjs";
|
|
4
4
|
import { r as setBootVerbose } from "./logger-BEB7pCI9.mjs";
|
|
5
|
-
import { i as VERSION, n as getAllTools, t as ESSENTIAL_TOOLS } from "./tools-registry-
|
|
5
|
+
import { i as VERSION, n as getAllTools, p as hydrateProcessEnvFromFile, t as ESSENTIAL_TOOLS } from "./tools-registry-BV_2bu7z.mjs";
|
|
6
6
|
import { execFileSync, spawn, spawnSync } from "node:child_process";
|
|
7
7
|
import { appendFileSync, closeSync, constants, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, readdirSync, readlinkSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
|
|
8
|
-
import { delimiter, dirname, join } from "node:path";
|
|
8
|
+
import { delimiter, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
9
9
|
import { fileURLToPath } from "node:url";
|
|
10
10
|
import { homedir, platform } from "node:os";
|
|
11
11
|
import * as p from "@clack/prompts";
|
|
@@ -525,7 +525,7 @@ const PROVIDERS = [
|
|
|
525
525
|
},
|
|
526
526
|
{
|
|
527
527
|
value: "minimax",
|
|
528
|
-
label: "MiniMax —
|
|
528
|
+
label: "MiniMax — MiniMax-M3",
|
|
529
529
|
envKey: "MINIMAX_API_KEY"
|
|
530
530
|
},
|
|
531
531
|
{
|
|
@@ -765,6 +765,87 @@ async function wireSelectedAgents(agents) {
|
|
|
765
765
|
p.note(summary.join("\n"), "wire summary");
|
|
766
766
|
}
|
|
767
767
|
//#endregion
|
|
768
|
+
//#region src/cli-data-dir.ts
|
|
769
|
+
function argValue(args, name) {
|
|
770
|
+
const equals = `${name}=`;
|
|
771
|
+
const inline = args.find((arg) => arg.startsWith(equals));
|
|
772
|
+
if (inline) return inline.slice(equals.length);
|
|
773
|
+
const idx = args.indexOf(name);
|
|
774
|
+
if (idx !== -1) return args[idx + 1];
|
|
775
|
+
}
|
|
776
|
+
function expandHome(pathValue, home) {
|
|
777
|
+
if (pathValue === "~") return home;
|
|
778
|
+
if (pathValue.startsWith("~/") || pathValue.startsWith("~\\")) return join(home, pathValue.slice(2));
|
|
779
|
+
return pathValue;
|
|
780
|
+
}
|
|
781
|
+
function absoluteDataDir(pathValue, cwd, home) {
|
|
782
|
+
const expanded = expandHome(pathValue, home);
|
|
783
|
+
return isAbsolute(expanded) ? expanded : resolve(cwd, expanded);
|
|
784
|
+
}
|
|
785
|
+
function platformDefaultDataDir(env, home, nodePlatform, useXdg = true) {
|
|
786
|
+
if (nodePlatform === "darwin") return join(home, "Library", "Application Support", "agentmemory");
|
|
787
|
+
if (nodePlatform === "win32") {
|
|
788
|
+
const appData = env["APPDATA"];
|
|
789
|
+
return appData ? join(appData, "agentmemory") : join(home, ".agentmemory");
|
|
790
|
+
}
|
|
791
|
+
const xdgDataHome = env["XDG_DATA_HOME"];
|
|
792
|
+
if (useXdg && xdgDataHome && isAbsolute(xdgDataHome)) return join(xdgDataHome, "agentmemory");
|
|
793
|
+
return join(home, ".local", "share", "agentmemory");
|
|
794
|
+
}
|
|
795
|
+
function nearestGitParent(pathValue) {
|
|
796
|
+
let current = pathValue;
|
|
797
|
+
while (true) {
|
|
798
|
+
if (existsSync(join(current, ".git"))) return current;
|
|
799
|
+
const parent = dirname(current);
|
|
800
|
+
if (parent === current) return void 0;
|
|
801
|
+
current = parent;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
function isWithin(parent, child) {
|
|
805
|
+
const pathFromParent = relative(parent, child);
|
|
806
|
+
return pathFromParent === "" || pathFromParent !== ".." && !pathFromParent.startsWith(`..${sep}`) && !isAbsolute(pathFromParent);
|
|
807
|
+
}
|
|
808
|
+
function resolveDataDir(options = {}) {
|
|
809
|
+
const args = options.args ?? process.argv.slice(2);
|
|
810
|
+
const env = options.env ?? process.env;
|
|
811
|
+
const cwd = options.cwd ?? process.cwd();
|
|
812
|
+
const home = options.home ?? homedir();
|
|
813
|
+
const nodePlatform = options.platform ?? platform();
|
|
814
|
+
const parsedInstance = parseInt(argValue(args, "--instance") ?? "0", 10);
|
|
815
|
+
const instance = parsedInstance > 0 && parsedInstance <= 50 ? parsedInstance : 0;
|
|
816
|
+
const forInstance = (dataDir) => instance ? join(dataDir, `instance-${instance}`) : dataDir;
|
|
817
|
+
const flagValue = argValue(args, "--data-dir");
|
|
818
|
+
if (flagValue) return {
|
|
819
|
+
dataDir: forInstance(absoluteDataDir(flagValue, cwd, home)),
|
|
820
|
+
source: "flag"
|
|
821
|
+
};
|
|
822
|
+
const envValue = env["AGENTMEMORY_DATA_DIR"];
|
|
823
|
+
if (envValue) return {
|
|
824
|
+
dataDir: forInstance(absoluteDataDir(envValue, cwd, home)),
|
|
825
|
+
source: "env"
|
|
826
|
+
};
|
|
827
|
+
const legacyDir = resolve(cwd, "data");
|
|
828
|
+
const hasLegacyStore = existsSync(join(legacyDir, "state_store.db")) || existsSync(join(legacyDir, "iii-config.yaml"));
|
|
829
|
+
if (instance === 0 && hasLegacyStore) return {
|
|
830
|
+
dataDir: legacyDir,
|
|
831
|
+
source: "default"
|
|
832
|
+
};
|
|
833
|
+
const defaultDir = platformDefaultDataDir(env, home, nodePlatform);
|
|
834
|
+
const gitParent = nearestGitParent(cwd);
|
|
835
|
+
if (gitParent && isWithin(gitParent, defaultDir)) {
|
|
836
|
+
const relocated = platformDefaultDataDir(env, home, nodePlatform, false);
|
|
837
|
+
if (relocated !== defaultDir) return {
|
|
838
|
+
dataDir: forInstance(relocated),
|
|
839
|
+
source: "default",
|
|
840
|
+
relocatedFrom: defaultDir
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
return {
|
|
844
|
+
dataDir: forInstance(defaultDir),
|
|
845
|
+
source: "default"
|
|
846
|
+
};
|
|
847
|
+
}
|
|
848
|
+
//#endregion
|
|
768
849
|
//#region src/cli.ts
|
|
769
850
|
const c = {
|
|
770
851
|
url: pc.cyan,
|
|
@@ -784,6 +865,7 @@ const IS_WINDOWS = platform() === "win32";
|
|
|
784
865
|
const IS_VERBOSE = args.includes("--verbose") || args.includes("-v") || process.env["AGENTMEMORY_VERBOSE"] === "1" || process.env["AGENTMEMORY_VERBOSE"] === "true";
|
|
785
866
|
setBootVerbose(IS_VERBOSE);
|
|
786
867
|
const IS_RESET = args.includes("--reset");
|
|
868
|
+
hydrateProcessEnvFromFile();
|
|
787
869
|
if (args.includes("--version") || args.includes("-V")) {
|
|
788
870
|
process.stdout.write(`${VERSION}\n`);
|
|
789
871
|
process.exit(0);
|
|
@@ -867,10 +949,12 @@ Options:
|
|
|
867
949
|
--instance <N> Shortcut for --port (3111 + N*100) to run multiple
|
|
868
950
|
daemons side-by-side without env gymnastics.
|
|
869
951
|
--instance 1 -> 3211/3212/3213/49234, etc. (max N=50)
|
|
952
|
+
--data-dir <path> Store iii-engine state outside the current repo
|
|
870
953
|
|
|
871
954
|
Environment:
|
|
872
955
|
AGENTMEMORY_URL Full REST base URL (e.g. http://localhost:3111).
|
|
873
956
|
Honored by status, doctor, and MCP shim commands.
|
|
957
|
+
AGENTMEMORY_DATA_DIR State directory fallback when --data-dir is not set.
|
|
874
958
|
AGENTMEMORY_USE_DOCKER=1 Prefer the bundled docker-compose path over the
|
|
875
959
|
native iii-engine binary on first run.
|
|
876
960
|
AGENTMEMORY_III_VERSION Override pinned iii-engine version (default ${IIPINNED_VERSION}).
|
|
@@ -905,6 +989,8 @@ if (instanceIdx !== -1 && args[instanceIdx + 1]) {
|
|
|
905
989
|
if (!process.env["III_REST_PORT"]) process.env["III_REST_PORT"] = String(base);
|
|
906
990
|
}
|
|
907
991
|
}
|
|
992
|
+
const dataDirResolution = resolveDataDir({ args });
|
|
993
|
+
if (dataDirResolution.source !== "default") process.env["AGENTMEMORY_DATA_DIR"] = dataDirResolution.dataDir;
|
|
908
994
|
const skipEngine = args.includes("--no-engine");
|
|
909
995
|
function getRestPort() {
|
|
910
996
|
const url = process.env["AGENTMEMORY_URL"];
|
|
@@ -999,6 +1085,30 @@ function findIiiConfig() {
|
|
|
999
1085
|
for (const c of candidates) if (existsSync(c)) return c;
|
|
1000
1086
|
return "";
|
|
1001
1087
|
}
|
|
1088
|
+
function yamlSingleQuoted(value) {
|
|
1089
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
1090
|
+
}
|
|
1091
|
+
function renderIiiConfig(template, dataDir) {
|
|
1092
|
+
return template.replace("file_path: ./data/state_store.db", `file_path: ${yamlSingleQuoted(join(dataDir, "state_store.db"))}`).replace("file_path: ./data/stream_store", `file_path: ${yamlSingleQuoted(join(dataDir, "stream_store"))}`);
|
|
1093
|
+
}
|
|
1094
|
+
function writeRuntimeIiiConfig(configPath, dataDir) {
|
|
1095
|
+
mkdirSync(dataDir, { recursive: true });
|
|
1096
|
+
const runtimeConfigPath = join(dataDir, "iii-config.yaml");
|
|
1097
|
+
writeFileSync(runtimeConfigPath, renderIiiConfig(readFileSync(configPath, "utf8"), dataDir));
|
|
1098
|
+
return runtimeConfigPath;
|
|
1099
|
+
}
|
|
1100
|
+
function warnIfRelocatedDataDir() {
|
|
1101
|
+
if (!dataDirResolution.relocatedFrom) return;
|
|
1102
|
+
try {
|
|
1103
|
+
mkdirSync(dataDirResolution.dataDir, { recursive: true });
|
|
1104
|
+
const marker = join(dataDirResolution.dataDir, ".cwd-relocation-warning");
|
|
1105
|
+
if (existsSync(marker)) return;
|
|
1106
|
+
p.log.warn(`Default data dir ${dataDirResolution.relocatedFrom} is inside a git worktree; using ${dataDirResolution.dataDir} instead.`);
|
|
1107
|
+
writeFileSync(marker, (/* @__PURE__ */ new Date()).toISOString());
|
|
1108
|
+
} catch {
|
|
1109
|
+
p.log.warn(`Default data dir ${dataDirResolution.relocatedFrom} is inside a git worktree; using ${dataDirResolution.dataDir} instead.`);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1002
1112
|
function whichBinary(name) {
|
|
1003
1113
|
const cmd = IS_WINDOWS ? "where" : "which";
|
|
1004
1114
|
try {
|
|
@@ -1175,8 +1285,8 @@ async function maybeOfferGlobalInstall() {
|
|
|
1175
1285
|
if (runCommand(npmBin, [
|
|
1176
1286
|
"install",
|
|
1177
1287
|
"-g",
|
|
1178
|
-
`@agentmemory/agentmemory@0.9.
|
|
1179
|
-
], { label: `Installing @agentmemory/agentmemory@0.9.
|
|
1288
|
+
`@agentmemory/agentmemory@0.9.29`
|
|
1289
|
+
], { label: `Installing @agentmemory/agentmemory@0.9.29 globally` })) {
|
|
1180
1290
|
p.log.success("Installed globally. `agentmemory stop` etc. will now work in new shells.");
|
|
1181
1291
|
writePrefs({ skipGlobalInstall: true });
|
|
1182
1292
|
} else p.log.warn("Global install failed. Try manually: npm install -g @agentmemory/agentmemory");
|
|
@@ -1231,6 +1341,13 @@ function adoptRunningEngine() {
|
|
|
1231
1341
|
const existingPid = readEnginePidfile();
|
|
1232
1342
|
if (existingState && existingPid) return;
|
|
1233
1343
|
const enginePid = findEnginePidsByPort(getRestPort())[0];
|
|
1344
|
+
if (enginePid) {
|
|
1345
|
+
const comm = pidCommand(enginePid);
|
|
1346
|
+
if (isForeignPortHolder(comm)) {
|
|
1347
|
+
vlog(`adoptRunningEngine: refusing to adopt pid ${enginePid} (${comm}) — not the iii engine binary`);
|
|
1348
|
+
return;
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1234
1351
|
if (enginePid && !existingPid) writeEnginePidfile(enginePid);
|
|
1235
1352
|
if (!existingState) writeEngineState({
|
|
1236
1353
|
kind: "native",
|
|
@@ -1352,17 +1469,19 @@ function pickCompatibleIii(candidates) {
|
|
|
1352
1469
|
}
|
|
1353
1470
|
async function startEngine() {
|
|
1354
1471
|
const configPath = findIiiConfig();
|
|
1472
|
+
warnIfRelocatedDataDir();
|
|
1473
|
+
const runtimeConfigPath = configPath ? writeRuntimeIiiConfig(configPath, dataDirResolution.dataDir) : "";
|
|
1355
1474
|
const pathIii = whichBinary("iii");
|
|
1356
|
-
vlog(`iii binary: ${pathIii ?? "(not on PATH)"}, config: ${
|
|
1475
|
+
vlog(`iii binary: ${pathIii ?? "(not on PATH)"}, config: ${runtimeConfigPath || "(not found)"}`);
|
|
1357
1476
|
const fallbacks = fallbackIiiPaths().filter((p) => existsSync(p));
|
|
1358
1477
|
for (const f of fallbacks) vlog(`fallback iii at ${f} reports version: ${iiiBinVersion(f) ?? "unknown"}`);
|
|
1359
1478
|
let iiiBin = pickCompatibleIii([pathIii, ...fallbacks]);
|
|
1360
|
-
if (iiiBin &&
|
|
1479
|
+
if (iiiBin && runtimeConfigPath) {
|
|
1361
1480
|
if (iiiBin !== pathIii) {
|
|
1362
1481
|
p.log.info(`Using iii at: ${c.dim(iiiBin)} (v${c.accent(IIPINNED_VERSION)})`);
|
|
1363
1482
|
process.env["PATH"] = `${dirname(iiiBin)}${delimiter}${process.env["PATH"] ?? ""}`;
|
|
1364
1483
|
}
|
|
1365
|
-
return startIiiBin(iiiBin,
|
|
1484
|
+
return startIiiBin(iiiBin, runtimeConfigPath);
|
|
1366
1485
|
}
|
|
1367
1486
|
if (pathIii && !iiiBin) vlog(`iii on PATH is v${iiiBinVersion(pathIii) ?? "unknown"}, pin is v${IIPINNED_VERSION}. Will install pinned engine to ${privateIiiPath()}.`);
|
|
1368
1487
|
if (!configPath) {
|
|
@@ -1371,6 +1490,7 @@ async function startEngine() {
|
|
|
1371
1490
|
}
|
|
1372
1491
|
const dockerBin = whichBinary("docker");
|
|
1373
1492
|
vlog(`docker binary: ${dockerBin ?? "(not on PATH)"}`);
|
|
1493
|
+
mkdirSync(dataDirResolution.dataDir, { recursive: true });
|
|
1374
1494
|
const composeFile = [
|
|
1375
1495
|
join(__dirname, "..", "docker-compose.yml"),
|
|
1376
1496
|
join(__dirname, "docker-compose.yml"),
|
|
@@ -1545,6 +1665,12 @@ function printReadyHint(consoleState) {
|
|
|
1545
1665
|
process.stdout.write(`\n${c.dim("Try:")} ${c.cmd(demoCommand)}\n`);
|
|
1546
1666
|
}
|
|
1547
1667
|
async function main() {
|
|
1668
|
+
try {
|
|
1669
|
+
if ((await fetch(`${getBaseUrl()}/agentmemory/livez`, { signal: AbortSignal.timeout(1500) })).ok) {
|
|
1670
|
+
p.log.error(`agentmemory is already running on port ${getRestPort()}. Starting a second instance here would corrupt the running daemon's REST routing. Use the REST API (or the MCP tools) against the running instance, run a different --instance, or stop it first with \`agentmemory stop\`.`);
|
|
1671
|
+
process.exit(1);
|
|
1672
|
+
}
|
|
1673
|
+
} catch {}
|
|
1548
1674
|
if (IS_RESET) resetPrefs();
|
|
1549
1675
|
const firstRun = isFirstRun();
|
|
1550
1676
|
const prefs = readPrefs();
|
|
@@ -1552,7 +1678,7 @@ async function main() {
|
|
|
1552
1678
|
if (firstRun || IS_RESET) await runOnboarding();
|
|
1553
1679
|
if (skipEngine) {
|
|
1554
1680
|
if (IS_VERBOSE) p.log.info("Skipping engine check (--no-engine)");
|
|
1555
|
-
await import("./src-
|
|
1681
|
+
await import("./src-G7yt8gGm.mjs");
|
|
1556
1682
|
if (await waitForAgentmemoryReady(15e3)) {
|
|
1557
1683
|
const consoleState = await ensureIiiConsole();
|
|
1558
1684
|
await maybeOfferGlobalInstall();
|
|
@@ -1567,7 +1693,7 @@ async function main() {
|
|
|
1567
1693
|
const detected = attachedBin ? iiiBinVersion(attachedBin) : null;
|
|
1568
1694
|
if (detected === IIPINNED_VERSION) {
|
|
1569
1695
|
adoptRunningEngine();
|
|
1570
|
-
await import("./src-
|
|
1696
|
+
await import("./src-G7yt8gGm.mjs");
|
|
1571
1697
|
if (await waitForAgentmemoryReady(15e3)) {
|
|
1572
1698
|
const consoleState = await ensureIiiConsole();
|
|
1573
1699
|
await maybeOfferGlobalInstall();
|
|
@@ -1638,7 +1764,7 @@ async function main() {
|
|
|
1638
1764
|
process.exit(1);
|
|
1639
1765
|
}
|
|
1640
1766
|
s.stop(c.ok("iii-engine is ready"));
|
|
1641
|
-
await import("./src-
|
|
1767
|
+
await import("./src-G7yt8gGm.mjs");
|
|
1642
1768
|
if (await waitForAgentmemoryReady(15e3)) {
|
|
1643
1769
|
const consoleState = await ensureIiiConsole();
|
|
1644
1770
|
await maybeOfferGlobalInstall();
|
|
@@ -2286,7 +2412,7 @@ async function startServerForDemo() {
|
|
|
2286
2412
|
process.exit(1);
|
|
2287
2413
|
}
|
|
2288
2414
|
}
|
|
2289
|
-
await import("./src-
|
|
2415
|
+
await import("./src-G7yt8gGm.mjs");
|
|
2290
2416
|
if (!await waitForAgentmemoryReady(15e3)) {
|
|
2291
2417
|
p.log.error("agentmemory worker did not become ready within 15s.");
|
|
2292
2418
|
process.exit(1);
|
|
@@ -2346,6 +2472,7 @@ async function runDemoBody(base) {
|
|
|
2346
2472
|
const results = [];
|
|
2347
2473
|
for (const query of queries) results.push(await runDemoSearch(base, query));
|
|
2348
2474
|
sQuery.stop("Search complete");
|
|
2475
|
+
const semanticHits = results.find((r) => r.query === "database performance optimization")?.hits ?? 0;
|
|
2349
2476
|
const lines = [
|
|
2350
2477
|
`Project: ${demoProject}`,
|
|
2351
2478
|
`Sessions: ${sessions.length} seeded (${totalObs} observations)`,
|
|
@@ -2353,8 +2480,11 @@ async function runDemoBody(base) {
|
|
|
2353
2480
|
c.label("Search results:"),
|
|
2354
2481
|
...results.flatMap((r) => [` ${c.label(`"${r.query}"`)}`, ` ${c.dim("→")} ${c.ok(`${r.hits} hit(s)`)}, top: ${r.topTitle.slice(0, 60)}`]),
|
|
2355
2482
|
"",
|
|
2356
|
-
c.accent(`Notice: searching "database performance optimization"`),
|
|
2357
|
-
|
|
2483
|
+
...semanticHits > 0 ? [c.accent(`Notice: searching "database performance optimization"`), c.accent(`found the N+1 query fix — keyword matching can't do that.`)] : [
|
|
2484
|
+
c.dim(`Note: "database performance optimization" found nothing —`),
|
|
2485
|
+
c.dim(`semantic recall needs an embedding provider key (e.g.`),
|
|
2486
|
+
c.dim(`OPENAI_API_KEY or GEMINI_API_KEY in ~/.agentmemory/.env).`)
|
|
2487
|
+
],
|
|
2358
2488
|
"",
|
|
2359
2489
|
`Viewer: ${c.url(getViewerUrl())}`,
|
|
2360
2490
|
`Clean up with: ${c.dim(`curl -X DELETE "${base}/agentmemory/sessions?project=${demoProject}"`)}`
|
|
@@ -2476,6 +2606,38 @@ async function signalAndWait(pid, initialSignal, timeoutMs) {
|
|
|
2476
2606
|
await new Promise((r) => setTimeout(r, 200));
|
|
2477
2607
|
return !pidAlive(pid);
|
|
2478
2608
|
}
|
|
2609
|
+
async function stopWorkerPid(pid, graceMs) {
|
|
2610
|
+
const s = p.spinner();
|
|
2611
|
+
s.start(`Stopping agentmemory worker (pid ${pid})... [flushing state]`);
|
|
2612
|
+
const ok = await signalAndWait(pid, "SIGTERM", graceMs);
|
|
2613
|
+
s.stop(ok ? `Stopped worker pid ${pid}` : `Failed to stop worker pid ${pid}`);
|
|
2614
|
+
return ok;
|
|
2615
|
+
}
|
|
2616
|
+
function pidCommand(pid) {
|
|
2617
|
+
if (IS_WINDOWS) return "";
|
|
2618
|
+
try {
|
|
2619
|
+
return execFileSync("ps", [
|
|
2620
|
+
"-p",
|
|
2621
|
+
String(pid),
|
|
2622
|
+
"-o",
|
|
2623
|
+
"comm="
|
|
2624
|
+
], {
|
|
2625
|
+
encoding: "utf-8",
|
|
2626
|
+
stdio: [
|
|
2627
|
+
"ignore",
|
|
2628
|
+
"pipe",
|
|
2629
|
+
"ignore"
|
|
2630
|
+
]
|
|
2631
|
+
}).trim();
|
|
2632
|
+
} catch {
|
|
2633
|
+
return "";
|
|
2634
|
+
}
|
|
2635
|
+
}
|
|
2636
|
+
function isForeignPortHolder(comm) {
|
|
2637
|
+
if (!comm) return false;
|
|
2638
|
+
const base = comm.split("/").pop() || comm;
|
|
2639
|
+
return base !== "iii" && !base.startsWith("iii-");
|
|
2640
|
+
}
|
|
2479
2641
|
function findEnginePidsByPort(port) {
|
|
2480
2642
|
if (IS_WINDOWS) return [];
|
|
2481
2643
|
const lsof = whichBinary("lsof");
|
|
@@ -2510,17 +2672,35 @@ async function stopDockerEngine(composeFile, port) {
|
|
|
2510
2672
|
p.log.error(`Engine state references ${composeFile}, but the file is gone. Stop it manually:\n docker compose down (from the dir holding the original docker-compose.yml)`);
|
|
2511
2673
|
process.exit(1);
|
|
2512
2674
|
}
|
|
2675
|
+
const workerPid = readWorkerPidfile();
|
|
2676
|
+
let workerStopped = true;
|
|
2677
|
+
if (workerPid) workerStopped = await stopWorkerPid(workerPid, 5e3);
|
|
2678
|
+
let composeText = "";
|
|
2679
|
+
try {
|
|
2680
|
+
composeText = readFileSync(composeFile, "utf-8");
|
|
2681
|
+
} catch {
|
|
2682
|
+
composeText = "";
|
|
2683
|
+
}
|
|
2684
|
+
const ownServices = ["iii-engine", "iii-init"].filter((svc) => new RegExp(`^\\s+${svc}:`, "m").test(composeText));
|
|
2685
|
+
if (ownServices.length === 0) {
|
|
2686
|
+
p.log.error(`${composeFile} does not define the agentmemory services (iii-engine/iii-init). Refusing to run an unscoped \`docker compose down\` against it — that would tear down every service in the file.\n\nStop the engine service manually:\n docker compose -f ${composeFile} stop <service>`);
|
|
2687
|
+
process.exit(1);
|
|
2688
|
+
}
|
|
2513
2689
|
const ok = runCommand(dockerBin, [
|
|
2514
2690
|
"compose",
|
|
2515
2691
|
"-f",
|
|
2516
2692
|
composeFile,
|
|
2517
|
-
"
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
if (
|
|
2523
|
-
|
|
2693
|
+
"rm",
|
|
2694
|
+
"-s",
|
|
2695
|
+
"-f",
|
|
2696
|
+
...ownServices
|
|
2697
|
+
], { label: `docker compose -f ${composeFile} rm -s -f ${ownServices.join(" ")}` });
|
|
2698
|
+
if (workerStopped) clearWorkerPidfile();
|
|
2699
|
+
if (ok) {
|
|
2700
|
+
clearEnginePidfile();
|
|
2701
|
+
clearEngineState();
|
|
2702
|
+
} else {
|
|
2703
|
+
p.log.error(`docker compose rm failed. The engine may still be running on :${port}. Inspect with:\n docker compose -f ${composeFile} ps`);
|
|
2524
2704
|
process.exit(1);
|
|
2525
2705
|
}
|
|
2526
2706
|
p.outro("Stopped. Memories persisted to disk; restart anytime with: npx @agentmemory/agentmemory");
|
|
@@ -2594,15 +2774,18 @@ async function runStop() {
|
|
|
2594
2774
|
process.exit(1);
|
|
2595
2775
|
}
|
|
2596
2776
|
let allStopped = true;
|
|
2597
|
-
for (const pid of workerCandidates)
|
|
2598
|
-
|
|
2599
|
-
s.start(`Stopping agentmemory worker (pid ${pid})... [flushing state]`);
|
|
2600
|
-
const ok = await signalAndWait(pid, "SIGTERM", 5e3);
|
|
2601
|
-
s.stop(ok ? `Stopped worker pid ${pid}` : `Failed to stop worker pid ${pid}`);
|
|
2602
|
-
if (!ok) allStopped = false;
|
|
2603
|
-
}
|
|
2777
|
+
for (const pid of workerCandidates) if (!await stopWorkerPid(pid, 5e3)) allStopped = false;
|
|
2778
|
+
const skippedForeign = [];
|
|
2604
2779
|
for (const pid of candidates) {
|
|
2605
2780
|
if (workerCandidates.has(pid)) continue;
|
|
2781
|
+
const comm = pidCommand(pid);
|
|
2782
|
+
if (!force && isForeignPortHolder(comm)) {
|
|
2783
|
+
skippedForeign.push({
|
|
2784
|
+
pid,
|
|
2785
|
+
comm
|
|
2786
|
+
});
|
|
2787
|
+
continue;
|
|
2788
|
+
}
|
|
2606
2789
|
const s = p.spinner();
|
|
2607
2790
|
s.start(`Stopping iii-engine (pid ${pid})...`);
|
|
2608
2791
|
const ok = await signalAndWait(pid, "SIGTERM", 3e3);
|
|
@@ -2612,6 +2795,11 @@ async function runStop() {
|
|
|
2612
2795
|
clearEnginePidfile();
|
|
2613
2796
|
clearEngineState();
|
|
2614
2797
|
clearWorkerPidfile();
|
|
2798
|
+
if (skippedForeign.length > 0) {
|
|
2799
|
+
const list = skippedForeign.map((sf) => ` pid ${sf.pid} ${sf.comm}`).join("\n");
|
|
2800
|
+
p.log.error(`Refused to signal process(es) holding :${port} that are not the iii engine:\n${list}\n\nIf the engine runs in Docker, stop it there:\n docker compose ps && docker compose rm -s -f <service>\n\nOr re-run with --force to signal them anyway.`);
|
|
2801
|
+
process.exit(1);
|
|
2802
|
+
}
|
|
2615
2803
|
if (!allStopped) {
|
|
2616
2804
|
p.log.error("One or more processes survived SIGKILL. Investigate with `ps`.");
|
|
2617
2805
|
process.exit(1);
|
|
@@ -2619,14 +2807,18 @@ async function runStop() {
|
|
|
2619
2807
|
p.outro("Stopped. Memories persisted to disk; restart anytime with: npx @agentmemory/agentmemory");
|
|
2620
2808
|
}
|
|
2621
2809
|
async function runMcp() {
|
|
2622
|
-
await import("./standalone-
|
|
2810
|
+
await import("./standalone-BqNJDJ04.mjs");
|
|
2623
2811
|
}
|
|
2624
2812
|
async function runConnectCmd() {
|
|
2625
|
-
const { runConnect } = await import("./connect-
|
|
2813
|
+
const { runConnect } = await import("./connect-Qaeq15TQ.mjs").then((n) => n.n);
|
|
2626
2814
|
await runConnect(args.slice(1));
|
|
2627
2815
|
}
|
|
2628
2816
|
async function runImportJsonl() {
|
|
2629
|
-
const VALUE_FLAGS = new Set([
|
|
2817
|
+
const VALUE_FLAGS = new Set([
|
|
2818
|
+
"--port",
|
|
2819
|
+
"--tools",
|
|
2820
|
+
"--data-dir"
|
|
2821
|
+
]);
|
|
2630
2822
|
let maxFiles;
|
|
2631
2823
|
const tail = args.slice(1);
|
|
2632
2824
|
const positional = [];
|
|
@@ -2838,7 +3030,7 @@ async function runRemove() {
|
|
|
2838
3030
|
}
|
|
2839
3031
|
p.outro("Done. agentmemory cleanly removed. The npm package itself: npm uninstall -g @agentmemory/agentmemory");
|
|
2840
3032
|
}
|
|
2841
|
-
|
|
3033
|
+
const commands = {
|
|
2842
3034
|
init: runInit,
|
|
2843
3035
|
connect: runConnectCmd,
|
|
2844
3036
|
status: runStatus,
|
|
@@ -2849,7 +3041,13 @@ async function runRemove() {
|
|
|
2849
3041
|
remove: runRemove,
|
|
2850
3042
|
mcp: runMcp,
|
|
2851
3043
|
"import-jsonl": runImportJsonl
|
|
2852
|
-
}
|
|
3044
|
+
};
|
|
3045
|
+
const first = args[0] ?? "";
|
|
3046
|
+
async function unknownCommand() {
|
|
3047
|
+
p.log.error(`Unknown command: ${first}. Supported: ${Object.keys(commands).join(", ")}. Run \`agentmemory\` with no arguments to start the memory server, or \`agentmemory --help\` for usage.`);
|
|
3048
|
+
process.exit(1);
|
|
3049
|
+
}
|
|
3050
|
+
(commands[first] ?? (first && !first.startsWith("-") ? unknownCommand : main))().catch((err) => {
|
|
2853
3051
|
p.log.error(err instanceof Error ? err.message : String(err));
|
|
2854
3052
|
process.exit(1);
|
|
2855
3053
|
});
|