@aman_asmuei/aman-agent 0.16.2 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -797,18 +797,18 @@ var McpManager = class {
797
797
 
798
798
  // src/agent.ts
799
799
  import * as readline from "readline";
800
- import fs12 from "fs";
801
- import path12 from "path";
802
- import os11 from "os";
800
+ import fs13 from "fs";
801
+ import path13 from "path";
802
+ import os12 from "os";
803
803
  import pc6 from "picocolors";
804
804
  import { marked } from "marked";
805
805
  import { markedTerminal } from "marked-terminal";
806
806
  import logUpdate from "log-update";
807
807
 
808
808
  // src/commands.ts
809
- import fs8 from "fs";
810
- import path8 from "path";
811
- import os8 from "os";
809
+ import fs9 from "fs";
810
+ import path9 from "path";
811
+ import os9 from "os";
812
812
  import { execFileSync } from "child_process";
813
813
  import pc3 from "picocolors";
814
814
 
@@ -869,10 +869,85 @@ function getEcosystemStatus(mcpToolCount, amemConnected) {
869
869
  };
870
870
  }
871
871
 
872
- // src/profile-templates.ts
873
- import fs5 from "fs";
872
+ // src/memory.ts
873
+ import {
874
+ createDatabase,
875
+ recall,
876
+ buildContext,
877
+ storeMemory,
878
+ consolidateMemories,
879
+ cosineSimilarity,
880
+ preloadEmbeddings,
881
+ buildVectorIndex
882
+ } from "@aman_asmuei/amem-core";
874
883
  import path5 from "path";
875
884
  import os5 from "os";
885
+ import fs5 from "fs";
886
+ var db = null;
887
+ var currentProject = "global";
888
+ async function initMemory(project) {
889
+ if (db) return db;
890
+ const amemDir = process.env.AMEM_DIR ?? path5.join(os5.homedir(), ".amem");
891
+ if (!fs5.existsSync(amemDir)) fs5.mkdirSync(amemDir, { recursive: true });
892
+ const dbPath = process.env.AMEM_DB ?? path5.join(amemDir, "memory.db");
893
+ db = createDatabase(dbPath);
894
+ currentProject = project ?? "global";
895
+ preloadEmbeddings();
896
+ setTimeout(() => {
897
+ try {
898
+ buildVectorIndex(db);
899
+ } catch {
900
+ }
901
+ }, 1e3);
902
+ return db;
903
+ }
904
+ function getDb() {
905
+ if (!db) throw new Error("Memory not initialized \u2014 call initMemory() first");
906
+ return db;
907
+ }
908
+ async function memoryRecall(query, opts) {
909
+ return recall(getDb(), {
910
+ query,
911
+ limit: opts?.limit ?? 10,
912
+ compact: opts?.compact ?? true,
913
+ type: opts?.type,
914
+ tag: opts?.tag,
915
+ minConfidence: opts?.minConfidence,
916
+ explain: opts?.explain,
917
+ scope: currentProject
918
+ });
919
+ }
920
+ async function memoryContext(topic, maxTokens) {
921
+ return buildContext(getDb(), topic, { maxTokens, scope: currentProject });
922
+ }
923
+ async function memoryStore(opts) {
924
+ return storeMemory(getDb(), opts);
925
+ }
926
+ function memoryLog(sessionId, role, content) {
927
+ return getDb().appendLog({
928
+ sessionId,
929
+ role,
930
+ content,
931
+ project: currentProject,
932
+ metadata: {}
933
+ });
934
+ }
935
+ function reminderCheck() {
936
+ return getDb().checkReminders();
937
+ }
938
+ function memoryConsolidate(dryRun = false) {
939
+ return consolidateMemories(getDb(), cosineSimilarity, {
940
+ dryRun,
941
+ maxStaleDays: 90,
942
+ minConfidence: 0.3,
943
+ minAccessCount: 0
944
+ });
945
+ }
946
+
947
+ // src/profile-templates.ts
948
+ import fs6 from "fs";
949
+ import path6 from "path";
950
+ import os6 from "os";
876
951
  var BUILT_IN_PROFILES = [
877
952
  {
878
953
  name: "coder",
@@ -965,9 +1040,9 @@ var BUILT_IN_PROFILES = [
965
1040
  function installProfileTemplate(templateName, userName) {
966
1041
  const template = BUILT_IN_PROFILES.find((t) => t.name === templateName);
967
1042
  if (!template) return null;
968
- const profileDir = path5.join(os5.homedir(), ".acore", "profiles", template.name);
969
- if (fs5.existsSync(profileDir)) return `Profile already exists: ${template.name}`;
970
- fs5.mkdirSync(profileDir, { recursive: true });
1043
+ const profileDir = path6.join(os6.homedir(), ".acore", "profiles", template.name);
1044
+ if (fs6.existsSync(profileDir)) return `Profile already exists: ${template.name}`;
1045
+ fs6.mkdirSync(profileDir, { recursive: true });
971
1046
  let core = template.core;
972
1047
  if (userName) {
973
1048
  core += `
@@ -981,12 +1056,12 @@ function installProfileTemplate(templateName, userName) {
981
1056
  - Detail level: balanced
982
1057
  `;
983
1058
  }
984
- fs5.writeFileSync(path5.join(profileDir, "core.md"), core, "utf-8");
1059
+ fs6.writeFileSync(path6.join(profileDir, "core.md"), core, "utf-8");
985
1060
  if (template.rules) {
986
- fs5.writeFileSync(path5.join(profileDir, "rules.md"), template.rules, "utf-8");
1061
+ fs6.writeFileSync(path6.join(profileDir, "rules.md"), template.rules, "utf-8");
987
1062
  }
988
1063
  if (template.skills) {
989
- fs5.writeFileSync(path5.join(profileDir, "skills.md"), template.skills, "utf-8");
1064
+ fs6.writeFileSync(path6.join(profileDir, "skills.md"), template.skills, "utf-8");
990
1065
  }
991
1066
  return null;
992
1067
  }
@@ -1113,43 +1188,43 @@ async function delegatePipeline(steps, initialInput, client, mcpManager, options
1113
1188
  }
1114
1189
 
1115
1190
  // src/teams.ts
1116
- import fs6 from "fs";
1117
- import path6 from "path";
1118
- import os6 from "os";
1191
+ import fs7 from "fs";
1192
+ import path7 from "path";
1193
+ import os7 from "os";
1119
1194
  import pc2 from "picocolors";
1120
1195
  function getTeamsDir() {
1121
- return path6.join(os6.homedir(), ".acore", "teams");
1196
+ return path7.join(os7.homedir(), ".acore", "teams");
1122
1197
  }
1123
1198
  function ensureTeamsDir() {
1124
1199
  const dir = getTeamsDir();
1125
- if (!fs6.existsSync(dir)) fs6.mkdirSync(dir, { recursive: true });
1200
+ if (!fs7.existsSync(dir)) fs7.mkdirSync(dir, { recursive: true });
1126
1201
  return dir;
1127
1202
  }
1128
1203
  function teamPath(name) {
1129
1204
  const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
1130
- return path6.join(ensureTeamsDir(), `${slug}.json`);
1205
+ return path7.join(ensureTeamsDir(), `${slug}.json`);
1131
1206
  }
1132
1207
  function createTeam(team) {
1133
1208
  const fp = teamPath(team.name);
1134
- fs6.writeFileSync(fp, JSON.stringify(team, null, 2), "utf-8");
1209
+ fs7.writeFileSync(fp, JSON.stringify(team, null, 2), "utf-8");
1135
1210
  }
1136
1211
  function loadTeam(name) {
1137
1212
  const fp = teamPath(name);
1138
- if (!fs6.existsSync(fp)) return null;
1213
+ if (!fs7.existsSync(fp)) return null;
1139
1214
  try {
1140
- return JSON.parse(fs6.readFileSync(fp, "utf-8"));
1215
+ return JSON.parse(fs7.readFileSync(fp, "utf-8"));
1141
1216
  } catch {
1142
1217
  return null;
1143
1218
  }
1144
1219
  }
1145
1220
  function listTeams() {
1146
1221
  const dir = getTeamsDir();
1147
- if (!fs6.existsSync(dir)) return [];
1222
+ if (!fs7.existsSync(dir)) return [];
1148
1223
  const teams = [];
1149
- for (const file of fs6.readdirSync(dir)) {
1224
+ for (const file of fs7.readdirSync(dir)) {
1150
1225
  if (!file.endsWith(".json")) continue;
1151
1226
  try {
1152
- const content = fs6.readFileSync(path6.join(dir, file), "utf-8");
1227
+ const content = fs7.readFileSync(path7.join(dir, file), "utf-8");
1153
1228
  teams.push(JSON.parse(content));
1154
1229
  } catch {
1155
1230
  }
@@ -1158,8 +1233,8 @@ function listTeams() {
1158
1233
  }
1159
1234
  function deleteTeam(name) {
1160
1235
  const fp = teamPath(name);
1161
- if (!fs6.existsSync(fp)) return false;
1162
- fs6.unlinkSync(fp);
1236
+ if (!fs7.existsSync(fp)) return false;
1237
+ fs7.unlinkSync(fp);
1163
1238
  return true;
1164
1239
  }
1165
1240
  async function runTeam(team, task, client, mcpManager, tools) {
@@ -1385,23 +1460,23 @@ var BUILT_IN_TEAMS = [
1385
1460
  ];
1386
1461
 
1387
1462
  // src/plans.ts
1388
- import fs7 from "fs";
1389
- import path7 from "path";
1390
- import os7 from "os";
1463
+ import fs8 from "fs";
1464
+ import path8 from "path";
1465
+ import os8 from "os";
1391
1466
  function getPlansDir() {
1392
- const localDir = path7.join(process.cwd(), ".acore", "plans");
1393
- const localAcore = path7.join(process.cwd(), ".acore");
1394
- if (fs7.existsSync(localAcore)) return localDir;
1395
- return path7.join(os7.homedir(), ".acore", "plans");
1467
+ const localDir = path8.join(process.cwd(), ".acore", "plans");
1468
+ const localAcore = path8.join(process.cwd(), ".acore");
1469
+ if (fs8.existsSync(localAcore)) return localDir;
1470
+ return path8.join(os8.homedir(), ".acore", "plans");
1396
1471
  }
1397
1472
  function ensurePlansDir() {
1398
1473
  const dir = getPlansDir();
1399
- if (!fs7.existsSync(dir)) fs7.mkdirSync(dir, { recursive: true });
1474
+ if (!fs8.existsSync(dir)) fs8.mkdirSync(dir, { recursive: true });
1400
1475
  return dir;
1401
1476
  }
1402
1477
  function planPath(name) {
1403
1478
  const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
1404
- return path7.join(ensurePlansDir(), `${slug}.md`);
1479
+ return path8.join(ensurePlansDir(), `${slug}.md`);
1405
1480
  }
1406
1481
  function serializePlan(plan) {
1407
1482
  const lines = [];
@@ -1427,7 +1502,7 @@ function parsePlan(content, filePath) {
1427
1502
  const createdMatch = content.match(/\*\*Created:\*\*\s*(.+)/);
1428
1503
  const updatedMatch = content.match(/\*\*Updated:\*\*\s*(.+)/);
1429
1504
  const activeMatch = content.match(/\*\*Active:\*\*\s*(.+)/);
1430
- const name = nameMatch?.[1]?.trim() || path7.basename(filePath, ".md");
1505
+ const name = nameMatch?.[1]?.trim() || path8.basename(filePath, ".md");
1431
1506
  const goal = goalMatch?.[1]?.trim() || "";
1432
1507
  const createdAt = createdMatch?.[1]?.trim() || "";
1433
1508
  const updatedAt = updatedMatch?.[1]?.trim() || "";
@@ -1469,22 +1544,22 @@ function createPlan(name, goal, steps) {
1469
1544
  }
1470
1545
  function savePlan(plan) {
1471
1546
  const fp = planPath(plan.name);
1472
- fs7.writeFileSync(fp, serializePlan(plan), "utf-8");
1547
+ fs8.writeFileSync(fp, serializePlan(plan), "utf-8");
1473
1548
  }
1474
1549
  function loadPlan(name) {
1475
1550
  const fp = planPath(name);
1476
- if (!fs7.existsSync(fp)) return null;
1477
- const content = fs7.readFileSync(fp, "utf-8");
1551
+ if (!fs8.existsSync(fp)) return null;
1552
+ const content = fs8.readFileSync(fp, "utf-8");
1478
1553
  return parsePlan(content, fp);
1479
1554
  }
1480
1555
  function listPlans() {
1481
1556
  const dir = getPlansDir();
1482
- if (!fs7.existsSync(dir)) return [];
1557
+ if (!fs8.existsSync(dir)) return [];
1483
1558
  const plans = [];
1484
- for (const file of fs7.readdirSync(dir)) {
1559
+ for (const file of fs8.readdirSync(dir)) {
1485
1560
  if (!file.endsWith(".md")) continue;
1486
- const fp = path7.join(dir, file);
1487
- const content = fs7.readFileSync(fp, "utf-8");
1561
+ const fp = path8.join(dir, file);
1562
+ const content = fs8.readFileSync(fp, "utf-8");
1488
1563
  const plan = parsePlan(content, fp);
1489
1564
  if (plan) plans.push(plan);
1490
1565
  }
@@ -1580,10 +1655,10 @@ function progressBar(pct) {
1580
1655
 
1581
1656
  // src/commands.ts
1582
1657
  function readEcosystemFile(filePath, label) {
1583
- if (!fs8.existsSync(filePath)) {
1658
+ if (!fs9.existsSync(filePath)) {
1584
1659
  return pc3.dim(`No ${label} file found at ${filePath}`);
1585
1660
  }
1586
- return fs8.readFileSync(filePath, "utf-8").trim();
1661
+ return fs9.readFileSync(filePath, "utf-8").trim();
1587
1662
  }
1588
1663
  function parseCommand(input) {
1589
1664
  const trimmed = input.trim();
@@ -1604,9 +1679,9 @@ async function mcpWrite(ctx, layer, tool, args) {
1604
1679
  return pc3.green(result);
1605
1680
  }
1606
1681
  async function handleIdentityCommand(action, args, ctx) {
1607
- const home2 = os8.homedir();
1682
+ const home2 = os9.homedir();
1608
1683
  if (!action) {
1609
- const content = readEcosystemFile(path8.join(home2, ".acore", "core.md"), "identity (acore)");
1684
+ const content = readEcosystemFile(path9.join(home2, ".acore", "core.md"), "identity (acore)");
1610
1685
  return { handled: true, output: content };
1611
1686
  }
1612
1687
  if (action === "update") {
@@ -1630,9 +1705,9 @@ async function handleIdentityCommand(action, args, ctx) {
1630
1705
  return { handled: true, output: pc3.yellow(`Unknown action: /identity ${action}. Use /identity or /identity update <section>.`) };
1631
1706
  }
1632
1707
  async function handleRulesCommand(action, args, ctx) {
1633
- const home2 = os8.homedir();
1708
+ const home2 = os9.homedir();
1634
1709
  if (!action) {
1635
- const content = readEcosystemFile(path8.join(home2, ".arules", "rules.md"), "guardrails (arules)");
1710
+ const content = readEcosystemFile(path9.join(home2, ".arules", "rules.md"), "guardrails (arules)");
1636
1711
  return { handled: true, output: content };
1637
1712
  }
1638
1713
  if (action === "add") {
@@ -1661,9 +1736,9 @@ async function handleRulesCommand(action, args, ctx) {
1661
1736
  return { handled: true, output: pc3.yellow(`Unknown action: /rules ${action}. Use /rules [add|remove|toggle].`) };
1662
1737
  }
1663
1738
  async function handleWorkflowsCommand(action, args, ctx) {
1664
- const home2 = os8.homedir();
1739
+ const home2 = os9.homedir();
1665
1740
  if (!action) {
1666
- const content = readEcosystemFile(path8.join(home2, ".aflow", "flow.md"), "workflows (aflow)");
1741
+ const content = readEcosystemFile(path9.join(home2, ".aflow", "flow.md"), "workflows (aflow)");
1667
1742
  return { handled: true, output: content };
1668
1743
  }
1669
1744
  if (action === "add") {
@@ -1702,38 +1777,38 @@ var AKIT_REGISTRY = [
1702
1777
  { name: "docling", description: "Convert PDF, DOCX, PPTX, XLSX to markdown", category: "documents", mcp: { package: "docling-mcp", command: "uvx", args: ["docling-mcp"] }, envHint: "Requires Python 3.10+. Install: pip install docling" }
1703
1778
  ];
1704
1779
  function loadAkitInstalled() {
1705
- const filePath = path8.join(os8.homedir(), ".akit", "installed.json");
1706
- if (!fs8.existsSync(filePath)) return [];
1780
+ const filePath = path9.join(os9.homedir(), ".akit", "installed.json");
1781
+ if (!fs9.existsSync(filePath)) return [];
1707
1782
  try {
1708
- return JSON.parse(fs8.readFileSync(filePath, "utf-8"));
1783
+ return JSON.parse(fs9.readFileSync(filePath, "utf-8"));
1709
1784
  } catch {
1710
1785
  return [];
1711
1786
  }
1712
1787
  }
1713
1788
  function saveAkitInstalled(tools) {
1714
- const dir = path8.join(os8.homedir(), ".akit");
1715
- fs8.mkdirSync(dir, { recursive: true });
1716
- fs8.writeFileSync(path8.join(dir, "installed.json"), JSON.stringify(tools, null, 2) + "\n", "utf-8");
1789
+ const dir = path9.join(os9.homedir(), ".akit");
1790
+ fs9.mkdirSync(dir, { recursive: true });
1791
+ fs9.writeFileSync(path9.join(dir, "installed.json"), JSON.stringify(tools, null, 2) + "\n", "utf-8");
1717
1792
  }
1718
1793
  function addToAmanAgentConfig(name, mcpConfig) {
1719
- const configPath = path8.join(os8.homedir(), ".aman-agent", "config.json");
1720
- if (!fs8.existsSync(configPath)) return;
1794
+ const configPath = path9.join(os9.homedir(), ".aman-agent", "config.json");
1795
+ if (!fs9.existsSync(configPath)) return;
1721
1796
  try {
1722
- const config = JSON.parse(fs8.readFileSync(configPath, "utf-8"));
1797
+ const config = JSON.parse(fs9.readFileSync(configPath, "utf-8"));
1723
1798
  if (!config.mcpServers) config.mcpServers = {};
1724
1799
  config.mcpServers[name] = mcpConfig;
1725
- fs8.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
1800
+ fs9.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
1726
1801
  } catch {
1727
1802
  }
1728
1803
  }
1729
1804
  function removeFromAmanAgentConfig(name) {
1730
- const configPath = path8.join(os8.homedir(), ".aman-agent", "config.json");
1731
- if (!fs8.existsSync(configPath)) return;
1805
+ const configPath = path9.join(os9.homedir(), ".aman-agent", "config.json");
1806
+ if (!fs9.existsSync(configPath)) return;
1732
1807
  try {
1733
- const config = JSON.parse(fs8.readFileSync(configPath, "utf-8"));
1808
+ const config = JSON.parse(fs9.readFileSync(configPath, "utf-8"));
1734
1809
  if (config.mcpServers) {
1735
1810
  delete config.mcpServers[name];
1736
- fs8.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
1811
+ fs9.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
1737
1812
  }
1738
1813
  } catch {
1739
1814
  }
@@ -1883,9 +1958,9 @@ function handleAkitCommand(action, args) {
1883
1958
  return { handled: true, output: lines.join("\n") };
1884
1959
  }
1885
1960
  async function handleSkillsCommand(action, args, ctx) {
1886
- const home2 = os8.homedir();
1961
+ const home2 = os9.homedir();
1887
1962
  if (!action) {
1888
- const content = readEcosystemFile(path8.join(home2, ".askill", "skills.md"), "skills (askill)");
1963
+ const content = readEcosystemFile(path9.join(home2, ".askill", "skills.md"), "skills (askill)");
1889
1964
  return { handled: true, output: content };
1890
1965
  }
1891
1966
  if (action === "install") {
@@ -1905,9 +1980,9 @@ async function handleSkillsCommand(action, args, ctx) {
1905
1980
  return { handled: true, output: pc3.yellow(`Unknown action: /skills ${action}. Use /skills [install|uninstall].`) };
1906
1981
  }
1907
1982
  async function handleEvalCommand(action, args, ctx) {
1908
- const home2 = os8.homedir();
1983
+ const home2 = os9.homedir();
1909
1984
  if (!action) {
1910
- const content = readEcosystemFile(path8.join(home2, ".aeval", "eval.md"), "evaluation (aeval)");
1985
+ const content = readEcosystemFile(path9.join(home2, ".aeval", "eval.md"), "evaluation (aeval)");
1911
1986
  return { handled: true, output: content };
1912
1987
  }
1913
1988
  if (action === "milestone") {
@@ -1922,36 +1997,39 @@ async function handleEvalCommand(action, args, ctx) {
1922
1997
  }
1923
1998
  async function handleMemoryCommand(action, args, ctx) {
1924
1999
  if (!action) {
1925
- if (!ctx.mcpManager) {
1926
- return {
1927
- handled: true,
1928
- output: pc3.red("Memory not available: aman-mcp not connected. Start it with: npx @aman_asmuei/aman-mcp")
1929
- };
1930
- }
1931
- const result = await ctx.mcpManager.callTool("memory_context", { topic: "recent context" });
1932
- if (result.startsWith("Error")) {
1933
- return { handled: true, output: pc3.red(result) };
2000
+ try {
2001
+ const result = await memoryContext("recent context");
2002
+ if (result.memoriesUsed === 0) {
2003
+ return { handled: true, output: pc3.dim("No memories yet. Start chatting and I'll remember what matters.") };
2004
+ }
2005
+ return { handled: true, output: result.text };
2006
+ } catch (err) {
2007
+ return { handled: true, output: pc3.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
1934
2008
  }
1935
- return { handled: true, output: result };
1936
2009
  }
1937
2010
  if (action && !["search", "clear", "timeline"].includes(action)) {
1938
- if (!ctx.mcpManager) {
1939
- return { handled: true, output: pc3.red("Memory not available: MCP not connected.") };
1940
- }
1941
- const topic = [action, ...args].join(" ");
1942
- const result = await ctx.mcpManager.callTool("memory_context", { topic });
1943
- if (result.startsWith("Error")) {
1944
- return { handled: true, output: pc3.red(result) };
2011
+ try {
2012
+ const topic = [action, ...args].join(" ");
2013
+ const result = await memoryContext(topic);
2014
+ if (result.memoriesUsed === 0) {
2015
+ return { handled: true, output: pc3.dim(`No memories found for: "${topic}".`) };
2016
+ }
2017
+ return { handled: true, output: result.text };
2018
+ } catch (err) {
2019
+ return { handled: true, output: pc3.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
1945
2020
  }
1946
- return { handled: true, output: result };
1947
2021
  }
1948
2022
  if (action === "search") {
1949
2023
  if (args.length < 1) {
1950
2024
  return { handled: true, output: pc3.yellow("Usage: /memory search <query...>") };
1951
2025
  }
1952
2026
  const query = args.join(" ");
1953
- const output = await mcpWrite(ctx, "memory", "memory_recall", { query });
1954
- return { handled: true, output };
2027
+ try {
2028
+ const result = await memoryRecall(query);
2029
+ return { handled: true, output: result.total === 0 ? pc3.dim("No memories found.") : result.text };
2030
+ } catch (err) {
2031
+ return { handled: true, output: pc3.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
2032
+ }
1955
2033
  }
1956
2034
  if (action === "clear") {
1957
2035
  if (args.length < 1) {
@@ -1961,50 +2039,45 @@ async function handleMemoryCommand(action, args, ctx) {
1961
2039
  return { handled: true, output };
1962
2040
  }
1963
2041
  if (action === "timeline") {
1964
- if (!ctx.mcpManager) {
1965
- return { handled: true, output: pc3.red("Memory not available: MCP not connected.") };
1966
- }
1967
2042
  try {
1968
- const result = await ctx.mcpManager.callTool("memory_recall", { query: "*", limit: 500 });
1969
- if (result.startsWith("Error") || result.includes("No memories found")) {
2043
+ const result = await memoryRecall("*", { limit: 500, compact: false });
2044
+ if (result.total === 0) {
1970
2045
  return { handled: true, output: pc3.dim("No memories yet. Start chatting and I'll remember what matters.") };
1971
2046
  }
1972
- try {
1973
- const memories = JSON.parse(result);
1974
- if (Array.isArray(memories) && memories.length > 0) {
1975
- const byDate = /* @__PURE__ */ new Map();
1976
- for (const mem of memories) {
1977
- const date = mem.created_at ? new Date(mem.created_at).toLocaleDateString("en-US", { month: "short", day: "numeric" }) : "Unknown";
1978
- byDate.set(date, (byDate.get(date) || 0) + 1);
1979
- }
1980
- const maxCount = Math.max(...byDate.values());
1981
- const barWidth = 10;
1982
- const lines = [pc3.bold("Memory Timeline:"), ""];
1983
- for (const [date, count] of byDate) {
1984
- const filled = Math.round(count / maxCount * barWidth);
1985
- const bar = "\u2588".repeat(filled) + "\u2591".repeat(barWidth - filled);
1986
- lines.push(` ${date.padEnd(8)} ${bar} ${count} memories`);
1987
- }
1988
- const tags = /* @__PURE__ */ new Map();
1989
- for (const mem of memories) {
1990
- if (Array.isArray(mem.tags)) {
1991
- for (const tag of mem.tags) {
1992
- tags.set(tag, (tags.get(tag) || 0) + 1);
1993
- }
2047
+ const memories = result.memories;
2048
+ if (memories.length > 0) {
2049
+ const byDate = /* @__PURE__ */ new Map();
2050
+ for (const mem of memories) {
2051
+ const createdAt = mem.created_at;
2052
+ const date = createdAt ? new Date(createdAt).toLocaleDateString("en-US", { month: "short", day: "numeric" }) : "Unknown";
2053
+ byDate.set(date, (byDate.get(date) || 0) + 1);
2054
+ }
2055
+ const maxCount = Math.max(...byDate.values());
2056
+ const barWidth = 10;
2057
+ const lines = [pc3.bold("Memory Timeline:"), ""];
2058
+ for (const [date, count] of byDate) {
2059
+ const filled = Math.round(count / maxCount * barWidth);
2060
+ const bar = "\u2588".repeat(filled) + "\u2591".repeat(barWidth - filled);
2061
+ lines.push(` ${date.padEnd(8)} ${bar} ${count} memories`);
2062
+ }
2063
+ const tags = /* @__PURE__ */ new Map();
2064
+ for (const mem of memories) {
2065
+ const memTags = mem.tags;
2066
+ if (Array.isArray(memTags)) {
2067
+ for (const tag of memTags) {
2068
+ tags.set(tag, (tags.get(tag) || 0) + 1);
1994
2069
  }
1995
2070
  }
1996
- lines.push("");
1997
- lines.push(` Total: ${memories.length} memories`);
1998
- if (tags.size > 0) {
1999
- const topTags = [...tags.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5).map(([tag, count]) => `#${tag} (${count})`).join(", ");
2000
- lines.push(` Top tags: ${topTags}`);
2001
- }
2002
- return { handled: true, output: lines.join("\n") };
2003
2071
  }
2004
- } catch {
2072
+ lines.push("");
2073
+ lines.push(` Total: ${result.total} memories`);
2074
+ if (tags.size > 0) {
2075
+ const topTags = [...tags.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5).map(([tag, count]) => `#${tag} (${count})`).join(", ");
2076
+ lines.push(` Top tags: ${topTags}`);
2077
+ }
2078
+ return { handled: true, output: lines.join("\n") };
2005
2079
  }
2006
- const lineCount = result.split("\n").filter((l) => l.trim()).length;
2007
- return { handled: true, output: `Total memories: ~${lineCount} entries.` };
2080
+ return { handled: true, output: `Total memories: ${result.total} entries.` };
2008
2081
  } catch {
2009
2082
  return { handled: true, output: pc3.red("Failed to retrieve memory timeline.") };
2010
2083
  }
@@ -2104,13 +2177,13 @@ function handleSave() {
2104
2177
  return { handled: true, saveConversation: true };
2105
2178
  }
2106
2179
  function handleReconfig() {
2107
- const configDir = path8.join(os8.homedir(), ".aman-agent");
2108
- const configPath = path8.join(configDir, "config.json");
2109
- if (fs8.existsSync(configPath)) {
2110
- fs8.unlinkSync(configPath);
2180
+ const configDir = path9.join(os9.homedir(), ".aman-agent");
2181
+ const configPath = path9.join(configDir, "config.json");
2182
+ if (fs9.existsSync(configPath)) {
2183
+ fs9.unlinkSync(configPath);
2111
2184
  }
2112
- fs8.mkdirSync(configDir, { recursive: true });
2113
- fs8.writeFileSync(path8.join(configDir, ".reconfig"), "", "utf-8");
2185
+ fs9.mkdirSync(configDir, { recursive: true });
2186
+ fs9.writeFileSync(path9.join(configDir, ".reconfig"), "", "utf-8");
2114
2187
  return {
2115
2188
  handled: true,
2116
2189
  quit: true,
@@ -2123,7 +2196,7 @@ function handleReconfig() {
2123
2196
  function handleUpdate() {
2124
2197
  try {
2125
2198
  const current = execFileSync("npm", ["view", "@aman_asmuei/aman-agent", "version"], { encoding: "utf-8" }).trim();
2126
- const local = JSON.parse(fs8.readFileSync(path8.join(__dirname, "..", "package.json"), "utf-8")).version;
2199
+ const local = JSON.parse(fs9.readFileSync(path9.join(__dirname, "..", "package.json"), "utf-8")).version;
2127
2200
  if (current === local) {
2128
2201
  return { handled: true, output: `${pc3.green("Up to date")} \u2014 v${local}` };
2129
2202
  }
@@ -2152,31 +2225,26 @@ function handleUpdate() {
2152
2225
  };
2153
2226
  }
2154
2227
  }
2155
- async function handleDecisionsCommand(action, _args, ctx) {
2156
- if (!ctx.mcpManager) {
2157
- return { handled: true, output: pc3.red("Decisions not available: MCP not connected.") };
2158
- }
2159
- const scope = action || void 0;
2160
- const result = await ctx.mcpManager.callTool("memory_recall", {
2161
- query: "decision",
2162
- type: "decision",
2163
- limit: 20,
2164
- ...scope ? { scope } : {}
2165
- });
2166
- if (result.startsWith("Error")) {
2167
- return { handled: true, output: pc3.red(result) };
2228
+ async function handleDecisionsCommand(action, _args, _ctx) {
2229
+ try {
2230
+ const result = await memoryRecall("decision", { type: "decision", limit: 20 });
2231
+ if (result.total === 0) {
2232
+ return { handled: true, output: pc3.dim("No decisions recorded yet.") };
2233
+ }
2234
+ return { handled: true, output: pc3.bold("Decision Log:\n") + result.text };
2235
+ } catch (err) {
2236
+ return { handled: true, output: pc3.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
2168
2237
  }
2169
- return { handled: true, output: pc3.bold("Decision Log:\n") + result };
2170
2238
  }
2171
2239
  function handleExportCommand() {
2172
2240
  return { handled: true, exportConversation: true };
2173
2241
  }
2174
2242
  function handleDebugCommand() {
2175
- const logPath = path8.join(os8.homedir(), ".aman-agent", "debug.log");
2176
- if (!fs8.existsSync(logPath)) {
2243
+ const logPath = path9.join(os9.homedir(), ".aman-agent", "debug.log");
2244
+ if (!fs9.existsSync(logPath)) {
2177
2245
  return { handled: true, output: pc3.dim("No debug log found.") };
2178
2246
  }
2179
- const content = fs8.readFileSync(logPath, "utf-8");
2247
+ const content = fs9.readFileSync(logPath, "utf-8");
2180
2248
  const lines = content.trim().split("\n");
2181
2249
  const last20 = lines.slice(-20).join("\n");
2182
2250
  return { handled: true, output: pc3.bold("Debug Log (last 20 entries):\n") + pc3.dim(last20) };
@@ -2374,7 +2442,7 @@ ${result.response}`
2374
2442
  };
2375
2443
  }
2376
2444
  function handleProfileCommand(action, args) {
2377
- const profilesDir = path8.join(os8.homedir(), ".acore", "profiles");
2445
+ const profilesDir = path9.join(os9.homedir(), ".acore", "profiles");
2378
2446
  if (!action || action === "list") {
2379
2447
  const profiles = listProfiles();
2380
2448
  if (profiles.length === 0) {
@@ -2398,8 +2466,8 @@ function handleProfileCommand(action, args) {
2398
2466
  };
2399
2467
  }
2400
2468
  const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
2401
- const profileDir = path8.join(profilesDir, slug);
2402
- if (fs8.existsSync(profileDir)) {
2469
+ const profileDir = path9.join(profilesDir, slug);
2470
+ if (fs9.existsSync(profileDir)) {
2403
2471
  return { handled: true, output: pc3.yellow(`Profile already exists: ${slug}`) };
2404
2472
  }
2405
2473
  const builtIn = BUILT_IN_PROFILES.find((t) => t.name === slug);
@@ -2415,16 +2483,16 @@ function handleProfileCommand(action, args) {
2415
2483
  Use: aman-agent --profile ${slug}`
2416
2484
  };
2417
2485
  }
2418
- fs8.mkdirSync(profileDir, { recursive: true });
2419
- const globalCore = path8.join(os8.homedir(), ".acore", "core.md");
2420
- if (fs8.existsSync(globalCore)) {
2421
- let content = fs8.readFileSync(globalCore, "utf-8");
2486
+ fs9.mkdirSync(profileDir, { recursive: true });
2487
+ const globalCore = path9.join(os9.homedir(), ".acore", "core.md");
2488
+ if (fs9.existsSync(globalCore)) {
2489
+ let content = fs9.readFileSync(globalCore, "utf-8");
2422
2490
  const aiName = name.charAt(0).toUpperCase() + name.slice(1);
2423
2491
  content = content.replace(/^# .+$/m, `# ${aiName}`);
2424
- fs8.writeFileSync(path8.join(profileDir, "core.md"), content, "utf-8");
2492
+ fs9.writeFileSync(path9.join(profileDir, "core.md"), content, "utf-8");
2425
2493
  } else {
2426
2494
  const aiName = name.charAt(0).toUpperCase() + name.slice(1);
2427
- fs8.writeFileSync(path8.join(profileDir, "core.md"), `# ${aiName}
2495
+ fs9.writeFileSync(path9.join(profileDir, "core.md"), `# ${aiName}
2428
2496
 
2429
2497
  ## Identity
2430
2498
  - Role: ${aiName} is your AI companion
@@ -2437,7 +2505,7 @@ function handleProfileCommand(action, args) {
2437
2505
  return {
2438
2506
  handled: true,
2439
2507
  output: pc3.green(`Profile created: ${slug}`) + `
2440
- Edit: ${path8.join(profileDir, "core.md")}
2508
+ Edit: ${path9.join(profileDir, "core.md")}
2441
2509
  Use: aman-agent --profile ${slug}
2442
2510
 
2443
2511
  ${pc3.dim("Add rules.md or skills.md for profile-specific overrides.")}`
@@ -2446,9 +2514,9 @@ function handleProfileCommand(action, args) {
2446
2514
  case "show": {
2447
2515
  const name = args[0];
2448
2516
  if (!name) return { handled: true, output: pc3.yellow("Usage: /profile show <name>") };
2449
- const profileDir = path8.join(profilesDir, name);
2450
- if (!fs8.existsSync(profileDir)) return { handled: true, output: pc3.red(`Profile not found: ${name}`) };
2451
- const files = fs8.readdirSync(profileDir).filter((f) => f.endsWith(".md"));
2517
+ const profileDir = path9.join(profilesDir, name);
2518
+ if (!fs9.existsSync(profileDir)) return { handled: true, output: pc3.red(`Profile not found: ${name}`) };
2519
+ const files = fs9.readdirSync(profileDir).filter((f) => f.endsWith(".md"));
2452
2520
  const lines = files.map((f) => ` ${f}`);
2453
2521
  return { handled: true, output: `Profile: ${pc3.bold(name)}
2454
2522
  Files:
@@ -2457,9 +2525,9 @@ ${lines.join("\n")}` };
2457
2525
  case "delete": {
2458
2526
  const name = args[0];
2459
2527
  if (!name) return { handled: true, output: pc3.yellow("Usage: /profile delete <name>") };
2460
- const profileDir = path8.join(profilesDir, name);
2461
- if (!fs8.existsSync(profileDir)) return { handled: true, output: pc3.red(`Profile not found: ${name}`) };
2462
- fs8.rmSync(profileDir, { recursive: true });
2528
+ const profileDir = path9.join(profilesDir, name);
2529
+ if (!fs9.existsSync(profileDir)) return { handled: true, output: pc3.red(`Profile not found: ${name}`) };
2530
+ fs9.rmSync(profileDir, { recursive: true });
2463
2531
  return { handled: true, output: pc3.dim(`Profile deleted: ${name}`) };
2464
2532
  }
2465
2533
  case "help":
@@ -2661,8 +2729,8 @@ async function handleCommand(input, ctx) {
2661
2729
  // src/hooks.ts
2662
2730
  import pc4 from "picocolors";
2663
2731
  import * as p from "@clack/prompts";
2664
- import fs9 from "fs";
2665
- import path9 from "path";
2732
+ import fs10 from "fs";
2733
+ import path10 from "path";
2666
2734
 
2667
2735
  // src/personality.ts
2668
2736
  var FRUSTRATION_SIGNALS = [
@@ -2867,10 +2935,8 @@ async function onSessionStart(ctx) {
2867
2935
  const visibleReminders = [];
2868
2936
  try {
2869
2937
  isHookCall = true;
2870
- const recallResult = await ctx.mcpManager.callTool("memory_recall", { query: "*", limit: 1 });
2871
- if (!recallResult || recallResult.startsWith("Error") || recallResult.includes("No memories found")) {
2872
- firstRun = true;
2873
- }
2938
+ const recallResult = await memoryRecall("*", { limit: 1 });
2939
+ firstRun = recallResult.total === 0;
2874
2940
  } catch {
2875
2941
  firstRun = true;
2876
2942
  } finally {
@@ -2900,9 +2966,9 @@ ${contextInjection}`;
2900
2966
  if (ctx.config.memoryRecall) {
2901
2967
  try {
2902
2968
  isHookCall = true;
2903
- const result = await ctx.mcpManager.callTool("memory_context", { topic: "session context" });
2904
- if (result && !result.startsWith("Error")) {
2905
- greeting += result;
2969
+ const contextResult = await memoryContext("session context");
2970
+ if (contextResult.memoriesUsed > 0) {
2971
+ greeting += contextResult.text;
2906
2972
  }
2907
2973
  } catch (err) {
2908
2974
  log.warn("hooks", "memory_context recall failed", err);
@@ -2933,12 +2999,12 @@ ${contextInjection}`;
2933
2999
  else greeting = timeContext;
2934
3000
  try {
2935
3001
  isHookCall = true;
2936
- const reminderResult = await ctx.mcpManager.callTool("reminder_check", {});
2937
- if (reminderResult && !reminderResult.startsWith("Error") && !reminderResult.includes("No pending")) {
2938
- greeting += "\n\n<pending-reminders>\n" + reminderResult + "\n</pending-reminders>";
2939
- const lines = reminderResult.split("\n").filter((l) => l.trim().length > 0);
2940
- for (const line of lines) {
2941
- visibleReminders.push(line.trim());
3002
+ const reminders = reminderCheck();
3003
+ if (reminders.length > 0) {
3004
+ const reminderText = reminders.map((r) => r.content).join("\n");
3005
+ greeting += "\n\n<pending-reminders>\n" + reminderText + "\n</pending-reminders>";
3006
+ for (const r of reminders) {
3007
+ visibleReminders.push(r.content);
2942
3008
  }
2943
3009
  }
2944
3010
  } catch (err) {
@@ -3053,11 +3119,7 @@ async function onSessionEnd(ctx, messages, sessionId) {
3053
3119
  for (const msg of textMessages) {
3054
3120
  try {
3055
3121
  isHookCall = true;
3056
- await ctx.mcpManager.callTool("memory_log", {
3057
- session_id: sessionId,
3058
- role: msg.role,
3059
- content: msg.content.slice(0, 5e3)
3060
- });
3122
+ memoryLog(sessionId, msg.role, msg.content.slice(0, 5e3));
3061
3123
  } catch (err) {
3062
3124
  log.debug("hooks", "memory_log write failed for " + sessionId, err);
3063
3125
  } finally {
@@ -3085,10 +3147,10 @@ async function onSessionEnd(ctx, messages, sessionId) {
3085
3147
  }
3086
3148
  console.log(pc4.dim(` Saved ${textMessages.length} messages (session: ${sessionId})`));
3087
3149
  }
3088
- const projectContextPath = path9.join(process.cwd(), ".acore", "context.md");
3089
- if (fs9.existsSync(projectContextPath) && messages.length > 2) {
3150
+ const projectContextPath = path10.join(process.cwd(), ".acore", "context.md");
3151
+ if (fs10.existsSync(projectContextPath) && messages.length > 2) {
3090
3152
  try {
3091
- let contextContent = fs9.readFileSync(projectContextPath, "utf-8");
3153
+ let contextContent = fs10.readFileSync(projectContextPath, "utf-8");
3092
3154
  const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
3093
3155
  let lastUserMsg = "";
3094
3156
  for (let i = messages.length - 1; i >= 0; i--) {
@@ -3106,7 +3168,7 @@ async function onSessionEnd(ctx, messages, sessionId) {
3106
3168
  - Recent decisions: [see memory]
3107
3169
  - Temp notes: [cleared]`;
3108
3170
  contextContent = contextContent.replace(sessionPattern, newSession);
3109
- fs9.writeFileSync(projectContextPath, contextContent, "utf-8");
3171
+ fs10.writeFileSync(projectContextPath, contextContent, "utf-8");
3110
3172
  log.debug("hooks", `Updated project context: ${projectContextPath}`);
3111
3173
  }
3112
3174
  } catch (err) {
@@ -3236,9 +3298,9 @@ ${summaryParts.slice(0, 20).join("\n")}
3236
3298
  }
3237
3299
 
3238
3300
  // src/skill-engine.ts
3239
- import fs10 from "fs";
3240
- import path10 from "path";
3241
- import os9 from "os";
3301
+ import fs11 from "fs";
3302
+ import path11 from "path";
3303
+ import os10 from "os";
3242
3304
  var SKILL_TRIGGERS = {
3243
3305
  testing: ["test", "spec", "coverage", "tdd", "jest", "vitest", "mocha", "assert", "mock", "stub", "fixture", "e2e", "integration test", "unit test"],
3244
3306
  "api-design": ["api", "endpoint", "rest", "graphql", "route", "controller", "middleware", "http", "request", "response", "status code", "pagination"],
@@ -3253,20 +3315,20 @@ var SKILL_TRIGGERS = {
3253
3315
  typescript: ["typescript", "type", "interface", "generic", "infer", "utility type", "zod", "discriminated union", "type guard", "as const"],
3254
3316
  accessibility: ["accessibility", "a11y", "aria", "screen reader", "wcag", "semantic html", "tab order", "focus", "contrast"]
3255
3317
  };
3256
- var LEVEL_FILE = path10.join(os9.homedir(), ".aman-agent", "skill-levels.json");
3318
+ var LEVEL_FILE = path11.join(os10.homedir(), ".aman-agent", "skill-levels.json");
3257
3319
  function loadSkillLevels() {
3258
3320
  try {
3259
- if (fs10.existsSync(LEVEL_FILE)) {
3260
- return JSON.parse(fs10.readFileSync(LEVEL_FILE, "utf-8"));
3321
+ if (fs11.existsSync(LEVEL_FILE)) {
3322
+ return JSON.parse(fs11.readFileSync(LEVEL_FILE, "utf-8"));
3261
3323
  }
3262
3324
  } catch {
3263
3325
  }
3264
3326
  return {};
3265
3327
  }
3266
3328
  function saveSkillLevels(levels) {
3267
- const dir = path10.dirname(LEVEL_FILE);
3268
- if (!fs10.existsSync(dir)) fs10.mkdirSync(dir, { recursive: true });
3269
- fs10.writeFileSync(LEVEL_FILE, JSON.stringify(levels, null, 2), "utf-8");
3329
+ const dir = path11.dirname(LEVEL_FILE);
3330
+ if (!fs11.existsSync(dir)) fs11.mkdirSync(dir, { recursive: true });
3331
+ fs11.writeFileSync(LEVEL_FILE, JSON.stringify(levels, null, 2), "utf-8");
3270
3332
  }
3271
3333
  function computeLevel(activations) {
3272
3334
  if (activations >= 50) return { level: 5, label: "Expert" };
@@ -3644,7 +3706,7 @@ function parseExtractionResult(raw) {
3644
3706
  return [];
3645
3707
  }
3646
3708
  }
3647
- async function extractMemories(userMessage, assistantResponse, client, mcpManager, state) {
3709
+ async function extractMemories(userMessage, assistantResponse, client, state) {
3648
3710
  if (!shouldExtract(assistantResponse, state.turnsSinceLastExtraction, state.lastExtractionCount)) {
3649
3711
  state.turnsSinceLastExtraction++;
3650
3712
  return 0;
@@ -3668,24 +3730,18 @@ Assistant: ${assistantResponse.slice(0, 2e3)}`;
3668
3730
  let stored = 0;
3669
3731
  for (const candidate of candidates) {
3670
3732
  try {
3671
- const existing = await mcpManager.callTool("memory_recall", {
3672
- query: candidate.content,
3673
- limit: 1
3674
- });
3675
- if (existing && !existing.startsWith("Error")) {
3676
- try {
3677
- const parsed = JSON.parse(existing);
3678
- if (Array.isArray(parsed) && parsed.length > 0 && parsed[0].score > 0.85) {
3679
- log.debug("extractor", "Skipping duplicate: " + candidate.content);
3680
- continue;
3681
- }
3682
- } catch {
3733
+ const existing = await memoryRecall(candidate.content, { limit: 1 });
3734
+ if (existing.total > 0 && existing.memories.length > 0) {
3735
+ const topScore = existing.memories[0]?.score;
3736
+ if (topScore && topScore > 0.85) {
3737
+ log.debug("extractor", "Skipping duplicate: " + candidate.content);
3738
+ continue;
3683
3739
  }
3684
3740
  }
3685
3741
  } catch {
3686
3742
  }
3687
3743
  try {
3688
- await mcpManager.callTool("memory_store", {
3744
+ await memoryStore({
3689
3745
  content: candidate.content,
3690
3746
  type: candidate.type,
3691
3747
  tags: candidate.tags,
@@ -3876,9 +3932,9 @@ function humanizeError(message) {
3876
3932
  }
3877
3933
 
3878
3934
  // src/hints.ts
3879
- import fs11 from "fs";
3880
- import path11 from "path";
3881
- import os10 from "os";
3935
+ import fs12 from "fs";
3936
+ import path12 from "path";
3937
+ import os11 from "os";
3882
3938
  var HINTS = [
3883
3939
  {
3884
3940
  id: "eval",
@@ -3916,11 +3972,11 @@ function getHint(state, ctx) {
3916
3972
  }
3917
3973
  return null;
3918
3974
  }
3919
- var HINTS_FILE = path11.join(os10.homedir(), ".aman-agent", "hints-seen.json");
3975
+ var HINTS_FILE = path12.join(os11.homedir(), ".aman-agent", "hints-seen.json");
3920
3976
  function loadShownHints() {
3921
3977
  try {
3922
- if (fs11.existsSync(HINTS_FILE)) {
3923
- const data = JSON.parse(fs11.readFileSync(HINTS_FILE, "utf-8"));
3978
+ if (fs12.existsSync(HINTS_FILE)) {
3979
+ const data = JSON.parse(fs12.readFileSync(HINTS_FILE, "utf-8"));
3924
3980
  return new Set(Array.isArray(data) ? data : []);
3925
3981
  }
3926
3982
  } catch {
@@ -3929,31 +3985,27 @@ function loadShownHints() {
3929
3985
  }
3930
3986
  function saveShownHints(shown) {
3931
3987
  try {
3932
- const dir = path11.dirname(HINTS_FILE);
3933
- fs11.mkdirSync(dir, { recursive: true });
3934
- fs11.writeFileSync(HINTS_FILE, JSON.stringify([...shown]), "utf-8");
3988
+ const dir = path12.dirname(HINTS_FILE);
3989
+ fs12.mkdirSync(dir, { recursive: true });
3990
+ fs12.writeFileSync(HINTS_FILE, JSON.stringify([...shown]), "utf-8");
3935
3991
  } catch {
3936
3992
  }
3937
3993
  }
3938
3994
 
3939
3995
  // src/agent.ts
3940
3996
  marked.use(markedTerminal());
3941
- async function recallForMessage(input, mcpManager) {
3997
+ async function recallForMessage(input) {
3942
3998
  try {
3943
- const result = await mcpManager.callTool("memory_recall", {
3944
- query: input,
3945
- limit: 5,
3946
- compact: true
3947
- });
3948
- if (!result || result.startsWith("Error") || result.includes("No memories found")) {
3999
+ const result = await memoryRecall(input, { limit: 5, compact: true });
4000
+ if (result.total === 0) {
3949
4001
  return null;
3950
4002
  }
3951
- const tokenEstimate = Math.round(result.split(/\s+/).filter(Boolean).length * 1.3);
4003
+ const tokenEstimate = result.tokenEstimate ?? Math.round(result.text.split(/\s+/).filter(Boolean).length * 1.3);
3952
4004
  return {
3953
4005
  text: `
3954
4006
 
3955
4007
  <relevant-memories>
3956
- ${result}
4008
+ ${result.text}
3957
4009
  </relevant-memories>`,
3958
4010
  tokenEstimate
3959
4011
  };
@@ -4124,9 +4176,9 @@ Type a message, ${pc6.dim("/help")} for commands, or ${pc6.dim("/quit")} to exit
4124
4176
  }
4125
4177
  if (cmdResult.exportConversation) {
4126
4178
  try {
4127
- const exportDir = path12.join(os11.homedir(), ".aman-agent", "exports");
4128
- fs12.mkdirSync(exportDir, { recursive: true });
4129
- const exportPath = path12.join(exportDir, `${sessionId}.md`);
4179
+ const exportDir = path13.join(os12.homedir(), ".aman-agent", "exports");
4180
+ fs13.mkdirSync(exportDir, { recursive: true });
4181
+ const exportPath = path13.join(exportDir, `${sessionId}.md`);
4130
4182
  const lines = [
4131
4183
  `# Conversation \u2014 ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
4132
4184
  `**Model:** ${model}`,
@@ -4140,16 +4192,16 @@ Type a message, ${pc6.dim("/help")} for commands, or ${pc6.dim("/quit")} to exit
4140
4192
  lines.push(`${label} ${msg.content}`, "");
4141
4193
  }
4142
4194
  }
4143
- fs12.writeFileSync(exportPath, lines.join("\n"), "utf-8");
4195
+ fs13.writeFileSync(exportPath, lines.join("\n"), "utf-8");
4144
4196
  console.log(pc6.green(`Exported to ${exportPath}`));
4145
4197
  } catch {
4146
4198
  console.log(pc6.red("Failed to export conversation."));
4147
4199
  }
4148
4200
  continue;
4149
4201
  }
4150
- if (cmdResult.saveConversation && mcpManager) {
4202
+ if (cmdResult.saveConversation) {
4151
4203
  try {
4152
- await saveConversationToMemory(mcpManager, messages, sessionId);
4204
+ await saveConversationToMemory(messages, sessionId);
4153
4205
  console.log(pc6.green("Conversation saved to memory."));
4154
4206
  } catch {
4155
4207
  console.log(pc6.red("Failed to save conversation."));
@@ -4266,25 +4318,25 @@ ${knowledgeItem.content}
4266
4318
  for (const match of filePathMatches) {
4267
4319
  let filePath = match[1];
4268
4320
  if (filePath.startsWith("~/")) {
4269
- filePath = path12.join(os11.homedir(), filePath.slice(2));
4321
+ filePath = path13.join(os12.homedir(), filePath.slice(2));
4270
4322
  }
4271
- if (!fs12.existsSync(filePath) || !fs12.statSync(filePath).isFile()) continue;
4272
- const ext = path12.extname(filePath).toLowerCase();
4323
+ if (!fs13.existsSync(filePath) || !fs13.statSync(filePath).isFile()) continue;
4324
+ const ext = path13.extname(filePath).toLowerCase();
4273
4325
  if (imageExts.has(ext)) {
4274
4326
  try {
4275
- const stat = fs12.statSync(filePath);
4327
+ const stat = fs13.statSync(filePath);
4276
4328
  if (stat.size > maxImageBytes) {
4277
- process.stdout.write(pc6.yellow(` [skipped: ${path12.basename(filePath)} \u2014 exceeds 20MB limit]
4329
+ process.stdout.write(pc6.yellow(` [skipped: ${path13.basename(filePath)} \u2014 exceeds 20MB limit]
4278
4330
  `));
4279
4331
  continue;
4280
4332
  }
4281
- const data = fs12.readFileSync(filePath).toString("base64");
4333
+ const data = fs13.readFileSync(filePath).toString("base64");
4282
4334
  const mediaType = mimeMap[ext] || "image/png";
4283
4335
  imageBlocks.push({
4284
4336
  type: "image",
4285
4337
  source: { type: "base64", media_type: mediaType, data }
4286
4338
  });
4287
- process.stdout.write(pc6.dim(` [attached image: ${path12.basename(filePath)} (${(stat.size / 1024).toFixed(1)}KB)]
4339
+ process.stdout.write(pc6.dim(` [attached image: ${path13.basename(filePath)} (${(stat.size / 1024).toFixed(1)}KB)]
4288
4340
  `));
4289
4341
  } catch {
4290
4342
  process.stdout.write(pc6.dim(` [could not read image: ${filePath}]
@@ -4292,7 +4344,7 @@ ${knowledgeItem.content}
4292
4344
  }
4293
4345
  } else if (textExts.has(ext) || ext === "") {
4294
4346
  try {
4295
- const content = fs12.readFileSync(filePath, "utf-8");
4347
+ const content = fs13.readFileSync(filePath, "utf-8");
4296
4348
  const maxChars = 5e4;
4297
4349
  const trimmed = content.length > maxChars ? content.slice(0, maxChars) + `
4298
4350
 
@@ -4302,7 +4354,7 @@ ${knowledgeItem.content}
4302
4354
  <file path="${filePath}" size="${content.length} chars">
4303
4355
  ${trimmed}
4304
4356
  </file>`;
4305
- process.stdout.write(pc6.dim(` [attached: ${path12.basename(filePath)} (${(content.length / 1024).toFixed(1)}KB)]
4357
+ process.stdout.write(pc6.dim(` [attached: ${path13.basename(filePath)} (${(content.length / 1024).toFixed(1)}KB)]
4306
4358
  `));
4307
4359
  } catch {
4308
4360
  process.stdout.write(pc6.dim(` [could not read: ${filePath}]
@@ -4311,7 +4363,7 @@ ${trimmed}
4311
4363
  } else if (docExts.has(ext)) {
4312
4364
  if (mcpManager) {
4313
4365
  try {
4314
- process.stdout.write(pc6.dim(` [converting: ${path12.basename(filePath)}...]
4366
+ process.stdout.write(pc6.dim(` [converting: ${path13.basename(filePath)}...]
4315
4367
  `));
4316
4368
  const converted = await mcpManager.callTool("doc_convert", { path: filePath });
4317
4369
  if (converted && !converted.startsWith("Error") && !converted.includes("Could not convert")) {
@@ -4320,7 +4372,7 @@ ${trimmed}
4320
4372
  <file path="${filePath}" format="${ext}">
4321
4373
  ${converted.slice(0, 5e4)}
4322
4374
  </file>`;
4323
- process.stdout.write(pc6.dim(` [attached: ${path12.basename(filePath)} (converted from ${ext})]
4375
+ process.stdout.write(pc6.dim(` [attached: ${path13.basename(filePath)} (converted from ${ext})]
4324
4376
  `));
4325
4377
  } else {
4326
4378
  textContent += `
@@ -4332,7 +4384,7 @@ ${converted}
4332
4384
  `));
4333
4385
  }
4334
4386
  } catch {
4335
- process.stdout.write(pc6.dim(` [could not convert: ${path12.basename(filePath)}]
4387
+ process.stdout.write(pc6.dim(` [could not convert: ${path13.basename(filePath)}]
4336
4388
  `));
4337
4389
  }
4338
4390
  } else {
@@ -4387,11 +4439,11 @@ ${converted}
4387
4439
  }
4388
4440
  let augmentedSystemPrompt = activeSystemPrompt;
4389
4441
  let memoryTokens = 0;
4390
- if (mcpManager) {
4391
- const recall = await recallForMessage(input, mcpManager);
4392
- if (recall) {
4393
- augmentedSystemPrompt = activeSystemPrompt + recall.text;
4394
- memoryTokens = recall.tokenEstimate;
4442
+ {
4443
+ const recall2 = await recallForMessage(input);
4444
+ if (recall2) {
4445
+ augmentedSystemPrompt = activeSystemPrompt + recall2.text;
4446
+ memoryTokens = recall2.tokenEstimate;
4395
4447
  }
4396
4448
  }
4397
4449
  const userTurnCount = messages.filter((m) => m.role === "user").length;
@@ -4493,12 +4545,10 @@ ${result2.response}` : `[${input2.profile}] failed: ${result2.error}`;
4493
4545
  const result = await mcpManager.callTool(toolUse.name, toolUse.input);
4494
4546
  const skipLogging = ["memory_log", "memory_recall", "memory_context", "memory_detail", "reminder_check"].includes(toolUse.name);
4495
4547
  if (!skipLogging) {
4496
- mcpManager.callTool("memory_log", {
4497
- session_id: sessionId,
4498
- role: "system",
4499
- content: `[tool:${toolUse.name}] input=${JSON.stringify(toolUse.input).slice(0, 500)} result=${result.slice(0, 500)}`
4500
- }).catch(() => {
4501
- });
4548
+ try {
4549
+ memoryLog(sessionId, "system", `[tool:${toolUse.name}] input=${JSON.stringify(toolUse.input).slice(0, 500)} result=${result.slice(0, 500)}`);
4550
+ } catch {
4551
+ }
4502
4552
  }
4503
4553
  return {
4504
4554
  type: "tool_result",
@@ -4523,14 +4573,13 @@ ${result2.response}` : `[${input2.profile}] failed: ${result2.error}`;
4523
4573
  const footerDivider = "\u2500".repeat(Math.min(process.stdout.columns || 60, 60) - footer.length - 1);
4524
4574
  process.stdout.write(pc6.dim(` ${footerDivider}${footer}
4525
4575
  `));
4526
- if (mcpManager && hooksConfig?.extractMemories) {
4576
+ if (hooksConfig?.extractMemories) {
4527
4577
  const assistantText = typeof response.message.content === "string" ? response.message.content : response.message.content.filter((b) => b.type === "text").map((b) => "text" in b ? b.text : "").join("");
4528
4578
  if (assistantText) {
4529
4579
  const count = await extractMemories(
4530
4580
  input,
4531
4581
  assistantText,
4532
4582
  client,
4533
- mcpManager,
4534
4583
  extractorState
4535
4584
  );
4536
4585
  if (count > 0) {
@@ -4543,7 +4592,7 @@ ${result2.response}` : `[${input2.profile}] failed: ${result2.error}`;
4543
4592
  }
4544
4593
  if (hooksConfig?.featureHints) {
4545
4594
  hintState.turnCount++;
4546
- const hasWorkflows = fs12.existsSync(path12.join(os11.homedir(), ".aflow", "flow.md"));
4595
+ const hasWorkflows = fs13.existsSync(path13.join(os12.homedir(), ".aflow", "flow.md"));
4547
4596
  const memoryCount = memoryTokens > 0 ? Math.floor(memoryTokens / 5) : 0;
4548
4597
  const hint = getHint(hintState, { hasWorkflows, memoryCount });
4549
4598
  if (hint) {
@@ -4560,16 +4609,12 @@ ${result2.response}` : `[${input2.profile}] failed: ${result2.error}`;
4560
4609
  }
4561
4610
  }
4562
4611
  }
4563
- async function saveConversationToMemory(mcpManager, messages, sessionId) {
4612
+ async function saveConversationToMemory(messages, sessionId) {
4564
4613
  const recentMessages = messages.slice(-50);
4565
4614
  for (const msg of recentMessages) {
4566
4615
  if (typeof msg.content !== "string") continue;
4567
4616
  try {
4568
- await mcpManager.callTool("memory_log", {
4569
- session_id: sessionId,
4570
- role: msg.role,
4571
- content: msg.content.slice(0, 5e3)
4572
- });
4617
+ memoryLog(sessionId, msg.role, msg.content.slice(0, 5e3));
4573
4618
  } catch (err) {
4574
4619
  log.debug("agent", "memory_log write failed", err);
4575
4620
  }
@@ -4577,9 +4622,9 @@ async function saveConversationToMemory(mcpManager, messages, sessionId) {
4577
4622
  }
4578
4623
 
4579
4624
  // src/index.ts
4580
- import fs13 from "fs";
4581
- import path13 from "path";
4582
- import os12 from "os";
4625
+ import fs14 from "fs";
4626
+ import path14 from "path";
4627
+ import os13 from "os";
4583
4628
 
4584
4629
  // src/presets.ts
4585
4630
  var PRESETS = {
@@ -4688,9 +4733,9 @@ ${wfSections}`;
4688
4733
 
4689
4734
  // src/index.ts
4690
4735
  async function autoDetectConfig() {
4691
- const reconfigMarker = path13.join(os12.homedir(), ".aman-agent", ".reconfig");
4692
- if (fs13.existsSync(reconfigMarker)) {
4693
- fs13.unlinkSync(reconfigMarker);
4736
+ const reconfigMarker = path14.join(os13.homedir(), ".aman-agent", ".reconfig");
4737
+ if (fs14.existsSync(reconfigMarker)) {
4738
+ fs14.unlinkSync(reconfigMarker);
4694
4739
  return null;
4695
4740
  }
4696
4741
  const anthropicKey = process.env.ANTHROPIC_API_KEY;
@@ -4719,11 +4764,11 @@ async function autoDetectConfig() {
4719
4764
  return null;
4720
4765
  }
4721
4766
  function bootstrapEcosystem() {
4722
- const home2 = os12.homedir();
4723
- const corePath = path13.join(home2, ".acore", "core.md");
4724
- if (fs13.existsSync(corePath)) return false;
4725
- fs13.mkdirSync(path13.join(home2, ".acore"), { recursive: true });
4726
- fs13.writeFileSync(corePath, [
4767
+ const home2 = os13.homedir();
4768
+ const corePath = path14.join(home2, ".acore", "core.md");
4769
+ if (fs14.existsSync(corePath)) return false;
4770
+ fs14.mkdirSync(path14.join(home2, ".acore"), { recursive: true });
4771
+ fs14.writeFileSync(corePath, [
4727
4772
  "# Aman",
4728
4773
  "",
4729
4774
  "## Personality",
@@ -4735,11 +4780,11 @@ function bootstrapEcosystem() {
4735
4780
  "## Session",
4736
4781
  "_New companion \u2014 no prior sessions._"
4737
4782
  ].join("\n"), "utf-8");
4738
- const rulesDir = path13.join(home2, ".arules");
4739
- const rulesPath = path13.join(rulesDir, "rules.md");
4740
- if (!fs13.existsSync(rulesPath)) {
4741
- fs13.mkdirSync(rulesDir, { recursive: true });
4742
- fs13.writeFileSync(rulesPath, [
4783
+ const rulesDir = path14.join(home2, ".arules");
4784
+ const rulesPath = path14.join(rulesDir, "rules.md");
4785
+ if (!fs14.existsSync(rulesPath)) {
4786
+ fs14.mkdirSync(rulesDir, { recursive: true });
4787
+ fs14.writeFileSync(rulesPath, [
4743
4788
  "# Guardrails",
4744
4789
  "",
4745
4790
  "## safety",
@@ -4881,11 +4926,11 @@ program.name("aman-agent").description("Your AI companion, running locally").ver
4881
4926
  }
4882
4927
  }
4883
4928
  const aiName = getProfileAiName(profile);
4929
+ await initMemory();
4884
4930
  const mcpManager = new McpManager();
4885
4931
  const mcpSpinner = p2.spinner();
4886
4932
  mcpSpinner.start("Connecting to MCP servers");
4887
4933
  await mcpManager.connect("aman", "npx", ["-y", "@aman_asmuei/aman-mcp"]);
4888
- await mcpManager.connect("amem", "npx", ["-y", "@aman_asmuei/amem"]);
4889
4934
  if (config.mcpServers) {
4890
4935
  for (const [name, serverConfig] of Object.entries(config.mcpServers)) {
4891
4936
  if (name === "aman" || name === "amem") continue;
@@ -4896,25 +4941,16 @@ program.name("aman-agent").description("Your AI companion, running locally").ver
4896
4941
  mcpSpinner.stop("MCP connected");
4897
4942
  if (mcpTools.length > 0) {
4898
4943
  p2.log.success(`${mcpTools.length} MCP tools available`);
4899
- if (mcpTools.some((t) => t.name === "memory_consolidate")) {
4944
+ {
4900
4945
  const memSpinner = p2.spinner();
4901
4946
  memSpinner.start("Consolidating memory");
4902
4947
  try {
4903
- const consolidateResult = await mcpManager.callTool("memory_consolidate", { dry_run: false });
4904
- if (consolidateResult && !consolidateResult.startsWith("Error")) {
4905
- try {
4906
- const report = JSON.parse(consolidateResult);
4907
- memSpinner.stop("Memory consolidated");
4908
- if (report.merged > 0 || report.pruned > 0 || report.promoted > 0) {
4909
- p2.log.info(
4910
- `Memory health: ${report.healthScore ?? "?"}% ` + pc7.dim(`(merged ${report.merged}, pruned ${report.pruned}, promoted ${report.promoted})`)
4911
- );
4912
- }
4913
- } catch {
4914
- memSpinner.stop("Memory consolidated");
4915
- }
4916
- } else {
4917
- memSpinner.stop("Memory consolidated");
4948
+ const report = memoryConsolidate();
4949
+ memSpinner.stop("Memory consolidated");
4950
+ if (report.merged > 0 || report.pruned > 0 || report.promoted > 0) {
4951
+ p2.log.info(
4952
+ `Memory health: ${report.healthScore ?? "?"}% ` + pc7.dim(`(merged ${report.merged}, pruned ${report.pruned}, promoted ${report.promoted})`)
4953
+ );
4918
4954
  }
4919
4955
  } catch {
4920
4956
  memSpinner.stop("Memory consolidation skipped");
@@ -4971,19 +5007,19 @@ program.command("init").description("Set up your AI companion with a guided wiza
4971
5007
  });
4972
5008
  if (p2.isCancel(preset)) process.exit(0);
4973
5009
  const result = applyPreset(preset, name || "Aman");
4974
- const home2 = os12.homedir();
4975
- fs13.mkdirSync(path13.join(home2, ".acore"), { recursive: true });
4976
- fs13.writeFileSync(path13.join(home2, ".acore", "core.md"), result.coreMd, "utf-8");
5010
+ const home2 = os13.homedir();
5011
+ fs14.mkdirSync(path14.join(home2, ".acore"), { recursive: true });
5012
+ fs14.writeFileSync(path14.join(home2, ".acore", "core.md"), result.coreMd, "utf-8");
4977
5013
  p2.log.success(`Identity created \u2014 ${PRESETS[preset].identity.personality.split(".")[0].toLowerCase()}`);
4978
5014
  if (result.rulesMd) {
4979
- fs13.mkdirSync(path13.join(home2, ".arules"), { recursive: true });
4980
- fs13.writeFileSync(path13.join(home2, ".arules", "rules.md"), result.rulesMd, "utf-8");
5015
+ fs14.mkdirSync(path14.join(home2, ".arules"), { recursive: true });
5016
+ fs14.writeFileSync(path14.join(home2, ".arules", "rules.md"), result.rulesMd, "utf-8");
4981
5017
  const ruleCount = (result.rulesMd.match(/^- /gm) || []).length;
4982
5018
  p2.log.success(`${ruleCount} rules set`);
4983
5019
  }
4984
5020
  if (result.flowMd) {
4985
- fs13.mkdirSync(path13.join(home2, ".aflow"), { recursive: true });
4986
- fs13.writeFileSync(path13.join(home2, ".aflow", "flow.md"), result.flowMd, "utf-8");
5021
+ fs14.mkdirSync(path14.join(home2, ".aflow"), { recursive: true });
5022
+ fs14.writeFileSync(path14.join(home2, ".aflow", "flow.md"), result.flowMd, "utf-8");
4987
5023
  const wfCount = (result.flowMd.match(/^## /gm) || []).length;
4988
5024
  p2.log.success(`${wfCount} workflow${wfCount > 1 ? "s" : ""} added`);
4989
5025
  }