@aman_asmuei/aman-agent 0.16.2 → 0.17.1
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 +722 -350
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
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
|
|
801
|
-
import
|
|
802
|
-
import
|
|
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
|
|
810
|
-
import
|
|
811
|
-
import
|
|
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,151 @@ function getEcosystemStatus(mcpToolCount, amemConnected) {
|
|
|
869
869
|
};
|
|
870
870
|
}
|
|
871
871
|
|
|
872
|
-
// src/
|
|
873
|
-
import
|
|
872
|
+
// src/memory.ts
|
|
873
|
+
import {
|
|
874
|
+
createDatabase,
|
|
875
|
+
recall,
|
|
876
|
+
buildContext,
|
|
877
|
+
storeMemory,
|
|
878
|
+
consolidateMemories,
|
|
879
|
+
cosineSimilarity,
|
|
880
|
+
preloadEmbeddings,
|
|
881
|
+
buildVectorIndex,
|
|
882
|
+
recallMemories,
|
|
883
|
+
generateEmbedding,
|
|
884
|
+
getVectorIndex
|
|
885
|
+
} from "@aman_asmuei/amem-core";
|
|
874
886
|
import path5 from "path";
|
|
875
887
|
import os5 from "os";
|
|
888
|
+
import fs5 from "fs";
|
|
889
|
+
var db = null;
|
|
890
|
+
var currentProject = "global";
|
|
891
|
+
async function initMemory(project) {
|
|
892
|
+
if (db) return db;
|
|
893
|
+
const amemDir = process.env.AMEM_DIR ?? path5.join(os5.homedir(), ".amem");
|
|
894
|
+
if (!fs5.existsSync(amemDir)) fs5.mkdirSync(amemDir, { recursive: true });
|
|
895
|
+
const dbPath = process.env.AMEM_DB ?? path5.join(amemDir, "memory.db");
|
|
896
|
+
db = createDatabase(dbPath);
|
|
897
|
+
currentProject = project ?? "global";
|
|
898
|
+
preloadEmbeddings();
|
|
899
|
+
setTimeout(() => {
|
|
900
|
+
try {
|
|
901
|
+
buildVectorIndex(db);
|
|
902
|
+
} catch {
|
|
903
|
+
}
|
|
904
|
+
}, 1e3);
|
|
905
|
+
return db;
|
|
906
|
+
}
|
|
907
|
+
function getDb() {
|
|
908
|
+
if (!db) throw new Error("Memory not initialized \u2014 call initMemory() first");
|
|
909
|
+
return db;
|
|
910
|
+
}
|
|
911
|
+
async function memoryRecall(query, opts) {
|
|
912
|
+
return recall(getDb(), {
|
|
913
|
+
query,
|
|
914
|
+
limit: opts?.limit ?? 10,
|
|
915
|
+
compact: opts?.compact ?? true,
|
|
916
|
+
type: opts?.type,
|
|
917
|
+
tag: opts?.tag,
|
|
918
|
+
minConfidence: opts?.minConfidence,
|
|
919
|
+
explain: opts?.explain,
|
|
920
|
+
scope: currentProject
|
|
921
|
+
});
|
|
922
|
+
}
|
|
923
|
+
async function memoryContext(topic, maxTokens) {
|
|
924
|
+
return buildContext(getDb(), topic, { maxTokens, scope: currentProject });
|
|
925
|
+
}
|
|
926
|
+
async function memoryStore(opts) {
|
|
927
|
+
return storeMemory(getDb(), opts);
|
|
928
|
+
}
|
|
929
|
+
function memoryLog(sessionId, role, content) {
|
|
930
|
+
return getDb().appendLog({
|
|
931
|
+
sessionId,
|
|
932
|
+
role,
|
|
933
|
+
content,
|
|
934
|
+
project: currentProject,
|
|
935
|
+
metadata: {}
|
|
936
|
+
});
|
|
937
|
+
}
|
|
938
|
+
function reminderCheck() {
|
|
939
|
+
const all = getDb().checkReminders();
|
|
940
|
+
return all.filter((r) => r.scope === "global" || r.scope === currentProject);
|
|
941
|
+
}
|
|
942
|
+
async function memoryForget(opts) {
|
|
943
|
+
const db2 = getDb();
|
|
944
|
+
if (opts.id) {
|
|
945
|
+
const fullId = db2.resolveId(opts.id) ?? opts.id;
|
|
946
|
+
const memory = db2.getById(fullId);
|
|
947
|
+
if (!memory) return { deleted: 0, message: `Memory ${opts.id} not found.` };
|
|
948
|
+
db2.deleteMemory(fullId);
|
|
949
|
+
const vecIdx = getVectorIndex();
|
|
950
|
+
if (vecIdx) vecIdx.remove(fullId);
|
|
951
|
+
return { deleted: 1, message: `Deleted: "${memory.content}" (${memory.type})` };
|
|
952
|
+
}
|
|
953
|
+
if (opts.type) {
|
|
954
|
+
const all = db2.getAllForProject(currentProject);
|
|
955
|
+
const matches = all.filter((m) => m.type === opts.type);
|
|
956
|
+
if (matches.length === 0) return { deleted: 0, message: `No memories of type "${opts.type}" found.` };
|
|
957
|
+
const vecIdx = getVectorIndex();
|
|
958
|
+
for (const m of matches) {
|
|
959
|
+
db2.deleteMemory(m.id);
|
|
960
|
+
if (vecIdx) vecIdx.remove(m.id);
|
|
961
|
+
}
|
|
962
|
+
return { deleted: matches.length, message: `Deleted ${matches.length} "${opts.type}" memories.` };
|
|
963
|
+
}
|
|
964
|
+
if (opts.query) {
|
|
965
|
+
const queryEmbedding = await generateEmbedding(opts.query);
|
|
966
|
+
const matches = recallMemories(db2, { query: opts.query, queryEmbedding, limit: 50, minConfidence: 0, scope: currentProject });
|
|
967
|
+
if (matches.length === 0) return { deleted: 0, message: `No memories found matching "${opts.query}".` };
|
|
968
|
+
const vecIdx = getVectorIndex();
|
|
969
|
+
for (const m of matches) {
|
|
970
|
+
db2.deleteMemory(m.id);
|
|
971
|
+
if (vecIdx) vecIdx.remove(m.id);
|
|
972
|
+
}
|
|
973
|
+
return { deleted: matches.length, message: `Deleted ${matches.length} memories matching "${opts.query}".` };
|
|
974
|
+
}
|
|
975
|
+
return { deleted: 0, message: "Provide an id, type, or query to forget." };
|
|
976
|
+
}
|
|
977
|
+
function memoryConsolidate(dryRun = false) {
|
|
978
|
+
return consolidateMemories(getDb(), cosineSimilarity, {
|
|
979
|
+
dryRun,
|
|
980
|
+
maxStaleDays: 90,
|
|
981
|
+
minConfidence: 0.3,
|
|
982
|
+
minAccessCount: 0
|
|
983
|
+
});
|
|
984
|
+
}
|
|
985
|
+
function isMemoryInitialized() {
|
|
986
|
+
return db !== null;
|
|
987
|
+
}
|
|
988
|
+
function memoryStats() {
|
|
989
|
+
return getDb().getStats();
|
|
990
|
+
}
|
|
991
|
+
function memoryExport() {
|
|
992
|
+
return getDb().getAllForProject(currentProject);
|
|
993
|
+
}
|
|
994
|
+
function memorySince(hours) {
|
|
995
|
+
const since = Date.now() - hours * 60 * 60 * 1e3;
|
|
996
|
+
const all = getDb().getMemoriesSince(since);
|
|
997
|
+
return all.filter((m) => m.scope === "global" || m.scope === currentProject);
|
|
998
|
+
}
|
|
999
|
+
function memorySearch(query, limit) {
|
|
1000
|
+
return getDb().fullTextSearch(query, limit, currentProject);
|
|
1001
|
+
}
|
|
1002
|
+
function reminderSet(content, dueAt) {
|
|
1003
|
+
return getDb().insertReminder(content, dueAt ?? null, currentProject);
|
|
1004
|
+
}
|
|
1005
|
+
function reminderList(includeCompleted) {
|
|
1006
|
+
return getDb().listReminders(includeCompleted, currentProject);
|
|
1007
|
+
}
|
|
1008
|
+
function reminderComplete(id) {
|
|
1009
|
+
const fullId = getDb().resolveReminderId(id) ?? id;
|
|
1010
|
+
return getDb().completeReminder(fullId);
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
// src/profile-templates.ts
|
|
1014
|
+
import fs6 from "fs";
|
|
1015
|
+
import path6 from "path";
|
|
1016
|
+
import os6 from "os";
|
|
876
1017
|
var BUILT_IN_PROFILES = [
|
|
877
1018
|
{
|
|
878
1019
|
name: "coder",
|
|
@@ -965,9 +1106,9 @@ var BUILT_IN_PROFILES = [
|
|
|
965
1106
|
function installProfileTemplate(templateName, userName) {
|
|
966
1107
|
const template = BUILT_IN_PROFILES.find((t) => t.name === templateName);
|
|
967
1108
|
if (!template) return null;
|
|
968
|
-
const profileDir =
|
|
969
|
-
if (
|
|
970
|
-
|
|
1109
|
+
const profileDir = path6.join(os6.homedir(), ".acore", "profiles", template.name);
|
|
1110
|
+
if (fs6.existsSync(profileDir)) return `Profile already exists: ${template.name}`;
|
|
1111
|
+
fs6.mkdirSync(profileDir, { recursive: true });
|
|
971
1112
|
let core = template.core;
|
|
972
1113
|
if (userName) {
|
|
973
1114
|
core += `
|
|
@@ -981,12 +1122,12 @@ function installProfileTemplate(templateName, userName) {
|
|
|
981
1122
|
- Detail level: balanced
|
|
982
1123
|
`;
|
|
983
1124
|
}
|
|
984
|
-
|
|
1125
|
+
fs6.writeFileSync(path6.join(profileDir, "core.md"), core, "utf-8");
|
|
985
1126
|
if (template.rules) {
|
|
986
|
-
|
|
1127
|
+
fs6.writeFileSync(path6.join(profileDir, "rules.md"), template.rules, "utf-8");
|
|
987
1128
|
}
|
|
988
1129
|
if (template.skills) {
|
|
989
|
-
|
|
1130
|
+
fs6.writeFileSync(path6.join(profileDir, "skills.md"), template.skills, "utf-8");
|
|
990
1131
|
}
|
|
991
1132
|
return null;
|
|
992
1133
|
}
|
|
@@ -1113,43 +1254,43 @@ async function delegatePipeline(steps, initialInput, client, mcpManager, options
|
|
|
1113
1254
|
}
|
|
1114
1255
|
|
|
1115
1256
|
// src/teams.ts
|
|
1116
|
-
import
|
|
1117
|
-
import
|
|
1118
|
-
import
|
|
1257
|
+
import fs7 from "fs";
|
|
1258
|
+
import path7 from "path";
|
|
1259
|
+
import os7 from "os";
|
|
1119
1260
|
import pc2 from "picocolors";
|
|
1120
1261
|
function getTeamsDir() {
|
|
1121
|
-
return
|
|
1262
|
+
return path7.join(os7.homedir(), ".acore", "teams");
|
|
1122
1263
|
}
|
|
1123
1264
|
function ensureTeamsDir() {
|
|
1124
1265
|
const dir = getTeamsDir();
|
|
1125
|
-
if (!
|
|
1266
|
+
if (!fs7.existsSync(dir)) fs7.mkdirSync(dir, { recursive: true });
|
|
1126
1267
|
return dir;
|
|
1127
1268
|
}
|
|
1128
1269
|
function teamPath(name) {
|
|
1129
1270
|
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
1130
|
-
return
|
|
1271
|
+
return path7.join(ensureTeamsDir(), `${slug}.json`);
|
|
1131
1272
|
}
|
|
1132
1273
|
function createTeam(team) {
|
|
1133
1274
|
const fp = teamPath(team.name);
|
|
1134
|
-
|
|
1275
|
+
fs7.writeFileSync(fp, JSON.stringify(team, null, 2), "utf-8");
|
|
1135
1276
|
}
|
|
1136
1277
|
function loadTeam(name) {
|
|
1137
1278
|
const fp = teamPath(name);
|
|
1138
|
-
if (!
|
|
1279
|
+
if (!fs7.existsSync(fp)) return null;
|
|
1139
1280
|
try {
|
|
1140
|
-
return JSON.parse(
|
|
1281
|
+
return JSON.parse(fs7.readFileSync(fp, "utf-8"));
|
|
1141
1282
|
} catch {
|
|
1142
1283
|
return null;
|
|
1143
1284
|
}
|
|
1144
1285
|
}
|
|
1145
1286
|
function listTeams() {
|
|
1146
1287
|
const dir = getTeamsDir();
|
|
1147
|
-
if (!
|
|
1288
|
+
if (!fs7.existsSync(dir)) return [];
|
|
1148
1289
|
const teams = [];
|
|
1149
|
-
for (const file of
|
|
1290
|
+
for (const file of fs7.readdirSync(dir)) {
|
|
1150
1291
|
if (!file.endsWith(".json")) continue;
|
|
1151
1292
|
try {
|
|
1152
|
-
const content =
|
|
1293
|
+
const content = fs7.readFileSync(path7.join(dir, file), "utf-8");
|
|
1153
1294
|
teams.push(JSON.parse(content));
|
|
1154
1295
|
} catch {
|
|
1155
1296
|
}
|
|
@@ -1158,8 +1299,8 @@ function listTeams() {
|
|
|
1158
1299
|
}
|
|
1159
1300
|
function deleteTeam(name) {
|
|
1160
1301
|
const fp = teamPath(name);
|
|
1161
|
-
if (!
|
|
1162
|
-
|
|
1302
|
+
if (!fs7.existsSync(fp)) return false;
|
|
1303
|
+
fs7.unlinkSync(fp);
|
|
1163
1304
|
return true;
|
|
1164
1305
|
}
|
|
1165
1306
|
async function runTeam(team, task, client, mcpManager, tools) {
|
|
@@ -1385,23 +1526,23 @@ var BUILT_IN_TEAMS = [
|
|
|
1385
1526
|
];
|
|
1386
1527
|
|
|
1387
1528
|
// src/plans.ts
|
|
1388
|
-
import
|
|
1389
|
-
import
|
|
1390
|
-
import
|
|
1529
|
+
import fs8 from "fs";
|
|
1530
|
+
import path8 from "path";
|
|
1531
|
+
import os8 from "os";
|
|
1391
1532
|
function getPlansDir() {
|
|
1392
|
-
const localDir =
|
|
1393
|
-
const localAcore =
|
|
1394
|
-
if (
|
|
1395
|
-
return
|
|
1533
|
+
const localDir = path8.join(process.cwd(), ".acore", "plans");
|
|
1534
|
+
const localAcore = path8.join(process.cwd(), ".acore");
|
|
1535
|
+
if (fs8.existsSync(localAcore)) return localDir;
|
|
1536
|
+
return path8.join(os8.homedir(), ".acore", "plans");
|
|
1396
1537
|
}
|
|
1397
1538
|
function ensurePlansDir() {
|
|
1398
1539
|
const dir = getPlansDir();
|
|
1399
|
-
if (!
|
|
1540
|
+
if (!fs8.existsSync(dir)) fs8.mkdirSync(dir, { recursive: true });
|
|
1400
1541
|
return dir;
|
|
1401
1542
|
}
|
|
1402
1543
|
function planPath(name) {
|
|
1403
1544
|
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
1404
|
-
return
|
|
1545
|
+
return path8.join(ensurePlansDir(), `${slug}.md`);
|
|
1405
1546
|
}
|
|
1406
1547
|
function serializePlan(plan) {
|
|
1407
1548
|
const lines = [];
|
|
@@ -1427,7 +1568,7 @@ function parsePlan(content, filePath) {
|
|
|
1427
1568
|
const createdMatch = content.match(/\*\*Created:\*\*\s*(.+)/);
|
|
1428
1569
|
const updatedMatch = content.match(/\*\*Updated:\*\*\s*(.+)/);
|
|
1429
1570
|
const activeMatch = content.match(/\*\*Active:\*\*\s*(.+)/);
|
|
1430
|
-
const name = nameMatch?.[1]?.trim() ||
|
|
1571
|
+
const name = nameMatch?.[1]?.trim() || path8.basename(filePath, ".md");
|
|
1431
1572
|
const goal = goalMatch?.[1]?.trim() || "";
|
|
1432
1573
|
const createdAt = createdMatch?.[1]?.trim() || "";
|
|
1433
1574
|
const updatedAt = updatedMatch?.[1]?.trim() || "";
|
|
@@ -1469,22 +1610,22 @@ function createPlan(name, goal, steps) {
|
|
|
1469
1610
|
}
|
|
1470
1611
|
function savePlan(plan) {
|
|
1471
1612
|
const fp = planPath(plan.name);
|
|
1472
|
-
|
|
1613
|
+
fs8.writeFileSync(fp, serializePlan(plan), "utf-8");
|
|
1473
1614
|
}
|
|
1474
1615
|
function loadPlan(name) {
|
|
1475
1616
|
const fp = planPath(name);
|
|
1476
|
-
if (!
|
|
1477
|
-
const content =
|
|
1617
|
+
if (!fs8.existsSync(fp)) return null;
|
|
1618
|
+
const content = fs8.readFileSync(fp, "utf-8");
|
|
1478
1619
|
return parsePlan(content, fp);
|
|
1479
1620
|
}
|
|
1480
1621
|
function listPlans() {
|
|
1481
1622
|
const dir = getPlansDir();
|
|
1482
|
-
if (!
|
|
1623
|
+
if (!fs8.existsSync(dir)) return [];
|
|
1483
1624
|
const plans = [];
|
|
1484
|
-
for (const file of
|
|
1625
|
+
for (const file of fs8.readdirSync(dir)) {
|
|
1485
1626
|
if (!file.endsWith(".md")) continue;
|
|
1486
|
-
const fp =
|
|
1487
|
-
const content =
|
|
1627
|
+
const fp = path8.join(dir, file);
|
|
1628
|
+
const content = fs8.readFileSync(fp, "utf-8");
|
|
1488
1629
|
const plan = parsePlan(content, fp);
|
|
1489
1630
|
if (plan) plans.push(plan);
|
|
1490
1631
|
}
|
|
@@ -1580,16 +1721,17 @@ function progressBar(pct) {
|
|
|
1580
1721
|
|
|
1581
1722
|
// src/commands.ts
|
|
1582
1723
|
function readEcosystemFile(filePath, label) {
|
|
1583
|
-
if (!
|
|
1724
|
+
if (!fs9.existsSync(filePath)) {
|
|
1584
1725
|
return pc3.dim(`No ${label} file found at ${filePath}`);
|
|
1585
1726
|
}
|
|
1586
|
-
return
|
|
1727
|
+
return fs9.readFileSync(filePath, "utf-8").trim();
|
|
1587
1728
|
}
|
|
1588
1729
|
function parseCommand(input) {
|
|
1589
1730
|
const trimmed = input.trim();
|
|
1590
1731
|
const parts = trimmed.split(/\s+/);
|
|
1591
1732
|
const base = parts[0].toLowerCase().replace(/^\//, "");
|
|
1592
|
-
|
|
1733
|
+
let action = parts.length > 1 ? parts[1].toLowerCase() : void 0;
|
|
1734
|
+
if (action === "--help" || action === "-h") action = "help";
|
|
1593
1735
|
const args = parts.slice(2);
|
|
1594
1736
|
return { base, action, args };
|
|
1595
1737
|
}
|
|
@@ -1604,9 +1746,9 @@ async function mcpWrite(ctx, layer, tool, args) {
|
|
|
1604
1746
|
return pc3.green(result);
|
|
1605
1747
|
}
|
|
1606
1748
|
async function handleIdentityCommand(action, args, ctx) {
|
|
1607
|
-
const home2 =
|
|
1749
|
+
const home2 = os9.homedir();
|
|
1608
1750
|
if (!action) {
|
|
1609
|
-
const content = readEcosystemFile(
|
|
1751
|
+
const content = readEcosystemFile(path9.join(home2, ".acore", "core.md"), "identity (acore)");
|
|
1610
1752
|
return { handled: true, output: content };
|
|
1611
1753
|
}
|
|
1612
1754
|
if (action === "update") {
|
|
@@ -1627,12 +1769,19 @@ async function handleIdentityCommand(action, args, ctx) {
|
|
|
1627
1769
|
const output = await mcpWrite(ctx, "identity", "identity_update_section", { section, content });
|
|
1628
1770
|
return { handled: true, output };
|
|
1629
1771
|
}
|
|
1630
|
-
|
|
1772
|
+
if (action === "help") {
|
|
1773
|
+
return { handled: true, output: [
|
|
1774
|
+
pc3.bold("Identity commands:"),
|
|
1775
|
+
` ${pc3.cyan("/identity")} View current identity`,
|
|
1776
|
+
` ${pc3.cyan("/identity update")} <section> Update a section`
|
|
1777
|
+
].join("\n") };
|
|
1778
|
+
}
|
|
1779
|
+
return { handled: true, output: pc3.yellow(`Unknown action: /identity ${action}. Try /identity --help`) };
|
|
1631
1780
|
}
|
|
1632
1781
|
async function handleRulesCommand(action, args, ctx) {
|
|
1633
|
-
const home2 =
|
|
1782
|
+
const home2 = os9.homedir();
|
|
1634
1783
|
if (!action) {
|
|
1635
|
-
const content = readEcosystemFile(
|
|
1784
|
+
const content = readEcosystemFile(path9.join(home2, ".arules", "rules.md"), "guardrails (arules)");
|
|
1636
1785
|
return { handled: true, output: content };
|
|
1637
1786
|
}
|
|
1638
1787
|
if (action === "add") {
|
|
@@ -1658,12 +1807,21 @@ async function handleRulesCommand(action, args, ctx) {
|
|
|
1658
1807
|
const output = await mcpWrite(ctx, "rules", "rules_toggle", { category: args[0], index: parseInt(args[1], 10) });
|
|
1659
1808
|
return { handled: true, output };
|
|
1660
1809
|
}
|
|
1661
|
-
|
|
1810
|
+
if (action === "help") {
|
|
1811
|
+
return { handled: true, output: [
|
|
1812
|
+
pc3.bold("Rules commands:"),
|
|
1813
|
+
` ${pc3.cyan("/rules")} View current rules`,
|
|
1814
|
+
` ${pc3.cyan("/rules add")} <category> <text> Add a rule`,
|
|
1815
|
+
` ${pc3.cyan("/rules remove")} <category> <idx> Remove a rule`,
|
|
1816
|
+
` ${pc3.cyan("/rules toggle")} <category> <idx> Toggle a rule`
|
|
1817
|
+
].join("\n") };
|
|
1818
|
+
}
|
|
1819
|
+
return { handled: true, output: pc3.yellow(`Unknown action: /rules ${action}. Try /rules --help`) };
|
|
1662
1820
|
}
|
|
1663
1821
|
async function handleWorkflowsCommand(action, args, ctx) {
|
|
1664
|
-
const home2 =
|
|
1822
|
+
const home2 = os9.homedir();
|
|
1665
1823
|
if (!action) {
|
|
1666
|
-
const content = readEcosystemFile(
|
|
1824
|
+
const content = readEcosystemFile(path9.join(home2, ".aflow", "flow.md"), "workflows (aflow)");
|
|
1667
1825
|
return { handled: true, output: content };
|
|
1668
1826
|
}
|
|
1669
1827
|
if (action === "add") {
|
|
@@ -1680,7 +1838,15 @@ async function handleWorkflowsCommand(action, args, ctx) {
|
|
|
1680
1838
|
const output = await mcpWrite(ctx, "workflows", "workflow_remove", { name: args.join(" ") });
|
|
1681
1839
|
return { handled: true, output };
|
|
1682
1840
|
}
|
|
1683
|
-
|
|
1841
|
+
if (action === "help") {
|
|
1842
|
+
return { handled: true, output: [
|
|
1843
|
+
pc3.bold("Workflow commands:"),
|
|
1844
|
+
` ${pc3.cyan("/workflows")} View current workflows`,
|
|
1845
|
+
` ${pc3.cyan("/workflows add")} <name> Add a workflow`,
|
|
1846
|
+
` ${pc3.cyan("/workflows remove")} <name> Remove a workflow`
|
|
1847
|
+
].join("\n") };
|
|
1848
|
+
}
|
|
1849
|
+
return { handled: true, output: pc3.yellow(`Unknown action: /workflows ${action}. Try /workflows --help`) };
|
|
1684
1850
|
}
|
|
1685
1851
|
var AKIT_REGISTRY = [
|
|
1686
1852
|
{ name: "web-search", description: "Search the web for current information", category: "search", mcp: { package: "@anthropic/web-search", command: "npx", args: ["-y", "@anthropic/web-search"] } },
|
|
@@ -1702,38 +1868,38 @@ var AKIT_REGISTRY = [
|
|
|
1702
1868
|
{ 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
1869
|
];
|
|
1704
1870
|
function loadAkitInstalled() {
|
|
1705
|
-
const filePath =
|
|
1706
|
-
if (!
|
|
1871
|
+
const filePath = path9.join(os9.homedir(), ".akit", "installed.json");
|
|
1872
|
+
if (!fs9.existsSync(filePath)) return [];
|
|
1707
1873
|
try {
|
|
1708
|
-
return JSON.parse(
|
|
1874
|
+
return JSON.parse(fs9.readFileSync(filePath, "utf-8"));
|
|
1709
1875
|
} catch {
|
|
1710
1876
|
return [];
|
|
1711
1877
|
}
|
|
1712
1878
|
}
|
|
1713
1879
|
function saveAkitInstalled(tools) {
|
|
1714
|
-
const dir =
|
|
1715
|
-
|
|
1716
|
-
|
|
1880
|
+
const dir = path9.join(os9.homedir(), ".akit");
|
|
1881
|
+
fs9.mkdirSync(dir, { recursive: true });
|
|
1882
|
+
fs9.writeFileSync(path9.join(dir, "installed.json"), JSON.stringify(tools, null, 2) + "\n", "utf-8");
|
|
1717
1883
|
}
|
|
1718
1884
|
function addToAmanAgentConfig(name, mcpConfig) {
|
|
1719
|
-
const configPath =
|
|
1720
|
-
if (!
|
|
1885
|
+
const configPath = path9.join(os9.homedir(), ".aman-agent", "config.json");
|
|
1886
|
+
if (!fs9.existsSync(configPath)) return;
|
|
1721
1887
|
try {
|
|
1722
|
-
const config = JSON.parse(
|
|
1888
|
+
const config = JSON.parse(fs9.readFileSync(configPath, "utf-8"));
|
|
1723
1889
|
if (!config.mcpServers) config.mcpServers = {};
|
|
1724
1890
|
config.mcpServers[name] = mcpConfig;
|
|
1725
|
-
|
|
1891
|
+
fs9.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
1726
1892
|
} catch {
|
|
1727
1893
|
}
|
|
1728
1894
|
}
|
|
1729
1895
|
function removeFromAmanAgentConfig(name) {
|
|
1730
|
-
const configPath =
|
|
1731
|
-
if (!
|
|
1896
|
+
const configPath = path9.join(os9.homedir(), ".aman-agent", "config.json");
|
|
1897
|
+
if (!fs9.existsSync(configPath)) return;
|
|
1732
1898
|
try {
|
|
1733
|
-
const config = JSON.parse(
|
|
1899
|
+
const config = JSON.parse(fs9.readFileSync(configPath, "utf-8"));
|
|
1734
1900
|
if (config.mcpServers) {
|
|
1735
1901
|
delete config.mcpServers[name];
|
|
1736
|
-
|
|
1902
|
+
fs9.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
1737
1903
|
}
|
|
1738
1904
|
} catch {
|
|
1739
1905
|
}
|
|
@@ -1883,9 +2049,9 @@ function handleAkitCommand(action, args) {
|
|
|
1883
2049
|
return { handled: true, output: lines.join("\n") };
|
|
1884
2050
|
}
|
|
1885
2051
|
async function handleSkillsCommand(action, args, ctx) {
|
|
1886
|
-
const home2 =
|
|
2052
|
+
const home2 = os9.homedir();
|
|
1887
2053
|
if (!action) {
|
|
1888
|
-
const content = readEcosystemFile(
|
|
2054
|
+
const content = readEcosystemFile(path9.join(home2, ".askill", "skills.md"), "skills (askill)");
|
|
1889
2055
|
return { handled: true, output: content };
|
|
1890
2056
|
}
|
|
1891
2057
|
if (action === "install") {
|
|
@@ -1902,12 +2068,20 @@ async function handleSkillsCommand(action, args, ctx) {
|
|
|
1902
2068
|
const output = await mcpWrite(ctx, "skills", "skill_uninstall", { name: args.join(" ") });
|
|
1903
2069
|
return { handled: true, output };
|
|
1904
2070
|
}
|
|
1905
|
-
|
|
2071
|
+
if (action === "help") {
|
|
2072
|
+
return { handled: true, output: [
|
|
2073
|
+
pc3.bold("Skills commands:"),
|
|
2074
|
+
` ${pc3.cyan("/skills")} View installed skills`,
|
|
2075
|
+
` ${pc3.cyan("/skills install")} <name> Install a skill`,
|
|
2076
|
+
` ${pc3.cyan("/skills uninstall")} <name> Uninstall a skill`
|
|
2077
|
+
].join("\n") };
|
|
2078
|
+
}
|
|
2079
|
+
return { handled: true, output: pc3.yellow(`Unknown action: /skills ${action}. Try /skills --help`) };
|
|
1906
2080
|
}
|
|
1907
2081
|
async function handleEvalCommand(action, args, ctx) {
|
|
1908
|
-
const home2 =
|
|
2082
|
+
const home2 = os9.homedir();
|
|
1909
2083
|
if (!action) {
|
|
1910
|
-
const content = readEcosystemFile(
|
|
2084
|
+
const content = readEcosystemFile(path9.join(home2, ".aeval", "eval.md"), "evaluation (aeval)");
|
|
1911
2085
|
return { handled: true, output: content };
|
|
1912
2086
|
}
|
|
1913
2087
|
if (action === "milestone") {
|
|
@@ -1922,98 +2096,208 @@ async function handleEvalCommand(action, args, ctx) {
|
|
|
1922
2096
|
}
|
|
1923
2097
|
async function handleMemoryCommand(action, args, ctx) {
|
|
1924
2098
|
if (!action) {
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
output: pc3.
|
|
1929
|
-
}
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
return { handled: true, output: pc3.red(result) };
|
|
2099
|
+
try {
|
|
2100
|
+
const result = await memoryContext("recent context");
|
|
2101
|
+
if (result.memoriesUsed === 0) {
|
|
2102
|
+
return { handled: true, output: pc3.dim("No memories yet. Start chatting and I'll remember what matters.") };
|
|
2103
|
+
}
|
|
2104
|
+
return { handled: true, output: result.text };
|
|
2105
|
+
} catch (err) {
|
|
2106
|
+
return { handled: true, output: pc3.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
1934
2107
|
}
|
|
1935
|
-
return { handled: true, output: result };
|
|
1936
2108
|
}
|
|
1937
|
-
if (action && !["search", "clear", "timeline"].includes(action)) {
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
return { handled: true, output:
|
|
2109
|
+
if (action && !["search", "clear", "timeline", "stats", "export", "since", "fts", "help"].includes(action)) {
|
|
2110
|
+
try {
|
|
2111
|
+
const topic = [action, ...args].join(" ");
|
|
2112
|
+
const result = await memoryContext(topic);
|
|
2113
|
+
if (result.memoriesUsed === 0) {
|
|
2114
|
+
return { handled: true, output: pc3.dim(`No memories found for: "${topic}".`) };
|
|
2115
|
+
}
|
|
2116
|
+
return { handled: true, output: result.text };
|
|
2117
|
+
} catch (err) {
|
|
2118
|
+
return { handled: true, output: pc3.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
1945
2119
|
}
|
|
1946
|
-
return { handled: true, output: result };
|
|
1947
2120
|
}
|
|
1948
2121
|
if (action === "search") {
|
|
1949
2122
|
if (args.length < 1) {
|
|
1950
2123
|
return { handled: true, output: pc3.yellow("Usage: /memory search <query...>") };
|
|
1951
2124
|
}
|
|
1952
2125
|
const query = args.join(" ");
|
|
1953
|
-
|
|
1954
|
-
|
|
2126
|
+
try {
|
|
2127
|
+
const result = await memoryRecall(query);
|
|
2128
|
+
return { handled: true, output: result.total === 0 ? pc3.dim("No memories found.") : result.text };
|
|
2129
|
+
} catch (err) {
|
|
2130
|
+
return { handled: true, output: pc3.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
2131
|
+
}
|
|
1955
2132
|
}
|
|
1956
2133
|
if (action === "clear") {
|
|
1957
2134
|
if (args.length < 1) {
|
|
1958
|
-
return { handled: true, output: pc3.yellow("Usage: /memory clear <
|
|
2135
|
+
return { handled: true, output: pc3.yellow("Usage: /memory clear <query> \u2014 delete memories matching a search query\n /memory clear --type <type> \u2014 delete all memories of a type (correction|decision|pattern|preference|topology|fact)") };
|
|
2136
|
+
}
|
|
2137
|
+
try {
|
|
2138
|
+
if (args[0] === "--type" && args[1]) {
|
|
2139
|
+
const result2 = await memoryForget({ query: args[1], type: args[1] });
|
|
2140
|
+
return { handled: true, output: result2.deleted > 0 ? pc3.green(result2.message) : pc3.dim(result2.message) };
|
|
2141
|
+
}
|
|
2142
|
+
const result = await memoryForget({ query: args.join(" ") });
|
|
2143
|
+
return { handled: true, output: result.deleted > 0 ? pc3.green(result.message) : pc3.dim(result.message) };
|
|
2144
|
+
} catch (err) {
|
|
2145
|
+
return { handled: true, output: pc3.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
1959
2146
|
}
|
|
1960
|
-
const output = await mcpWrite(ctx, "memory", "memory_forget", { category: args[0] });
|
|
1961
|
-
return { handled: true, output };
|
|
1962
2147
|
}
|
|
1963
2148
|
if (action === "timeline") {
|
|
1964
|
-
if (!ctx.mcpManager) {
|
|
1965
|
-
return { handled: true, output: pc3.red("Memory not available: MCP not connected.") };
|
|
1966
|
-
}
|
|
1967
2149
|
try {
|
|
1968
|
-
const result = await
|
|
1969
|
-
if (result.
|
|
2150
|
+
const result = await memoryRecall("*", { limit: 500, compact: false });
|
|
2151
|
+
if (result.total === 0) {
|
|
1970
2152
|
return { handled: true, output: pc3.dim("No memories yet. Start chatting and I'll remember what matters.") };
|
|
1971
2153
|
}
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
2154
|
+
const memories = result.memories;
|
|
2155
|
+
if (memories.length > 0) {
|
|
2156
|
+
const byDate = /* @__PURE__ */ new Map();
|
|
2157
|
+
for (const mem of memories) {
|
|
2158
|
+
const createdAt = mem.created_at;
|
|
2159
|
+
const date = createdAt ? new Date(createdAt).toLocaleDateString("en-US", { month: "short", day: "numeric" }) : "Unknown";
|
|
2160
|
+
byDate.set(date, (byDate.get(date) || 0) + 1);
|
|
2161
|
+
}
|
|
2162
|
+
const maxCount = Math.max(...byDate.values());
|
|
2163
|
+
const barWidth = 10;
|
|
2164
|
+
const lines = [pc3.bold("Memory Timeline:"), ""];
|
|
2165
|
+
for (const [date, count] of byDate) {
|
|
2166
|
+
const filled = Math.round(count / maxCount * barWidth);
|
|
2167
|
+
const bar = "\u2588".repeat(filled) + "\u2591".repeat(barWidth - filled);
|
|
2168
|
+
lines.push(` ${date.padEnd(8)} ${bar} ${count} memories`);
|
|
2169
|
+
}
|
|
2170
|
+
const tags = /* @__PURE__ */ new Map();
|
|
2171
|
+
for (const mem of memories) {
|
|
2172
|
+
const memTags = mem.tags;
|
|
2173
|
+
if (Array.isArray(memTags)) {
|
|
2174
|
+
for (const tag of memTags) {
|
|
2175
|
+
tags.set(tag, (tags.get(tag) || 0) + 1);
|
|
1994
2176
|
}
|
|
1995
2177
|
}
|
|
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
2178
|
}
|
|
2004
|
-
|
|
2179
|
+
lines.push("");
|
|
2180
|
+
lines.push(` Total: ${result.total} memories`);
|
|
2181
|
+
if (tags.size > 0) {
|
|
2182
|
+
const topTags = [...tags.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5).map(([tag, count]) => `#${tag} (${count})`).join(", ");
|
|
2183
|
+
lines.push(` Top tags: ${topTags}`);
|
|
2184
|
+
}
|
|
2185
|
+
return { handled: true, output: lines.join("\n") };
|
|
2005
2186
|
}
|
|
2006
|
-
|
|
2007
|
-
return { handled: true, output: `Total memories: ~${lineCount} entries.` };
|
|
2187
|
+
return { handled: true, output: `Total memories: ${result.total} entries.` };
|
|
2008
2188
|
} catch {
|
|
2009
2189
|
return { handled: true, output: pc3.red("Failed to retrieve memory timeline.") };
|
|
2010
2190
|
}
|
|
2011
2191
|
}
|
|
2012
|
-
|
|
2192
|
+
if (action === "stats") {
|
|
2193
|
+
try {
|
|
2194
|
+
const stats = memoryStats();
|
|
2195
|
+
const lines = [pc3.bold("Memory Statistics:"), ""];
|
|
2196
|
+
lines.push(` Total memories: ${pc3.bold(String(stats.total))}`);
|
|
2197
|
+
if (Object.keys(stats.byType).length > 0) {
|
|
2198
|
+
lines.push("");
|
|
2199
|
+
lines.push(` ${pc3.dim("By type:")}`);
|
|
2200
|
+
for (const [type, count] of Object.entries(stats.byType)) {
|
|
2201
|
+
lines.push(` ${type.padEnd(16)} ${count}`);
|
|
2202
|
+
}
|
|
2203
|
+
}
|
|
2204
|
+
return { handled: true, output: lines.join("\n") };
|
|
2205
|
+
} catch (err) {
|
|
2206
|
+
return { handled: true, output: pc3.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
if (action === "export") {
|
|
2210
|
+
try {
|
|
2211
|
+
const format = args[0] === "json" ? "json" : "markdown";
|
|
2212
|
+
const memories = memoryExport();
|
|
2213
|
+
if (memories.length === 0) {
|
|
2214
|
+
return { handled: true, output: pc3.dim("No memories to export.") };
|
|
2215
|
+
}
|
|
2216
|
+
if (format === "json") {
|
|
2217
|
+
const jsonOut = memories.map((m) => ({ id: m.id, type: m.type, content: m.content, tags: m.tags, confidence: m.confidence, createdAt: m.createdAt, tier: m.tier }));
|
|
2218
|
+
return { handled: true, output: JSON.stringify(jsonOut, null, 2) };
|
|
2219
|
+
}
|
|
2220
|
+
const lines = [`# Memory Export (${memories.length} memories)`, ""];
|
|
2221
|
+
for (const m of memories) {
|
|
2222
|
+
const date = new Date(m.createdAt).toLocaleDateString();
|
|
2223
|
+
const tags = m.tags.length > 0 ? ` [${m.tags.map((t) => `#${t}`).join(", ")}]` : "";
|
|
2224
|
+
lines.push(`- **[${m.type}]** ${m.content}${tags} ${pc3.dim(`(${date}, ${Math.round(m.confidence * 100)}%)`)}`);
|
|
2225
|
+
}
|
|
2226
|
+
return { handled: true, output: lines.join("\n") };
|
|
2227
|
+
} catch (err) {
|
|
2228
|
+
return { handled: true, output: pc3.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
if (action === "since") {
|
|
2232
|
+
try {
|
|
2233
|
+
let hours = 24;
|
|
2234
|
+
if (args[0]) {
|
|
2235
|
+
const match = args[0].match(/^(\d+)(h|d|w)$/);
|
|
2236
|
+
if (match) {
|
|
2237
|
+
const value = parseInt(match[1], 10);
|
|
2238
|
+
const unit = match[2];
|
|
2239
|
+
if (unit === "h") hours = value;
|
|
2240
|
+
else if (unit === "d") hours = value * 24;
|
|
2241
|
+
else if (unit === "w") hours = value * 24 * 7;
|
|
2242
|
+
} else {
|
|
2243
|
+
return { handled: true, output: pc3.yellow("Usage: /memory since <Nh|Nd|Nw> (e.g., 24h, 7d, 1w)") };
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
const memories = memorySince(hours);
|
|
2247
|
+
if (memories.length === 0) {
|
|
2248
|
+
return { handled: true, output: pc3.dim(`No memories in the last ${args[0] || "24h"}.`) };
|
|
2249
|
+
}
|
|
2250
|
+
const lines = [pc3.bold(`Memories since ${args[0] || "24h"} (${memories.length}):`), ""];
|
|
2251
|
+
for (const m of memories) {
|
|
2252
|
+
const age = Math.round((Date.now() - m.createdAt) / 36e5);
|
|
2253
|
+
const ageStr = age < 1 ? "<1h ago" : `${age}h ago`;
|
|
2254
|
+
lines.push(` ${pc3.dim(ageStr.padEnd(10))} [${m.type}] ${m.content}`);
|
|
2255
|
+
}
|
|
2256
|
+
return { handled: true, output: lines.join("\n") };
|
|
2257
|
+
} catch (err) {
|
|
2258
|
+
return { handled: true, output: pc3.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
if (action === "fts") {
|
|
2262
|
+
if (args.length < 1) {
|
|
2263
|
+
return { handled: true, output: pc3.yellow("Usage: /memory fts <query...> \u2014 full-text search") };
|
|
2264
|
+
}
|
|
2265
|
+
try {
|
|
2266
|
+
const query = args.join(" ");
|
|
2267
|
+
const results = memorySearch(query, 20);
|
|
2268
|
+
if (results.length === 0) {
|
|
2269
|
+
return { handled: true, output: pc3.dim(`No results for full-text search: "${query}".`) };
|
|
2270
|
+
}
|
|
2271
|
+
const lines = [pc3.bold(`FTS results for "${query}" (${results.length}):`), ""];
|
|
2272
|
+
for (const m of results) {
|
|
2273
|
+
const tags = m.tags.length > 0 ? ` ${pc3.dim(m.tags.map((t) => `#${t}`).join(" "))}` : "";
|
|
2274
|
+
lines.push(` [${m.type}] ${m.content}${tags}`);
|
|
2275
|
+
}
|
|
2276
|
+
return { handled: true, output: lines.join("\n") };
|
|
2277
|
+
} catch (err) {
|
|
2278
|
+
return { handled: true, output: pc3.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
if (action === "help") {
|
|
2282
|
+
return { handled: true, output: [
|
|
2283
|
+
pc3.bold("Memory commands:"),
|
|
2284
|
+
` ${pc3.cyan("/memory")} View recent context`,
|
|
2285
|
+
` ${pc3.cyan("/memory")} <topic> Context for a topic`,
|
|
2286
|
+
` ${pc3.cyan("/memory search")} <query> Search memories (semantic)`,
|
|
2287
|
+
` ${pc3.cyan("/memory fts")} <query> Full-text search (FTS5)`,
|
|
2288
|
+
` ${pc3.cyan("/memory since")} <Nh|Nd|Nw> Memories from time window`,
|
|
2289
|
+
` ${pc3.cyan("/memory stats")} Show memory statistics`,
|
|
2290
|
+
` ${pc3.cyan("/memory export")} [json] Export all memories`,
|
|
2291
|
+
` ${pc3.cyan("/memory timeline")} View memory timeline`,
|
|
2292
|
+
` ${pc3.cyan("/memory clear")} <query> Delete matching memories`,
|
|
2293
|
+
` ${pc3.cyan("/memory clear --type")} <type> Delete all of a type`
|
|
2294
|
+
].join("\n") };
|
|
2295
|
+
}
|
|
2296
|
+
return { handled: true, output: pc3.yellow(`Unknown action: /memory ${action}. Try /memory --help`) };
|
|
2013
2297
|
}
|
|
2014
2298
|
function handleStatusCommand(ctx) {
|
|
2015
2299
|
const mcpToolCount = ctx.mcpManager ? ctx.mcpManager.getTools().length : 0;
|
|
2016
|
-
const amemConnected =
|
|
2300
|
+
const amemConnected = isMemoryInitialized();
|
|
2017
2301
|
const status = getEcosystemStatus(mcpToolCount, amemConnected);
|
|
2018
2302
|
const lines = [pc3.bold("Aman Ecosystem Dashboard"), ""];
|
|
2019
2303
|
for (const layer of status.layers) {
|
|
@@ -2029,7 +2313,7 @@ function handleStatusCommand(ctx) {
|
|
|
2029
2313
|
}
|
|
2030
2314
|
function handleDoctorCommand(ctx) {
|
|
2031
2315
|
const mcpToolCount = ctx.mcpManager ? ctx.mcpManager.getTools().length : 0;
|
|
2032
|
-
const amemConnected =
|
|
2316
|
+
const amemConnected = isMemoryInitialized();
|
|
2033
2317
|
const status = getEcosystemStatus(mcpToolCount, amemConnected);
|
|
2034
2318
|
const lines = [pc3.bold("Aman Health Check"), ""];
|
|
2035
2319
|
let healthy = 0;
|
|
@@ -2063,7 +2347,7 @@ function handleDoctorCommand(ctx) {
|
|
|
2063
2347
|
}
|
|
2064
2348
|
lines.push(` ${status.amemConnected ? pc3.green("\u2713") : pc3.red("\u2717")} ${"Memory".padEnd(12)} ${status.amemConnected ? pc3.green("connected") : pc3.red("not connected")}`);
|
|
2065
2349
|
if (!status.amemConnected) {
|
|
2066
|
-
lines.push(` ${pc3.dim("\u2192 Fix:
|
|
2350
|
+
lines.push(` ${pc3.dim("\u2192 Fix: restart aman-agent (memory initializes automatically)")}`);
|
|
2067
2351
|
fixes++;
|
|
2068
2352
|
} else {
|
|
2069
2353
|
healthy++;
|
|
@@ -2085,7 +2369,8 @@ function handleHelp() {
|
|
|
2085
2369
|
` ${pc3.cyan("/akit")} Manage tools [add|remove <tool>]`,
|
|
2086
2370
|
` ${pc3.cyan("/skills")} View skills [install|uninstall ...]`,
|
|
2087
2371
|
` ${pc3.cyan("/eval")} View evaluation [milestone ...]`,
|
|
2088
|
-
` ${pc3.cyan("/memory")} View recent memories [search|clear|timeline]`,
|
|
2372
|
+
` ${pc3.cyan("/memory")} View recent memories [search|fts|since|stats|export|clear|timeline]`,
|
|
2373
|
+
` ${pc3.cyan("/reminder")} Manage reminders [set|check|done]`,
|
|
2089
2374
|
` ${pc3.cyan("/status")} Ecosystem dashboard`,
|
|
2090
2375
|
` ${pc3.cyan("/doctor")} Health check all layers`,
|
|
2091
2376
|
` ${pc3.cyan("/decisions")} View decision log [<project>]`,
|
|
@@ -2094,7 +2379,7 @@ function handleHelp() {
|
|
|
2094
2379
|
` ${pc3.cyan("/save")} Save conversation to memory`,
|
|
2095
2380
|
` ${pc3.cyan("/model")} Show current LLM model`,
|
|
2096
2381
|
` ${pc3.cyan("/update")} Check for updates`,
|
|
2097
|
-
` ${pc3.cyan("/
|
|
2382
|
+
` ${pc3.cyan("/reset")} Full reset [all|memory|config|identity|rules]`,
|
|
2098
2383
|
` ${pc3.cyan("/clear")} Clear conversation history`,
|
|
2099
2384
|
` ${pc3.cyan("/quit")} Exit`
|
|
2100
2385
|
].join("\n")
|
|
@@ -2103,27 +2388,62 @@ function handleHelp() {
|
|
|
2103
2388
|
function handleSave() {
|
|
2104
2389
|
return { handled: true, saveConversation: true };
|
|
2105
2390
|
}
|
|
2106
|
-
function
|
|
2107
|
-
const
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2391
|
+
function handleReset(action) {
|
|
2392
|
+
const dirs = {
|
|
2393
|
+
config: path9.join(os9.homedir(), ".aman-agent"),
|
|
2394
|
+
memory: path9.join(os9.homedir(), ".amem"),
|
|
2395
|
+
identity: path9.join(os9.homedir(), ".acore"),
|
|
2396
|
+
rules: path9.join(os9.homedir(), ".arules")
|
|
2397
|
+
};
|
|
2398
|
+
if (action === "help" || !action) {
|
|
2399
|
+
return {
|
|
2400
|
+
handled: true,
|
|
2401
|
+
output: [
|
|
2402
|
+
pc3.bold("Reset options:"),
|
|
2403
|
+
` ${pc3.cyan("/reset all")} Full reset \u2014 config, memory, identity, rules`,
|
|
2404
|
+
` ${pc3.cyan("/reset memory")} Clear all memories only`,
|
|
2405
|
+
` ${pc3.cyan("/reset config")} Reset LLM config only`,
|
|
2406
|
+
` ${pc3.cyan("/reset identity")} Reset persona/identity only`,
|
|
2407
|
+
` ${pc3.cyan("/reset rules")} Reset guardrails only`,
|
|
2408
|
+
"",
|
|
2409
|
+
pc3.dim("Directories:"),
|
|
2410
|
+
...Object.entries(dirs).map(([k, v]) => ` ${k}: ${pc3.dim(v)}`)
|
|
2411
|
+
].join("\n")
|
|
2412
|
+
};
|
|
2413
|
+
}
|
|
2414
|
+
const targets = action === "all" ? ["config", "memory", "identity", "rules"] : [action];
|
|
2415
|
+
if (!targets.every((t) => t in dirs)) {
|
|
2416
|
+
return { handled: true, output: pc3.red(`Unknown target: ${action}. Use /reset help`) };
|
|
2417
|
+
}
|
|
2418
|
+
const removed = [];
|
|
2419
|
+
for (const target of targets) {
|
|
2420
|
+
const dir = dirs[target];
|
|
2421
|
+
if (fs9.existsSync(dir)) {
|
|
2422
|
+
fs9.rmSync(dir, { recursive: true, force: true });
|
|
2423
|
+
removed.push(target);
|
|
2424
|
+
}
|
|
2425
|
+
}
|
|
2426
|
+
if (targets.includes("config")) {
|
|
2427
|
+
const configDir = dirs.config;
|
|
2428
|
+
fs9.mkdirSync(configDir, { recursive: true });
|
|
2429
|
+
fs9.writeFileSync(path9.join(configDir, ".reconfig"), "", "utf-8");
|
|
2430
|
+
}
|
|
2431
|
+
if (removed.length === 0) {
|
|
2432
|
+
return { handled: true, output: pc3.dim("Nothing to reset \u2014 directories don't exist.") };
|
|
2111
2433
|
}
|
|
2112
|
-
fs8.mkdirSync(configDir, { recursive: true });
|
|
2113
|
-
fs8.writeFileSync(path8.join(configDir, ".reconfig"), "", "utf-8");
|
|
2114
2434
|
return {
|
|
2115
2435
|
handled: true,
|
|
2116
2436
|
quit: true,
|
|
2117
2437
|
output: [
|
|
2118
|
-
pc3.green(
|
|
2119
|
-
"
|
|
2438
|
+
pc3.green(`Reset complete: ${removed.join(", ")}`),
|
|
2439
|
+
"Restart aman-agent to begin fresh."
|
|
2120
2440
|
].join("\n")
|
|
2121
2441
|
};
|
|
2122
2442
|
}
|
|
2123
2443
|
function handleUpdate() {
|
|
2124
2444
|
try {
|
|
2125
2445
|
const current = execFileSync("npm", ["view", "@aman_asmuei/aman-agent", "version"], { encoding: "utf-8" }).trim();
|
|
2126
|
-
const local = JSON.parse(
|
|
2446
|
+
const local = JSON.parse(fs9.readFileSync(path9.join(__dirname, "..", "package.json"), "utf-8")).version;
|
|
2127
2447
|
if (current === local) {
|
|
2128
2448
|
return { handled: true, output: `${pc3.green("Up to date")} \u2014 v${local}` };
|
|
2129
2449
|
}
|
|
@@ -2152,31 +2472,26 @@ function handleUpdate() {
|
|
|
2152
2472
|
};
|
|
2153
2473
|
}
|
|
2154
2474
|
}
|
|
2155
|
-
async function handleDecisionsCommand(action, _args,
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
...scope ? { scope } : {}
|
|
2165
|
-
});
|
|
2166
|
-
if (result.startsWith("Error")) {
|
|
2167
|
-
return { handled: true, output: pc3.red(result) };
|
|
2475
|
+
async function handleDecisionsCommand(action, _args, _ctx) {
|
|
2476
|
+
try {
|
|
2477
|
+
const result = await memoryRecall("decision", { type: "decision", limit: 20 });
|
|
2478
|
+
if (result.total === 0) {
|
|
2479
|
+
return { handled: true, output: pc3.dim("No decisions recorded yet.") };
|
|
2480
|
+
}
|
|
2481
|
+
return { handled: true, output: pc3.bold("Decision Log:\n") + result.text };
|
|
2482
|
+
} catch (err) {
|
|
2483
|
+
return { handled: true, output: pc3.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
2168
2484
|
}
|
|
2169
|
-
return { handled: true, output: pc3.bold("Decision Log:\n") + result };
|
|
2170
2485
|
}
|
|
2171
2486
|
function handleExportCommand() {
|
|
2172
2487
|
return { handled: true, exportConversation: true };
|
|
2173
2488
|
}
|
|
2174
2489
|
function handleDebugCommand() {
|
|
2175
|
-
const logPath =
|
|
2176
|
-
if (!
|
|
2490
|
+
const logPath = path9.join(os9.homedir(), ".aman-agent", "debug.log");
|
|
2491
|
+
if (!fs9.existsSync(logPath)) {
|
|
2177
2492
|
return { handled: true, output: pc3.dim("No debug log found.") };
|
|
2178
2493
|
}
|
|
2179
|
-
const content =
|
|
2494
|
+
const content = fs9.readFileSync(logPath, "utf-8");
|
|
2180
2495
|
const lines = content.trim().split("\n");
|
|
2181
2496
|
const last20 = lines.slice(-20).join("\n");
|
|
2182
2497
|
return { handled: true, output: pc3.bold("Debug Log (last 20 entries):\n") + pc3.dim(last20) };
|
|
@@ -2374,7 +2689,7 @@ ${result.response}`
|
|
|
2374
2689
|
};
|
|
2375
2690
|
}
|
|
2376
2691
|
function handleProfileCommand(action, args) {
|
|
2377
|
-
const profilesDir =
|
|
2692
|
+
const profilesDir = path9.join(os9.homedir(), ".acore", "profiles");
|
|
2378
2693
|
if (!action || action === "list") {
|
|
2379
2694
|
const profiles = listProfiles();
|
|
2380
2695
|
if (profiles.length === 0) {
|
|
@@ -2398,8 +2713,8 @@ function handleProfileCommand(action, args) {
|
|
|
2398
2713
|
};
|
|
2399
2714
|
}
|
|
2400
2715
|
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
2401
|
-
const profileDir =
|
|
2402
|
-
if (
|
|
2716
|
+
const profileDir = path9.join(profilesDir, slug);
|
|
2717
|
+
if (fs9.existsSync(profileDir)) {
|
|
2403
2718
|
return { handled: true, output: pc3.yellow(`Profile already exists: ${slug}`) };
|
|
2404
2719
|
}
|
|
2405
2720
|
const builtIn = BUILT_IN_PROFILES.find((t) => t.name === slug);
|
|
@@ -2415,16 +2730,16 @@ function handleProfileCommand(action, args) {
|
|
|
2415
2730
|
Use: aman-agent --profile ${slug}`
|
|
2416
2731
|
};
|
|
2417
2732
|
}
|
|
2418
|
-
|
|
2419
|
-
const globalCore =
|
|
2420
|
-
if (
|
|
2421
|
-
let content =
|
|
2733
|
+
fs9.mkdirSync(profileDir, { recursive: true });
|
|
2734
|
+
const globalCore = path9.join(os9.homedir(), ".acore", "core.md");
|
|
2735
|
+
if (fs9.existsSync(globalCore)) {
|
|
2736
|
+
let content = fs9.readFileSync(globalCore, "utf-8");
|
|
2422
2737
|
const aiName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
2423
2738
|
content = content.replace(/^# .+$/m, `# ${aiName}`);
|
|
2424
|
-
|
|
2739
|
+
fs9.writeFileSync(path9.join(profileDir, "core.md"), content, "utf-8");
|
|
2425
2740
|
} else {
|
|
2426
2741
|
const aiName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
2427
|
-
|
|
2742
|
+
fs9.writeFileSync(path9.join(profileDir, "core.md"), `# ${aiName}
|
|
2428
2743
|
|
|
2429
2744
|
## Identity
|
|
2430
2745
|
- Role: ${aiName} is your AI companion
|
|
@@ -2437,7 +2752,7 @@ function handleProfileCommand(action, args) {
|
|
|
2437
2752
|
return {
|
|
2438
2753
|
handled: true,
|
|
2439
2754
|
output: pc3.green(`Profile created: ${slug}`) + `
|
|
2440
|
-
Edit: ${
|
|
2755
|
+
Edit: ${path9.join(profileDir, "core.md")}
|
|
2441
2756
|
Use: aman-agent --profile ${slug}
|
|
2442
2757
|
|
|
2443
2758
|
${pc3.dim("Add rules.md or skills.md for profile-specific overrides.")}`
|
|
@@ -2446,9 +2761,9 @@ function handleProfileCommand(action, args) {
|
|
|
2446
2761
|
case "show": {
|
|
2447
2762
|
const name = args[0];
|
|
2448
2763
|
if (!name) return { handled: true, output: pc3.yellow("Usage: /profile show <name>") };
|
|
2449
|
-
const profileDir =
|
|
2450
|
-
if (!
|
|
2451
|
-
const files =
|
|
2764
|
+
const profileDir = path9.join(profilesDir, name);
|
|
2765
|
+
if (!fs9.existsSync(profileDir)) return { handled: true, output: pc3.red(`Profile not found: ${name}`) };
|
|
2766
|
+
const files = fs9.readdirSync(profileDir).filter((f) => f.endsWith(".md"));
|
|
2452
2767
|
const lines = files.map((f) => ` ${f}`);
|
|
2453
2768
|
return { handled: true, output: `Profile: ${pc3.bold(name)}
|
|
2454
2769
|
Files:
|
|
@@ -2457,9 +2772,9 @@ ${lines.join("\n")}` };
|
|
|
2457
2772
|
case "delete": {
|
|
2458
2773
|
const name = args[0];
|
|
2459
2774
|
if (!name) return { handled: true, output: pc3.yellow("Usage: /profile delete <name>") };
|
|
2460
|
-
const profileDir =
|
|
2461
|
-
if (!
|
|
2462
|
-
|
|
2775
|
+
const profileDir = path9.join(profilesDir, name);
|
|
2776
|
+
if (!fs9.existsSync(profileDir)) return { handled: true, output: pc3.red(`Profile not found: ${name}`) };
|
|
2777
|
+
fs9.rmSync(profileDir, { recursive: true });
|
|
2463
2778
|
return { handled: true, output: pc3.dim(`Profile deleted: ${name}`) };
|
|
2464
2779
|
}
|
|
2465
2780
|
case "help":
|
|
@@ -2566,6 +2881,86 @@ function handlePlanCommand(action, args) {
|
|
|
2566
2881
|
return { handled: true, output: pc3.yellow(`Unknown plan action: ${action}. Try /plan help`) };
|
|
2567
2882
|
}
|
|
2568
2883
|
}
|
|
2884
|
+
async function handleReminderCommand(action, args) {
|
|
2885
|
+
if (!action || action === "list") {
|
|
2886
|
+
try {
|
|
2887
|
+
const reminders = reminderList();
|
|
2888
|
+
if (reminders.length === 0) return { handled: true, output: pc3.dim("No reminders.") };
|
|
2889
|
+
const lines = [pc3.bold(`Reminders (${reminders.length}):`), ""];
|
|
2890
|
+
for (const r of reminders) {
|
|
2891
|
+
const status = r.completed ? pc3.green("[done]") : pc3.yellow("[todo]");
|
|
2892
|
+
const due = r.dueAt ? ` ${pc3.dim(`due: ${new Date(r.dueAt).toLocaleString()}`)}` : "";
|
|
2893
|
+
lines.push(` ${status} ${r.content}${due} ${pc3.dim(`(${r.id.slice(0, 8)})`)}`);
|
|
2894
|
+
}
|
|
2895
|
+
return { handled: true, output: lines.join("\n") };
|
|
2896
|
+
} catch (err) {
|
|
2897
|
+
return { handled: true, output: pc3.red(`Reminder error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
2898
|
+
}
|
|
2899
|
+
}
|
|
2900
|
+
if (action === "set" || action === "add") {
|
|
2901
|
+
if (args.length === 0) return { handled: true, output: pc3.yellow("Usage: /reminder set <text> [--due <time>]\n Time formats: 1h, 2d, 1w, or ISO date (2026-04-10)") };
|
|
2902
|
+
let dueAt;
|
|
2903
|
+
const dueIdx = args.indexOf("--due");
|
|
2904
|
+
let contentArgs = args;
|
|
2905
|
+
if (dueIdx >= 0 && args[dueIdx + 1]) {
|
|
2906
|
+
const dueStr = args[dueIdx + 1];
|
|
2907
|
+
contentArgs = [...args.slice(0, dueIdx), ...args.slice(dueIdx + 2)];
|
|
2908
|
+
const relMatch = dueStr.match(/^(\d+)(h|d|w)$/);
|
|
2909
|
+
if (relMatch) {
|
|
2910
|
+
const num = parseInt(relMatch[1], 10);
|
|
2911
|
+
const unit = relMatch[2];
|
|
2912
|
+
const ms = unit === "h" ? num * 36e5 : unit === "d" ? num * 864e5 : num * 6048e5;
|
|
2913
|
+
dueAt = Date.now() + ms;
|
|
2914
|
+
} else {
|
|
2915
|
+
const parsed = Date.parse(dueStr);
|
|
2916
|
+
if (!isNaN(parsed)) dueAt = parsed;
|
|
2917
|
+
}
|
|
2918
|
+
}
|
|
2919
|
+
const content = contentArgs.join(" ");
|
|
2920
|
+
if (!content) return { handled: true, output: pc3.yellow("Usage: /reminder set <text> [--due <time>]") };
|
|
2921
|
+
try {
|
|
2922
|
+
const id = reminderSet(content, dueAt);
|
|
2923
|
+
const dueInfo = dueAt ? ` (due: ${new Date(dueAt).toLocaleDateString()})` : "";
|
|
2924
|
+
return { handled: true, output: pc3.green(`Reminder set: "${content}"${dueInfo} (ID: ${id.slice(0, 8)})`) };
|
|
2925
|
+
} catch (err) {
|
|
2926
|
+
return { handled: true, output: pc3.red(`Reminder error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2929
|
+
if (action === "done" || action === "complete") {
|
|
2930
|
+
if (!args[0]) return { handled: true, output: pc3.yellow("Usage: /reminder done <id>") };
|
|
2931
|
+
try {
|
|
2932
|
+
const result = reminderComplete(args[0]);
|
|
2933
|
+
return { handled: true, output: result ? pc3.green("Reminder completed.") : pc3.yellow("Reminder not found.") };
|
|
2934
|
+
} catch (err) {
|
|
2935
|
+
return { handled: true, output: pc3.red(`Reminder error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
2936
|
+
}
|
|
2937
|
+
}
|
|
2938
|
+
if (action === "check") {
|
|
2939
|
+
try {
|
|
2940
|
+
const reminders = reminderCheck();
|
|
2941
|
+
if (reminders.length === 0) return { handled: true, output: pc3.dim("No pending reminders.") };
|
|
2942
|
+
const lines = [pc3.bold("Pending Reminders:"), ""];
|
|
2943
|
+
for (const r of reminders) {
|
|
2944
|
+
const icon = r.status === "overdue" ? pc3.red("!!!") : r.status === "today" ? pc3.yellow("(!)") : pc3.dim("( )");
|
|
2945
|
+
const due = r.dueAt ? ` ${pc3.dim(`due: ${new Date(r.dueAt).toLocaleString()}`)}` : "";
|
|
2946
|
+
lines.push(` ${icon} ${r.content}${due} ${pc3.dim(`[${r.status}]`)}`);
|
|
2947
|
+
}
|
|
2948
|
+
return { handled: true, output: lines.join("\n") };
|
|
2949
|
+
} catch (err) {
|
|
2950
|
+
return { handled: true, output: pc3.red(`Reminder error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
2951
|
+
}
|
|
2952
|
+
}
|
|
2953
|
+
if (action === "help") {
|
|
2954
|
+
return { handled: true, output: [
|
|
2955
|
+
pc3.bold("Reminder commands:"),
|
|
2956
|
+
` ${pc3.cyan("/reminder")} List all reminders`,
|
|
2957
|
+
` ${pc3.cyan("/reminder set")} <text> Create a reminder [--due 1h|2d|1w|date]`,
|
|
2958
|
+
` ${pc3.cyan("/reminder check")} Show overdue/upcoming`,
|
|
2959
|
+
` ${pc3.cyan("/reminder done")} <id> Mark as completed`
|
|
2960
|
+
].join("\n") };
|
|
2961
|
+
}
|
|
2962
|
+
return { handled: true, output: pc3.yellow(`Unknown action: /reminder ${action}. Try /reminder --help`) };
|
|
2963
|
+
}
|
|
2569
2964
|
var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
|
|
2570
2965
|
"quit",
|
|
2571
2966
|
"exit",
|
|
@@ -2587,8 +2982,8 @@ var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
2587
2982
|
"decisions",
|
|
2588
2983
|
"export",
|
|
2589
2984
|
"debug",
|
|
2590
|
-
"
|
|
2591
|
-
"
|
|
2985
|
+
"reset",
|
|
2986
|
+
"reminder",
|
|
2592
2987
|
"update",
|
|
2593
2988
|
"upgrade",
|
|
2594
2989
|
"plan",
|
|
@@ -2639,9 +3034,8 @@ async function handleCommand(input, ctx) {
|
|
|
2639
3034
|
return handleExportCommand();
|
|
2640
3035
|
case "debug":
|
|
2641
3036
|
return handleDebugCommand();
|
|
2642
|
-
case "
|
|
2643
|
-
|
|
2644
|
-
return handleReconfig();
|
|
3037
|
+
case "reset":
|
|
3038
|
+
return handleReset(action);
|
|
2645
3039
|
case "plan":
|
|
2646
3040
|
return handlePlanCommand(action, args);
|
|
2647
3041
|
case "profile":
|
|
@@ -2650,6 +3044,8 @@ async function handleCommand(input, ctx) {
|
|
|
2650
3044
|
return handleDelegateCommand(action, args, ctx);
|
|
2651
3045
|
case "team":
|
|
2652
3046
|
return handleTeamCommand(action, args, ctx);
|
|
3047
|
+
case "reminder":
|
|
3048
|
+
return handleReminderCommand(action, args);
|
|
2653
3049
|
case "update":
|
|
2654
3050
|
case "upgrade":
|
|
2655
3051
|
return handleUpdate();
|
|
@@ -2661,8 +3057,8 @@ async function handleCommand(input, ctx) {
|
|
|
2661
3057
|
// src/hooks.ts
|
|
2662
3058
|
import pc4 from "picocolors";
|
|
2663
3059
|
import * as p from "@clack/prompts";
|
|
2664
|
-
import
|
|
2665
|
-
import
|
|
3060
|
+
import fs10 from "fs";
|
|
3061
|
+
import path10 from "path";
|
|
2666
3062
|
|
|
2667
3063
|
// src/personality.ts
|
|
2668
3064
|
var FRUSTRATION_SIGNALS = [
|
|
@@ -2865,16 +3261,18 @@ async function onSessionStart(ctx) {
|
|
|
2865
3261
|
let firstRun = false;
|
|
2866
3262
|
let resumeTopic;
|
|
2867
3263
|
const visibleReminders = [];
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
3264
|
+
if (!isMemoryInitialized()) {
|
|
3265
|
+
firstRun = false;
|
|
3266
|
+
} else {
|
|
3267
|
+
try {
|
|
3268
|
+
isHookCall = true;
|
|
3269
|
+
const recallResult = await memoryRecall("*", { limit: 1 });
|
|
3270
|
+
firstRun = recallResult.total === 0;
|
|
3271
|
+
} catch {
|
|
2872
3272
|
firstRun = true;
|
|
3273
|
+
} finally {
|
|
3274
|
+
isHookCall = false;
|
|
2873
3275
|
}
|
|
2874
|
-
} catch {
|
|
2875
|
-
firstRun = true;
|
|
2876
|
-
} finally {
|
|
2877
|
-
isHookCall = false;
|
|
2878
3276
|
}
|
|
2879
3277
|
if (firstRun) {
|
|
2880
3278
|
contextInjection = `<first-session>
|
|
@@ -2900,9 +3298,9 @@ ${contextInjection}`;
|
|
|
2900
3298
|
if (ctx.config.memoryRecall) {
|
|
2901
3299
|
try {
|
|
2902
3300
|
isHookCall = true;
|
|
2903
|
-
const
|
|
2904
|
-
if (
|
|
2905
|
-
greeting +=
|
|
3301
|
+
const contextResult = await memoryContext("session context");
|
|
3302
|
+
if (contextResult.memoriesUsed > 0) {
|
|
3303
|
+
greeting += contextResult.text;
|
|
2906
3304
|
}
|
|
2907
3305
|
} catch (err) {
|
|
2908
3306
|
log.warn("hooks", "memory_context recall failed", err);
|
|
@@ -2933,12 +3331,12 @@ ${contextInjection}`;
|
|
|
2933
3331
|
else greeting = timeContext;
|
|
2934
3332
|
try {
|
|
2935
3333
|
isHookCall = true;
|
|
2936
|
-
const
|
|
2937
|
-
if (
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
for (const
|
|
2941
|
-
visibleReminders.push(
|
|
3334
|
+
const reminders = reminderCheck();
|
|
3335
|
+
if (reminders.length > 0) {
|
|
3336
|
+
const reminderText = reminders.map((r) => r.content).join("\n");
|
|
3337
|
+
greeting += "\n\n<pending-reminders>\n" + reminderText + "\n</pending-reminders>";
|
|
3338
|
+
for (const r of reminders) {
|
|
3339
|
+
visibleReminders.push(r.content);
|
|
2942
3340
|
}
|
|
2943
3341
|
}
|
|
2944
3342
|
} catch (err) {
|
|
@@ -3053,11 +3451,7 @@ async function onSessionEnd(ctx, messages, sessionId) {
|
|
|
3053
3451
|
for (const msg of textMessages) {
|
|
3054
3452
|
try {
|
|
3055
3453
|
isHookCall = true;
|
|
3056
|
-
|
|
3057
|
-
session_id: sessionId,
|
|
3058
|
-
role: msg.role,
|
|
3059
|
-
content: msg.content.slice(0, 5e3)
|
|
3060
|
-
});
|
|
3454
|
+
memoryLog(sessionId, msg.role, msg.content.slice(0, 5e3));
|
|
3061
3455
|
} catch (err) {
|
|
3062
3456
|
log.debug("hooks", "memory_log write failed for " + sessionId, err);
|
|
3063
3457
|
} finally {
|
|
@@ -3085,10 +3479,10 @@ async function onSessionEnd(ctx, messages, sessionId) {
|
|
|
3085
3479
|
}
|
|
3086
3480
|
console.log(pc4.dim(` Saved ${textMessages.length} messages (session: ${sessionId})`));
|
|
3087
3481
|
}
|
|
3088
|
-
const projectContextPath =
|
|
3089
|
-
if (
|
|
3482
|
+
const projectContextPath = path10.join(process.cwd(), ".acore", "context.md");
|
|
3483
|
+
if (fs10.existsSync(projectContextPath) && messages.length > 2) {
|
|
3090
3484
|
try {
|
|
3091
|
-
let contextContent =
|
|
3485
|
+
let contextContent = fs10.readFileSync(projectContextPath, "utf-8");
|
|
3092
3486
|
const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
3093
3487
|
let lastUserMsg = "";
|
|
3094
3488
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
@@ -3106,7 +3500,7 @@ async function onSessionEnd(ctx, messages, sessionId) {
|
|
|
3106
3500
|
- Recent decisions: [see memory]
|
|
3107
3501
|
- Temp notes: [cleared]`;
|
|
3108
3502
|
contextContent = contextContent.replace(sessionPattern, newSession);
|
|
3109
|
-
|
|
3503
|
+
fs10.writeFileSync(projectContextPath, contextContent, "utf-8");
|
|
3110
3504
|
log.debug("hooks", `Updated project context: ${projectContextPath}`);
|
|
3111
3505
|
}
|
|
3112
3506
|
} catch (err) {
|
|
@@ -3236,9 +3630,9 @@ ${summaryParts.slice(0, 20).join("\n")}
|
|
|
3236
3630
|
}
|
|
3237
3631
|
|
|
3238
3632
|
// src/skill-engine.ts
|
|
3239
|
-
import
|
|
3240
|
-
import
|
|
3241
|
-
import
|
|
3633
|
+
import fs11 from "fs";
|
|
3634
|
+
import path11 from "path";
|
|
3635
|
+
import os10 from "os";
|
|
3242
3636
|
var SKILL_TRIGGERS = {
|
|
3243
3637
|
testing: ["test", "spec", "coverage", "tdd", "jest", "vitest", "mocha", "assert", "mock", "stub", "fixture", "e2e", "integration test", "unit test"],
|
|
3244
3638
|
"api-design": ["api", "endpoint", "rest", "graphql", "route", "controller", "middleware", "http", "request", "response", "status code", "pagination"],
|
|
@@ -3253,20 +3647,20 @@ var SKILL_TRIGGERS = {
|
|
|
3253
3647
|
typescript: ["typescript", "type", "interface", "generic", "infer", "utility type", "zod", "discriminated union", "type guard", "as const"],
|
|
3254
3648
|
accessibility: ["accessibility", "a11y", "aria", "screen reader", "wcag", "semantic html", "tab order", "focus", "contrast"]
|
|
3255
3649
|
};
|
|
3256
|
-
var LEVEL_FILE =
|
|
3650
|
+
var LEVEL_FILE = path11.join(os10.homedir(), ".aman-agent", "skill-levels.json");
|
|
3257
3651
|
function loadSkillLevels() {
|
|
3258
3652
|
try {
|
|
3259
|
-
if (
|
|
3260
|
-
return JSON.parse(
|
|
3653
|
+
if (fs11.existsSync(LEVEL_FILE)) {
|
|
3654
|
+
return JSON.parse(fs11.readFileSync(LEVEL_FILE, "utf-8"));
|
|
3261
3655
|
}
|
|
3262
3656
|
} catch {
|
|
3263
3657
|
}
|
|
3264
3658
|
return {};
|
|
3265
3659
|
}
|
|
3266
3660
|
function saveSkillLevels(levels) {
|
|
3267
|
-
const dir =
|
|
3268
|
-
if (!
|
|
3269
|
-
|
|
3661
|
+
const dir = path11.dirname(LEVEL_FILE);
|
|
3662
|
+
if (!fs11.existsSync(dir)) fs11.mkdirSync(dir, { recursive: true });
|
|
3663
|
+
fs11.writeFileSync(LEVEL_FILE, JSON.stringify(levels, null, 2), "utf-8");
|
|
3270
3664
|
}
|
|
3271
3665
|
function computeLevel(activations) {
|
|
3272
3666
|
if (activations >= 50) return { level: 5, label: "Expert" };
|
|
@@ -3644,7 +4038,7 @@ function parseExtractionResult(raw) {
|
|
|
3644
4038
|
return [];
|
|
3645
4039
|
}
|
|
3646
4040
|
}
|
|
3647
|
-
async function extractMemories(userMessage, assistantResponse, client,
|
|
4041
|
+
async function extractMemories(userMessage, assistantResponse, client, state) {
|
|
3648
4042
|
if (!shouldExtract(assistantResponse, state.turnsSinceLastExtraction, state.lastExtractionCount)) {
|
|
3649
4043
|
state.turnsSinceLastExtraction++;
|
|
3650
4044
|
return 0;
|
|
@@ -3668,24 +4062,18 @@ Assistant: ${assistantResponse.slice(0, 2e3)}`;
|
|
|
3668
4062
|
let stored = 0;
|
|
3669
4063
|
for (const candidate of candidates) {
|
|
3670
4064
|
try {
|
|
3671
|
-
const existing = await
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
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 {
|
|
4065
|
+
const existing = await memoryRecall(candidate.content, { limit: 1 });
|
|
4066
|
+
if (existing.total > 0 && existing.memories.length > 0) {
|
|
4067
|
+
const topScore = existing.memories[0]?.score;
|
|
4068
|
+
if (topScore && topScore > 0.85) {
|
|
4069
|
+
log.debug("extractor", "Skipping duplicate: " + candidate.content);
|
|
4070
|
+
continue;
|
|
3683
4071
|
}
|
|
3684
4072
|
}
|
|
3685
4073
|
} catch {
|
|
3686
4074
|
}
|
|
3687
4075
|
try {
|
|
3688
|
-
await
|
|
4076
|
+
await memoryStore({
|
|
3689
4077
|
content: candidate.content,
|
|
3690
4078
|
type: candidate.type,
|
|
3691
4079
|
tags: candidate.tags,
|
|
@@ -3858,7 +4246,7 @@ var BackgroundTaskManager = class {
|
|
|
3858
4246
|
// src/errors.ts
|
|
3859
4247
|
var ERROR_MAPPINGS = [
|
|
3860
4248
|
{ pattern: /rate.?limit|429/i, message: "Rate limited. I'll retry automatically." },
|
|
3861
|
-
{ pattern: /401|unauthorized/i, message: "API key invalid. Run /
|
|
4249
|
+
{ pattern: /401|unauthorized/i, message: "API key invalid. Run /reset config to fix." },
|
|
3862
4250
|
{ pattern: /403|forbidden/i, message: "API key doesn't have access to this model. Try a different model with --model." },
|
|
3863
4251
|
{ pattern: /fetch failed|network/i, message: "Network error. Check your internet connection." },
|
|
3864
4252
|
{ pattern: /ECONNREFUSED/i, message: "Can't reach the API. Are you behind a proxy or firewall?" },
|
|
@@ -3876,9 +4264,9 @@ function humanizeError(message) {
|
|
|
3876
4264
|
}
|
|
3877
4265
|
|
|
3878
4266
|
// src/hints.ts
|
|
3879
|
-
import
|
|
3880
|
-
import
|
|
3881
|
-
import
|
|
4267
|
+
import fs12 from "fs";
|
|
4268
|
+
import path12 from "path";
|
|
4269
|
+
import os11 from "os";
|
|
3882
4270
|
var HINTS = [
|
|
3883
4271
|
{
|
|
3884
4272
|
id: "eval",
|
|
@@ -3916,11 +4304,11 @@ function getHint(state, ctx) {
|
|
|
3916
4304
|
}
|
|
3917
4305
|
return null;
|
|
3918
4306
|
}
|
|
3919
|
-
var HINTS_FILE =
|
|
4307
|
+
var HINTS_FILE = path12.join(os11.homedir(), ".aman-agent", "hints-seen.json");
|
|
3920
4308
|
function loadShownHints() {
|
|
3921
4309
|
try {
|
|
3922
|
-
if (
|
|
3923
|
-
const data = JSON.parse(
|
|
4310
|
+
if (fs12.existsSync(HINTS_FILE)) {
|
|
4311
|
+
const data = JSON.parse(fs12.readFileSync(HINTS_FILE, "utf-8"));
|
|
3924
4312
|
return new Set(Array.isArray(data) ? data : []);
|
|
3925
4313
|
}
|
|
3926
4314
|
} catch {
|
|
@@ -3929,31 +4317,27 @@ function loadShownHints() {
|
|
|
3929
4317
|
}
|
|
3930
4318
|
function saveShownHints(shown) {
|
|
3931
4319
|
try {
|
|
3932
|
-
const dir =
|
|
3933
|
-
|
|
3934
|
-
|
|
4320
|
+
const dir = path12.dirname(HINTS_FILE);
|
|
4321
|
+
fs12.mkdirSync(dir, { recursive: true });
|
|
4322
|
+
fs12.writeFileSync(HINTS_FILE, JSON.stringify([...shown]), "utf-8");
|
|
3935
4323
|
} catch {
|
|
3936
4324
|
}
|
|
3937
4325
|
}
|
|
3938
4326
|
|
|
3939
4327
|
// src/agent.ts
|
|
3940
4328
|
marked.use(markedTerminal());
|
|
3941
|
-
async function recallForMessage(input
|
|
4329
|
+
async function recallForMessage(input) {
|
|
3942
4330
|
try {
|
|
3943
|
-
const result = await
|
|
3944
|
-
|
|
3945
|
-
limit: 5,
|
|
3946
|
-
compact: true
|
|
3947
|
-
});
|
|
3948
|
-
if (!result || result.startsWith("Error") || result.includes("No memories found")) {
|
|
4331
|
+
const result = await memoryRecall(input, { limit: 5, compact: true });
|
|
4332
|
+
if (result.total === 0) {
|
|
3949
4333
|
return null;
|
|
3950
4334
|
}
|
|
3951
|
-
const tokenEstimate = Math.round(result.split(/\s+/).filter(Boolean).length * 1.3);
|
|
4335
|
+
const tokenEstimate = result.tokenEstimate ?? Math.round(result.text.split(/\s+/).filter(Boolean).length * 1.3);
|
|
3952
4336
|
return {
|
|
3953
4337
|
text: `
|
|
3954
4338
|
|
|
3955
4339
|
<relevant-memories>
|
|
3956
|
-
${result}
|
|
4340
|
+
${result.text}
|
|
3957
4341
|
</relevant-memories>`,
|
|
3958
4342
|
tokenEstimate
|
|
3959
4343
|
};
|
|
@@ -4124,9 +4508,9 @@ Type a message, ${pc6.dim("/help")} for commands, or ${pc6.dim("/quit")} to exit
|
|
|
4124
4508
|
}
|
|
4125
4509
|
if (cmdResult.exportConversation) {
|
|
4126
4510
|
try {
|
|
4127
|
-
const exportDir =
|
|
4128
|
-
|
|
4129
|
-
const exportPath =
|
|
4511
|
+
const exportDir = path13.join(os12.homedir(), ".aman-agent", "exports");
|
|
4512
|
+
fs13.mkdirSync(exportDir, { recursive: true });
|
|
4513
|
+
const exportPath = path13.join(exportDir, `${sessionId}.md`);
|
|
4130
4514
|
const lines = [
|
|
4131
4515
|
`# Conversation \u2014 ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
|
|
4132
4516
|
`**Model:** ${model}`,
|
|
@@ -4140,16 +4524,16 @@ Type a message, ${pc6.dim("/help")} for commands, or ${pc6.dim("/quit")} to exit
|
|
|
4140
4524
|
lines.push(`${label} ${msg.content}`, "");
|
|
4141
4525
|
}
|
|
4142
4526
|
}
|
|
4143
|
-
|
|
4527
|
+
fs13.writeFileSync(exportPath, lines.join("\n"), "utf-8");
|
|
4144
4528
|
console.log(pc6.green(`Exported to ${exportPath}`));
|
|
4145
4529
|
} catch {
|
|
4146
4530
|
console.log(pc6.red("Failed to export conversation."));
|
|
4147
4531
|
}
|
|
4148
4532
|
continue;
|
|
4149
4533
|
}
|
|
4150
|
-
if (cmdResult.saveConversation
|
|
4534
|
+
if (cmdResult.saveConversation) {
|
|
4151
4535
|
try {
|
|
4152
|
-
await saveConversationToMemory(
|
|
4536
|
+
await saveConversationToMemory(messages, sessionId);
|
|
4153
4537
|
console.log(pc6.green("Conversation saved to memory."));
|
|
4154
4538
|
} catch {
|
|
4155
4539
|
console.log(pc6.red("Failed to save conversation."));
|
|
@@ -4266,25 +4650,25 @@ ${knowledgeItem.content}
|
|
|
4266
4650
|
for (const match of filePathMatches) {
|
|
4267
4651
|
let filePath = match[1];
|
|
4268
4652
|
if (filePath.startsWith("~/")) {
|
|
4269
|
-
filePath =
|
|
4653
|
+
filePath = path13.join(os12.homedir(), filePath.slice(2));
|
|
4270
4654
|
}
|
|
4271
|
-
if (!
|
|
4272
|
-
const ext =
|
|
4655
|
+
if (!fs13.existsSync(filePath) || !fs13.statSync(filePath).isFile()) continue;
|
|
4656
|
+
const ext = path13.extname(filePath).toLowerCase();
|
|
4273
4657
|
if (imageExts.has(ext)) {
|
|
4274
4658
|
try {
|
|
4275
|
-
const stat =
|
|
4659
|
+
const stat = fs13.statSync(filePath);
|
|
4276
4660
|
if (stat.size > maxImageBytes) {
|
|
4277
|
-
process.stdout.write(pc6.yellow(` [skipped: ${
|
|
4661
|
+
process.stdout.write(pc6.yellow(` [skipped: ${path13.basename(filePath)} \u2014 exceeds 20MB limit]
|
|
4278
4662
|
`));
|
|
4279
4663
|
continue;
|
|
4280
4664
|
}
|
|
4281
|
-
const data =
|
|
4665
|
+
const data = fs13.readFileSync(filePath).toString("base64");
|
|
4282
4666
|
const mediaType = mimeMap[ext] || "image/png";
|
|
4283
4667
|
imageBlocks.push({
|
|
4284
4668
|
type: "image",
|
|
4285
4669
|
source: { type: "base64", media_type: mediaType, data }
|
|
4286
4670
|
});
|
|
4287
|
-
process.stdout.write(pc6.dim(` [attached image: ${
|
|
4671
|
+
process.stdout.write(pc6.dim(` [attached image: ${path13.basename(filePath)} (${(stat.size / 1024).toFixed(1)}KB)]
|
|
4288
4672
|
`));
|
|
4289
4673
|
} catch {
|
|
4290
4674
|
process.stdout.write(pc6.dim(` [could not read image: ${filePath}]
|
|
@@ -4292,7 +4676,7 @@ ${knowledgeItem.content}
|
|
|
4292
4676
|
}
|
|
4293
4677
|
} else if (textExts.has(ext) || ext === "") {
|
|
4294
4678
|
try {
|
|
4295
|
-
const content =
|
|
4679
|
+
const content = fs13.readFileSync(filePath, "utf-8");
|
|
4296
4680
|
const maxChars = 5e4;
|
|
4297
4681
|
const trimmed = content.length > maxChars ? content.slice(0, maxChars) + `
|
|
4298
4682
|
|
|
@@ -4302,7 +4686,7 @@ ${knowledgeItem.content}
|
|
|
4302
4686
|
<file path="${filePath}" size="${content.length} chars">
|
|
4303
4687
|
${trimmed}
|
|
4304
4688
|
</file>`;
|
|
4305
|
-
process.stdout.write(pc6.dim(` [attached: ${
|
|
4689
|
+
process.stdout.write(pc6.dim(` [attached: ${path13.basename(filePath)} (${(content.length / 1024).toFixed(1)}KB)]
|
|
4306
4690
|
`));
|
|
4307
4691
|
} catch {
|
|
4308
4692
|
process.stdout.write(pc6.dim(` [could not read: ${filePath}]
|
|
@@ -4311,7 +4695,7 @@ ${trimmed}
|
|
|
4311
4695
|
} else if (docExts.has(ext)) {
|
|
4312
4696
|
if (mcpManager) {
|
|
4313
4697
|
try {
|
|
4314
|
-
process.stdout.write(pc6.dim(` [converting: ${
|
|
4698
|
+
process.stdout.write(pc6.dim(` [converting: ${path13.basename(filePath)}...]
|
|
4315
4699
|
`));
|
|
4316
4700
|
const converted = await mcpManager.callTool("doc_convert", { path: filePath });
|
|
4317
4701
|
if (converted && !converted.startsWith("Error") && !converted.includes("Could not convert")) {
|
|
@@ -4320,7 +4704,7 @@ ${trimmed}
|
|
|
4320
4704
|
<file path="${filePath}" format="${ext}">
|
|
4321
4705
|
${converted.slice(0, 5e4)}
|
|
4322
4706
|
</file>`;
|
|
4323
|
-
process.stdout.write(pc6.dim(` [attached: ${
|
|
4707
|
+
process.stdout.write(pc6.dim(` [attached: ${path13.basename(filePath)} (converted from ${ext})]
|
|
4324
4708
|
`));
|
|
4325
4709
|
} else {
|
|
4326
4710
|
textContent += `
|
|
@@ -4332,7 +4716,7 @@ ${converted}
|
|
|
4332
4716
|
`));
|
|
4333
4717
|
}
|
|
4334
4718
|
} catch {
|
|
4335
|
-
process.stdout.write(pc6.dim(` [could not convert: ${
|
|
4719
|
+
process.stdout.write(pc6.dim(` [could not convert: ${path13.basename(filePath)}]
|
|
4336
4720
|
`));
|
|
4337
4721
|
}
|
|
4338
4722
|
} else {
|
|
@@ -4387,11 +4771,11 @@ ${converted}
|
|
|
4387
4771
|
}
|
|
4388
4772
|
let augmentedSystemPrompt = activeSystemPrompt;
|
|
4389
4773
|
let memoryTokens = 0;
|
|
4390
|
-
|
|
4391
|
-
const
|
|
4392
|
-
if (
|
|
4393
|
-
augmentedSystemPrompt = activeSystemPrompt +
|
|
4394
|
-
memoryTokens =
|
|
4774
|
+
{
|
|
4775
|
+
const recall2 = await recallForMessage(input);
|
|
4776
|
+
if (recall2) {
|
|
4777
|
+
augmentedSystemPrompt = activeSystemPrompt + recall2.text;
|
|
4778
|
+
memoryTokens = recall2.tokenEstimate;
|
|
4395
4779
|
}
|
|
4396
4780
|
}
|
|
4397
4781
|
const userTurnCount = messages.filter((m) => m.role === "user").length;
|
|
@@ -4493,12 +4877,10 @@ ${result2.response}` : `[${input2.profile}] failed: ${result2.error}`;
|
|
|
4493
4877
|
const result = await mcpManager.callTool(toolUse.name, toolUse.input);
|
|
4494
4878
|
const skipLogging = ["memory_log", "memory_recall", "memory_context", "memory_detail", "reminder_check"].includes(toolUse.name);
|
|
4495
4879
|
if (!skipLogging) {
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
}).catch(() => {
|
|
4501
|
-
});
|
|
4880
|
+
try {
|
|
4881
|
+
memoryLog(sessionId, "system", `[tool:${toolUse.name}] input=${JSON.stringify(toolUse.input).slice(0, 500)} result=${result.slice(0, 500)}`);
|
|
4882
|
+
} catch {
|
|
4883
|
+
}
|
|
4502
4884
|
}
|
|
4503
4885
|
return {
|
|
4504
4886
|
type: "tool_result",
|
|
@@ -4523,14 +4905,13 @@ ${result2.response}` : `[${input2.profile}] failed: ${result2.error}`;
|
|
|
4523
4905
|
const footerDivider = "\u2500".repeat(Math.min(process.stdout.columns || 60, 60) - footer.length - 1);
|
|
4524
4906
|
process.stdout.write(pc6.dim(` ${footerDivider}${footer}
|
|
4525
4907
|
`));
|
|
4526
|
-
if (
|
|
4908
|
+
if (hooksConfig?.extractMemories) {
|
|
4527
4909
|
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
4910
|
if (assistantText) {
|
|
4529
4911
|
const count = await extractMemories(
|
|
4530
4912
|
input,
|
|
4531
4913
|
assistantText,
|
|
4532
4914
|
client,
|
|
4533
|
-
mcpManager,
|
|
4534
4915
|
extractorState
|
|
4535
4916
|
);
|
|
4536
4917
|
if (count > 0) {
|
|
@@ -4543,7 +4924,7 @@ ${result2.response}` : `[${input2.profile}] failed: ${result2.error}`;
|
|
|
4543
4924
|
}
|
|
4544
4925
|
if (hooksConfig?.featureHints) {
|
|
4545
4926
|
hintState.turnCount++;
|
|
4546
|
-
const hasWorkflows =
|
|
4927
|
+
const hasWorkflows = fs13.existsSync(path13.join(os12.homedir(), ".aflow", "flow.md"));
|
|
4547
4928
|
const memoryCount = memoryTokens > 0 ? Math.floor(memoryTokens / 5) : 0;
|
|
4548
4929
|
const hint = getHint(hintState, { hasWorkflows, memoryCount });
|
|
4549
4930
|
if (hint) {
|
|
@@ -4560,16 +4941,12 @@ ${result2.response}` : `[${input2.profile}] failed: ${result2.error}`;
|
|
|
4560
4941
|
}
|
|
4561
4942
|
}
|
|
4562
4943
|
}
|
|
4563
|
-
async function saveConversationToMemory(
|
|
4944
|
+
async function saveConversationToMemory(messages, sessionId) {
|
|
4564
4945
|
const recentMessages = messages.slice(-50);
|
|
4565
4946
|
for (const msg of recentMessages) {
|
|
4566
4947
|
if (typeof msg.content !== "string") continue;
|
|
4567
4948
|
try {
|
|
4568
|
-
|
|
4569
|
-
session_id: sessionId,
|
|
4570
|
-
role: msg.role,
|
|
4571
|
-
content: msg.content.slice(0, 5e3)
|
|
4572
|
-
});
|
|
4949
|
+
memoryLog(sessionId, msg.role, msg.content.slice(0, 5e3));
|
|
4573
4950
|
} catch (err) {
|
|
4574
4951
|
log.debug("agent", "memory_log write failed", err);
|
|
4575
4952
|
}
|
|
@@ -4577,9 +4954,9 @@ async function saveConversationToMemory(mcpManager, messages, sessionId) {
|
|
|
4577
4954
|
}
|
|
4578
4955
|
|
|
4579
4956
|
// src/index.ts
|
|
4580
|
-
import
|
|
4581
|
-
import
|
|
4582
|
-
import
|
|
4957
|
+
import fs14 from "fs";
|
|
4958
|
+
import path14 from "path";
|
|
4959
|
+
import os13 from "os";
|
|
4583
4960
|
|
|
4584
4961
|
// src/presets.ts
|
|
4585
4962
|
var PRESETS = {
|
|
@@ -4688,9 +5065,9 @@ ${wfSections}`;
|
|
|
4688
5065
|
|
|
4689
5066
|
// src/index.ts
|
|
4690
5067
|
async function autoDetectConfig() {
|
|
4691
|
-
const reconfigMarker =
|
|
4692
|
-
if (
|
|
4693
|
-
|
|
5068
|
+
const reconfigMarker = path14.join(os13.homedir(), ".aman-agent", ".reconfig");
|
|
5069
|
+
if (fs14.existsSync(reconfigMarker)) {
|
|
5070
|
+
fs14.unlinkSync(reconfigMarker);
|
|
4694
5071
|
return null;
|
|
4695
5072
|
}
|
|
4696
5073
|
const anthropicKey = process.env.ANTHROPIC_API_KEY;
|
|
@@ -4719,11 +5096,11 @@ async function autoDetectConfig() {
|
|
|
4719
5096
|
return null;
|
|
4720
5097
|
}
|
|
4721
5098
|
function bootstrapEcosystem() {
|
|
4722
|
-
const home2 =
|
|
4723
|
-
const corePath =
|
|
4724
|
-
if (
|
|
4725
|
-
|
|
4726
|
-
|
|
5099
|
+
const home2 = os13.homedir();
|
|
5100
|
+
const corePath = path14.join(home2, ".acore", "core.md");
|
|
5101
|
+
if (fs14.existsSync(corePath)) return false;
|
|
5102
|
+
fs14.mkdirSync(path14.join(home2, ".acore"), { recursive: true });
|
|
5103
|
+
fs14.writeFileSync(corePath, [
|
|
4727
5104
|
"# Aman",
|
|
4728
5105
|
"",
|
|
4729
5106
|
"## Personality",
|
|
@@ -4735,11 +5112,11 @@ function bootstrapEcosystem() {
|
|
|
4735
5112
|
"## Session",
|
|
4736
5113
|
"_New companion \u2014 no prior sessions._"
|
|
4737
5114
|
].join("\n"), "utf-8");
|
|
4738
|
-
const rulesDir =
|
|
4739
|
-
const rulesPath =
|
|
4740
|
-
if (!
|
|
4741
|
-
|
|
4742
|
-
|
|
5115
|
+
const rulesDir = path14.join(home2, ".arules");
|
|
5116
|
+
const rulesPath = path14.join(rulesDir, "rules.md");
|
|
5117
|
+
if (!fs14.existsSync(rulesPath)) {
|
|
5118
|
+
fs14.mkdirSync(rulesDir, { recursive: true });
|
|
5119
|
+
fs14.writeFileSync(rulesPath, [
|
|
4743
5120
|
"# Guardrails",
|
|
4744
5121
|
"",
|
|
4745
5122
|
"## safety",
|
|
@@ -4754,7 +5131,7 @@ function bootstrapEcosystem() {
|
|
|
4754
5131
|
return true;
|
|
4755
5132
|
}
|
|
4756
5133
|
var program = new Command();
|
|
4757
|
-
program.name("aman-agent").description("Your AI companion, running locally").version("0.1
|
|
5134
|
+
program.name("aman-agent").description("Your AI companion, running locally").version("0.17.1").option("--model <model>", "Override LLM model").option("--budget <tokens>", "Token budget for system prompt (default: 8000)", parseInt).option("--profile <name>", "Use a specific agent profile (e.g., coder, writer, researcher)").action(async (options) => {
|
|
4758
5135
|
p2.intro(pc7.bold("aman agent") + pc7.dim(" \u2014 your AI companion"));
|
|
4759
5136
|
let config = loadConfig();
|
|
4760
5137
|
if (!config) {
|
|
@@ -4763,7 +5140,7 @@ program.name("aman-agent").description("Your AI companion, running locally").ver
|
|
|
4763
5140
|
config = detected;
|
|
4764
5141
|
const providerLabel = detected.provider === "anthropic" ? "Anthropic API key" : detected.provider === "openai" ? "OpenAI API key" : "Ollama";
|
|
4765
5142
|
p2.log.success(`Auto-detected ${providerLabel}. Using ${pc7.bold(detected.model)}.`);
|
|
4766
|
-
p2.log.info(pc7.dim("Change anytime with /
|
|
5143
|
+
p2.log.info(pc7.dim("Change anytime with /reset config"));
|
|
4767
5144
|
saveConfig(config);
|
|
4768
5145
|
} else {
|
|
4769
5146
|
p2.log.info("First-time setup \u2014 configure your LLM connection.");
|
|
@@ -4881,11 +5258,30 @@ program.name("aman-agent").description("Your AI companion, running locally").ver
|
|
|
4881
5258
|
}
|
|
4882
5259
|
}
|
|
4883
5260
|
const aiName = getProfileAiName(profile);
|
|
5261
|
+
try {
|
|
5262
|
+
await initMemory();
|
|
5263
|
+
} catch (err) {
|
|
5264
|
+
p2.log.warning(`Memory initialization failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
5265
|
+
}
|
|
5266
|
+
if (isMemoryInitialized()) {
|
|
5267
|
+
const memSpinner = p2.spinner();
|
|
5268
|
+
memSpinner.start("Consolidating memory");
|
|
5269
|
+
try {
|
|
5270
|
+
const report = memoryConsolidate();
|
|
5271
|
+
memSpinner.stop("Memory consolidated");
|
|
5272
|
+
if (report.merged > 0 || report.pruned > 0 || report.promoted > 0) {
|
|
5273
|
+
p2.log.info(
|
|
5274
|
+
`Memory health: ${report.healthScore ?? "?"}% ` + pc7.dim(`(merged ${report.merged}, pruned ${report.pruned}, promoted ${report.promoted})`)
|
|
5275
|
+
);
|
|
5276
|
+
}
|
|
5277
|
+
} catch {
|
|
5278
|
+
memSpinner.stop("Memory consolidation skipped");
|
|
5279
|
+
}
|
|
5280
|
+
}
|
|
4884
5281
|
const mcpManager = new McpManager();
|
|
4885
5282
|
const mcpSpinner = p2.spinner();
|
|
4886
5283
|
mcpSpinner.start("Connecting to MCP servers");
|
|
4887
5284
|
await mcpManager.connect("aman", "npx", ["-y", "@aman_asmuei/aman-mcp"]);
|
|
4888
|
-
await mcpManager.connect("amem", "npx", ["-y", "@aman_asmuei/amem"]);
|
|
4889
5285
|
if (config.mcpServers) {
|
|
4890
5286
|
for (const [name, serverConfig] of Object.entries(config.mcpServers)) {
|
|
4891
5287
|
if (name === "aman" || name === "amem") continue;
|
|
@@ -4896,33 +5292,9 @@ program.name("aman-agent").description("Your AI companion, running locally").ver
|
|
|
4896
5292
|
mcpSpinner.stop("MCP connected");
|
|
4897
5293
|
if (mcpTools.length > 0) {
|
|
4898
5294
|
p2.log.success(`${mcpTools.length} MCP tools available`);
|
|
4899
|
-
if (mcpTools.some((t) => t.name === "memory_consolidate")) {
|
|
4900
|
-
const memSpinner = p2.spinner();
|
|
4901
|
-
memSpinner.start("Consolidating memory");
|
|
4902
|
-
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");
|
|
4918
|
-
}
|
|
4919
|
-
} catch {
|
|
4920
|
-
memSpinner.stop("Memory consolidation skipped");
|
|
4921
|
-
}
|
|
4922
|
-
}
|
|
4923
5295
|
} else {
|
|
4924
5296
|
p2.log.info(
|
|
4925
|
-
"No MCP tools connected (install aman-mcp
|
|
5297
|
+
"No MCP tools connected (install aman-mcp for tool support)"
|
|
4926
5298
|
);
|
|
4927
5299
|
}
|
|
4928
5300
|
const toolDefs = mcpTools.map((t) => ({
|
|
@@ -4971,19 +5343,19 @@ program.command("init").description("Set up your AI companion with a guided wiza
|
|
|
4971
5343
|
});
|
|
4972
5344
|
if (p2.isCancel(preset)) process.exit(0);
|
|
4973
5345
|
const result = applyPreset(preset, name || "Aman");
|
|
4974
|
-
const home2 =
|
|
4975
|
-
|
|
4976
|
-
|
|
5346
|
+
const home2 = os13.homedir();
|
|
5347
|
+
fs14.mkdirSync(path14.join(home2, ".acore"), { recursive: true });
|
|
5348
|
+
fs14.writeFileSync(path14.join(home2, ".acore", "core.md"), result.coreMd, "utf-8");
|
|
4977
5349
|
p2.log.success(`Identity created \u2014 ${PRESETS[preset].identity.personality.split(".")[0].toLowerCase()}`);
|
|
4978
5350
|
if (result.rulesMd) {
|
|
4979
|
-
|
|
4980
|
-
|
|
5351
|
+
fs14.mkdirSync(path14.join(home2, ".arules"), { recursive: true });
|
|
5352
|
+
fs14.writeFileSync(path14.join(home2, ".arules", "rules.md"), result.rulesMd, "utf-8");
|
|
4981
5353
|
const ruleCount = (result.rulesMd.match(/^- /gm) || []).length;
|
|
4982
5354
|
p2.log.success(`${ruleCount} rules set`);
|
|
4983
5355
|
}
|
|
4984
5356
|
if (result.flowMd) {
|
|
4985
|
-
|
|
4986
|
-
|
|
5357
|
+
fs14.mkdirSync(path14.join(home2, ".aflow"), { recursive: true });
|
|
5358
|
+
fs14.writeFileSync(path14.join(home2, ".aflow", "flow.md"), result.flowMd, "utf-8");
|
|
4987
5359
|
const wfCount = (result.flowMd.match(/^## /gm) || []).length;
|
|
4988
5360
|
p2.log.success(`${wfCount} workflow${wfCount > 1 ? "s" : ""} added`);
|
|
4989
5361
|
}
|