@aman_asmuei/aman-agent 0.23.0 → 0.24.3
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/README.md +1 -1
- package/dist/index.js +809 -177
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1387,18 +1387,18 @@ var McpManager = class {
|
|
|
1387
1387
|
|
|
1388
1388
|
// src/agent.ts
|
|
1389
1389
|
import * as readline from "readline";
|
|
1390
|
-
import
|
|
1391
|
-
import
|
|
1392
|
-
import
|
|
1390
|
+
import fs16 from "fs";
|
|
1391
|
+
import path16 from "path";
|
|
1392
|
+
import os15 from "os";
|
|
1393
1393
|
import pc7 from "picocolors";
|
|
1394
1394
|
import { marked } from "marked";
|
|
1395
1395
|
import { markedTerminal } from "marked-terminal";
|
|
1396
1396
|
import logUpdate from "log-update";
|
|
1397
1397
|
|
|
1398
1398
|
// src/commands.ts
|
|
1399
|
-
import
|
|
1400
|
-
import
|
|
1401
|
-
import
|
|
1399
|
+
import fs13 from "fs";
|
|
1400
|
+
import path13 from "path";
|
|
1401
|
+
import os12 from "os";
|
|
1402
1402
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
1403
1403
|
import pc5 from "picocolors";
|
|
1404
1404
|
|
|
@@ -1471,7 +1471,18 @@ import {
|
|
|
1471
1471
|
buildVectorIndex,
|
|
1472
1472
|
recallMemories,
|
|
1473
1473
|
generateEmbedding,
|
|
1474
|
-
getVectorIndex
|
|
1474
|
+
getVectorIndex,
|
|
1475
|
+
runDiagnostics,
|
|
1476
|
+
repairDatabase,
|
|
1477
|
+
loadConfig as loadConfig2,
|
|
1478
|
+
saveConfig as saveConfig2,
|
|
1479
|
+
multiStrategyRecall,
|
|
1480
|
+
reflect,
|
|
1481
|
+
isReflectionDue,
|
|
1482
|
+
syncFromClaude,
|
|
1483
|
+
exportForTeam,
|
|
1484
|
+
importFromTeam,
|
|
1485
|
+
syncToCopilot
|
|
1475
1486
|
} from "@aman_asmuei/amem-core";
|
|
1476
1487
|
import path6 from "path";
|
|
1477
1488
|
import os6 from "os";
|
|
@@ -1584,19 +1595,19 @@ async function memoryForget(opts) {
|
|
|
1584
1595
|
}
|
|
1585
1596
|
return { deleted: 0, message: "Provide an id, type, or query to forget." };
|
|
1586
1597
|
}
|
|
1587
|
-
var
|
|
1598
|
+
var _localMemoryConfig = {};
|
|
1588
1599
|
function setMemoryConfig(config) {
|
|
1589
|
-
|
|
1600
|
+
_localMemoryConfig = config;
|
|
1590
1601
|
}
|
|
1591
1602
|
function getMaxRecallTokens() {
|
|
1592
|
-
return
|
|
1603
|
+
return _localMemoryConfig.maxRecallTokens ?? 1500;
|
|
1593
1604
|
}
|
|
1594
1605
|
function memoryConsolidate(dryRun = false) {
|
|
1595
1606
|
return consolidateMemories(getDb(), cosineSimilarity, {
|
|
1596
1607
|
dryRun,
|
|
1597
|
-
maxStaleDays:
|
|
1598
|
-
minConfidence:
|
|
1599
|
-
minAccessCount:
|
|
1608
|
+
maxStaleDays: _localMemoryConfig.maxStaleDays ?? 90,
|
|
1609
|
+
minConfidence: _localMemoryConfig.minConfidence ?? 0.3,
|
|
1610
|
+
minAccessCount: _localMemoryConfig.minAccessCount ?? 0
|
|
1600
1611
|
});
|
|
1601
1612
|
}
|
|
1602
1613
|
function isMemoryInitialized() {
|
|
@@ -1626,6 +1637,114 @@ function reminderComplete(id) {
|
|
|
1626
1637
|
const fullId = getDb().resolveReminderId(id) ?? id;
|
|
1627
1638
|
return getDb().completeReminder(fullId);
|
|
1628
1639
|
}
|
|
1640
|
+
async function memoryDoctor() {
|
|
1641
|
+
return runDiagnostics(getDb());
|
|
1642
|
+
}
|
|
1643
|
+
async function memoryRepair(opts = {}) {
|
|
1644
|
+
const dryRun = opts.dryRun ?? true;
|
|
1645
|
+
if (dryRun) {
|
|
1646
|
+
const diag = runDiagnostics(getDb());
|
|
1647
|
+
return {
|
|
1648
|
+
dryRun: true,
|
|
1649
|
+
status: diag.status,
|
|
1650
|
+
issues: diag.issues.map((issue) => issue.message),
|
|
1651
|
+
actions: diag.issues.map((issue) => `Would fix: ${issue.suggestion}`)
|
|
1652
|
+
};
|
|
1653
|
+
}
|
|
1654
|
+
const dbPath = process.env.AMEM_DB ?? path6.join(os6.homedir(), ".amem", "memory.db");
|
|
1655
|
+
const result = repairDatabase(dbPath);
|
|
1656
|
+
return {
|
|
1657
|
+
dryRun: false,
|
|
1658
|
+
status: result.status === "repaired" ? "warning" : result.status === "failed" ? "critical" : "healthy",
|
|
1659
|
+
issues: [],
|
|
1660
|
+
actions: result.memoriesRecovered > 0 ? [`Recovered ${result.memoriesRecovered} memories`] : []
|
|
1661
|
+
};
|
|
1662
|
+
}
|
|
1663
|
+
async function memoryConfig(updates) {
|
|
1664
|
+
const current = loadConfig2();
|
|
1665
|
+
if (updates && Object.keys(updates).length > 0) {
|
|
1666
|
+
saveConfig2(updates);
|
|
1667
|
+
return loadConfig2();
|
|
1668
|
+
}
|
|
1669
|
+
return current;
|
|
1670
|
+
}
|
|
1671
|
+
async function memoryMultiRecall(query, opts = {}) {
|
|
1672
|
+
const queryEmbedding = await generateEmbedding(query);
|
|
1673
|
+
const memories = await multiStrategyRecall(getDb(), {
|
|
1674
|
+
query,
|
|
1675
|
+
queryEmbedding,
|
|
1676
|
+
limit: opts.limit ?? 10,
|
|
1677
|
+
scope: opts.scope ?? currentProject ?? void 0
|
|
1678
|
+
});
|
|
1679
|
+
return { memories, total: memories.length };
|
|
1680
|
+
}
|
|
1681
|
+
async function memoryReflect(config) {
|
|
1682
|
+
return reflect(getDb(), config);
|
|
1683
|
+
}
|
|
1684
|
+
function memoryTier(id, tier) {
|
|
1685
|
+
try {
|
|
1686
|
+
const db2 = getDb();
|
|
1687
|
+
const fullId = db2.resolveId(id) ?? id;
|
|
1688
|
+
db2.updateTier(fullId, tier);
|
|
1689
|
+
return { id: fullId, tier, ok: true };
|
|
1690
|
+
} catch (err) {
|
|
1691
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
function memoryDetail(id) {
|
|
1695
|
+
const db2 = getDb();
|
|
1696
|
+
const fullId = db2.resolveId(id) ?? id;
|
|
1697
|
+
return db2.getById(fullId);
|
|
1698
|
+
}
|
|
1699
|
+
function memoryRelate(fromId, toId, type, strength) {
|
|
1700
|
+
try {
|
|
1701
|
+
const relationId = getDb().addRelation(fromId, toId, type, strength);
|
|
1702
|
+
return { ok: true, relationId };
|
|
1703
|
+
} catch (err) {
|
|
1704
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
function memoryExpire(id, reason) {
|
|
1708
|
+
try {
|
|
1709
|
+
const db2 = getDb();
|
|
1710
|
+
const fullId = db2.resolveId(id) ?? id;
|
|
1711
|
+
db2.expireMemory(fullId);
|
|
1712
|
+
return { ok: true, id: fullId, ...reason !== void 0 ? { reason } : {} };
|
|
1713
|
+
} catch (err) {
|
|
1714
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
function memoryVersions(id) {
|
|
1718
|
+
const db2 = getDb();
|
|
1719
|
+
const fullId = db2.resolveId(id) ?? id;
|
|
1720
|
+
return db2.getVersionHistory(fullId);
|
|
1721
|
+
}
|
|
1722
|
+
async function memorySync(action, opts = {}) {
|
|
1723
|
+
const db2 = getDb();
|
|
1724
|
+
try {
|
|
1725
|
+
switch (action) {
|
|
1726
|
+
case "import-claude":
|
|
1727
|
+
return await syncFromClaude(db2, opts.projectFilter, opts.dryRun ?? false);
|
|
1728
|
+
case "export-team": {
|
|
1729
|
+
const exportOptions = {
|
|
1730
|
+
userId: opts.userId ?? currentProject
|
|
1731
|
+
};
|
|
1732
|
+
return await exportForTeam(db2, opts.outputDir ?? process.cwd(), exportOptions);
|
|
1733
|
+
}
|
|
1734
|
+
case "import-team":
|
|
1735
|
+
if (!opts.filePath) {
|
|
1736
|
+
return { ok: false, error: "filePath is required for import-team" };
|
|
1737
|
+
}
|
|
1738
|
+
return await importFromTeam(db2, opts.filePath, opts.importOptions);
|
|
1739
|
+
case "sync-copilot":
|
|
1740
|
+
return syncToCopilot(db2, opts.copilotOptions);
|
|
1741
|
+
default:
|
|
1742
|
+
return { ok: false, error: `Unknown sync action: ${action}` };
|
|
1743
|
+
}
|
|
1744
|
+
} catch (err) {
|
|
1745
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1629
1748
|
|
|
1630
1749
|
// src/profile-templates.ts
|
|
1631
1750
|
import fs7 from "fs";
|
|
@@ -2152,14 +2271,98 @@ async function editProfile(current) {
|
|
|
2152
2271
|
return updated;
|
|
2153
2272
|
}
|
|
2154
2273
|
|
|
2274
|
+
// src/files.ts
|
|
2275
|
+
import fs9 from "fs";
|
|
2276
|
+
import path9 from "path";
|
|
2277
|
+
import os9 from "os";
|
|
2278
|
+
var MAX_READ_BYTES = 5e4;
|
|
2279
|
+
var HOME = fs9.realpathSync(os9.homedir());
|
|
2280
|
+
var TMPDIR = fs9.realpathSync(os9.tmpdir());
|
|
2281
|
+
var CWD = fs9.realpathSync(process.cwd());
|
|
2282
|
+
function realOrBest(p4) {
|
|
2283
|
+
const parts = p4.split(path9.sep);
|
|
2284
|
+
for (let i = parts.length; i > 0; i--) {
|
|
2285
|
+
const candidate = parts.slice(0, i).join(path9.sep) || path9.sep;
|
|
2286
|
+
try {
|
|
2287
|
+
const real = fs9.realpathSync(candidate);
|
|
2288
|
+
const remainder = parts.slice(i).join(path9.sep);
|
|
2289
|
+
return remainder ? `${real}${path9.sep}${remainder}` : real;
|
|
2290
|
+
} catch {
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
return p4;
|
|
2294
|
+
}
|
|
2295
|
+
function isUnderDir(real, dir) {
|
|
2296
|
+
return real === dir || real.startsWith(dir + path9.sep);
|
|
2297
|
+
}
|
|
2298
|
+
function assertSafePath(filePath) {
|
|
2299
|
+
const resolved = path9.resolve(filePath);
|
|
2300
|
+
const real = realOrBest(resolved);
|
|
2301
|
+
if (!isUnderDir(real, HOME) && !isUnderDir(real, CWD) && !isUnderDir(real, TMPDIR)) {
|
|
2302
|
+
throw new Error(`Path is outside allowed directories (home or cwd): ${real}`);
|
|
2303
|
+
}
|
|
2304
|
+
return resolved;
|
|
2305
|
+
}
|
|
2306
|
+
async function readFile(filePath) {
|
|
2307
|
+
const resolved = assertSafePath(filePath);
|
|
2308
|
+
if (!fs9.existsSync(resolved)) {
|
|
2309
|
+
throw new Error(`File not found: ${resolved}`);
|
|
2310
|
+
}
|
|
2311
|
+
const stat = fs9.statSync(resolved);
|
|
2312
|
+
if (stat.isDirectory()) {
|
|
2313
|
+
throw new Error(`Path is a directory, not a file: ${resolved}. Use /file list instead.`);
|
|
2314
|
+
}
|
|
2315
|
+
const size = stat.size;
|
|
2316
|
+
const buf = Buffer.alloc(Math.min(size, MAX_READ_BYTES));
|
|
2317
|
+
const fd = fs9.openSync(resolved, "r");
|
|
2318
|
+
try {
|
|
2319
|
+
fs9.readSync(fd, buf, 0, buf.length, 0);
|
|
2320
|
+
} finally {
|
|
2321
|
+
fs9.closeSync(fd);
|
|
2322
|
+
}
|
|
2323
|
+
return {
|
|
2324
|
+
path: resolved,
|
|
2325
|
+
content: buf.toString("utf-8"),
|
|
2326
|
+
size,
|
|
2327
|
+
truncated: size > MAX_READ_BYTES,
|
|
2328
|
+
encoding: "utf-8"
|
|
2329
|
+
};
|
|
2330
|
+
}
|
|
2331
|
+
async function listFiles(dirPath, opts = {}) {
|
|
2332
|
+
const resolved = assertSafePath(dirPath);
|
|
2333
|
+
if (!fs9.existsSync(resolved)) {
|
|
2334
|
+
throw new Error(`Directory not found: ${resolved}`);
|
|
2335
|
+
}
|
|
2336
|
+
const stat = fs9.statSync(resolved);
|
|
2337
|
+
if (!stat.isDirectory()) {
|
|
2338
|
+
throw new Error(`Path is a file, not a directory: ${resolved}. Use /file read instead.`);
|
|
2339
|
+
}
|
|
2340
|
+
const entries = [];
|
|
2341
|
+
function walk(dir, prefix) {
|
|
2342
|
+
const items = fs9.readdirSync(dir, { withFileTypes: true });
|
|
2343
|
+
for (const item of items) {
|
|
2344
|
+
const rel = prefix ? `${prefix}/${item.name}` : item.name;
|
|
2345
|
+
if (item.isDirectory()) {
|
|
2346
|
+
entries.push({ name: rel, type: "dir", size: 0 });
|
|
2347
|
+
if (opts.recursive) walk(path9.join(dir, item.name), rel);
|
|
2348
|
+
} else {
|
|
2349
|
+
const s = fs9.statSync(path9.join(dir, item.name));
|
|
2350
|
+
entries.push({ name: rel, type: "file", size: s.size });
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
walk(resolved, "");
|
|
2355
|
+
return { path: resolved, entries, total: entries.length };
|
|
2356
|
+
}
|
|
2357
|
+
|
|
2155
2358
|
// src/delegate.ts
|
|
2156
2359
|
import pc3 from "picocolors";
|
|
2157
2360
|
|
|
2158
2361
|
// src/hooks.ts
|
|
2159
2362
|
import pc2 from "picocolors";
|
|
2160
2363
|
import * as p2 from "@clack/prompts";
|
|
2161
|
-
import
|
|
2162
|
-
import
|
|
2364
|
+
import fs10 from "fs";
|
|
2365
|
+
import path10 from "path";
|
|
2163
2366
|
|
|
2164
2367
|
// src/personality.ts
|
|
2165
2368
|
var FRUSTRATION_SIGNALS = [
|
|
@@ -2600,10 +2803,10 @@ async function onSessionEnd(ctx, messages, sessionId) {
|
|
|
2600
2803
|
}
|
|
2601
2804
|
console.log(pc2.dim(` Saved ${textMessages.length} messages (session: ${sessionId})`));
|
|
2602
2805
|
}
|
|
2603
|
-
const projectContextPath =
|
|
2604
|
-
if (
|
|
2806
|
+
const projectContextPath = path10.join(process.cwd(), ".acore", "context.md");
|
|
2807
|
+
if (fs10.existsSync(projectContextPath) && messages.length > 2) {
|
|
2605
2808
|
try {
|
|
2606
|
-
let contextContent =
|
|
2809
|
+
let contextContent = fs10.readFileSync(projectContextPath, "utf-8");
|
|
2607
2810
|
const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
2608
2811
|
let lastUserMsg = "";
|
|
2609
2812
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
@@ -2621,7 +2824,7 @@ async function onSessionEnd(ctx, messages, sessionId) {
|
|
|
2621
2824
|
- Recent decisions: [see memory]
|
|
2622
2825
|
- Temp notes: [cleared]`;
|
|
2623
2826
|
contextContent = contextContent.replace(sessionPattern, newSession);
|
|
2624
|
-
|
|
2827
|
+
fs10.writeFileSync(projectContextPath, contextContent, "utf-8");
|
|
2625
2828
|
log.debug("hooks", `Updated project context: ${projectContextPath}`);
|
|
2626
2829
|
}
|
|
2627
2830
|
} catch (err) {
|
|
@@ -2827,43 +3030,43 @@ async function delegatePipeline(steps, initialInput, client, mcpManager, options
|
|
|
2827
3030
|
}
|
|
2828
3031
|
|
|
2829
3032
|
// src/teams.ts
|
|
2830
|
-
import
|
|
2831
|
-
import
|
|
2832
|
-
import
|
|
3033
|
+
import fs11 from "fs";
|
|
3034
|
+
import path11 from "path";
|
|
3035
|
+
import os10 from "os";
|
|
2833
3036
|
import pc4 from "picocolors";
|
|
2834
3037
|
function getTeamsDir() {
|
|
2835
|
-
return
|
|
3038
|
+
return path11.join(os10.homedir(), ".acore", "teams");
|
|
2836
3039
|
}
|
|
2837
3040
|
function ensureTeamsDir() {
|
|
2838
3041
|
const dir = getTeamsDir();
|
|
2839
|
-
if (!
|
|
3042
|
+
if (!fs11.existsSync(dir)) fs11.mkdirSync(dir, { recursive: true });
|
|
2840
3043
|
return dir;
|
|
2841
3044
|
}
|
|
2842
3045
|
function teamPath(name) {
|
|
2843
3046
|
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
2844
|
-
return
|
|
3047
|
+
return path11.join(ensureTeamsDir(), `${slug}.json`);
|
|
2845
3048
|
}
|
|
2846
3049
|
function createTeam(team) {
|
|
2847
3050
|
const fp = teamPath(team.name);
|
|
2848
|
-
|
|
3051
|
+
fs11.writeFileSync(fp, JSON.stringify(team, null, 2), "utf-8");
|
|
2849
3052
|
}
|
|
2850
3053
|
function loadTeam(name) {
|
|
2851
3054
|
const fp = teamPath(name);
|
|
2852
|
-
if (!
|
|
3055
|
+
if (!fs11.existsSync(fp)) return null;
|
|
2853
3056
|
try {
|
|
2854
|
-
return JSON.parse(
|
|
3057
|
+
return JSON.parse(fs11.readFileSync(fp, "utf-8"));
|
|
2855
3058
|
} catch {
|
|
2856
3059
|
return null;
|
|
2857
3060
|
}
|
|
2858
3061
|
}
|
|
2859
3062
|
function listTeams() {
|
|
2860
3063
|
const dir = getTeamsDir();
|
|
2861
|
-
if (!
|
|
3064
|
+
if (!fs11.existsSync(dir)) return [];
|
|
2862
3065
|
const teams = [];
|
|
2863
|
-
for (const file of
|
|
3066
|
+
for (const file of fs11.readdirSync(dir)) {
|
|
2864
3067
|
if (!file.endsWith(".json")) continue;
|
|
2865
3068
|
try {
|
|
2866
|
-
const content =
|
|
3069
|
+
const content = fs11.readFileSync(path11.join(dir, file), "utf-8");
|
|
2867
3070
|
teams.push(JSON.parse(content));
|
|
2868
3071
|
} catch {
|
|
2869
3072
|
}
|
|
@@ -2872,8 +3075,8 @@ function listTeams() {
|
|
|
2872
3075
|
}
|
|
2873
3076
|
function deleteTeam(name) {
|
|
2874
3077
|
const fp = teamPath(name);
|
|
2875
|
-
if (!
|
|
2876
|
-
|
|
3078
|
+
if (!fs11.existsSync(fp)) return false;
|
|
3079
|
+
fs11.unlinkSync(fp);
|
|
2877
3080
|
return true;
|
|
2878
3081
|
}
|
|
2879
3082
|
async function runTeam(team, task, client, mcpManager, tools) {
|
|
@@ -3099,23 +3302,23 @@ var BUILT_IN_TEAMS = [
|
|
|
3099
3302
|
];
|
|
3100
3303
|
|
|
3101
3304
|
// src/plans.ts
|
|
3102
|
-
import
|
|
3103
|
-
import
|
|
3104
|
-
import
|
|
3305
|
+
import fs12 from "fs";
|
|
3306
|
+
import path12 from "path";
|
|
3307
|
+
import os11 from "os";
|
|
3105
3308
|
function getPlansDir() {
|
|
3106
|
-
const localDir =
|
|
3107
|
-
const localAcore =
|
|
3108
|
-
if (
|
|
3109
|
-
return
|
|
3309
|
+
const localDir = path12.join(process.cwd(), ".acore", "plans");
|
|
3310
|
+
const localAcore = path12.join(process.cwd(), ".acore");
|
|
3311
|
+
if (fs12.existsSync(localAcore)) return localDir;
|
|
3312
|
+
return path12.join(os11.homedir(), ".acore", "plans");
|
|
3110
3313
|
}
|
|
3111
3314
|
function ensurePlansDir() {
|
|
3112
3315
|
const dir = getPlansDir();
|
|
3113
|
-
if (!
|
|
3316
|
+
if (!fs12.existsSync(dir)) fs12.mkdirSync(dir, { recursive: true });
|
|
3114
3317
|
return dir;
|
|
3115
3318
|
}
|
|
3116
3319
|
function planPath(name) {
|
|
3117
3320
|
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
3118
|
-
return
|
|
3321
|
+
return path12.join(ensurePlansDir(), `${slug}.md`);
|
|
3119
3322
|
}
|
|
3120
3323
|
function serializePlan(plan) {
|
|
3121
3324
|
const lines = [];
|
|
@@ -3141,7 +3344,7 @@ function parsePlan(content, filePath) {
|
|
|
3141
3344
|
const createdMatch = content.match(/\*\*Created:\*\*\s*(.+)/);
|
|
3142
3345
|
const updatedMatch = content.match(/\*\*Updated:\*\*\s*(.+)/);
|
|
3143
3346
|
const activeMatch = content.match(/\*\*Active:\*\*\s*(.+)/);
|
|
3144
|
-
const name = nameMatch?.[1]?.trim() ||
|
|
3347
|
+
const name = nameMatch?.[1]?.trim() || path12.basename(filePath, ".md");
|
|
3145
3348
|
const goal = goalMatch?.[1]?.trim() || "";
|
|
3146
3349
|
const createdAt = createdMatch?.[1]?.trim() || "";
|
|
3147
3350
|
const updatedAt = updatedMatch?.[1]?.trim() || "";
|
|
@@ -3183,22 +3386,22 @@ function createPlan(name, goal, steps) {
|
|
|
3183
3386
|
}
|
|
3184
3387
|
function savePlan(plan) {
|
|
3185
3388
|
const fp = planPath(plan.name);
|
|
3186
|
-
|
|
3389
|
+
fs12.writeFileSync(fp, serializePlan(plan), "utf-8");
|
|
3187
3390
|
}
|
|
3188
3391
|
function loadPlan(name) {
|
|
3189
3392
|
const fp = planPath(name);
|
|
3190
|
-
if (!
|
|
3191
|
-
const content =
|
|
3393
|
+
if (!fs12.existsSync(fp)) return null;
|
|
3394
|
+
const content = fs12.readFileSync(fp, "utf-8");
|
|
3192
3395
|
return parsePlan(content, fp);
|
|
3193
3396
|
}
|
|
3194
3397
|
function listPlans() {
|
|
3195
3398
|
const dir = getPlansDir();
|
|
3196
|
-
if (!
|
|
3399
|
+
if (!fs12.existsSync(dir)) return [];
|
|
3197
3400
|
const plans = [];
|
|
3198
|
-
for (const file of
|
|
3401
|
+
for (const file of fs12.readdirSync(dir)) {
|
|
3199
3402
|
if (!file.endsWith(".md")) continue;
|
|
3200
|
-
const fp =
|
|
3201
|
-
const content =
|
|
3403
|
+
const fp = path12.join(dir, file);
|
|
3404
|
+
const content = fs12.readFileSync(fp, "utf-8");
|
|
3202
3405
|
const plan = parsePlan(content, fp);
|
|
3203
3406
|
if (plan) plans.push(plan);
|
|
3204
3407
|
}
|
|
@@ -3295,20 +3498,22 @@ function progressBar(pct) {
|
|
|
3295
3498
|
// src/commands.ts
|
|
3296
3499
|
import {
|
|
3297
3500
|
getIdentity as acoreGetIdentity,
|
|
3298
|
-
updateSection as acoreUpdateSection
|
|
3501
|
+
updateSection as acoreUpdateSection,
|
|
3502
|
+
updateDynamics as acoreUpdateDynamics
|
|
3299
3503
|
} from "@aman_asmuei/acore-core";
|
|
3300
3504
|
import {
|
|
3301
3505
|
listRuleCategories as arulesListCategories,
|
|
3302
3506
|
addRule as arulesAddRule,
|
|
3303
3507
|
removeRule as arulesRemoveRule,
|
|
3304
|
-
toggleRuleAt as arulesToggleRule
|
|
3508
|
+
toggleRuleAt as arulesToggleRule,
|
|
3509
|
+
checkAction as arulesCheckAction
|
|
3305
3510
|
} from "@aman_asmuei/arules-core";
|
|
3306
3511
|
var AGENT_SCOPE = process.env.AMAN_AGENT_SCOPE ?? "dev:agent";
|
|
3307
3512
|
function readEcosystemFile(filePath, label) {
|
|
3308
|
-
if (!
|
|
3513
|
+
if (!fs13.existsSync(filePath)) {
|
|
3309
3514
|
return pc5.dim(`No ${label} file found at ${filePath}`);
|
|
3310
3515
|
}
|
|
3311
|
-
return
|
|
3516
|
+
return fs13.readFileSync(filePath, "utf-8").trim();
|
|
3312
3517
|
}
|
|
3313
3518
|
function parseCommand(input) {
|
|
3314
3519
|
const trimmed = input.trim();
|
|
@@ -3319,6 +3524,18 @@ function parseCommand(input) {
|
|
|
3319
3524
|
const args = parts.slice(2);
|
|
3320
3525
|
return { base, action, args };
|
|
3321
3526
|
}
|
|
3527
|
+
function buildNestedUpdate(key, val) {
|
|
3528
|
+
const parts = key.split(".");
|
|
3529
|
+
if (parts.length === 1) return { [key]: val };
|
|
3530
|
+
const result = {};
|
|
3531
|
+
let curr = result;
|
|
3532
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
3533
|
+
curr[parts[i]] = {};
|
|
3534
|
+
curr = curr[parts[i]];
|
|
3535
|
+
}
|
|
3536
|
+
curr[parts[parts.length - 1]] = val;
|
|
3537
|
+
return result;
|
|
3538
|
+
}
|
|
3322
3539
|
async function mcpWrite(ctx, layer, tool, args) {
|
|
3323
3540
|
if (!ctx.mcpManager) {
|
|
3324
3541
|
return pc5.red(`Cannot modify ${layer}: aman-mcp not connected. Start it with: npx @aman_asmuei/aman-mcp`);
|
|
@@ -3373,13 +3590,50 @@ async function handleIdentityCommand(action, args, _ctx) {
|
|
|
3373
3590
|
};
|
|
3374
3591
|
}
|
|
3375
3592
|
}
|
|
3593
|
+
if (action === "dynamics") {
|
|
3594
|
+
const updates = {};
|
|
3595
|
+
for (const arg of args) {
|
|
3596
|
+
const eq = arg.indexOf("=");
|
|
3597
|
+
if (eq > 0) updates[arg.slice(0, eq)] = arg.slice(eq + 1);
|
|
3598
|
+
}
|
|
3599
|
+
if (!Object.keys(updates).length) {
|
|
3600
|
+
return { handled: true, output: pc5.yellow("Usage: /identity dynamics energy=high mode=focused read='Book Title'") };
|
|
3601
|
+
}
|
|
3602
|
+
try {
|
|
3603
|
+
await acoreUpdateDynamics({
|
|
3604
|
+
energy: updates.energy,
|
|
3605
|
+
activeMode: updates.mode,
|
|
3606
|
+
currentRead: updates.read
|
|
3607
|
+
}, AGENT_SCOPE);
|
|
3608
|
+
return { handled: true, output: `Dynamics updated: ${Object.entries(updates).map(([k, v]) => `${k}=${v}`).join(", ")}` };
|
|
3609
|
+
} catch (err) {
|
|
3610
|
+
return { handled: true, output: pc5.red(`Dynamics error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
3611
|
+
}
|
|
3612
|
+
}
|
|
3613
|
+
if (action === "summary") {
|
|
3614
|
+
try {
|
|
3615
|
+
const identity = await acoreGetIdentity(AGENT_SCOPE);
|
|
3616
|
+
if (!identity) return { handled: true, output: pc5.yellow("No identity configured.") };
|
|
3617
|
+
const nameMatch = identity.content.match(/\*\*Name:\*\*\s*(.+)/);
|
|
3618
|
+
const lines = [
|
|
3619
|
+
`**Identity Summary**`,
|
|
3620
|
+
nameMatch ? `Name: ${nameMatch[1].trim()}` : "",
|
|
3621
|
+
`Scope: ${AGENT_SCOPE}`
|
|
3622
|
+
].filter(Boolean);
|
|
3623
|
+
return { handled: true, output: lines.join("\n") };
|
|
3624
|
+
} catch (err) {
|
|
3625
|
+
return { handled: true, output: pc5.red(`Summary error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
3626
|
+
}
|
|
3627
|
+
}
|
|
3376
3628
|
if (action === "help") {
|
|
3377
3629
|
return {
|
|
3378
3630
|
handled: true,
|
|
3379
3631
|
output: [
|
|
3380
3632
|
pc5.bold("Identity commands:"),
|
|
3381
3633
|
` ${pc5.cyan("/identity")} View current identity`,
|
|
3382
|
-
` ${pc5.cyan("/identity update")} <section> Update a section
|
|
3634
|
+
` ${pc5.cyan("/identity update")} <section> Update a section`,
|
|
3635
|
+
` ${pc5.cyan("/identity dynamics")} key=val Update dynamic fields (energy, mode, read)`,
|
|
3636
|
+
` ${pc5.cyan("/identity summary")} Show structured identity summary`
|
|
3383
3637
|
].join("\n")
|
|
3384
3638
|
};
|
|
3385
3639
|
}
|
|
@@ -3495,6 +3749,26 @@ async function handleRulesCommand(action, args, _ctx) {
|
|
|
3495
3749
|
};
|
|
3496
3750
|
}
|
|
3497
3751
|
}
|
|
3752
|
+
if (action === "check") {
|
|
3753
|
+
if (args.length === 0) {
|
|
3754
|
+
return { handled: true, output: pc5.yellow("Usage: /rules check <action description...>") };
|
|
3755
|
+
}
|
|
3756
|
+
const description = args.join(" ");
|
|
3757
|
+
try {
|
|
3758
|
+
const result = await arulesCheckAction(description, AGENT_SCOPE);
|
|
3759
|
+
if (result.safe) {
|
|
3760
|
+
return { handled: true, output: pc5.green(`Action is allowed: "${description}"`) };
|
|
3761
|
+
}
|
|
3762
|
+
return {
|
|
3763
|
+
handled: true,
|
|
3764
|
+
output: pc5.red(`Action blocked: "${description}"
|
|
3765
|
+
Violations:
|
|
3766
|
+
${result.violations.map((v) => ` - ${v}`).join("\n")}`)
|
|
3767
|
+
};
|
|
3768
|
+
} catch (err) {
|
|
3769
|
+
return { handled: true, output: pc5.red(`Check error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
3770
|
+
}
|
|
3771
|
+
}
|
|
3498
3772
|
if (action === "help") {
|
|
3499
3773
|
return {
|
|
3500
3774
|
handled: true,
|
|
@@ -3503,7 +3777,8 @@ async function handleRulesCommand(action, args, _ctx) {
|
|
|
3503
3777
|
` ${pc5.cyan("/rules")} View current rules`,
|
|
3504
3778
|
` ${pc5.cyan("/rules add")} <category> <text> Add a rule`,
|
|
3505
3779
|
` ${pc5.cyan("/rules remove")} <category> <idx> Remove a rule`,
|
|
3506
|
-
` ${pc5.cyan("/rules toggle")} <category> <idx> Toggle a rule
|
|
3780
|
+
` ${pc5.cyan("/rules toggle")} <category> <idx> Toggle a rule`,
|
|
3781
|
+
` ${pc5.cyan("/rules check")} <action...> Check if an action is allowed`
|
|
3507
3782
|
].join("\n")
|
|
3508
3783
|
};
|
|
3509
3784
|
}
|
|
@@ -3513,9 +3788,9 @@ async function handleRulesCommand(action, args, _ctx) {
|
|
|
3513
3788
|
};
|
|
3514
3789
|
}
|
|
3515
3790
|
async function handleWorkflowsCommand(action, args, ctx) {
|
|
3516
|
-
const home2 =
|
|
3791
|
+
const home2 = os12.homedir();
|
|
3517
3792
|
if (!action) {
|
|
3518
|
-
const content = readEcosystemFile(
|
|
3793
|
+
const content = readEcosystemFile(path13.join(home2, ".aflow", "flow.md"), "workflows (aflow)");
|
|
3519
3794
|
return { handled: true, output: content };
|
|
3520
3795
|
}
|
|
3521
3796
|
if (action === "add") {
|
|
@@ -3532,12 +3807,33 @@ async function handleWorkflowsCommand(action, args, ctx) {
|
|
|
3532
3807
|
const output = await mcpWrite(ctx, "workflows", "workflow_remove", { name: args.join(" ") });
|
|
3533
3808
|
return { handled: true, output };
|
|
3534
3809
|
}
|
|
3810
|
+
if (action === "get") {
|
|
3811
|
+
if (args.length === 0) {
|
|
3812
|
+
return { handled: true, output: pc5.yellow("Usage: /workflows get <name>") };
|
|
3813
|
+
}
|
|
3814
|
+
const name = args.join(" ").toLowerCase();
|
|
3815
|
+
const raw = readEcosystemFile(path13.join(home2, ".aflow", "flow.md"), "workflows (aflow)");
|
|
3816
|
+
if (raw.startsWith("No ")) {
|
|
3817
|
+
return { handled: true, output: raw };
|
|
3818
|
+
}
|
|
3819
|
+
const sections = raw.split(/^## /m).slice(1);
|
|
3820
|
+
const match = sections.find((s) => s.split("\n")[0].trim().toLowerCase() === name);
|
|
3821
|
+
if (!match) {
|
|
3822
|
+
return { handled: true, output: pc5.yellow(`No workflow found: "${args.join(" ")}"`) };
|
|
3823
|
+
}
|
|
3824
|
+
const title = match.split("\n")[0].trim();
|
|
3825
|
+
const body = match.split("\n").slice(1).join("\n").trim();
|
|
3826
|
+
return { handled: true, output: `## ${title}
|
|
3827
|
+
|
|
3828
|
+
${body}` };
|
|
3829
|
+
}
|
|
3535
3830
|
if (action === "help") {
|
|
3536
3831
|
return { handled: true, output: [
|
|
3537
3832
|
pc5.bold("Workflow commands:"),
|
|
3538
3833
|
` ${pc5.cyan("/workflows")} View current workflows`,
|
|
3539
3834
|
` ${pc5.cyan("/workflows add")} <name> Add a workflow`,
|
|
3540
|
-
` ${pc5.cyan("/workflows remove")} <name> Remove a workflow
|
|
3835
|
+
` ${pc5.cyan("/workflows remove")} <name> Remove a workflow`,
|
|
3836
|
+
` ${pc5.cyan("/workflows get")} <name> Show a specific workflow`
|
|
3541
3837
|
].join("\n") };
|
|
3542
3838
|
}
|
|
3543
3839
|
return { handled: true, output: pc5.yellow(`Unknown action: /workflows ${action}. Try /workflows --help`) };
|
|
@@ -3566,10 +3862,34 @@ function handleAkitCommand(_action, _args) {
|
|
|
3566
3862
|
].join("\n")
|
|
3567
3863
|
};
|
|
3568
3864
|
}
|
|
3865
|
+
async function handleToolsCommand(action, args, _ctx) {
|
|
3866
|
+
if (!action || action === "list") {
|
|
3867
|
+
return handleAkitCommand(action, args);
|
|
3868
|
+
}
|
|
3869
|
+
if (action === "search") {
|
|
3870
|
+
if (args.length === 0) {
|
|
3871
|
+
return { handled: true, output: pc5.yellow("Usage: /tools search <query...>") };
|
|
3872
|
+
}
|
|
3873
|
+
const query = args.join(" ").toLowerCase();
|
|
3874
|
+
const home2 = os12.homedir();
|
|
3875
|
+
const toolsFile = path13.join(home2, ".akit", "tools.md");
|
|
3876
|
+
if (!fs13.existsSync(toolsFile)) {
|
|
3877
|
+
return { handled: true, output: pc5.dim(`No tools file found. Use 'npx @aman_asmuei/akit search ${args.join(" ")}' to search the registry.`) };
|
|
3878
|
+
}
|
|
3879
|
+
const raw = fs13.readFileSync(toolsFile, "utf-8").trim();
|
|
3880
|
+
const lines = raw.split("\n");
|
|
3881
|
+
const matches = lines.filter((l) => l.toLowerCase().includes(query));
|
|
3882
|
+
if (matches.length === 0) {
|
|
3883
|
+
return { handled: true, output: pc5.dim(`No tools matching "${query}".`) };
|
|
3884
|
+
}
|
|
3885
|
+
return { handled: true, output: [pc5.bold(`Tools matching "${query}":`), ...matches].join("\n") };
|
|
3886
|
+
}
|
|
3887
|
+
return handleAkitCommand(action, args);
|
|
3888
|
+
}
|
|
3569
3889
|
async function handleSkillsCommand(action, args, ctx) {
|
|
3570
|
-
const home2 =
|
|
3890
|
+
const home2 = os12.homedir();
|
|
3571
3891
|
if (!action) {
|
|
3572
|
-
const content = readEcosystemFile(
|
|
3892
|
+
const content = readEcosystemFile(path13.join(home2, ".askill", "skills.md"), "skills (askill)");
|
|
3573
3893
|
return { handled: true, output: content };
|
|
3574
3894
|
}
|
|
3575
3895
|
if (action === "install") {
|
|
@@ -3586,20 +3906,38 @@ async function handleSkillsCommand(action, args, ctx) {
|
|
|
3586
3906
|
const output = await mcpWrite(ctx, "skills", "skill_uninstall", { name: args.join(" ") });
|
|
3587
3907
|
return { handled: true, output };
|
|
3588
3908
|
}
|
|
3909
|
+
if (action === "search") {
|
|
3910
|
+
if (args.length === 0) {
|
|
3911
|
+
return { handled: true, output: pc5.yellow("Usage: /skills search <query...>") };
|
|
3912
|
+
}
|
|
3913
|
+
const query = args.join(" ").toLowerCase();
|
|
3914
|
+
const home3 = os12.homedir();
|
|
3915
|
+
const raw = readEcosystemFile(path13.join(home3, ".askill", "skills.md"), "skills (askill)");
|
|
3916
|
+
if (raw.startsWith("No ")) {
|
|
3917
|
+
return { handled: true, output: raw };
|
|
3918
|
+
}
|
|
3919
|
+
const lines = raw.split("\n");
|
|
3920
|
+
const matches = lines.filter((l) => l.toLowerCase().includes(query));
|
|
3921
|
+
if (matches.length === 0) {
|
|
3922
|
+
return { handled: true, output: pc5.dim(`No skills matching "${query}".`) };
|
|
3923
|
+
}
|
|
3924
|
+
return { handled: true, output: [pc5.bold(`Skills matching "${query}":`), ...matches].join("\n") };
|
|
3925
|
+
}
|
|
3589
3926
|
if (action === "help") {
|
|
3590
3927
|
return { handled: true, output: [
|
|
3591
3928
|
pc5.bold("Skills commands:"),
|
|
3592
3929
|
` ${pc5.cyan("/skills")} View installed skills`,
|
|
3593
3930
|
` ${pc5.cyan("/skills install")} <name> Install a skill`,
|
|
3594
|
-
` ${pc5.cyan("/skills uninstall")} <name> Uninstall a skill
|
|
3931
|
+
` ${pc5.cyan("/skills uninstall")} <name> Uninstall a skill`,
|
|
3932
|
+
` ${pc5.cyan("/skills search")} <query> Search skills by name/description`
|
|
3595
3933
|
].join("\n") };
|
|
3596
3934
|
}
|
|
3597
3935
|
return { handled: true, output: pc5.yellow(`Unknown action: /skills ${action}. Try /skills --help`) };
|
|
3598
3936
|
}
|
|
3599
3937
|
async function handleEvalCommand(action, args, ctx) {
|
|
3600
|
-
const home2 =
|
|
3938
|
+
const home2 = os12.homedir();
|
|
3601
3939
|
if (!action) {
|
|
3602
|
-
const content = readEcosystemFile(
|
|
3940
|
+
const content = readEcosystemFile(path13.join(home2, ".aeval", "eval.md"), "evaluation (aeval)");
|
|
3603
3941
|
return { handled: true, output: content };
|
|
3604
3942
|
}
|
|
3605
3943
|
if (action === "milestone") {
|
|
@@ -3610,7 +3948,15 @@ async function handleEvalCommand(action, args, ctx) {
|
|
|
3610
3948
|
const output = await mcpWrite(ctx, "eval", "eval_milestone", { text: text3 });
|
|
3611
3949
|
return { handled: true, output };
|
|
3612
3950
|
}
|
|
3613
|
-
|
|
3951
|
+
if (action === "report") {
|
|
3952
|
+
const evalFile = path13.join(home2, ".aeval", "eval.md");
|
|
3953
|
+
if (!fs13.existsSync(evalFile)) {
|
|
3954
|
+
return { handled: true, output: pc5.dim("No eval report found. Log milestones with /eval milestone <text>.") };
|
|
3955
|
+
}
|
|
3956
|
+
const content = fs13.readFileSync(evalFile, "utf-8").trim();
|
|
3957
|
+
return { handled: true, output: [pc5.bold("Eval Report"), "", content].join("\n") };
|
|
3958
|
+
}
|
|
3959
|
+
return { handled: true, output: pc5.yellow(`Unknown action: /eval ${action}. Use /eval, /eval report, or /eval milestone <text>.`) };
|
|
3614
3960
|
}
|
|
3615
3961
|
async function handleMemoryCommand(action, args, ctx) {
|
|
3616
3962
|
if (!action) {
|
|
@@ -3624,7 +3970,7 @@ async function handleMemoryCommand(action, args, ctx) {
|
|
|
3624
3970
|
return { handled: true, output: pc5.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
3625
3971
|
}
|
|
3626
3972
|
}
|
|
3627
|
-
if (action && !["search", "clear", "timeline", "stats", "export", "since", "fts", "help"].includes(action)) {
|
|
3973
|
+
if (action && !["search", "clear", "timeline", "stats", "export", "since", "fts", "help", "doctor", "repair", "config", "reflect", "consolidate", "tier", "detail", "relate", "expire", "versions", "sync"].includes(action)) {
|
|
3628
3974
|
try {
|
|
3629
3975
|
const topic = [action, ...args].join(" ");
|
|
3630
3976
|
const result = await memoryContext(topic);
|
|
@@ -3642,8 +3988,17 @@ async function handleMemoryCommand(action, args, ctx) {
|
|
|
3642
3988
|
}
|
|
3643
3989
|
const query = args.join(" ");
|
|
3644
3990
|
try {
|
|
3645
|
-
const result = await
|
|
3646
|
-
|
|
3991
|
+
const result = await memoryMultiRecall(query, { limit: 10 });
|
|
3992
|
+
if (result.total === 0) {
|
|
3993
|
+
return { handled: true, output: pc5.dim("No memories found.") };
|
|
3994
|
+
}
|
|
3995
|
+
const header = `Search results for "${query}" (${result.total}):`;
|
|
3996
|
+
const lines = [pc5.bold(header), ""];
|
|
3997
|
+
for (const m of result.memories) {
|
|
3998
|
+
const tags = m.tags?.length > 0 ? ` ${pc5.dim(m.tags.map((t) => `#${t}`).join(" "))}` : "";
|
|
3999
|
+
lines.push(` [${m.type}] ${m.content}${tags}`);
|
|
4000
|
+
}
|
|
4001
|
+
return { handled: true, output: lines.join("\n") };
|
|
3647
4002
|
} catch (err) {
|
|
3648
4003
|
return { handled: true, output: pc5.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
3649
4004
|
}
|
|
@@ -3808,9 +4163,214 @@ async function handleMemoryCommand(action, args, ctx) {
|
|
|
3808
4163
|
` ${pc5.cyan("/memory export")} [json] Export all memories`,
|
|
3809
4164
|
` ${pc5.cyan("/memory timeline")} View memory timeline`,
|
|
3810
4165
|
` ${pc5.cyan("/memory clear")} <query> Delete matching memories`,
|
|
3811
|
-
` ${pc5.cyan("/memory clear --type")} <type> Delete all of a type
|
|
4166
|
+
` ${pc5.cyan("/memory clear --type")} <type> Delete all of a type`,
|
|
4167
|
+
` ${pc5.cyan("/memory doctor")} Run memory diagnostics`,
|
|
4168
|
+
` ${pc5.cyan("/memory repair")} Dry-run repair (safe)`,
|
|
4169
|
+
` ${pc5.cyan("/memory config")} [key=value] View or update config (e.g. consolidation.maxStaleDays=60)`
|
|
3812
4170
|
].join("\n") };
|
|
3813
4171
|
}
|
|
4172
|
+
if (action === "doctor") {
|
|
4173
|
+
try {
|
|
4174
|
+
const diag = await memoryDoctor();
|
|
4175
|
+
const statusIcon = diag.status === "healthy" ? "\u2705" : "\u26A0\uFE0F";
|
|
4176
|
+
const lines = [
|
|
4177
|
+
`**Memory Diagnostics**`,
|
|
4178
|
+
`Status: ${statusIcon} ${diag.status}`
|
|
4179
|
+
];
|
|
4180
|
+
if (diag.issues?.length) {
|
|
4181
|
+
lines.push("", "**Issues:**");
|
|
4182
|
+
for (const issue of diag.issues) {
|
|
4183
|
+
lines.push(`- ${typeof issue === "string" ? issue : issue.message ?? String(issue)}`);
|
|
4184
|
+
}
|
|
4185
|
+
lines.push("", "_Run `/memory repair` (dry-run) or `/memory repair --apply` to fix._");
|
|
4186
|
+
}
|
|
4187
|
+
return { handled: true, output: lines.join("\n") };
|
|
4188
|
+
} catch (err) {
|
|
4189
|
+
return { handled: true, output: pc5.red(`Memory doctor error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
4190
|
+
}
|
|
4191
|
+
}
|
|
4192
|
+
if (action === "repair") {
|
|
4193
|
+
try {
|
|
4194
|
+
const dryRun = !args.includes("--apply");
|
|
4195
|
+
const result = await memoryRepair({ dryRun });
|
|
4196
|
+
const prefix = dryRun ? "[DRY RUN] " : "";
|
|
4197
|
+
const lines = [`**${prefix}Memory Repair**`];
|
|
4198
|
+
if (result.actions?.length) {
|
|
4199
|
+
lines.push("", "**Actions:**");
|
|
4200
|
+
for (const act of result.actions) {
|
|
4201
|
+
lines.push(`- ${act}`);
|
|
4202
|
+
}
|
|
4203
|
+
} else {
|
|
4204
|
+
lines.push("No actions needed.");
|
|
4205
|
+
}
|
|
4206
|
+
if (dryRun) {
|
|
4207
|
+
lines.push("", "_Run `/memory repair --apply` to execute._");
|
|
4208
|
+
}
|
|
4209
|
+
return { handled: true, output: lines.join("\n") };
|
|
4210
|
+
} catch (err) {
|
|
4211
|
+
return { handled: true, output: pc5.red(`Memory repair error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
4212
|
+
}
|
|
4213
|
+
}
|
|
4214
|
+
if (action === "config") {
|
|
4215
|
+
try {
|
|
4216
|
+
const kvArg = args.find((a) => a.includes("=") && !a.startsWith("-"));
|
|
4217
|
+
if (kvArg) {
|
|
4218
|
+
const eqIdx = kvArg.indexOf("=");
|
|
4219
|
+
const key = kvArg.slice(0, eqIdx);
|
|
4220
|
+
const rawVal = kvArg.slice(eqIdx + 1);
|
|
4221
|
+
if (!rawVal) {
|
|
4222
|
+
return { handled: true, output: pc5.yellow(`Usage: /memory config <key>=<value>`) };
|
|
4223
|
+
}
|
|
4224
|
+
const val = isNaN(Number(rawVal)) ? rawVal : Number(rawVal);
|
|
4225
|
+
const update = buildNestedUpdate(key, val);
|
|
4226
|
+
await memoryConfig(update);
|
|
4227
|
+
return { handled: true, output: `\u2705 Set \`${key}\` \u2192 \`${val}\`` };
|
|
4228
|
+
}
|
|
4229
|
+
const config = await memoryConfig();
|
|
4230
|
+
const lines = ["**Memory Config**", "```"];
|
|
4231
|
+
for (const [k, v] of Object.entries(config)) {
|
|
4232
|
+
if (typeof v === "object" && v !== null) {
|
|
4233
|
+
for (const [sk, sv] of Object.entries(v)) {
|
|
4234
|
+
lines.push(`${k}.${sk}: ${sv}`);
|
|
4235
|
+
}
|
|
4236
|
+
} else {
|
|
4237
|
+
lines.push(`${k}: ${v}`);
|
|
4238
|
+
}
|
|
4239
|
+
}
|
|
4240
|
+
lines.push("```", "", "_Use `/memory config key=value` to change a setting._");
|
|
4241
|
+
return { handled: true, output: lines.join("\n") };
|
|
4242
|
+
} catch (err) {
|
|
4243
|
+
return { handled: true, output: pc5.red(`Memory config error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
4244
|
+
}
|
|
4245
|
+
}
|
|
4246
|
+
if (action === "reflect") {
|
|
4247
|
+
try {
|
|
4248
|
+
const report = await memoryReflect();
|
|
4249
|
+
const lines = [
|
|
4250
|
+
pc5.bold("Reflection complete"),
|
|
4251
|
+
`Clusters: ${report.clusters.length}`,
|
|
4252
|
+
`Contradictions: ${report.contradictions.length}`,
|
|
4253
|
+
`Synthesis candidates: ${report.synthesisCandidates.length}`,
|
|
4254
|
+
`Knowledge gaps: ${report.knowledgeGaps.length}`,
|
|
4255
|
+
`Health score: ${(report.stats.healthScore * 100).toFixed(0)}%`,
|
|
4256
|
+
`Duration: ${report.durationMs}ms`
|
|
4257
|
+
];
|
|
4258
|
+
return { handled: true, output: lines.join("\n") };
|
|
4259
|
+
} catch (err) {
|
|
4260
|
+
return { handled: true, output: pc5.red(`Reflect error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
4261
|
+
}
|
|
4262
|
+
}
|
|
4263
|
+
if (action === "consolidate") {
|
|
4264
|
+
const apply = args.includes("--apply");
|
|
4265
|
+
try {
|
|
4266
|
+
const report = memoryConsolidate(!apply);
|
|
4267
|
+
const lines = [
|
|
4268
|
+
apply ? pc5.bold("Consolidation applied") : pc5.bold("Consolidation dry-run"),
|
|
4269
|
+
`Merged: ${report.merged}`,
|
|
4270
|
+
`Pruned: ${report.pruned}`,
|
|
4271
|
+
`Promoted: ${report.promoted}`,
|
|
4272
|
+
`Decayed: ${report.decayed}`,
|
|
4273
|
+
`Health score: ${(report.healthScore * 100).toFixed(0)}%`,
|
|
4274
|
+
`Before: ${report.before.total} \u2192 After: ${report.after.total}`
|
|
4275
|
+
];
|
|
4276
|
+
if (!apply) lines.push(pc5.dim("Run with --apply to execute."));
|
|
4277
|
+
return { handled: true, output: lines.join("\n") };
|
|
4278
|
+
} catch (err) {
|
|
4279
|
+
return { handled: true, output: pc5.red(`Consolidate error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
4280
|
+
}
|
|
4281
|
+
}
|
|
4282
|
+
if (action === "tier") {
|
|
4283
|
+
const id = args[0];
|
|
4284
|
+
const tier = args[1];
|
|
4285
|
+
if (!id || !tier) {
|
|
4286
|
+
return { handled: true, output: pc5.yellow("Usage: /memory tier <id> <core|working|archival>") };
|
|
4287
|
+
}
|
|
4288
|
+
const tierResult = memoryTier(id, tier);
|
|
4289
|
+
if (!tierResult.ok) {
|
|
4290
|
+
return { handled: true, output: pc5.red(`Tier error: ${tierResult.error}`) };
|
|
4291
|
+
}
|
|
4292
|
+
return { handled: true, output: `\u2705 Memory ${tierResult.id} moved to tier: ${tierResult.tier}` };
|
|
4293
|
+
}
|
|
4294
|
+
if (action === "detail") {
|
|
4295
|
+
const id = args[0];
|
|
4296
|
+
if (!id) {
|
|
4297
|
+
return { handled: true, output: pc5.yellow("Usage: /memory detail <id>") };
|
|
4298
|
+
}
|
|
4299
|
+
const memory = memoryDetail(id);
|
|
4300
|
+
if (!memory) {
|
|
4301
|
+
return { handled: true, output: pc5.dim(`Memory not found: ${id}`) };
|
|
4302
|
+
}
|
|
4303
|
+
const lines = [
|
|
4304
|
+
pc5.bold(`Memory: ${memory.id}`),
|
|
4305
|
+
`Content: ${memory.content}`,
|
|
4306
|
+
`Type: ${memory.type}`,
|
|
4307
|
+
`Confidence: ${memory.confidence}`,
|
|
4308
|
+
`Tier: ${memory.tier ?? "working"}`,
|
|
4309
|
+
`Access count: ${memory.accessCount}`,
|
|
4310
|
+
`Created: ${new Date(memory.createdAt).toISOString()}`,
|
|
4311
|
+
memory.tags?.length ? `Tags: ${memory.tags.join(", ")}` : ""
|
|
4312
|
+
].filter(Boolean);
|
|
4313
|
+
return { handled: true, output: lines.join("\n") };
|
|
4314
|
+
}
|
|
4315
|
+
if (action === "relate") {
|
|
4316
|
+
const [fromId, toId, relType, strengthStr] = args;
|
|
4317
|
+
if (!fromId || !toId || !relType) {
|
|
4318
|
+
return { handled: true, output: pc5.yellow("Usage: /memory relate <fromId> <toId> <type> [strength]") };
|
|
4319
|
+
}
|
|
4320
|
+
const strength = strengthStr !== void 0 ? parseFloat(strengthStr) : void 0;
|
|
4321
|
+
const relResult = memoryRelate(fromId, toId, relType, strength);
|
|
4322
|
+
if (!relResult.ok) {
|
|
4323
|
+
return { handled: true, output: pc5.red(`Relate error: ${relResult.error}`) };
|
|
4324
|
+
}
|
|
4325
|
+
return { handled: true, output: `\u2705 Relation created: ${fromId} --[${relType}]--> ${toId} (id: ${relResult.relationId})` };
|
|
4326
|
+
}
|
|
4327
|
+
if (action === "expire") {
|
|
4328
|
+
const id = args[0];
|
|
4329
|
+
if (!id) {
|
|
4330
|
+
return { handled: true, output: pc5.yellow("Usage: /memory expire <id> [reason]") };
|
|
4331
|
+
}
|
|
4332
|
+
const reason = args.slice(1).join(" ") || void 0;
|
|
4333
|
+
const expireResult = memoryExpire(id, reason);
|
|
4334
|
+
if (!expireResult.ok) {
|
|
4335
|
+
return { handled: true, output: pc5.red(`Expire error: ${expireResult.error}`) };
|
|
4336
|
+
}
|
|
4337
|
+
return { handled: true, output: `\u2705 Memory ${expireResult.id} expired${reason ? `: ${reason}` : ""}` };
|
|
4338
|
+
}
|
|
4339
|
+
if (action === "versions") {
|
|
4340
|
+
const id = args[0];
|
|
4341
|
+
if (!id) {
|
|
4342
|
+
return { handled: true, output: pc5.yellow("Usage: /memory versions <id>") };
|
|
4343
|
+
}
|
|
4344
|
+
const versions = memoryVersions(id);
|
|
4345
|
+
if (!versions.length) {
|
|
4346
|
+
return { handled: true, output: pc5.dim(`No version history for: ${id}`) };
|
|
4347
|
+
}
|
|
4348
|
+
const lines = [pc5.bold(`Version history for ${id}:`)];
|
|
4349
|
+
for (const v of versions) {
|
|
4350
|
+
lines.push(` [${new Date(v.editedAt).toISOString()}] ${v.content.slice(0, 80)}${v.content.length > 80 ? "\u2026" : ""}`);
|
|
4351
|
+
}
|
|
4352
|
+
return { handled: true, output: lines.join("\n") };
|
|
4353
|
+
}
|
|
4354
|
+
if (action === "sync") {
|
|
4355
|
+
const syncAction = args[0];
|
|
4356
|
+
if (!syncAction) {
|
|
4357
|
+
return { handled: true, output: pc5.yellow("Usage: /memory sync <import-claude|export-team|import-team|sync-copilot>") };
|
|
4358
|
+
}
|
|
4359
|
+
try {
|
|
4360
|
+
const opts = {};
|
|
4361
|
+
for (const arg of args.slice(1)) {
|
|
4362
|
+
if (arg.startsWith("--")) {
|
|
4363
|
+
const [k, v] = arg.slice(2).split("=");
|
|
4364
|
+
opts[k] = v ?? true;
|
|
4365
|
+
}
|
|
4366
|
+
}
|
|
4367
|
+
const result = await memorySync(syncAction, opts);
|
|
4368
|
+
return { handled: true, output: `\u2705 Sync [${syncAction}] complete:
|
|
4369
|
+
${JSON.stringify(result, null, 2)}` };
|
|
4370
|
+
} catch (err) {
|
|
4371
|
+
return { handled: true, output: pc5.red(`Sync error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
4372
|
+
}
|
|
4373
|
+
}
|
|
3814
4374
|
return { handled: true, output: pc5.yellow(`Unknown action: /memory ${action}. Try /memory --help`) };
|
|
3815
4375
|
}
|
|
3816
4376
|
function handleStatusCommand(ctx) {
|
|
@@ -3915,10 +4475,10 @@ function handleSave() {
|
|
|
3915
4475
|
}
|
|
3916
4476
|
function handleReset(action) {
|
|
3917
4477
|
const dirs = {
|
|
3918
|
-
config:
|
|
3919
|
-
memory:
|
|
3920
|
-
identity:
|
|
3921
|
-
rules:
|
|
4478
|
+
config: path13.join(os12.homedir(), ".aman-agent"),
|
|
4479
|
+
memory: path13.join(os12.homedir(), ".amem"),
|
|
4480
|
+
identity: path13.join(os12.homedir(), ".acore"),
|
|
4481
|
+
rules: path13.join(os12.homedir(), ".arules")
|
|
3922
4482
|
};
|
|
3923
4483
|
if (action === "help" || !action) {
|
|
3924
4484
|
return {
|
|
@@ -3943,15 +4503,15 @@ function handleReset(action) {
|
|
|
3943
4503
|
const removed = [];
|
|
3944
4504
|
for (const target of targets) {
|
|
3945
4505
|
const dir = dirs[target];
|
|
3946
|
-
if (
|
|
3947
|
-
|
|
4506
|
+
if (fs13.existsSync(dir)) {
|
|
4507
|
+
fs13.rmSync(dir, { recursive: true, force: true });
|
|
3948
4508
|
removed.push(target);
|
|
3949
4509
|
}
|
|
3950
4510
|
}
|
|
3951
4511
|
if (targets.includes("config")) {
|
|
3952
4512
|
const configDir = dirs.config;
|
|
3953
|
-
|
|
3954
|
-
|
|
4513
|
+
fs13.mkdirSync(configDir, { recursive: true });
|
|
4514
|
+
fs13.writeFileSync(path13.join(configDir, ".reconfig"), "", "utf-8");
|
|
3955
4515
|
}
|
|
3956
4516
|
if (removed.length === 0) {
|
|
3957
4517
|
return { handled: true, output: pc5.dim("Nothing to reset \u2014 directories don't exist.") };
|
|
@@ -3968,7 +4528,7 @@ function handleReset(action) {
|
|
|
3968
4528
|
function handleUpdate() {
|
|
3969
4529
|
try {
|
|
3970
4530
|
const current = execFileSync3("npm", ["view", "@aman_asmuei/aman-agent", "version"], { encoding: "utf-8" }).trim();
|
|
3971
|
-
const local = true ? "0.
|
|
4531
|
+
const local = true ? "0.24.3" : "unknown";
|
|
3972
4532
|
if (current === local) {
|
|
3973
4533
|
return { handled: true, output: `${pc5.green("Up to date")} \u2014 v${local}` };
|
|
3974
4534
|
}
|
|
@@ -4012,11 +4572,11 @@ function handleExportCommand() {
|
|
|
4012
4572
|
return { handled: true, exportConversation: true };
|
|
4013
4573
|
}
|
|
4014
4574
|
function handleDebugCommand() {
|
|
4015
|
-
const logPath =
|
|
4016
|
-
if (!
|
|
4575
|
+
const logPath = path13.join(os12.homedir(), ".aman-agent", "debug.log");
|
|
4576
|
+
if (!fs13.existsSync(logPath)) {
|
|
4017
4577
|
return { handled: true, output: pc5.dim("No debug log found.") };
|
|
4018
4578
|
}
|
|
4019
|
-
const content =
|
|
4579
|
+
const content = fs13.readFileSync(logPath, "utf-8");
|
|
4020
4580
|
const lines = content.trim().split("\n");
|
|
4021
4581
|
const last20 = lines.slice(-20).join("\n");
|
|
4022
4582
|
return { handled: true, output: pc5.bold("Debug Log (last 20 entries):\n") + pc5.dim(last20) };
|
|
@@ -4214,7 +4774,7 @@ ${result.response}`
|
|
|
4214
4774
|
};
|
|
4215
4775
|
}
|
|
4216
4776
|
function handleProfileCommand(action, args) {
|
|
4217
|
-
const profilesDir =
|
|
4777
|
+
const profilesDir = path13.join(os12.homedir(), ".acore", "profiles");
|
|
4218
4778
|
if (action === "me") {
|
|
4219
4779
|
const user = loadUserIdentity();
|
|
4220
4780
|
if (!user) {
|
|
@@ -4282,8 +4842,8 @@ ${pc5.dim("Edit with: /profile edit")}` };
|
|
|
4282
4842
|
};
|
|
4283
4843
|
}
|
|
4284
4844
|
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
4285
|
-
const profileDir =
|
|
4286
|
-
if (
|
|
4845
|
+
const profileDir = path13.join(profilesDir, slug);
|
|
4846
|
+
if (fs13.existsSync(profileDir)) {
|
|
4287
4847
|
return { handled: true, output: pc5.yellow(`Profile already exists: ${slug}`) };
|
|
4288
4848
|
}
|
|
4289
4849
|
const builtIn = BUILT_IN_PROFILES.find((t) => t.name === slug);
|
|
@@ -4299,16 +4859,16 @@ ${pc5.dim("Edit with: /profile edit")}` };
|
|
|
4299
4859
|
Use: aman-agent --profile ${slug}`
|
|
4300
4860
|
};
|
|
4301
4861
|
}
|
|
4302
|
-
|
|
4303
|
-
const globalCore =
|
|
4304
|
-
if (
|
|
4305
|
-
let content =
|
|
4862
|
+
fs13.mkdirSync(profileDir, { recursive: true });
|
|
4863
|
+
const globalCore = path13.join(os12.homedir(), ".acore", "core.md");
|
|
4864
|
+
if (fs13.existsSync(globalCore)) {
|
|
4865
|
+
let content = fs13.readFileSync(globalCore, "utf-8");
|
|
4306
4866
|
const aiName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
4307
4867
|
content = content.replace(/^# .+$/m, `# ${aiName}`);
|
|
4308
|
-
|
|
4868
|
+
fs13.writeFileSync(path13.join(profileDir, "core.md"), content, "utf-8");
|
|
4309
4869
|
} else {
|
|
4310
4870
|
const aiName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
4311
|
-
|
|
4871
|
+
fs13.writeFileSync(path13.join(profileDir, "core.md"), `# ${aiName}
|
|
4312
4872
|
|
|
4313
4873
|
## Identity
|
|
4314
4874
|
- Role: ${aiName} is your AI companion
|
|
@@ -4321,7 +4881,7 @@ ${pc5.dim("Edit with: /profile edit")}` };
|
|
|
4321
4881
|
return {
|
|
4322
4882
|
handled: true,
|
|
4323
4883
|
output: pc5.green(`Profile created: ${slug}`) + `
|
|
4324
|
-
Edit: ${
|
|
4884
|
+
Edit: ${path13.join(profileDir, "core.md")}
|
|
4325
4885
|
Use: aman-agent --profile ${slug}
|
|
4326
4886
|
|
|
4327
4887
|
${pc5.dim("Add rules.md or skills.md for profile-specific overrides.")}`
|
|
@@ -4330,9 +4890,9 @@ ${pc5.dim("Edit with: /profile edit")}` };
|
|
|
4330
4890
|
case "show": {
|
|
4331
4891
|
const name = args[0];
|
|
4332
4892
|
if (!name) return { handled: true, output: pc5.yellow("Usage: /profile show <name>") };
|
|
4333
|
-
const profileDir =
|
|
4334
|
-
if (!
|
|
4335
|
-
const files =
|
|
4893
|
+
const profileDir = path13.join(profilesDir, name);
|
|
4894
|
+
if (!fs13.existsSync(profileDir)) return { handled: true, output: pc5.red(`Profile not found: ${name}`) };
|
|
4895
|
+
const files = fs13.readdirSync(profileDir).filter((f) => f.endsWith(".md"));
|
|
4336
4896
|
const lines = files.map((f) => ` ${f}`);
|
|
4337
4897
|
return { handled: true, output: `Profile: ${pc5.bold(name)}
|
|
4338
4898
|
Files:
|
|
@@ -4341,9 +4901,9 @@ ${lines.join("\n")}` };
|
|
|
4341
4901
|
case "delete": {
|
|
4342
4902
|
const name = args[0];
|
|
4343
4903
|
if (!name) return { handled: true, output: pc5.yellow("Usage: /profile delete <name>") };
|
|
4344
|
-
const profileDir =
|
|
4345
|
-
if (!
|
|
4346
|
-
|
|
4904
|
+
const profileDir = path13.join(profilesDir, name);
|
|
4905
|
+
if (!fs13.existsSync(profileDir)) return { handled: true, output: pc5.red(`Profile not found: ${name}`) };
|
|
4906
|
+
fs13.rmSync(profileDir, { recursive: true });
|
|
4347
4907
|
return { handled: true, output: pc5.dim(`Profile deleted: ${name}`) };
|
|
4348
4908
|
}
|
|
4349
4909
|
case "help":
|
|
@@ -4549,10 +5109,10 @@ function handleShowcaseCommand(action, args) {
|
|
|
4549
5109
|
Or place it as a sibling directory to aman-agent.`
|
|
4550
5110
|
};
|
|
4551
5111
|
}
|
|
4552
|
-
const corePath =
|
|
5112
|
+
const corePath = path13.join(os12.homedir(), ".acore", "core.md");
|
|
4553
5113
|
let currentShowcase = null;
|
|
4554
|
-
if (
|
|
4555
|
-
const content =
|
|
5114
|
+
if (fs13.existsSync(corePath)) {
|
|
5115
|
+
const content = fs13.readFileSync(corePath, "utf-8");
|
|
4556
5116
|
const nameMatch = content.match(/^# (.+)/m);
|
|
4557
5117
|
if (nameMatch) {
|
|
4558
5118
|
const coreName = nameMatch[1].trim().toLowerCase();
|
|
@@ -4634,6 +5194,65 @@ ${pc5.dim("Existing files are backed up (.bak) before overwriting.")}` };
|
|
|
4634
5194
|
}
|
|
4635
5195
|
return { handled: true, output: pc5.yellow(`Unknown action: /showcase ${action}. Try /showcase help`) };
|
|
4636
5196
|
}
|
|
5197
|
+
async function handleFileCommand(action, args) {
|
|
5198
|
+
if (!action) {
|
|
5199
|
+
return {
|
|
5200
|
+
handled: true,
|
|
5201
|
+
output: [
|
|
5202
|
+
pc5.bold("File commands:"),
|
|
5203
|
+
` ${pc5.cyan("/file read")} <path> Read a text file (max 50 KB)`,
|
|
5204
|
+
` ${pc5.cyan("/file convert")} <path> Attempt to read binary file as text`,
|
|
5205
|
+
` ${pc5.cyan("/file list")} <path> [--recursive] List directory contents`
|
|
5206
|
+
].join("\n")
|
|
5207
|
+
};
|
|
5208
|
+
}
|
|
5209
|
+
if (action === "read" || action === "convert") {
|
|
5210
|
+
const filePath = args[0];
|
|
5211
|
+
if (!filePath) {
|
|
5212
|
+
return { handled: true, output: pc5.yellow(`Usage: /file ${action} <path>`) };
|
|
5213
|
+
}
|
|
5214
|
+
try {
|
|
5215
|
+
const result = await readFile(filePath);
|
|
5216
|
+
const lines = [
|
|
5217
|
+
pc5.bold(`\u{1F4C4} ${result.path}`) + pc5.dim(` (${(result.size / 1024).toFixed(1)} KB)`),
|
|
5218
|
+
"",
|
|
5219
|
+
result.content
|
|
5220
|
+
];
|
|
5221
|
+
if (result.truncated) {
|
|
5222
|
+
lines.push("", pc5.yellow(`\u26A0 File truncated at 50 KB. Use a text editor for the full file.`));
|
|
5223
|
+
}
|
|
5224
|
+
return { handled: true, output: lines.join("\n") };
|
|
5225
|
+
} catch (err) {
|
|
5226
|
+
return { handled: true, output: pc5.red(`File error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
5227
|
+
}
|
|
5228
|
+
}
|
|
5229
|
+
if (action === "list") {
|
|
5230
|
+
const dirPath = args.find((a) => !a.startsWith("-"));
|
|
5231
|
+
if (!dirPath) {
|
|
5232
|
+
return { handled: true, output: pc5.yellow(`Usage: /file list <path> [--recursive]`) };
|
|
5233
|
+
}
|
|
5234
|
+
const recursive = args.includes("--recursive") || args.includes("-r");
|
|
5235
|
+
try {
|
|
5236
|
+
const result = await listFiles(dirPath, { recursive });
|
|
5237
|
+
const lines = [
|
|
5238
|
+
pc5.bold(`\u{1F4C1} ${result.path}`) + pc5.dim(` (${result.total} items)`),
|
|
5239
|
+
""
|
|
5240
|
+
];
|
|
5241
|
+
for (const entry of result.entries) {
|
|
5242
|
+
if (entry.type === "dir") {
|
|
5243
|
+
lines.push(` ${pc5.cyan(entry.name + "/")}`);
|
|
5244
|
+
} else {
|
|
5245
|
+
const kb = entry.size > 0 ? pc5.dim(` ${(entry.size / 1024).toFixed(1)} KB`) : "";
|
|
5246
|
+
lines.push(` ${entry.name}${kb}`);
|
|
5247
|
+
}
|
|
5248
|
+
}
|
|
5249
|
+
return { handled: true, output: lines.join("\n") };
|
|
5250
|
+
} catch (err) {
|
|
5251
|
+
return { handled: true, output: pc5.red(`File error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
5252
|
+
}
|
|
5253
|
+
}
|
|
5254
|
+
return { handled: true, output: pc5.yellow(`Unknown /file subcommand: ${action}. Try /file for help.`) };
|
|
5255
|
+
}
|
|
4637
5256
|
var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
|
|
4638
5257
|
"quit",
|
|
4639
5258
|
"exit",
|
|
@@ -4663,7 +5282,8 @@ var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
4663
5282
|
"profile",
|
|
4664
5283
|
"delegate",
|
|
4665
5284
|
"team",
|
|
4666
|
-
"showcase"
|
|
5285
|
+
"showcase",
|
|
5286
|
+
"file"
|
|
4667
5287
|
]);
|
|
4668
5288
|
async function handleCommand(input, ctx) {
|
|
4669
5289
|
const trimmed = input.trim();
|
|
@@ -4688,6 +5308,7 @@ async function handleCommand(input, ctx) {
|
|
|
4688
5308
|
case "workflows":
|
|
4689
5309
|
return handleWorkflowsCommand(action, args, ctx);
|
|
4690
5310
|
case "tools":
|
|
5311
|
+
return handleToolsCommand(action, args, ctx);
|
|
4691
5312
|
case "akit":
|
|
4692
5313
|
return handleAkitCommand(action, args);
|
|
4693
5314
|
case "skills":
|
|
@@ -4722,6 +5343,8 @@ async function handleCommand(input, ctx) {
|
|
|
4722
5343
|
return handleReminderCommand(action, args);
|
|
4723
5344
|
case "showcase":
|
|
4724
5345
|
return handleShowcaseCommand(action, args);
|
|
5346
|
+
case "file":
|
|
5347
|
+
return handleFileCommand(action, args);
|
|
4725
5348
|
case "update":
|
|
4726
5349
|
case "upgrade":
|
|
4727
5350
|
return handleUpdate();
|
|
@@ -4804,9 +5427,9 @@ ${summaryParts.slice(0, 20).join("\n")}
|
|
|
4804
5427
|
}
|
|
4805
5428
|
|
|
4806
5429
|
// src/skill-engine.ts
|
|
4807
|
-
import
|
|
4808
|
-
import
|
|
4809
|
-
import
|
|
5430
|
+
import fs14 from "fs";
|
|
5431
|
+
import path14 from "path";
|
|
5432
|
+
import os13 from "os";
|
|
4810
5433
|
var SKILL_TRIGGERS = {
|
|
4811
5434
|
testing: ["test", "spec", "coverage", "tdd", "jest", "vitest", "mocha", "assert", "mock", "stub", "fixture", "e2e", "integration test", "unit test"],
|
|
4812
5435
|
"api-design": ["api", "endpoint", "rest", "graphql", "route", "controller", "middleware", "http", "request", "response", "status code", "pagination"],
|
|
@@ -4821,20 +5444,20 @@ var SKILL_TRIGGERS = {
|
|
|
4821
5444
|
typescript: ["typescript", "type", "interface", "generic", "infer", "utility type", "zod", "discriminated union", "type guard", "as const"],
|
|
4822
5445
|
accessibility: ["accessibility", "a11y", "aria", "screen reader", "wcag", "semantic html", "tab order", "focus", "contrast"]
|
|
4823
5446
|
};
|
|
4824
|
-
var LEVEL_FILE =
|
|
5447
|
+
var LEVEL_FILE = path14.join(os13.homedir(), ".aman-agent", "skill-levels.json");
|
|
4825
5448
|
function loadSkillLevels() {
|
|
4826
5449
|
try {
|
|
4827
|
-
if (
|
|
4828
|
-
return JSON.parse(
|
|
5450
|
+
if (fs14.existsSync(LEVEL_FILE)) {
|
|
5451
|
+
return JSON.parse(fs14.readFileSync(LEVEL_FILE, "utf-8"));
|
|
4829
5452
|
}
|
|
4830
5453
|
} catch {
|
|
4831
5454
|
}
|
|
4832
5455
|
return {};
|
|
4833
5456
|
}
|
|
4834
5457
|
function saveSkillLevels(levels) {
|
|
4835
|
-
const dir =
|
|
4836
|
-
if (!
|
|
4837
|
-
|
|
5458
|
+
const dir = path14.dirname(LEVEL_FILE);
|
|
5459
|
+
if (!fs14.existsSync(dir)) fs14.mkdirSync(dir, { recursive: true });
|
|
5460
|
+
fs14.writeFileSync(LEVEL_FILE, JSON.stringify(levels, null, 2), "utf-8");
|
|
4838
5461
|
}
|
|
4839
5462
|
function computeLevel(activations) {
|
|
4840
5463
|
if (activations >= 50) return { level: 5, label: "Expert" };
|
|
@@ -5163,6 +5786,7 @@ function matchKnowledge(userInput) {
|
|
|
5163
5786
|
}
|
|
5164
5787
|
|
|
5165
5788
|
// src/memory-extractor.ts
|
|
5789
|
+
import { reflect as reflect2, isReflectionDue as isReflectionDue2 } from "@aman_asmuei/amem-core";
|
|
5166
5790
|
var VALID_TYPES = /* @__PURE__ */ new Set(["preference", "fact", "pattern", "topology", "decision", "correction"]);
|
|
5167
5791
|
var MIN_RESPONSE_LENGTH = 50;
|
|
5168
5792
|
var MIN_TURNS_BETWEEN_EMPTY = 3;
|
|
@@ -5247,7 +5871,7 @@ Assistant: ${assistantResponse.slice(0, 2e3)}`;
|
|
|
5247
5871
|
} catch {
|
|
5248
5872
|
}
|
|
5249
5873
|
try {
|
|
5250
|
-
await memoryStore({
|
|
5874
|
+
const storeResult = await memoryStore({
|
|
5251
5875
|
content: candidate.content,
|
|
5252
5876
|
type: candidate.type,
|
|
5253
5877
|
tags: candidate.tags,
|
|
@@ -5255,18 +5879,26 @@ Assistant: ${assistantResponse.slice(0, 2e3)}`;
|
|
|
5255
5879
|
source: "auto-extraction",
|
|
5256
5880
|
scope: candidate.scope
|
|
5257
5881
|
});
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5882
|
+
if (storeResult.action !== "private") {
|
|
5883
|
+
stored++;
|
|
5884
|
+
log.debug("extractor", "Stored " + candidate.type + ": " + candidate.content);
|
|
5885
|
+
if (candidate.type === "pattern" || candidate.type === "preference") {
|
|
5886
|
+
const skillMatch = matchPatternToSkill(candidate.content, candidate.tags);
|
|
5887
|
+
if (skillMatch) {
|
|
5888
|
+
enrichSkill(skillMatch, candidate.content);
|
|
5889
|
+
}
|
|
5264
5890
|
}
|
|
5265
5891
|
}
|
|
5266
5892
|
} catch (err) {
|
|
5267
5893
|
log.warn("extractor", "Failed to store: " + candidate.content, err);
|
|
5268
5894
|
}
|
|
5269
5895
|
}
|
|
5896
|
+
if (stored > 0 && isReflectionDue2(getDb()).due) {
|
|
5897
|
+
try {
|
|
5898
|
+
reflect2(getDb());
|
|
5899
|
+
} catch {
|
|
5900
|
+
}
|
|
5901
|
+
}
|
|
5270
5902
|
return stored;
|
|
5271
5903
|
} catch (err) {
|
|
5272
5904
|
log.debug("extractor", "extraction failed", err);
|
|
@@ -5438,9 +6070,9 @@ function humanizeError(message) {
|
|
|
5438
6070
|
}
|
|
5439
6071
|
|
|
5440
6072
|
// src/hints.ts
|
|
5441
|
-
import
|
|
5442
|
-
import
|
|
5443
|
-
import
|
|
6073
|
+
import fs15 from "fs";
|
|
6074
|
+
import path15 from "path";
|
|
6075
|
+
import os14 from "os";
|
|
5444
6076
|
var HINTS = [
|
|
5445
6077
|
{
|
|
5446
6078
|
id: "eval",
|
|
@@ -5478,11 +6110,11 @@ function getHint(state, ctx) {
|
|
|
5478
6110
|
}
|
|
5479
6111
|
return null;
|
|
5480
6112
|
}
|
|
5481
|
-
var HINTS_FILE =
|
|
6113
|
+
var HINTS_FILE = path15.join(os14.homedir(), ".aman-agent", "hints-seen.json");
|
|
5482
6114
|
function loadShownHints() {
|
|
5483
6115
|
try {
|
|
5484
|
-
if (
|
|
5485
|
-
const data = JSON.parse(
|
|
6116
|
+
if (fs15.existsSync(HINTS_FILE)) {
|
|
6117
|
+
const data = JSON.parse(fs15.readFileSync(HINTS_FILE, "utf-8"));
|
|
5486
6118
|
return new Set(Array.isArray(data) ? data : []);
|
|
5487
6119
|
}
|
|
5488
6120
|
} catch {
|
|
@@ -5491,9 +6123,9 @@ function loadShownHints() {
|
|
|
5491
6123
|
}
|
|
5492
6124
|
function saveShownHints(shown) {
|
|
5493
6125
|
try {
|
|
5494
|
-
const dir =
|
|
5495
|
-
|
|
5496
|
-
|
|
6126
|
+
const dir = path15.dirname(HINTS_FILE);
|
|
6127
|
+
fs15.mkdirSync(dir, { recursive: true });
|
|
6128
|
+
fs15.writeFileSync(HINTS_FILE, JSON.stringify([...shown]), "utf-8");
|
|
5497
6129
|
} catch {
|
|
5498
6130
|
}
|
|
5499
6131
|
}
|
|
@@ -5738,9 +6370,9 @@ ${task.result}`
|
|
|
5738
6370
|
}
|
|
5739
6371
|
if (cmdResult.exportConversation) {
|
|
5740
6372
|
try {
|
|
5741
|
-
const exportDir =
|
|
5742
|
-
|
|
5743
|
-
const exportPath =
|
|
6373
|
+
const exportDir = path16.join(os15.homedir(), ".aman-agent", "exports");
|
|
6374
|
+
fs16.mkdirSync(exportDir, { recursive: true });
|
|
6375
|
+
const exportPath = path16.join(exportDir, `${sessionId}.md`);
|
|
5744
6376
|
const lines = [
|
|
5745
6377
|
`# Conversation \u2014 ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
|
|
5746
6378
|
`**Model:** ${model}`,
|
|
@@ -5754,7 +6386,7 @@ ${task.result}`
|
|
|
5754
6386
|
lines.push(`${label} ${msg.content}`, "");
|
|
5755
6387
|
}
|
|
5756
6388
|
}
|
|
5757
|
-
|
|
6389
|
+
fs16.writeFileSync(exportPath, lines.join("\n"), "utf-8");
|
|
5758
6390
|
console.log(pc7.green(`Exported to ${exportPath}`));
|
|
5759
6391
|
} catch {
|
|
5760
6392
|
console.log(pc7.red("Failed to export conversation."));
|
|
@@ -5880,25 +6512,25 @@ ${knowledgeItem.content}
|
|
|
5880
6512
|
for (const match of filePathMatches) {
|
|
5881
6513
|
let filePath = match[1];
|
|
5882
6514
|
if (filePath.startsWith("~/")) {
|
|
5883
|
-
filePath =
|
|
6515
|
+
filePath = path16.join(os15.homedir(), filePath.slice(2));
|
|
5884
6516
|
}
|
|
5885
|
-
if (!
|
|
5886
|
-
const ext =
|
|
6517
|
+
if (!fs16.existsSync(filePath) || !fs16.statSync(filePath).isFile()) continue;
|
|
6518
|
+
const ext = path16.extname(filePath).toLowerCase();
|
|
5887
6519
|
if (imageExts.has(ext)) {
|
|
5888
6520
|
try {
|
|
5889
|
-
const stat =
|
|
6521
|
+
const stat = fs16.statSync(filePath);
|
|
5890
6522
|
if (stat.size > maxImageBytes) {
|
|
5891
|
-
process.stdout.write(pc7.yellow(` [skipped: ${
|
|
6523
|
+
process.stdout.write(pc7.yellow(` [skipped: ${path16.basename(filePath)} \u2014 exceeds 20MB limit]
|
|
5892
6524
|
`));
|
|
5893
6525
|
continue;
|
|
5894
6526
|
}
|
|
5895
|
-
const data =
|
|
6527
|
+
const data = fs16.readFileSync(filePath).toString("base64");
|
|
5896
6528
|
const mediaType = mimeMap[ext] || "image/png";
|
|
5897
6529
|
imageBlocks.push({
|
|
5898
6530
|
type: "image",
|
|
5899
6531
|
source: { type: "base64", media_type: mediaType, data }
|
|
5900
6532
|
});
|
|
5901
|
-
process.stdout.write(pc7.dim(` [attached image: ${
|
|
6533
|
+
process.stdout.write(pc7.dim(` [attached image: ${path16.basename(filePath)} (${(stat.size / 1024).toFixed(1)}KB)]
|
|
5902
6534
|
`));
|
|
5903
6535
|
} catch {
|
|
5904
6536
|
process.stdout.write(pc7.dim(` [could not read image: ${filePath}]
|
|
@@ -5906,7 +6538,7 @@ ${knowledgeItem.content}
|
|
|
5906
6538
|
}
|
|
5907
6539
|
} else if (textExts.has(ext) || ext === "") {
|
|
5908
6540
|
try {
|
|
5909
|
-
const content =
|
|
6541
|
+
const content = fs16.readFileSync(filePath, "utf-8");
|
|
5910
6542
|
const maxChars = 5e4;
|
|
5911
6543
|
const trimmed = content.length > maxChars ? content.slice(0, maxChars) + `
|
|
5912
6544
|
|
|
@@ -5916,7 +6548,7 @@ ${knowledgeItem.content}
|
|
|
5916
6548
|
<file path="${filePath}" size="${content.length} chars">
|
|
5917
6549
|
${trimmed}
|
|
5918
6550
|
</file>`;
|
|
5919
|
-
process.stdout.write(pc7.dim(` [attached: ${
|
|
6551
|
+
process.stdout.write(pc7.dim(` [attached: ${path16.basename(filePath)} (${(content.length / 1024).toFixed(1)}KB)]
|
|
5920
6552
|
`));
|
|
5921
6553
|
} catch {
|
|
5922
6554
|
process.stdout.write(pc7.dim(` [could not read: ${filePath}]
|
|
@@ -5925,7 +6557,7 @@ ${trimmed}
|
|
|
5925
6557
|
} else if (docExts.has(ext)) {
|
|
5926
6558
|
if (mcpManager) {
|
|
5927
6559
|
try {
|
|
5928
|
-
process.stdout.write(pc7.dim(` [converting: ${
|
|
6560
|
+
process.stdout.write(pc7.dim(` [converting: ${path16.basename(filePath)}...]
|
|
5929
6561
|
`));
|
|
5930
6562
|
const converted = await mcpManager.callTool("doc_convert", { path: filePath });
|
|
5931
6563
|
if (converted && !converted.startsWith("Error") && !converted.includes("Could not convert")) {
|
|
@@ -5934,7 +6566,7 @@ ${trimmed}
|
|
|
5934
6566
|
<file path="${filePath}" format="${ext}">
|
|
5935
6567
|
${converted.slice(0, 5e4)}
|
|
5936
6568
|
</file>`;
|
|
5937
|
-
process.stdout.write(pc7.dim(` [attached: ${
|
|
6569
|
+
process.stdout.write(pc7.dim(` [attached: ${path16.basename(filePath)} (converted from ${ext})]
|
|
5938
6570
|
`));
|
|
5939
6571
|
} else {
|
|
5940
6572
|
textContent += `
|
|
@@ -5946,7 +6578,7 @@ ${converted}
|
|
|
5946
6578
|
`));
|
|
5947
6579
|
}
|
|
5948
6580
|
} catch {
|
|
5949
|
-
process.stdout.write(pc7.dim(` [could not convert: ${
|
|
6581
|
+
process.stdout.write(pc7.dim(` [could not convert: ${path16.basename(filePath)}]
|
|
5950
6582
|
`));
|
|
5951
6583
|
}
|
|
5952
6584
|
} else {
|
|
@@ -6188,7 +6820,7 @@ ${result2.response}` : `[${input2.profile}] failed: ${result2.error}`;
|
|
|
6188
6820
|
}
|
|
6189
6821
|
if (hooksConfig?.featureHints) {
|
|
6190
6822
|
hintState.turnCount++;
|
|
6191
|
-
const hasWorkflows =
|
|
6823
|
+
const hasWorkflows = fs16.existsSync(path16.join(os15.homedir(), ".aflow", "flow.md"));
|
|
6192
6824
|
const memoryCount = memoryTokens > 0 ? Math.floor(memoryTokens / 5) : 0;
|
|
6193
6825
|
const hint = getHint(hintState, { hasWorkflows, memoryCount });
|
|
6194
6826
|
if (hint) {
|
|
@@ -6234,9 +6866,9 @@ async function saveConversationToMemory(messages, sessionId) {
|
|
|
6234
6866
|
}
|
|
6235
6867
|
|
|
6236
6868
|
// src/index.ts
|
|
6237
|
-
import
|
|
6238
|
-
import
|
|
6239
|
-
import
|
|
6869
|
+
import fs17 from "fs";
|
|
6870
|
+
import path17 from "path";
|
|
6871
|
+
import os16 from "os";
|
|
6240
6872
|
|
|
6241
6873
|
// src/presets.ts
|
|
6242
6874
|
var PRESETS = {
|
|
@@ -6345,9 +6977,9 @@ ${wfSections}`;
|
|
|
6345
6977
|
|
|
6346
6978
|
// src/index.ts
|
|
6347
6979
|
async function autoDetectConfig() {
|
|
6348
|
-
const reconfigMarker =
|
|
6349
|
-
if (
|
|
6350
|
-
|
|
6980
|
+
const reconfigMarker = path17.join(os16.homedir(), ".aman-agent", ".reconfig");
|
|
6981
|
+
if (fs17.existsSync(reconfigMarker)) {
|
|
6982
|
+
fs17.unlinkSync(reconfigMarker);
|
|
6351
6983
|
return null;
|
|
6352
6984
|
}
|
|
6353
6985
|
const anthropicKey = process.env.ANTHROPIC_API_KEY;
|
|
@@ -6376,11 +7008,11 @@ async function autoDetectConfig() {
|
|
|
6376
7008
|
return null;
|
|
6377
7009
|
}
|
|
6378
7010
|
function bootstrapEcosystem() {
|
|
6379
|
-
const home2 =
|
|
6380
|
-
const corePath =
|
|
6381
|
-
if (
|
|
6382
|
-
|
|
6383
|
-
|
|
7011
|
+
const home2 = os16.homedir();
|
|
7012
|
+
const corePath = path17.join(home2, ".acore", "core.md");
|
|
7013
|
+
if (fs17.existsSync(corePath)) return false;
|
|
7014
|
+
fs17.mkdirSync(path17.join(home2, ".acore"), { recursive: true });
|
|
7015
|
+
fs17.writeFileSync(corePath, [
|
|
6384
7016
|
"# Aman",
|
|
6385
7017
|
"",
|
|
6386
7018
|
"## Personality",
|
|
@@ -6392,11 +7024,11 @@ function bootstrapEcosystem() {
|
|
|
6392
7024
|
"## Session",
|
|
6393
7025
|
"_New companion \u2014 no prior sessions._"
|
|
6394
7026
|
].join("\n"), "utf-8");
|
|
6395
|
-
const rulesDir =
|
|
6396
|
-
const rulesPath =
|
|
6397
|
-
if (!
|
|
6398
|
-
|
|
6399
|
-
|
|
7027
|
+
const rulesDir = path17.join(home2, ".arules");
|
|
7028
|
+
const rulesPath = path17.join(rulesDir, "rules.md");
|
|
7029
|
+
if (!fs17.existsSync(rulesPath)) {
|
|
7030
|
+
fs17.mkdirSync(rulesDir, { recursive: true });
|
|
7031
|
+
fs17.writeFileSync(rulesPath, [
|
|
6400
7032
|
"# Guardrails",
|
|
6401
7033
|
"",
|
|
6402
7034
|
"## safety",
|
|
@@ -6408,22 +7040,22 @@ function bootstrapEcosystem() {
|
|
|
6408
7040
|
"- Respect the user's preferences stored in memory"
|
|
6409
7041
|
].join("\n"), "utf-8");
|
|
6410
7042
|
}
|
|
6411
|
-
const flowDir =
|
|
6412
|
-
const flowPath =
|
|
6413
|
-
if (!
|
|
6414
|
-
|
|
6415
|
-
|
|
7043
|
+
const flowDir = path17.join(home2, ".aflow");
|
|
7044
|
+
const flowPath = path17.join(flowDir, "flow.md");
|
|
7045
|
+
if (!fs17.existsSync(flowPath)) {
|
|
7046
|
+
fs17.mkdirSync(flowDir, { recursive: true });
|
|
7047
|
+
fs17.writeFileSync(flowPath, "# Workflows\n\n_No workflows defined yet. Use /workflows add to create one._\n", "utf-8");
|
|
6416
7048
|
}
|
|
6417
|
-
const skillDir =
|
|
6418
|
-
const skillPath =
|
|
6419
|
-
if (!
|
|
6420
|
-
|
|
6421
|
-
|
|
7049
|
+
const skillDir = path17.join(home2, ".askill");
|
|
7050
|
+
const skillPath = path17.join(skillDir, "skills.md");
|
|
7051
|
+
if (!fs17.existsSync(skillPath)) {
|
|
7052
|
+
fs17.mkdirSync(skillDir, { recursive: true });
|
|
7053
|
+
fs17.writeFileSync(skillPath, "# Skills\n\n_No skills installed yet. Use /skills install to add domain expertise._\n", "utf-8");
|
|
6422
7054
|
}
|
|
6423
7055
|
return true;
|
|
6424
7056
|
}
|
|
6425
7057
|
var program = new Command();
|
|
6426
|
-
program.name("aman-agent").description("Your AI companion, running locally").version("0.
|
|
7058
|
+
program.name("aman-agent").description("Your AI companion, running locally").version("0.24.3").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) => {
|
|
6427
7059
|
p3.intro(pc8.bold("aman agent") + pc8.dim(" \u2014 your AI companion"));
|
|
6428
7060
|
let config = loadConfig();
|
|
6429
7061
|
if (!config) {
|
|
@@ -6775,19 +7407,19 @@ program.command("init").description("Set up your AI companion with a guided wiza
|
|
|
6775
7407
|
});
|
|
6776
7408
|
if (p3.isCancel(preset)) process.exit(0);
|
|
6777
7409
|
const result = applyPreset(preset, name || "Aman");
|
|
6778
|
-
const home2 =
|
|
6779
|
-
|
|
6780
|
-
|
|
7410
|
+
const home2 = os16.homedir();
|
|
7411
|
+
fs17.mkdirSync(path17.join(home2, ".acore"), { recursive: true });
|
|
7412
|
+
fs17.writeFileSync(path17.join(home2, ".acore", "core.md"), result.coreMd, "utf-8");
|
|
6781
7413
|
p3.log.success(`Identity created \u2014 ${PRESETS[preset].identity.personality.split(".")[0].toLowerCase()}`);
|
|
6782
7414
|
if (result.rulesMd) {
|
|
6783
|
-
|
|
6784
|
-
|
|
7415
|
+
fs17.mkdirSync(path17.join(home2, ".arules"), { recursive: true });
|
|
7416
|
+
fs17.writeFileSync(path17.join(home2, ".arules", "rules.md"), result.rulesMd, "utf-8");
|
|
6785
7417
|
const ruleCount = (result.rulesMd.match(/^- /gm) || []).length;
|
|
6786
7418
|
p3.log.success(`${ruleCount} rules set`);
|
|
6787
7419
|
}
|
|
6788
7420
|
if (result.flowMd) {
|
|
6789
|
-
|
|
6790
|
-
|
|
7421
|
+
fs17.mkdirSync(path17.join(home2, ".aflow"), { recursive: true });
|
|
7422
|
+
fs17.writeFileSync(path17.join(home2, ".aflow", "flow.md"), result.flowMd, "utf-8");
|
|
6791
7423
|
const wfCount = (result.flowMd.match(/^## /gm) || []).length;
|
|
6792
7424
|
p3.log.success(`${wfCount} workflow${wfCount > 1 ? "s" : ""} added`);
|
|
6793
7425
|
}
|