@aman_asmuei/aman-agent 0.17.0 → 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 CHANGED
@@ -878,7 +878,10 @@ import {
878
878
  consolidateMemories,
879
879
  cosineSimilarity,
880
880
  preloadEmbeddings,
881
- buildVectorIndex
881
+ buildVectorIndex,
882
+ recallMemories,
883
+ generateEmbedding,
884
+ getVectorIndex
882
885
  } from "@aman_asmuei/amem-core";
883
886
  import path5 from "path";
884
887
  import os5 from "os";
@@ -933,7 +936,43 @@ function memoryLog(sessionId, role, content) {
933
936
  });
934
937
  }
935
938
  function reminderCheck() {
936
- return getDb().checkReminders();
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." };
937
976
  }
938
977
  function memoryConsolidate(dryRun = false) {
939
978
  return consolidateMemories(getDb(), cosineSimilarity, {
@@ -943,6 +982,33 @@ function memoryConsolidate(dryRun = false) {
943
982
  minAccessCount: 0
944
983
  });
945
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
+ }
946
1012
 
947
1013
  // src/profile-templates.ts
948
1014
  import fs6 from "fs";
@@ -1664,7 +1730,8 @@ function parseCommand(input) {
1664
1730
  const trimmed = input.trim();
1665
1731
  const parts = trimmed.split(/\s+/);
1666
1732
  const base = parts[0].toLowerCase().replace(/^\//, "");
1667
- const action = parts.length > 1 ? parts[1].toLowerCase() : void 0;
1733
+ let action = parts.length > 1 ? parts[1].toLowerCase() : void 0;
1734
+ if (action === "--help" || action === "-h") action = "help";
1668
1735
  const args = parts.slice(2);
1669
1736
  return { base, action, args };
1670
1737
  }
@@ -1702,7 +1769,14 @@ async function handleIdentityCommand(action, args, ctx) {
1702
1769
  const output = await mcpWrite(ctx, "identity", "identity_update_section", { section, content });
1703
1770
  return { handled: true, output };
1704
1771
  }
1705
- return { handled: true, output: pc3.yellow(`Unknown action: /identity ${action}. Use /identity or /identity update <section>.`) };
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`) };
1706
1780
  }
1707
1781
  async function handleRulesCommand(action, args, ctx) {
1708
1782
  const home2 = os9.homedir();
@@ -1733,7 +1807,16 @@ async function handleRulesCommand(action, args, ctx) {
1733
1807
  const output = await mcpWrite(ctx, "rules", "rules_toggle", { category: args[0], index: parseInt(args[1], 10) });
1734
1808
  return { handled: true, output };
1735
1809
  }
1736
- return { handled: true, output: pc3.yellow(`Unknown action: /rules ${action}. Use /rules [add|remove|toggle].`) };
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`) };
1737
1820
  }
1738
1821
  async function handleWorkflowsCommand(action, args, ctx) {
1739
1822
  const home2 = os9.homedir();
@@ -1755,7 +1838,15 @@ async function handleWorkflowsCommand(action, args, ctx) {
1755
1838
  const output = await mcpWrite(ctx, "workflows", "workflow_remove", { name: args.join(" ") });
1756
1839
  return { handled: true, output };
1757
1840
  }
1758
- return { handled: true, output: pc3.yellow(`Unknown action: /workflows ${action}. Use /workflows [add|remove].`) };
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`) };
1759
1850
  }
1760
1851
  var AKIT_REGISTRY = [
1761
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"] } },
@@ -1977,7 +2068,15 @@ async function handleSkillsCommand(action, args, ctx) {
1977
2068
  const output = await mcpWrite(ctx, "skills", "skill_uninstall", { name: args.join(" ") });
1978
2069
  return { handled: true, output };
1979
2070
  }
1980
- return { handled: true, output: pc3.yellow(`Unknown action: /skills ${action}. Use /skills [install|uninstall].`) };
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`) };
1981
2080
  }
1982
2081
  async function handleEvalCommand(action, args, ctx) {
1983
2082
  const home2 = os9.homedir();
@@ -2007,7 +2106,7 @@ async function handleMemoryCommand(action, args, ctx) {
2007
2106
  return { handled: true, output: pc3.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
2008
2107
  }
2009
2108
  }
2010
- if (action && !["search", "clear", "timeline"].includes(action)) {
2109
+ if (action && !["search", "clear", "timeline", "stats", "export", "since", "fts", "help"].includes(action)) {
2011
2110
  try {
2012
2111
  const topic = [action, ...args].join(" ");
2013
2112
  const result = await memoryContext(topic);
@@ -2033,10 +2132,18 @@ async function handleMemoryCommand(action, args, ctx) {
2033
2132
  }
2034
2133
  if (action === "clear") {
2035
2134
  if (args.length < 1) {
2036
- return { handled: true, output: pc3.yellow("Usage: /memory clear <category>") };
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)}`) };
2037
2146
  }
2038
- const output = await mcpWrite(ctx, "memory", "memory_forget", { category: args[0] });
2039
- return { handled: true, output };
2040
2147
  }
2041
2148
  if (action === "timeline") {
2042
2149
  try {
@@ -2082,11 +2189,115 @@ async function handleMemoryCommand(action, args, ctx) {
2082
2189
  return { handled: true, output: pc3.red("Failed to retrieve memory timeline.") };
2083
2190
  }
2084
2191
  }
2085
- return { handled: true, output: pc3.yellow(`Unknown action: /memory ${action}. Use /memory [search|clear|timeline].`) };
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`) };
2086
2297
  }
2087
2298
  function handleStatusCommand(ctx) {
2088
2299
  const mcpToolCount = ctx.mcpManager ? ctx.mcpManager.getTools().length : 0;
2089
- const amemConnected = mcpToolCount > 0;
2300
+ const amemConnected = isMemoryInitialized();
2090
2301
  const status = getEcosystemStatus(mcpToolCount, amemConnected);
2091
2302
  const lines = [pc3.bold("Aman Ecosystem Dashboard"), ""];
2092
2303
  for (const layer of status.layers) {
@@ -2102,7 +2313,7 @@ function handleStatusCommand(ctx) {
2102
2313
  }
2103
2314
  function handleDoctorCommand(ctx) {
2104
2315
  const mcpToolCount = ctx.mcpManager ? ctx.mcpManager.getTools().length : 0;
2105
- const amemConnected = mcpToolCount > 0;
2316
+ const amemConnected = isMemoryInitialized();
2106
2317
  const status = getEcosystemStatus(mcpToolCount, amemConnected);
2107
2318
  const lines = [pc3.bold("Aman Health Check"), ""];
2108
2319
  let healthy = 0;
@@ -2136,7 +2347,7 @@ function handleDoctorCommand(ctx) {
2136
2347
  }
2137
2348
  lines.push(` ${status.amemConnected ? pc3.green("\u2713") : pc3.red("\u2717")} ${"Memory".padEnd(12)} ${status.amemConnected ? pc3.green("connected") : pc3.red("not connected")}`);
2138
2349
  if (!status.amemConnected) {
2139
- lines.push(` ${pc3.dim("\u2192 Fix: npx @aman_asmuei/amem")}`);
2350
+ lines.push(` ${pc3.dim("\u2192 Fix: restart aman-agent (memory initializes automatically)")}`);
2140
2351
  fixes++;
2141
2352
  } else {
2142
2353
  healthy++;
@@ -2158,7 +2369,8 @@ function handleHelp() {
2158
2369
  ` ${pc3.cyan("/akit")} Manage tools [add|remove <tool>]`,
2159
2370
  ` ${pc3.cyan("/skills")} View skills [install|uninstall ...]`,
2160
2371
  ` ${pc3.cyan("/eval")} View evaluation [milestone ...]`,
2161
- ` ${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]`,
2162
2374
  ` ${pc3.cyan("/status")} Ecosystem dashboard`,
2163
2375
  ` ${pc3.cyan("/doctor")} Health check all layers`,
2164
2376
  ` ${pc3.cyan("/decisions")} View decision log [<project>]`,
@@ -2167,7 +2379,7 @@ function handleHelp() {
2167
2379
  ` ${pc3.cyan("/save")} Save conversation to memory`,
2168
2380
  ` ${pc3.cyan("/model")} Show current LLM model`,
2169
2381
  ` ${pc3.cyan("/update")} Check for updates`,
2170
- ` ${pc3.cyan("/reconfig")} Reset LLM config`,
2382
+ ` ${pc3.cyan("/reset")} Full reset [all|memory|config|identity|rules]`,
2171
2383
  ` ${pc3.cyan("/clear")} Clear conversation history`,
2172
2384
  ` ${pc3.cyan("/quit")} Exit`
2173
2385
  ].join("\n")
@@ -2176,20 +2388,55 @@ function handleHelp() {
2176
2388
  function handleSave() {
2177
2389
  return { handled: true, saveConversation: true };
2178
2390
  }
2179
- function handleReconfig() {
2180
- const configDir = path9.join(os9.homedir(), ".aman-agent");
2181
- const configPath = path9.join(configDir, "config.json");
2182
- if (fs9.existsSync(configPath)) {
2183
- fs9.unlinkSync(configPath);
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.") };
2184
2433
  }
2185
- fs9.mkdirSync(configDir, { recursive: true });
2186
- fs9.writeFileSync(path9.join(configDir, ".reconfig"), "", "utf-8");
2187
2434
  return {
2188
2435
  handled: true,
2189
2436
  quit: true,
2190
2437
  output: [
2191
- pc3.green("Config reset."),
2192
- "Next run will prompt you to choose your LLM provider."
2438
+ pc3.green(`Reset complete: ${removed.join(", ")}`),
2439
+ "Restart aman-agent to begin fresh."
2193
2440
  ].join("\n")
2194
2441
  };
2195
2442
  }
@@ -2634,6 +2881,86 @@ function handlePlanCommand(action, args) {
2634
2881
  return { handled: true, output: pc3.yellow(`Unknown plan action: ${action}. Try /plan help`) };
2635
2882
  }
2636
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
+ }
2637
2964
  var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
2638
2965
  "quit",
2639
2966
  "exit",
@@ -2655,8 +2982,8 @@ var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
2655
2982
  "decisions",
2656
2983
  "export",
2657
2984
  "debug",
2658
- "update-config",
2659
- "reconfig",
2985
+ "reset",
2986
+ "reminder",
2660
2987
  "update",
2661
2988
  "upgrade",
2662
2989
  "plan",
@@ -2707,9 +3034,8 @@ async function handleCommand(input, ctx) {
2707
3034
  return handleExportCommand();
2708
3035
  case "debug":
2709
3036
  return handleDebugCommand();
2710
- case "update-config":
2711
- case "reconfig":
2712
- return handleReconfig();
3037
+ case "reset":
3038
+ return handleReset(action);
2713
3039
  case "plan":
2714
3040
  return handlePlanCommand(action, args);
2715
3041
  case "profile":
@@ -2718,6 +3044,8 @@ async function handleCommand(input, ctx) {
2718
3044
  return handleDelegateCommand(action, args, ctx);
2719
3045
  case "team":
2720
3046
  return handleTeamCommand(action, args, ctx);
3047
+ case "reminder":
3048
+ return handleReminderCommand(action, args);
2721
3049
  case "update":
2722
3050
  case "upgrade":
2723
3051
  return handleUpdate();
@@ -2933,14 +3261,18 @@ async function onSessionStart(ctx) {
2933
3261
  let firstRun = false;
2934
3262
  let resumeTopic;
2935
3263
  const visibleReminders = [];
2936
- try {
2937
- isHookCall = true;
2938
- const recallResult = await memoryRecall("*", { limit: 1 });
2939
- firstRun = recallResult.total === 0;
2940
- } catch {
2941
- firstRun = true;
2942
- } finally {
2943
- isHookCall = false;
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 {
3272
+ firstRun = true;
3273
+ } finally {
3274
+ isHookCall = false;
3275
+ }
2944
3276
  }
2945
3277
  if (firstRun) {
2946
3278
  contextInjection = `<first-session>
@@ -3914,7 +4246,7 @@ var BackgroundTaskManager = class {
3914
4246
  // src/errors.ts
3915
4247
  var ERROR_MAPPINGS = [
3916
4248
  { pattern: /rate.?limit|429/i, message: "Rate limited. I'll retry automatically." },
3917
- { pattern: /401|unauthorized/i, message: "API key invalid. Run /reconfig to fix." },
4249
+ { pattern: /401|unauthorized/i, message: "API key invalid. Run /reset config to fix." },
3918
4250
  { pattern: /403|forbidden/i, message: "API key doesn't have access to this model. Try a different model with --model." },
3919
4251
  { pattern: /fetch failed|network/i, message: "Network error. Check your internet connection." },
3920
4252
  { pattern: /ECONNREFUSED/i, message: "Can't reach the API. Are you behind a proxy or firewall?" },
@@ -4799,7 +5131,7 @@ function bootstrapEcosystem() {
4799
5131
  return true;
4800
5132
  }
4801
5133
  var program = new Command();
4802
- program.name("aman-agent").description("Your AI companion, running locally").version("0.1.0").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) => {
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) => {
4803
5135
  p2.intro(pc7.bold("aman agent") + pc7.dim(" \u2014 your AI companion"));
4804
5136
  let config = loadConfig();
4805
5137
  if (!config) {
@@ -4808,7 +5140,7 @@ program.name("aman-agent").description("Your AI companion, running locally").ver
4808
5140
  config = detected;
4809
5141
  const providerLabel = detected.provider === "anthropic" ? "Anthropic API key" : detected.provider === "openai" ? "OpenAI API key" : "Ollama";
4810
5142
  p2.log.success(`Auto-detected ${providerLabel}. Using ${pc7.bold(detected.model)}.`);
4811
- p2.log.info(pc7.dim("Change anytime with /reconfig"));
5143
+ p2.log.info(pc7.dim("Change anytime with /reset config"));
4812
5144
  saveConfig(config);
4813
5145
  } else {
4814
5146
  p2.log.info("First-time setup \u2014 configure your LLM connection.");
@@ -4926,7 +5258,26 @@ program.name("aman-agent").description("Your AI companion, running locally").ver
4926
5258
  }
4927
5259
  }
4928
5260
  const aiName = getProfileAiName(profile);
4929
- await initMemory();
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
+ }
4930
5281
  const mcpManager = new McpManager();
4931
5282
  const mcpSpinner = p2.spinner();
4932
5283
  mcpSpinner.start("Connecting to MCP servers");
@@ -4941,24 +5292,9 @@ program.name("aman-agent").description("Your AI companion, running locally").ver
4941
5292
  mcpSpinner.stop("MCP connected");
4942
5293
  if (mcpTools.length > 0) {
4943
5294
  p2.log.success(`${mcpTools.length} MCP tools available`);
4944
- {
4945
- const memSpinner = p2.spinner();
4946
- memSpinner.start("Consolidating memory");
4947
- try {
4948
- const report = memoryConsolidate();
4949
- memSpinner.stop("Memory consolidated");
4950
- if (report.merged > 0 || report.pruned > 0 || report.promoted > 0) {
4951
- p2.log.info(
4952
- `Memory health: ${report.healthScore ?? "?"}% ` + pc7.dim(`(merged ${report.merged}, pruned ${report.pruned}, promoted ${report.promoted})`)
4953
- );
4954
- }
4955
- } catch {
4956
- memSpinner.stop("Memory consolidation skipped");
4957
- }
4958
- }
4959
5295
  } else {
4960
5296
  p2.log.info(
4961
- "No MCP tools connected (install aman-mcp or amem for tool support)"
5297
+ "No MCP tools connected (install aman-mcp for tool support)"
4962
5298
  );
4963
5299
  }
4964
5300
  const toolDefs = mcpTools.map((t) => ({