@aman_asmuei/aman-agent 0.28.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -14
- package/dist/index.js +801 -683
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1721,20 +1721,20 @@ var McpManager = class {
|
|
|
1721
1721
|
|
|
1722
1722
|
// src/agent.ts
|
|
1723
1723
|
import * as readline from "readline";
|
|
1724
|
-
import
|
|
1725
|
-
import
|
|
1726
|
-
import
|
|
1724
|
+
import fs21 from "fs";
|
|
1725
|
+
import path21 from "path";
|
|
1726
|
+
import os20 from "os";
|
|
1727
1727
|
import pc7 from "picocolors";
|
|
1728
1728
|
import { marked } from "marked";
|
|
1729
1729
|
import { markedTerminal } from "marked-terminal";
|
|
1730
1730
|
import logUpdate from "log-update";
|
|
1731
1731
|
|
|
1732
1732
|
// src/commands.ts
|
|
1733
|
-
import
|
|
1734
|
-
import
|
|
1735
|
-
import
|
|
1733
|
+
import fs18 from "fs";
|
|
1734
|
+
import path18 from "path";
|
|
1735
|
+
import os17 from "os";
|
|
1736
1736
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
1737
|
-
import
|
|
1737
|
+
import pc6 from "picocolors";
|
|
1738
1738
|
|
|
1739
1739
|
// src/layers/parsers.ts
|
|
1740
1740
|
import fs5 from "fs";
|
|
@@ -4843,6 +4843,200 @@ function progressBar(pct) {
|
|
|
4843
4843
|
|
|
4844
4844
|
// src/commands.ts
|
|
4845
4845
|
init_user_model();
|
|
4846
|
+
|
|
4847
|
+
// src/background.ts
|
|
4848
|
+
import fs17 from "fs";
|
|
4849
|
+
import path17 from "path";
|
|
4850
|
+
import os16 from "os";
|
|
4851
|
+
import pc5 from "picocolors";
|
|
4852
|
+
var BACKGROUND_ELIGIBLE = /* @__PURE__ */ new Set([
|
|
4853
|
+
"run_tests",
|
|
4854
|
+
"npm_test",
|
|
4855
|
+
"build",
|
|
4856
|
+
"npm_build",
|
|
4857
|
+
"file_search",
|
|
4858
|
+
"code_search",
|
|
4859
|
+
"grep_search",
|
|
4860
|
+
"git_clone",
|
|
4861
|
+
"docker_build",
|
|
4862
|
+
"docker_run"
|
|
4863
|
+
]);
|
|
4864
|
+
var NEVER_BACKGROUND = /* @__PURE__ */ new Set([
|
|
4865
|
+
"memory_recall",
|
|
4866
|
+
"memory_store",
|
|
4867
|
+
"memory_log",
|
|
4868
|
+
"memory_context",
|
|
4869
|
+
"memory_detail",
|
|
4870
|
+
"identity_read",
|
|
4871
|
+
"identity_summary",
|
|
4872
|
+
"identity_update_session",
|
|
4873
|
+
"identity_update_dynamics",
|
|
4874
|
+
"rules_check",
|
|
4875
|
+
"rules_list",
|
|
4876
|
+
"workflow_list",
|
|
4877
|
+
"workflow_get",
|
|
4878
|
+
"skill_list",
|
|
4879
|
+
"skill_search",
|
|
4880
|
+
"eval_status",
|
|
4881
|
+
"eval_log",
|
|
4882
|
+
"reminder_check",
|
|
4883
|
+
"reminder_set",
|
|
4884
|
+
"file_read",
|
|
4885
|
+
"doc_convert",
|
|
4886
|
+
"file_list",
|
|
4887
|
+
"avatar_prompt"
|
|
4888
|
+
]);
|
|
4889
|
+
var TASK_LOG_DIR = path17.join(os16.homedir(), ".aman-agent");
|
|
4890
|
+
var TASK_LOG_FILE = path17.join(TASK_LOG_DIR, "bg-tasks.json");
|
|
4891
|
+
var MAX_LOG_ENTRIES = 50;
|
|
4892
|
+
function loadTaskLog() {
|
|
4893
|
+
try {
|
|
4894
|
+
if (!fs17.existsSync(TASK_LOG_FILE)) return [];
|
|
4895
|
+
const raw = fs17.readFileSync(TASK_LOG_FILE, "utf-8");
|
|
4896
|
+
return JSON.parse(raw);
|
|
4897
|
+
} catch {
|
|
4898
|
+
return [];
|
|
4899
|
+
}
|
|
4900
|
+
}
|
|
4901
|
+
function saveTaskLog(entries) {
|
|
4902
|
+
try {
|
|
4903
|
+
if (!fs17.existsSync(TASK_LOG_DIR)) fs17.mkdirSync(TASK_LOG_DIR, { recursive: true });
|
|
4904
|
+
const trimmed = entries.slice(-MAX_LOG_ENTRIES);
|
|
4905
|
+
fs17.writeFileSync(TASK_LOG_FILE, JSON.stringify(trimmed, null, 2));
|
|
4906
|
+
} catch (err) {
|
|
4907
|
+
log.debug("background", "Failed to save task log", err);
|
|
4908
|
+
}
|
|
4909
|
+
}
|
|
4910
|
+
function logTaskStart(task) {
|
|
4911
|
+
const entries = loadTaskLog();
|
|
4912
|
+
for (const e of entries) {
|
|
4913
|
+
if (e.status === "running") e.status = "interrupted";
|
|
4914
|
+
}
|
|
4915
|
+
entries.push({
|
|
4916
|
+
id: task.id,
|
|
4917
|
+
toolName: task.toolName,
|
|
4918
|
+
startedAt: task.startedAt,
|
|
4919
|
+
status: "running"
|
|
4920
|
+
});
|
|
4921
|
+
saveTaskLog(entries);
|
|
4922
|
+
}
|
|
4923
|
+
function logTaskComplete(task) {
|
|
4924
|
+
const entries = loadTaskLog();
|
|
4925
|
+
const entry = entries.find((e) => e.id === task.id);
|
|
4926
|
+
if (entry) {
|
|
4927
|
+
entry.completedAt = Date.now();
|
|
4928
|
+
entry.status = task.error ? "failed" : "completed";
|
|
4929
|
+
entry.resultPreview = (task.result || "").slice(0, 200);
|
|
4930
|
+
entry.error = task.error;
|
|
4931
|
+
}
|
|
4932
|
+
saveTaskLog(entries);
|
|
4933
|
+
}
|
|
4934
|
+
function shouldRunInBackground(toolName) {
|
|
4935
|
+
if (NEVER_BACKGROUND.has(toolName)) return false;
|
|
4936
|
+
if (BACKGROUND_ELIGIBLE.has(toolName)) return true;
|
|
4937
|
+
return false;
|
|
4938
|
+
}
|
|
4939
|
+
var BackgroundTaskManager = class {
|
|
4940
|
+
tasks = /* @__PURE__ */ new Map();
|
|
4941
|
+
taskCounter = 0;
|
|
4942
|
+
/**
|
|
4943
|
+
* Launch a tool call in the background.
|
|
4944
|
+
*/
|
|
4945
|
+
launch(toolName, toolUseId, mcpManager, toolInput) {
|
|
4946
|
+
const id = `bg-${++this.taskCounter}`;
|
|
4947
|
+
const task = {
|
|
4948
|
+
id,
|
|
4949
|
+
toolName,
|
|
4950
|
+
toolUseId,
|
|
4951
|
+
startedAt: Date.now(),
|
|
4952
|
+
done: false,
|
|
4953
|
+
promise: mcpManager.callTool(toolName, toolInput).then(
|
|
4954
|
+
(result) => {
|
|
4955
|
+
task.result = result;
|
|
4956
|
+
task.done = true;
|
|
4957
|
+
logTaskComplete(task);
|
|
4958
|
+
return result;
|
|
4959
|
+
},
|
|
4960
|
+
(error) => {
|
|
4961
|
+
task.error = error instanceof Error ? error.message : String(error);
|
|
4962
|
+
task.done = true;
|
|
4963
|
+
logTaskComplete(task);
|
|
4964
|
+
return `Error: ${task.error}`;
|
|
4965
|
+
}
|
|
4966
|
+
)
|
|
4967
|
+
};
|
|
4968
|
+
this.tasks.set(id, task);
|
|
4969
|
+
logTaskStart(task);
|
|
4970
|
+
process.stdout.write(pc5.dim(` [${toolName} running in background (${id})...]
|
|
4971
|
+
`));
|
|
4972
|
+
return task;
|
|
4973
|
+
}
|
|
4974
|
+
/**
|
|
4975
|
+
* Check for completed background tasks and return their results.
|
|
4976
|
+
*/
|
|
4977
|
+
collectCompleted() {
|
|
4978
|
+
const completed = [];
|
|
4979
|
+
for (const [id, task] of this.tasks) {
|
|
4980
|
+
if (task.done) {
|
|
4981
|
+
completed.push(task);
|
|
4982
|
+
this.tasks.delete(id);
|
|
4983
|
+
}
|
|
4984
|
+
}
|
|
4985
|
+
return completed;
|
|
4986
|
+
}
|
|
4987
|
+
/**
|
|
4988
|
+
* Display completed background task results to the user.
|
|
4989
|
+
*/
|
|
4990
|
+
displayCompleted() {
|
|
4991
|
+
const completed = this.collectCompleted();
|
|
4992
|
+
const outputs = [];
|
|
4993
|
+
for (const task of completed) {
|
|
4994
|
+
const elapsed = ((Date.now() - task.startedAt) / 1e3).toFixed(1);
|
|
4995
|
+
if (task.error) {
|
|
4996
|
+
process.stdout.write(pc5.yellow(`
|
|
4997
|
+
[${task.id}] ${task.toolName} failed after ${elapsed}s: ${task.error}
|
|
4998
|
+
`));
|
|
4999
|
+
outputs.push(`[Background task ${task.toolName} failed: ${task.error}]`);
|
|
5000
|
+
} else {
|
|
5001
|
+
process.stdout.write(pc5.green(`
|
|
5002
|
+
[${task.id}] ${task.toolName} completed in ${elapsed}s
|
|
5003
|
+
`));
|
|
5004
|
+
const preview = (task.result || "").slice(0, 200);
|
|
5005
|
+
if (preview) {
|
|
5006
|
+
process.stdout.write(pc5.dim(` ${preview}${(task.result || "").length > 200 ? "..." : ""}
|
|
5007
|
+
`));
|
|
5008
|
+
}
|
|
5009
|
+
outputs.push(`[Background task ${task.toolName} completed: ${task.result}]`);
|
|
5010
|
+
}
|
|
5011
|
+
}
|
|
5012
|
+
return outputs;
|
|
5013
|
+
}
|
|
5014
|
+
/**
|
|
5015
|
+
* Wait for all pending background tasks to complete.
|
|
5016
|
+
*/
|
|
5017
|
+
async waitAll() {
|
|
5018
|
+
const pending = [...this.tasks.values()].filter((t) => !t.done);
|
|
5019
|
+
if (pending.length === 0) return;
|
|
5020
|
+
process.stdout.write(pc5.dim(`
|
|
5021
|
+
Waiting for ${pending.length} background task(s)...
|
|
5022
|
+
`));
|
|
5023
|
+
await Promise.allSettled(pending.map((t) => t.promise));
|
|
5024
|
+
}
|
|
5025
|
+
/**
|
|
5026
|
+
* Number of currently running tasks.
|
|
5027
|
+
*/
|
|
5028
|
+
get pendingCount() {
|
|
5029
|
+
return [...this.tasks.values()].filter((t) => !t.done).length;
|
|
5030
|
+
}
|
|
5031
|
+
/**
|
|
5032
|
+
* Check if any tasks have completed (non-blocking).
|
|
5033
|
+
*/
|
|
5034
|
+
get hasCompleted() {
|
|
5035
|
+
return [...this.tasks.values()].some((t) => t.done);
|
|
5036
|
+
}
|
|
5037
|
+
};
|
|
5038
|
+
|
|
5039
|
+
// src/commands.ts
|
|
4846
5040
|
import {
|
|
4847
5041
|
getIdentity as acoreGetIdentity,
|
|
4848
5042
|
updateSection as acoreUpdateSection,
|
|
@@ -4857,10 +5051,10 @@ import {
|
|
|
4857
5051
|
} from "@aman_asmuei/arules-core";
|
|
4858
5052
|
var AGENT_SCOPE = process.env.AMAN_AGENT_SCOPE ?? "dev:agent";
|
|
4859
5053
|
function readEcosystemFile(filePath, label) {
|
|
4860
|
-
if (!
|
|
4861
|
-
return
|
|
5054
|
+
if (!fs18.existsSync(filePath)) {
|
|
5055
|
+
return pc6.dim(`No ${label} file found at ${filePath}`);
|
|
4862
5056
|
}
|
|
4863
|
-
return
|
|
5057
|
+
return fs18.readFileSync(filePath, "utf-8").trim();
|
|
4864
5058
|
}
|
|
4865
5059
|
function parseCommand(input) {
|
|
4866
5060
|
const trimmed = input.trim();
|
|
@@ -4885,13 +5079,13 @@ function buildNestedUpdate(key, val) {
|
|
|
4885
5079
|
}
|
|
4886
5080
|
async function mcpWrite(ctx, layer, tool, args) {
|
|
4887
5081
|
if (!ctx.mcpManager) {
|
|
4888
|
-
return
|
|
5082
|
+
return pc6.red(`Cannot modify ${layer}: aman-mcp not connected. Start it with: npx @aman_asmuei/aman-mcp`);
|
|
4889
5083
|
}
|
|
4890
5084
|
const result = await ctx.mcpManager.callTool(tool, args);
|
|
4891
5085
|
if (result.startsWith("Error")) {
|
|
4892
|
-
return
|
|
5086
|
+
return pc6.red(result);
|
|
4893
5087
|
}
|
|
4894
|
-
return
|
|
5088
|
+
return pc6.green(result);
|
|
4895
5089
|
}
|
|
4896
5090
|
async function handleIdentityCommand(action, args, _ctx) {
|
|
4897
5091
|
if (!action) {
|
|
@@ -4899,7 +5093,7 @@ async function handleIdentityCommand(action, args, _ctx) {
|
|
|
4899
5093
|
if (!identity) {
|
|
4900
5094
|
return {
|
|
4901
5095
|
handled: true,
|
|
4902
|
-
output:
|
|
5096
|
+
output: pc6.dim(
|
|
4903
5097
|
`No identity configured for ${AGENT_SCOPE}. Run: npx @aman_asmuei/acore`
|
|
4904
5098
|
)
|
|
4905
5099
|
};
|
|
@@ -4910,7 +5104,7 @@ async function handleIdentityCommand(action, args, _ctx) {
|
|
|
4910
5104
|
if (args.length === 0) {
|
|
4911
5105
|
return {
|
|
4912
5106
|
handled: true,
|
|
4913
|
-
output:
|
|
5107
|
+
output: pc6.yellow(
|
|
4914
5108
|
"Usage: /identity update <section>\nTip: describe changes in natural language and the AI will update via acore-core."
|
|
4915
5109
|
)
|
|
4916
5110
|
};
|
|
@@ -4920,18 +5114,18 @@ async function handleIdentityCommand(action, args, _ctx) {
|
|
|
4920
5114
|
if (!content) {
|
|
4921
5115
|
return {
|
|
4922
5116
|
handled: true,
|
|
4923
|
-
output:
|
|
5117
|
+
output: pc6.yellow(
|
|
4924
5118
|
"Usage: /identity update <section> <new content...>\nExample: /identity update Personality Warm, curious, and direct."
|
|
4925
5119
|
)
|
|
4926
5120
|
};
|
|
4927
5121
|
}
|
|
4928
5122
|
try {
|
|
4929
5123
|
await acoreUpdateSection(section, content, AGENT_SCOPE);
|
|
4930
|
-
return { handled: true, output:
|
|
5124
|
+
return { handled: true, output: pc6.green(`Updated section: ${section}`) };
|
|
4931
5125
|
} catch (err) {
|
|
4932
5126
|
return {
|
|
4933
5127
|
handled: true,
|
|
4934
|
-
output:
|
|
5128
|
+
output: pc6.red(
|
|
4935
5129
|
`Failed to update ${section}: ${err instanceof Error ? err.message : String(err)}`
|
|
4936
5130
|
)
|
|
4937
5131
|
};
|
|
@@ -4940,16 +5134,16 @@ async function handleIdentityCommand(action, args, _ctx) {
|
|
|
4940
5134
|
if (action === "dynamics") {
|
|
4941
5135
|
if (args.includes("--json")) {
|
|
4942
5136
|
const model2 = await loadUserModel();
|
|
4943
|
-
if (!model2) return { handled: true, output:
|
|
5137
|
+
if (!model2) return { handled: true, output: pc6.dim("No user model yet. Complete a few sessions first.") };
|
|
4944
5138
|
return { handled: true, output: JSON.stringify(model2, null, 2) };
|
|
4945
5139
|
}
|
|
4946
5140
|
if (args.includes("--reset")) {
|
|
4947
5141
|
const modelPath = defaultModelPath();
|
|
4948
|
-
if (
|
|
4949
|
-
|
|
4950
|
-
return { handled: true, output:
|
|
5142
|
+
if (fs18.existsSync(modelPath)) {
|
|
5143
|
+
fs18.unlinkSync(modelPath);
|
|
5144
|
+
return { handled: true, output: pc6.green("User model reset. Starting fresh.") };
|
|
4951
5145
|
}
|
|
4952
|
-
return { handled: true, output:
|
|
5146
|
+
return { handled: true, output: pc6.dim("No user model to reset.") };
|
|
4953
5147
|
}
|
|
4954
5148
|
const updates = {};
|
|
4955
5149
|
for (const arg of args) {
|
|
@@ -4965,25 +5159,25 @@ async function handleIdentityCommand(action, args, _ctx) {
|
|
|
4965
5159
|
}, AGENT_SCOPE);
|
|
4966
5160
|
return { handled: true, output: `Dynamics updated: ${Object.entries(updates).map(([k, v]) => `${k}=${v}`).join(", ")}` };
|
|
4967
5161
|
} catch (err) {
|
|
4968
|
-
return { handled: true, output:
|
|
5162
|
+
return { handled: true, output: pc6.red(`Dynamics error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
4969
5163
|
}
|
|
4970
5164
|
}
|
|
4971
5165
|
const model = await loadUserModel();
|
|
4972
5166
|
if (!model) {
|
|
4973
|
-
return { handled: true, output:
|
|
5167
|
+
return { handled: true, output: pc6.dim("No user model yet. Complete a few sessions to start building your profile.") };
|
|
4974
5168
|
}
|
|
4975
5169
|
const p4 = model.profile;
|
|
4976
5170
|
const trustBar = "\u2588".repeat(Math.round(p4.trustScore * 10)) + "\u2591".repeat(10 - Math.round(p4.trustScore * 10));
|
|
4977
5171
|
const frustBar = "\u2588".repeat(Math.round(p4.baselineFrustration * 10)) + "\u2591".repeat(10 - Math.round(p4.baselineFrustration * 10));
|
|
4978
5172
|
const lines = [
|
|
4979
|
-
|
|
5173
|
+
pc6.bold(" Dynamic User Model"),
|
|
4980
5174
|
"",
|
|
4981
|
-
` ${
|
|
4982
|
-
` ${
|
|
4983
|
-
` ${
|
|
5175
|
+
` ${pc6.cyan("Trust")} ${trustBar} ${(p4.trustScore * 100).toFixed(0)}% ${p4.trustTrajectory === "ascending" ? pc6.green("\u2191") : p4.trustTrajectory === "declining" ? pc6.red("\u2193") : "\u2192"}`,
|
|
5176
|
+
` ${pc6.cyan("Sessions")} ${p4.totalSessions} total (${model.sessions.length} in window)`,
|
|
5177
|
+
` ${pc6.cyan("Sentiment")} ${frustBar} frustration baseline ${p4.sentimentTrend === "improving" ? pc6.green("improving") : p4.sentimentTrend === "worsening" ? pc6.red("worsening") : "stable"}`,
|
|
4984
5178
|
"",
|
|
4985
|
-
` ${
|
|
4986
|
-
` ${
|
|
5179
|
+
` ${pc6.cyan("Preferred")} ${p4.preferredTimePeriod} (${Object.entries(p4.energyDistribution).map(([k, v]) => `${k}: ${v}`).join(", ")})`,
|
|
5180
|
+
` ${pc6.cyan("Avg session")} ${p4.avgSessionMinutes.toFixed(0)} min, ${p4.avgTurnsPerSession.toFixed(0)} turns ${p4.engagementTrend === "increasing" ? pc6.green("\u2191") : p4.engagementTrend === "decreasing" ? pc6.red("\u2193") : "\u2192"}`
|
|
4987
5181
|
];
|
|
4988
5182
|
if (p4.totalSessions >= 10) {
|
|
4989
5183
|
const corrs = [];
|
|
@@ -4997,22 +5191,22 @@ async function handleIdentityCommand(action, args, _ctx) {
|
|
|
4997
5191
|
corrs.push(`late night (${p4.frustrationCorrelations.lateNight.toFixed(2)})`);
|
|
4998
5192
|
}
|
|
4999
5193
|
if (corrs.length > 0) {
|
|
5000
|
-
lines.push(` ${
|
|
5194
|
+
lines.push(` ${pc6.cyan("Frustration")} correlates with: ${corrs.join(", ")}`);
|
|
5001
5195
|
}
|
|
5002
5196
|
}
|
|
5003
5197
|
const nudgeKeys = Object.keys(p4.nudgeStats);
|
|
5004
5198
|
if (nudgeKeys.length > 0) {
|
|
5005
5199
|
lines.push("");
|
|
5006
|
-
lines.push(` ${
|
|
5200
|
+
lines.push(` ${pc6.cyan("Nudges")} ${nudgeKeys.map((k) => `${k}: ${p4.nudgeStats[k].fired}\xD7`).join(", ")}`);
|
|
5007
5201
|
}
|
|
5008
5202
|
lines.push("");
|
|
5009
|
-
lines.push(
|
|
5203
|
+
lines.push(pc6.dim(` Use --json for raw data, --reset to start fresh`));
|
|
5010
5204
|
return { handled: true, output: lines.join("\n") };
|
|
5011
5205
|
}
|
|
5012
5206
|
if (action === "summary") {
|
|
5013
5207
|
try {
|
|
5014
5208
|
const identity = await acoreGetIdentity(AGENT_SCOPE);
|
|
5015
|
-
if (!identity) return { handled: true, output:
|
|
5209
|
+
if (!identity) return { handled: true, output: pc6.yellow("No identity configured.") };
|
|
5016
5210
|
const nameMatch = identity.content.match(/\*\*Name:\*\*\s*(.+)/);
|
|
5017
5211
|
const lines = [
|
|
5018
5212
|
`**Identity Summary**`,
|
|
@@ -5021,27 +5215,27 @@ async function handleIdentityCommand(action, args, _ctx) {
|
|
|
5021
5215
|
].filter(Boolean);
|
|
5022
5216
|
return { handled: true, output: lines.join("\n") };
|
|
5023
5217
|
} catch (err) {
|
|
5024
|
-
return { handled: true, output:
|
|
5218
|
+
return { handled: true, output: pc6.red(`Summary error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
5025
5219
|
}
|
|
5026
5220
|
}
|
|
5027
5221
|
if (action === "help") {
|
|
5028
5222
|
return {
|
|
5029
5223
|
handled: true,
|
|
5030
5224
|
output: [
|
|
5031
|
-
|
|
5032
|
-
` ${
|
|
5033
|
-
` ${
|
|
5034
|
-
` ${
|
|
5035
|
-
` ${
|
|
5036
|
-
` ${
|
|
5037
|
-
` ${
|
|
5038
|
-
` ${
|
|
5225
|
+
pc6.bold("Identity commands:"),
|
|
5226
|
+
` ${pc6.cyan("/identity")} View current identity`,
|
|
5227
|
+
` ${pc6.cyan("/identity update")} <section> Update a section`,
|
|
5228
|
+
` ${pc6.cyan("/identity dynamics")} View user model (trust, sentiment, patterns)`,
|
|
5229
|
+
` ${pc6.cyan("/identity dynamics")} key=val Update dynamic fields (energy, mode, read)`,
|
|
5230
|
+
` ${pc6.cyan("/identity dynamics")} --json Raw JSON user model`,
|
|
5231
|
+
` ${pc6.cyan("/identity dynamics")} --reset Reset user model`,
|
|
5232
|
+
` ${pc6.cyan("/identity summary")} Show structured identity summary`
|
|
5039
5233
|
].join("\n")
|
|
5040
5234
|
};
|
|
5041
5235
|
}
|
|
5042
5236
|
return {
|
|
5043
5237
|
handled: true,
|
|
5044
|
-
output:
|
|
5238
|
+
output: pc6.yellow(
|
|
5045
5239
|
`Unknown action: /identity ${action}. Try /identity --help`
|
|
5046
5240
|
)
|
|
5047
5241
|
};
|
|
@@ -5052,14 +5246,14 @@ async function handleRulesCommand(action, args, _ctx) {
|
|
|
5052
5246
|
if (cats.length === 0) {
|
|
5053
5247
|
return {
|
|
5054
5248
|
handled: true,
|
|
5055
|
-
output:
|
|
5249
|
+
output: pc6.dim(
|
|
5056
5250
|
`No rules configured for ${AGENT_SCOPE}. Run: npx @aman_asmuei/arules`
|
|
5057
5251
|
)
|
|
5058
5252
|
};
|
|
5059
5253
|
}
|
|
5060
5254
|
const lines = [];
|
|
5061
5255
|
for (const cat of cats) {
|
|
5062
|
-
lines.push(
|
|
5256
|
+
lines.push(pc6.bold(`## ${cat.name}`));
|
|
5063
5257
|
for (const rule of cat.rules) {
|
|
5064
5258
|
lines.push(` - ${rule}`);
|
|
5065
5259
|
}
|
|
@@ -5071,7 +5265,7 @@ async function handleRulesCommand(action, args, _ctx) {
|
|
|
5071
5265
|
if (args.length < 2) {
|
|
5072
5266
|
return {
|
|
5073
5267
|
handled: true,
|
|
5074
|
-
output:
|
|
5268
|
+
output: pc6.yellow("Usage: /rules add <category> <rule text...>")
|
|
5075
5269
|
};
|
|
5076
5270
|
}
|
|
5077
5271
|
const category = args[0];
|
|
@@ -5080,12 +5274,12 @@ async function handleRulesCommand(action, args, _ctx) {
|
|
|
5080
5274
|
await arulesAddRule(category, rule, AGENT_SCOPE);
|
|
5081
5275
|
return {
|
|
5082
5276
|
handled: true,
|
|
5083
|
-
output:
|
|
5277
|
+
output: pc6.green(`Added rule to "${category}": ${rule}`)
|
|
5084
5278
|
};
|
|
5085
5279
|
} catch (err) {
|
|
5086
5280
|
return {
|
|
5087
5281
|
handled: true,
|
|
5088
|
-
output:
|
|
5282
|
+
output: pc6.red(
|
|
5089
5283
|
`Failed: ${err instanceof Error ? err.message : String(err)}`
|
|
5090
5284
|
)
|
|
5091
5285
|
};
|
|
@@ -5095,7 +5289,7 @@ async function handleRulesCommand(action, args, _ctx) {
|
|
|
5095
5289
|
if (args.length < 2) {
|
|
5096
5290
|
return {
|
|
5097
5291
|
handled: true,
|
|
5098
|
-
output:
|
|
5292
|
+
output: pc6.yellow("Usage: /rules remove <category> <index>")
|
|
5099
5293
|
};
|
|
5100
5294
|
}
|
|
5101
5295
|
const category = args[0];
|
|
@@ -5103,19 +5297,19 @@ async function handleRulesCommand(action, args, _ctx) {
|
|
|
5103
5297
|
if (isNaN(idx) || idx < 1) {
|
|
5104
5298
|
return {
|
|
5105
5299
|
handled: true,
|
|
5106
|
-
output:
|
|
5300
|
+
output: pc6.yellow("Index must be a positive integer.")
|
|
5107
5301
|
};
|
|
5108
5302
|
}
|
|
5109
5303
|
try {
|
|
5110
5304
|
await arulesRemoveRule(category, idx, AGENT_SCOPE);
|
|
5111
5305
|
return {
|
|
5112
5306
|
handled: true,
|
|
5113
|
-
output:
|
|
5307
|
+
output: pc6.green(`Removed rule ${idx} from "${category}"`)
|
|
5114
5308
|
};
|
|
5115
5309
|
} catch (err) {
|
|
5116
5310
|
return {
|
|
5117
5311
|
handled: true,
|
|
5118
|
-
output:
|
|
5312
|
+
output: pc6.red(
|
|
5119
5313
|
`Failed: ${err instanceof Error ? err.message : String(err)}`
|
|
5120
5314
|
)
|
|
5121
5315
|
};
|
|
@@ -5125,7 +5319,7 @@ async function handleRulesCommand(action, args, _ctx) {
|
|
|
5125
5319
|
if (args.length < 2) {
|
|
5126
5320
|
return {
|
|
5127
5321
|
handled: true,
|
|
5128
|
-
output:
|
|
5322
|
+
output: pc6.yellow("Usage: /rules toggle <category> <index>")
|
|
5129
5323
|
};
|
|
5130
5324
|
}
|
|
5131
5325
|
const category = args[0];
|
|
@@ -5133,19 +5327,19 @@ async function handleRulesCommand(action, args, _ctx) {
|
|
|
5133
5327
|
if (isNaN(idx) || idx < 1) {
|
|
5134
5328
|
return {
|
|
5135
5329
|
handled: true,
|
|
5136
|
-
output:
|
|
5330
|
+
output: pc6.yellow("Index must be a positive integer.")
|
|
5137
5331
|
};
|
|
5138
5332
|
}
|
|
5139
5333
|
try {
|
|
5140
5334
|
await arulesToggleRule(category, idx, AGENT_SCOPE);
|
|
5141
5335
|
return {
|
|
5142
5336
|
handled: true,
|
|
5143
|
-
output:
|
|
5337
|
+
output: pc6.green(`Toggled rule ${idx} in "${category}"`)
|
|
5144
5338
|
};
|
|
5145
5339
|
} catch (err) {
|
|
5146
5340
|
return {
|
|
5147
5341
|
handled: true,
|
|
5148
|
-
output:
|
|
5342
|
+
output: pc6.red(
|
|
5149
5343
|
`Failed: ${err instanceof Error ? err.message : String(err)}`
|
|
5150
5344
|
)
|
|
5151
5345
|
};
|
|
@@ -5153,75 +5347,75 @@ async function handleRulesCommand(action, args, _ctx) {
|
|
|
5153
5347
|
}
|
|
5154
5348
|
if (action === "check") {
|
|
5155
5349
|
if (args.length === 0) {
|
|
5156
|
-
return { handled: true, output:
|
|
5350
|
+
return { handled: true, output: pc6.yellow("Usage: /rules check <action description...>") };
|
|
5157
5351
|
}
|
|
5158
5352
|
const description = args.join(" ");
|
|
5159
5353
|
try {
|
|
5160
5354
|
const result = await arulesCheckAction(description, AGENT_SCOPE);
|
|
5161
5355
|
if (result.safe) {
|
|
5162
|
-
return { handled: true, output:
|
|
5356
|
+
return { handled: true, output: pc6.green(`Action is allowed: "${description}"`) };
|
|
5163
5357
|
}
|
|
5164
5358
|
return {
|
|
5165
5359
|
handled: true,
|
|
5166
|
-
output:
|
|
5360
|
+
output: pc6.red(`Action blocked: "${description}"
|
|
5167
5361
|
Violations:
|
|
5168
5362
|
${result.violations.map((v) => ` - ${v}`).join("\n")}`)
|
|
5169
5363
|
};
|
|
5170
5364
|
} catch (err) {
|
|
5171
|
-
return { handled: true, output:
|
|
5365
|
+
return { handled: true, output: pc6.red(`Check error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
5172
5366
|
}
|
|
5173
5367
|
}
|
|
5174
5368
|
if (action === "help") {
|
|
5175
5369
|
return {
|
|
5176
5370
|
handled: true,
|
|
5177
5371
|
output: [
|
|
5178
|
-
|
|
5179
|
-
` ${
|
|
5180
|
-
` ${
|
|
5181
|
-
` ${
|
|
5182
|
-
` ${
|
|
5183
|
-
` ${
|
|
5372
|
+
pc6.bold("Rules commands:"),
|
|
5373
|
+
` ${pc6.cyan("/rules")} View current rules`,
|
|
5374
|
+
` ${pc6.cyan("/rules add")} <category> <text> Add a rule`,
|
|
5375
|
+
` ${pc6.cyan("/rules remove")} <category> <idx> Remove a rule`,
|
|
5376
|
+
` ${pc6.cyan("/rules toggle")} <category> <idx> Toggle a rule`,
|
|
5377
|
+
` ${pc6.cyan("/rules check")} <action...> Check if an action is allowed`
|
|
5184
5378
|
].join("\n")
|
|
5185
5379
|
};
|
|
5186
5380
|
}
|
|
5187
5381
|
return {
|
|
5188
5382
|
handled: true,
|
|
5189
|
-
output:
|
|
5383
|
+
output: pc6.yellow(`Unknown action: /rules ${action}. Try /rules --help`)
|
|
5190
5384
|
};
|
|
5191
5385
|
}
|
|
5192
5386
|
async function handleWorkflowsCommand(action, args, ctx) {
|
|
5193
|
-
const home2 =
|
|
5387
|
+
const home2 = os17.homedir();
|
|
5194
5388
|
if (!action) {
|
|
5195
|
-
const content = readEcosystemFile(
|
|
5389
|
+
const content = readEcosystemFile(path18.join(home2, ".aflow", "flow.md"), "workflows (aflow)");
|
|
5196
5390
|
return { handled: true, output: content };
|
|
5197
5391
|
}
|
|
5198
5392
|
if (action === "add") {
|
|
5199
5393
|
if (args.length < 1) {
|
|
5200
|
-
return { handled: true, output:
|
|
5394
|
+
return { handled: true, output: pc6.yellow("Usage: /workflows add <name>") };
|
|
5201
5395
|
}
|
|
5202
5396
|
const output = await mcpWrite(ctx, "workflows", "workflow_add", { name: args.join(" ") });
|
|
5203
5397
|
return { handled: true, output };
|
|
5204
5398
|
}
|
|
5205
5399
|
if (action === "remove") {
|
|
5206
5400
|
if (args.length < 1) {
|
|
5207
|
-
return { handled: true, output:
|
|
5401
|
+
return { handled: true, output: pc6.yellow("Usage: /workflows remove <name>") };
|
|
5208
5402
|
}
|
|
5209
5403
|
const output = await mcpWrite(ctx, "workflows", "workflow_remove", { name: args.join(" ") });
|
|
5210
5404
|
return { handled: true, output };
|
|
5211
5405
|
}
|
|
5212
5406
|
if (action === "get") {
|
|
5213
5407
|
if (args.length === 0) {
|
|
5214
|
-
return { handled: true, output:
|
|
5408
|
+
return { handled: true, output: pc6.yellow("Usage: /workflows get <name>") };
|
|
5215
5409
|
}
|
|
5216
5410
|
const name = args.join(" ").toLowerCase();
|
|
5217
|
-
const raw = readEcosystemFile(
|
|
5411
|
+
const raw = readEcosystemFile(path18.join(home2, ".aflow", "flow.md"), "workflows (aflow)");
|
|
5218
5412
|
if (raw.startsWith("No ")) {
|
|
5219
5413
|
return { handled: true, output: raw };
|
|
5220
5414
|
}
|
|
5221
5415
|
const sections = raw.split(/^## /m).slice(1);
|
|
5222
5416
|
const match = sections.find((s) => s.split("\n")[0].trim().toLowerCase() === name);
|
|
5223
5417
|
if (!match) {
|
|
5224
|
-
return { handled: true, output:
|
|
5418
|
+
return { handled: true, output: pc6.yellow(`No workflow found: "${args.join(" ")}"`) };
|
|
5225
5419
|
}
|
|
5226
5420
|
const title = match.split("\n")[0].trim();
|
|
5227
5421
|
const body = match.split("\n").slice(1).join("\n").trim();
|
|
@@ -5231,34 +5425,34 @@ ${body}` };
|
|
|
5231
5425
|
}
|
|
5232
5426
|
if (action === "help") {
|
|
5233
5427
|
return { handled: true, output: [
|
|
5234
|
-
|
|
5235
|
-
` ${
|
|
5236
|
-
` ${
|
|
5237
|
-
` ${
|
|
5238
|
-
` ${
|
|
5428
|
+
pc6.bold("Workflow commands:"),
|
|
5429
|
+
` ${pc6.cyan("/workflows")} View current workflows`,
|
|
5430
|
+
` ${pc6.cyan("/workflows add")} <name> Add a workflow`,
|
|
5431
|
+
` ${pc6.cyan("/workflows remove")} <name> Remove a workflow`,
|
|
5432
|
+
` ${pc6.cyan("/workflows get")} <name> Show a specific workflow`
|
|
5239
5433
|
].join("\n") };
|
|
5240
5434
|
}
|
|
5241
|
-
return { handled: true, output:
|
|
5435
|
+
return { handled: true, output: pc6.yellow(`Unknown action: /workflows ${action}. Try /workflows --help`) };
|
|
5242
5436
|
}
|
|
5243
5437
|
function handleAkitCommand(_action, _args) {
|
|
5244
5438
|
return {
|
|
5245
5439
|
handled: true,
|
|
5246
5440
|
output: [
|
|
5247
|
-
|
|
5441
|
+
pc6.bold("akit \u2014 Tool Management"),
|
|
5248
5442
|
"",
|
|
5249
|
-
|
|
5443
|
+
pc6.dim(
|
|
5250
5444
|
"Tool management is now handled by the standalone akit CLI rather than"
|
|
5251
5445
|
),
|
|
5252
|
-
|
|
5446
|
+
pc6.dim(
|
|
5253
5447
|
"duplicated inside aman-agent. The akit slash command is informational only."
|
|
5254
5448
|
),
|
|
5255
5449
|
"",
|
|
5256
|
-
` ${
|
|
5257
|
-
` ${
|
|
5258
|
-
` ${
|
|
5259
|
-
` ${
|
|
5450
|
+
` ${pc6.cyan("npx @aman_asmuei/akit list")} List installed tools`,
|
|
5451
|
+
` ${pc6.cyan("npx @aman_asmuei/akit search <query>")} Search the tool registry`,
|
|
5452
|
+
` ${pc6.cyan("npx @aman_asmuei/akit add <tool>")} Install a tool`,
|
|
5453
|
+
` ${pc6.cyan("npx @aman_asmuei/akit remove <tool>")} Uninstall a tool`,
|
|
5260
5454
|
"",
|
|
5261
|
-
|
|
5455
|
+
pc6.dim(
|
|
5262
5456
|
"Restart aman-agent after installing/removing tools to pick up changes."
|
|
5263
5457
|
)
|
|
5264
5458
|
].join("\n")
|
|
@@ -5270,81 +5464,81 @@ async function handleToolsCommand(action, args, _ctx) {
|
|
|
5270
5464
|
}
|
|
5271
5465
|
if (action === "search") {
|
|
5272
5466
|
if (args.length === 0) {
|
|
5273
|
-
return { handled: true, output:
|
|
5467
|
+
return { handled: true, output: pc6.yellow("Usage: /tools search <query...>") };
|
|
5274
5468
|
}
|
|
5275
5469
|
const query = args.join(" ").toLowerCase();
|
|
5276
|
-
const home2 =
|
|
5277
|
-
const toolsFile =
|
|
5278
|
-
if (!
|
|
5279
|
-
return { handled: true, output:
|
|
5470
|
+
const home2 = os17.homedir();
|
|
5471
|
+
const toolsFile = path18.join(home2, ".akit", "tools.md");
|
|
5472
|
+
if (!fs18.existsSync(toolsFile)) {
|
|
5473
|
+
return { handled: true, output: pc6.dim(`No tools file found. Use 'npx @aman_asmuei/akit search ${args.join(" ")}' to search the registry.`) };
|
|
5280
5474
|
}
|
|
5281
|
-
const raw =
|
|
5475
|
+
const raw = fs18.readFileSync(toolsFile, "utf-8").trim();
|
|
5282
5476
|
const lines = raw.split("\n");
|
|
5283
5477
|
const matches = lines.filter((l) => l.toLowerCase().includes(query));
|
|
5284
5478
|
if (matches.length === 0) {
|
|
5285
|
-
return { handled: true, output:
|
|
5479
|
+
return { handled: true, output: pc6.dim(`No tools matching "${query}".`) };
|
|
5286
5480
|
}
|
|
5287
|
-
return { handled: true, output: [
|
|
5481
|
+
return { handled: true, output: [pc6.bold(`Tools matching "${query}":`), ...matches].join("\n") };
|
|
5288
5482
|
}
|
|
5289
5483
|
return handleAkitCommand(action, args);
|
|
5290
5484
|
}
|
|
5291
5485
|
async function handleSkillsCommand(action, args, ctx) {
|
|
5292
|
-
const home2 =
|
|
5486
|
+
const home2 = os17.homedir();
|
|
5293
5487
|
if (!action) {
|
|
5294
|
-
const content = readEcosystemFile(
|
|
5488
|
+
const content = readEcosystemFile(path18.join(home2, ".askill", "skills.md"), "skills (askill)");
|
|
5295
5489
|
return { handled: true, output: content };
|
|
5296
5490
|
}
|
|
5297
5491
|
if (action === "install") {
|
|
5298
5492
|
if (args.length < 1) {
|
|
5299
|
-
return { handled: true, output:
|
|
5493
|
+
return { handled: true, output: pc6.yellow("Usage: /skills install <name>") };
|
|
5300
5494
|
}
|
|
5301
5495
|
const output = await mcpWrite(ctx, "skills", "skill_install", { name: args.join(" ") });
|
|
5302
5496
|
return { handled: true, output };
|
|
5303
5497
|
}
|
|
5304
5498
|
if (action === "uninstall") {
|
|
5305
5499
|
if (args.length < 1) {
|
|
5306
|
-
return { handled: true, output:
|
|
5500
|
+
return { handled: true, output: pc6.yellow("Usage: /skills uninstall <name>") };
|
|
5307
5501
|
}
|
|
5308
5502
|
const output = await mcpWrite(ctx, "skills", "skill_uninstall", { name: args.join(" ") });
|
|
5309
5503
|
return { handled: true, output };
|
|
5310
5504
|
}
|
|
5311
5505
|
if (action === "search") {
|
|
5312
5506
|
if (args.length === 0) {
|
|
5313
|
-
return { handled: true, output:
|
|
5507
|
+
return { handled: true, output: pc6.yellow("Usage: /skills search <query...>") };
|
|
5314
5508
|
}
|
|
5315
5509
|
const query = args.join(" ").toLowerCase();
|
|
5316
|
-
const home3 =
|
|
5317
|
-
const raw = readEcosystemFile(
|
|
5510
|
+
const home3 = os17.homedir();
|
|
5511
|
+
const raw = readEcosystemFile(path18.join(home3, ".askill", "skills.md"), "skills (askill)");
|
|
5318
5512
|
if (raw.startsWith("No ")) {
|
|
5319
5513
|
return { handled: true, output: raw };
|
|
5320
5514
|
}
|
|
5321
5515
|
const lines = raw.split("\n");
|
|
5322
5516
|
const matches = lines.filter((l) => l.toLowerCase().includes(query));
|
|
5323
5517
|
if (matches.length === 0) {
|
|
5324
|
-
return { handled: true, output:
|
|
5518
|
+
return { handled: true, output: pc6.dim(`No skills matching "${query}".`) };
|
|
5325
5519
|
}
|
|
5326
|
-
return { handled: true, output: [
|
|
5520
|
+
return { handled: true, output: [pc6.bold(`Skills matching "${query}":`), ...matches].join("\n") };
|
|
5327
5521
|
}
|
|
5328
5522
|
if (action === "list") {
|
|
5329
5523
|
const autoOnly = args.includes("--auto");
|
|
5330
5524
|
if (autoOnly) {
|
|
5331
|
-
const logPath =
|
|
5525
|
+
const logPath = path18.join(os17.homedir(), ".aman-agent", "crystallization-log.json");
|
|
5332
5526
|
try {
|
|
5333
|
-
const content2 =
|
|
5527
|
+
const content2 = fs18.readFileSync(logPath, "utf-8");
|
|
5334
5528
|
const entries = JSON.parse(content2);
|
|
5335
5529
|
if (entries.length === 0) {
|
|
5336
|
-
return { handled: true, output:
|
|
5530
|
+
return { handled: true, output: pc6.dim("No crystallized skills yet.") };
|
|
5337
5531
|
}
|
|
5338
|
-
const suggestionsPath =
|
|
5532
|
+
const suggestionsPath = path18.join(os17.homedir(), ".aman-agent", "crystallization-suggestions.json");
|
|
5339
5533
|
let sugCounts = {};
|
|
5340
5534
|
try {
|
|
5341
|
-
const sc =
|
|
5535
|
+
const sc = fs18.readFileSync(suggestionsPath, "utf-8");
|
|
5342
5536
|
sugCounts = JSON.parse(sc);
|
|
5343
5537
|
} catch {
|
|
5344
5538
|
}
|
|
5345
5539
|
let versionCounts = {};
|
|
5346
5540
|
try {
|
|
5347
|
-
const skillsContent =
|
|
5541
|
+
const skillsContent = fs18.readFileSync(path18.join(os17.homedir(), ".askill", "skills.md"), "utf-8");
|
|
5348
5542
|
const versionRe = /^# (.+)\.v(\d+)$/gm;
|
|
5349
5543
|
let vMatch;
|
|
5350
5544
|
while ((vMatch = versionRe.exec(skillsContent)) !== null) {
|
|
@@ -5354,62 +5548,62 @@ async function handleSkillsCommand(action, args, ctx) {
|
|
|
5354
5548
|
}
|
|
5355
5549
|
} catch {
|
|
5356
5550
|
}
|
|
5357
|
-
const lines = [
|
|
5551
|
+
const lines = [pc6.bold(`Crystallized skills (${entries.length}):`)];
|
|
5358
5552
|
for (const entry of entries) {
|
|
5359
5553
|
const date = entry.createdAt.slice(0, 10);
|
|
5360
5554
|
const count = sugCounts[entry.name];
|
|
5361
|
-
const reinforced = count && count >= 3 ?
|
|
5555
|
+
const reinforced = count && count >= 3 ? pc6.green(` \u2605 reinforced (${count}\xD7)`) : "";
|
|
5362
5556
|
const versions = versionCounts[entry.name];
|
|
5363
|
-
const versionLabel = versions ?
|
|
5364
|
-
lines.push(` ${
|
|
5365
|
-
lines.push(
|
|
5557
|
+
const versionLabel = versions ? pc6.dim(` [v${versions + 1}]`) : "";
|
|
5558
|
+
lines.push(` ${pc6.cyan(entry.name)} (${date}, conf ${entry.confidence})${reinforced}${versionLabel}`);
|
|
5559
|
+
lines.push(pc6.dim(` triggers: ${entry.triggers.join(", ")}`));
|
|
5366
5560
|
}
|
|
5367
5561
|
return { handled: true, output: lines.join("\n") };
|
|
5368
5562
|
} catch {
|
|
5369
|
-
return { handled: true, output:
|
|
5563
|
+
return { handled: true, output: pc6.dim("No crystallized skills yet.") };
|
|
5370
5564
|
}
|
|
5371
5565
|
}
|
|
5372
|
-
const content = readEcosystemFile(
|
|
5566
|
+
const content = readEcosystemFile(path18.join(home2, ".askill", "skills.md"), "skills (askill)");
|
|
5373
5567
|
return { handled: true, output: content };
|
|
5374
5568
|
}
|
|
5375
5569
|
if (action === "crystallize") {
|
|
5376
|
-
const pmDir =
|
|
5570
|
+
const pmDir = path18.join(os17.homedir(), ".acore", "postmortems");
|
|
5377
5571
|
try {
|
|
5378
|
-
const files =
|
|
5572
|
+
const files = fs18.readdirSync(pmDir);
|
|
5379
5573
|
const jsonFiles = files.filter((f) => f.endsWith(".json")).sort().reverse();
|
|
5380
5574
|
if (jsonFiles.length === 0) {
|
|
5381
5575
|
return {
|
|
5382
5576
|
handled: true,
|
|
5383
|
-
output:
|
|
5577
|
+
output: pc6.dim("No post-mortems found. Run a session that triggers a post-mortem first.")
|
|
5384
5578
|
};
|
|
5385
5579
|
}
|
|
5386
5580
|
const latest = jsonFiles[0];
|
|
5387
|
-
const content =
|
|
5581
|
+
const content = fs18.readFileSync(path18.join(pmDir, latest), "utf-8");
|
|
5388
5582
|
const report = JSON.parse(content);
|
|
5389
5583
|
if (!report.crystallizationCandidates || report.crystallizationCandidates.length === 0) {
|
|
5390
5584
|
return {
|
|
5391
5585
|
handled: true,
|
|
5392
|
-
output:
|
|
5586
|
+
output: pc6.dim(`No crystallization candidates in the most recent post-mortem (${latest}). Run a longer session or wait for the next auto-postmortem.`)
|
|
5393
5587
|
};
|
|
5394
5588
|
}
|
|
5395
|
-
const skillsMdPath =
|
|
5396
|
-
const logPath =
|
|
5589
|
+
const skillsMdPath = path18.join(os17.homedir(), ".askill", "skills.md");
|
|
5590
|
+
const logPath = path18.join(os17.homedir(), ".aman-agent", "crystallization-log.json");
|
|
5397
5591
|
const postmortemFilename = latest.replace(/\.json$/, ".md");
|
|
5398
5592
|
const lines = [
|
|
5399
|
-
|
|
5593
|
+
pc6.bold(`Found ${report.crystallizationCandidates.length} candidate(s) in ${latest}:`)
|
|
5400
5594
|
];
|
|
5401
5595
|
let written = 0;
|
|
5402
5596
|
for (const raw of report.crystallizationCandidates) {
|
|
5403
5597
|
const candidate = validateCandidate(raw);
|
|
5404
5598
|
if (!candidate) {
|
|
5405
5599
|
const rawName = raw.name ?? "unknown";
|
|
5406
|
-
lines.push(
|
|
5600
|
+
lines.push(pc6.dim(` \u2298 ${rawName} \u2014 failed validation`));
|
|
5407
5601
|
continue;
|
|
5408
5602
|
}
|
|
5409
5603
|
const result = await writeSkillToFile(candidate, skillsMdPath, postmortemFilename);
|
|
5410
5604
|
if (result.written) {
|
|
5411
5605
|
written++;
|
|
5412
|
-
lines.push(
|
|
5606
|
+
lines.push(pc6.green(` \u2713 Crystallized: ${candidate.name}`));
|
|
5413
5607
|
await appendCrystallizationLog(
|
|
5414
5608
|
{
|
|
5415
5609
|
name: candidate.name,
|
|
@@ -5421,68 +5615,101 @@ async function handleSkillsCommand(action, args, ctx) {
|
|
|
5421
5615
|
logPath
|
|
5422
5616
|
);
|
|
5423
5617
|
} else {
|
|
5424
|
-
lines.push(
|
|
5618
|
+
lines.push(pc6.yellow(` \u2298 ${candidate.name} \u2014 ${result.reason}`));
|
|
5425
5619
|
}
|
|
5426
5620
|
}
|
|
5427
5621
|
if (written > 0) {
|
|
5428
5622
|
lines.push("");
|
|
5429
|
-
lines.push(
|
|
5623
|
+
lines.push(pc6.dim(`Crystallized skills will auto-activate in your next session.`));
|
|
5430
5624
|
}
|
|
5431
5625
|
return { handled: true, output: lines.join("\n") };
|
|
5432
5626
|
} catch (err) {
|
|
5433
5627
|
return {
|
|
5434
5628
|
handled: true,
|
|
5435
|
-
output:
|
|
5629
|
+
output: pc6.red(`Failed to load post-mortems: ${err instanceof Error ? err.message : String(err)}`)
|
|
5436
5630
|
};
|
|
5437
5631
|
}
|
|
5438
5632
|
}
|
|
5439
5633
|
if (action === "help") {
|
|
5440
5634
|
return { handled: true, output: [
|
|
5441
|
-
|
|
5442
|
-
` ${
|
|
5443
|
-
` ${
|
|
5444
|
-
` ${
|
|
5445
|
-
` ${
|
|
5446
|
-
` ${
|
|
5447
|
-
` ${
|
|
5635
|
+
pc6.bold("Skills commands:"),
|
|
5636
|
+
` ${pc6.cyan("/skills")} View installed skills`,
|
|
5637
|
+
` ${pc6.cyan("/skills install")} <name> Install a skill`,
|
|
5638
|
+
` ${pc6.cyan("/skills uninstall")} <name> Uninstall a skill`,
|
|
5639
|
+
` ${pc6.cyan("/skills search")} <query> Search skills by name/description`,
|
|
5640
|
+
` ${pc6.cyan("/skills crystallize")} Crystallize skills from most recent post-mortem`,
|
|
5641
|
+
` ${pc6.cyan("/skills list --auto")} List crystallized (auto-created) skills`
|
|
5448
5642
|
].join("\n") };
|
|
5449
5643
|
}
|
|
5450
|
-
return { handled: true, output:
|
|
5644
|
+
return { handled: true, output: pc6.yellow(`Unknown action: /skills ${action}. Try /skills --help`) };
|
|
5451
5645
|
}
|
|
5452
5646
|
async function handleEvalCommand(action, args, ctx) {
|
|
5453
|
-
const home2 =
|
|
5647
|
+
const home2 = os17.homedir();
|
|
5454
5648
|
if (!action) {
|
|
5455
|
-
const content = readEcosystemFile(
|
|
5649
|
+
const content = readEcosystemFile(path18.join(home2, ".aeval", "eval.md"), "evaluation (aeval)");
|
|
5456
5650
|
return { handled: true, output: content };
|
|
5457
5651
|
}
|
|
5458
5652
|
if (action === "milestone") {
|
|
5459
5653
|
if (args.length < 1) {
|
|
5460
|
-
return { handled: true, output:
|
|
5654
|
+
return { handled: true, output: pc6.yellow("Usage: /eval milestone <text...>") };
|
|
5461
5655
|
}
|
|
5462
5656
|
const text3 = args.join(" ");
|
|
5463
5657
|
const output = await mcpWrite(ctx, "eval", "eval_milestone", { text: text3 });
|
|
5464
5658
|
return { handled: true, output };
|
|
5465
5659
|
}
|
|
5466
5660
|
if (action === "report") {
|
|
5467
|
-
const evalFile =
|
|
5468
|
-
|
|
5469
|
-
|
|
5661
|
+
const evalFile = path18.join(home2, ".aeval", "eval.md");
|
|
5662
|
+
const lines = [pc6.bold("\u{1F4CA} Eval Report")];
|
|
5663
|
+
if (fs18.existsSync(evalFile)) {
|
|
5664
|
+
lines.push("", fs18.readFileSync(evalFile, "utf-8").trim());
|
|
5665
|
+
} else {
|
|
5666
|
+
lines.push("", pc6.dim("No eval log yet. Use /eval milestone <text> to start."));
|
|
5667
|
+
}
|
|
5668
|
+
try {
|
|
5669
|
+
const model = await loadUserModel();
|
|
5670
|
+
if (model && model.sessions.length >= 3) {
|
|
5671
|
+
const profile = computeProfile(model.sessions, model.profile.totalSessions);
|
|
5672
|
+
const burnout = predictBurnout(model.sessions);
|
|
5673
|
+
lines.push("", pc6.bold("\u2500\u2500 Analytics \u2500\u2500"));
|
|
5674
|
+
lines.push(` Sessions tracked: ${pc6.cyan(String(profile.totalSessions))}`);
|
|
5675
|
+
lines.push(` Trust score: ${pc6.cyan(profile.trustScore.toFixed(2))}`);
|
|
5676
|
+
lines.push(` Sentiment trend: ${pc6.cyan(profile.sentimentTrend)}`);
|
|
5677
|
+
const topEnergy = Object.entries(profile.energyDistribution).sort((a, b) => b[1] - a[1]).slice(0, 2).map(([k, v]) => `${k} ${(v * 100).toFixed(0)}%`);
|
|
5678
|
+
lines.push(` Top energy: ${pc6.cyan(topEnergy.join(", "))}`);
|
|
5679
|
+
const riskColor = burnout.risk > 0.7 ? pc6.red : burnout.risk > 0.4 ? pc6.yellow : pc6.green;
|
|
5680
|
+
lines.push(` Burnout risk: ${riskColor((burnout.risk * 100).toFixed(0) + "%")} ${burnout.factors.length > 0 ? pc6.dim("(" + burnout.factors.join(", ") + ")") : ""}`);
|
|
5681
|
+
const cors = Object.entries(profile.frustrationCorrelations).filter(([, v]) => Math.abs(v) > 0.3).sort((a, b) => Math.abs(b[1]) - Math.abs(a[1])).slice(0, 3);
|
|
5682
|
+
if (cors.length > 0) {
|
|
5683
|
+
lines.push(` Frustration corr: ${cors.map(([k, v]) => `${k} ${v > 0 ? "\u2191" : "\u2193"}${Math.abs(v).toFixed(2)}`).join(", ")}`);
|
|
5684
|
+
}
|
|
5685
|
+
}
|
|
5686
|
+
} catch {
|
|
5470
5687
|
}
|
|
5471
|
-
|
|
5472
|
-
|
|
5688
|
+
try {
|
|
5689
|
+
const taskLog = loadTaskLog();
|
|
5690
|
+
if (taskLog.length > 0) {
|
|
5691
|
+
const completed = taskLog.filter((t) => t.status === "completed").length;
|
|
5692
|
+
const failed = taskLog.filter((t) => t.status === "failed").length;
|
|
5693
|
+
const interrupted = taskLog.filter((t) => t.status === "interrupted").length;
|
|
5694
|
+
lines.push("", pc6.bold("\u2500\u2500 Background Tasks \u2500\u2500"));
|
|
5695
|
+
lines.push(` Total: ${taskLog.length} \u2705 ${completed} \u274C ${failed} \u26A0\uFE0F ${interrupted}`);
|
|
5696
|
+
}
|
|
5697
|
+
} catch {
|
|
5698
|
+
}
|
|
5699
|
+
return { handled: true, output: lines.join("\n") };
|
|
5473
5700
|
}
|
|
5474
|
-
return { handled: true, output:
|
|
5701
|
+
return { handled: true, output: pc6.yellow(`Unknown action: /eval ${action}. Use /eval, /eval report, or /eval milestone <text>.`) };
|
|
5475
5702
|
}
|
|
5476
5703
|
async function handleMemoryCommand(action, args, ctx) {
|
|
5477
5704
|
if (!action) {
|
|
5478
5705
|
try {
|
|
5479
5706
|
const result = await memoryContext("recent context");
|
|
5480
5707
|
if (result.memoriesUsed === 0) {
|
|
5481
|
-
return { handled: true, output:
|
|
5708
|
+
return { handled: true, output: pc6.dim("No memories yet. Start chatting and I'll remember what matters.") };
|
|
5482
5709
|
}
|
|
5483
5710
|
return { handled: true, output: result.text };
|
|
5484
5711
|
} catch (err) {
|
|
5485
|
-
return { handled: true, output:
|
|
5712
|
+
return { handled: true, output: pc6.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
5486
5713
|
}
|
|
5487
5714
|
}
|
|
5488
5715
|
if (action && !["search", "clear", "timeline", "stats", "export", "since", "fts", "help", "doctor", "repair", "config", "reflect", "consolidate", "tier", "detail", "relate", "expire", "versions", "sync"].includes(action)) {
|
|
@@ -5490,54 +5717,54 @@ async function handleMemoryCommand(action, args, ctx) {
|
|
|
5490
5717
|
const topic = [action, ...args].join(" ");
|
|
5491
5718
|
const result = await memoryContext(topic);
|
|
5492
5719
|
if (result.memoriesUsed === 0) {
|
|
5493
|
-
return { handled: true, output:
|
|
5720
|
+
return { handled: true, output: pc6.dim(`No memories found for: "${topic}".`) };
|
|
5494
5721
|
}
|
|
5495
5722
|
return { handled: true, output: result.text };
|
|
5496
5723
|
} catch (err) {
|
|
5497
|
-
return { handled: true, output:
|
|
5724
|
+
return { handled: true, output: pc6.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
5498
5725
|
}
|
|
5499
5726
|
}
|
|
5500
5727
|
if (action === "search") {
|
|
5501
5728
|
if (args.length < 1) {
|
|
5502
|
-
return { handled: true, output:
|
|
5729
|
+
return { handled: true, output: pc6.yellow("Usage: /memory search <query...>") };
|
|
5503
5730
|
}
|
|
5504
5731
|
const query = args.join(" ");
|
|
5505
5732
|
try {
|
|
5506
5733
|
const result = await memoryMultiRecall(query, { limit: 10 });
|
|
5507
5734
|
if (result.total === 0) {
|
|
5508
|
-
return { handled: true, output:
|
|
5735
|
+
return { handled: true, output: pc6.dim("No memories found.") };
|
|
5509
5736
|
}
|
|
5510
5737
|
const header = `Search results for "${query}" (${result.total}):`;
|
|
5511
|
-
const lines = [
|
|
5738
|
+
const lines = [pc6.bold(header), ""];
|
|
5512
5739
|
for (const m of result.memories) {
|
|
5513
|
-
const tags = m.tags?.length > 0 ? ` ${
|
|
5740
|
+
const tags = m.tags?.length > 0 ? ` ${pc6.dim(m.tags.map((t) => `#${t}`).join(" "))}` : "";
|
|
5514
5741
|
lines.push(` [${m.type}] ${m.content}${tags}`);
|
|
5515
5742
|
}
|
|
5516
5743
|
return { handled: true, output: lines.join("\n") };
|
|
5517
5744
|
} catch (err) {
|
|
5518
|
-
return { handled: true, output:
|
|
5745
|
+
return { handled: true, output: pc6.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
5519
5746
|
}
|
|
5520
5747
|
}
|
|
5521
5748
|
if (action === "clear") {
|
|
5522
5749
|
if (args.length < 1) {
|
|
5523
|
-
return { handled: true, output:
|
|
5750
|
+
return { handled: true, output: pc6.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)") };
|
|
5524
5751
|
}
|
|
5525
5752
|
try {
|
|
5526
5753
|
if (args[0] === "--type" && args[1]) {
|
|
5527
5754
|
const result2 = await memoryForget({ type: args[1] });
|
|
5528
|
-
return { handled: true, output: result2.deleted > 0 ?
|
|
5755
|
+
return { handled: true, output: result2.deleted > 0 ? pc6.green(result2.message) : pc6.dim(result2.message) };
|
|
5529
5756
|
}
|
|
5530
5757
|
const result = await memoryForget({ query: args.join(" ") });
|
|
5531
|
-
return { handled: true, output: result.deleted > 0 ?
|
|
5758
|
+
return { handled: true, output: result.deleted > 0 ? pc6.green(result.message) : pc6.dim(result.message) };
|
|
5532
5759
|
} catch (err) {
|
|
5533
|
-
return { handled: true, output:
|
|
5760
|
+
return { handled: true, output: pc6.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
5534
5761
|
}
|
|
5535
5762
|
}
|
|
5536
5763
|
if (action === "timeline") {
|
|
5537
5764
|
try {
|
|
5538
5765
|
const result = await memoryRecall("*", { limit: 500, compact: false });
|
|
5539
5766
|
if (result.total === 0) {
|
|
5540
|
-
return { handled: true, output:
|
|
5767
|
+
return { handled: true, output: pc6.dim("No memories yet. Start chatting and I'll remember what matters.") };
|
|
5541
5768
|
}
|
|
5542
5769
|
const memories = result.memories;
|
|
5543
5770
|
if (memories.length > 0) {
|
|
@@ -5549,7 +5776,7 @@ async function handleMemoryCommand(action, args, ctx) {
|
|
|
5549
5776
|
}
|
|
5550
5777
|
const maxCount = Math.max(...byDate.values());
|
|
5551
5778
|
const barWidth = 10;
|
|
5552
|
-
const lines = [
|
|
5779
|
+
const lines = [pc6.bold("Memory Timeline:"), ""];
|
|
5553
5780
|
for (const [date, count] of byDate) {
|
|
5554
5781
|
const filled = Math.round(count / maxCount * barWidth);
|
|
5555
5782
|
const bar = "\u2588".repeat(filled) + "\u2591".repeat(barWidth - filled);
|
|
@@ -5574,24 +5801,24 @@ async function handleMemoryCommand(action, args, ctx) {
|
|
|
5574
5801
|
}
|
|
5575
5802
|
return { handled: true, output: `Total memories: ${result.total} entries.` };
|
|
5576
5803
|
} catch {
|
|
5577
|
-
return { handled: true, output:
|
|
5804
|
+
return { handled: true, output: pc6.red("Failed to retrieve memory timeline.") };
|
|
5578
5805
|
}
|
|
5579
5806
|
}
|
|
5580
5807
|
if (action === "stats") {
|
|
5581
5808
|
try {
|
|
5582
5809
|
const stats = memoryStats();
|
|
5583
|
-
const lines = [
|
|
5584
|
-
lines.push(` Total memories: ${
|
|
5810
|
+
const lines = [pc6.bold("Memory Statistics:"), ""];
|
|
5811
|
+
lines.push(` Total memories: ${pc6.bold(String(stats.total))}`);
|
|
5585
5812
|
if (Object.keys(stats.byType).length > 0) {
|
|
5586
5813
|
lines.push("");
|
|
5587
|
-
lines.push(` ${
|
|
5814
|
+
lines.push(` ${pc6.dim("By type:")}`);
|
|
5588
5815
|
for (const [type, count] of Object.entries(stats.byType)) {
|
|
5589
5816
|
lines.push(` ${type.padEnd(16)} ${count}`);
|
|
5590
5817
|
}
|
|
5591
5818
|
}
|
|
5592
5819
|
return { handled: true, output: lines.join("\n") };
|
|
5593
5820
|
} catch (err) {
|
|
5594
|
-
return { handled: true, output:
|
|
5821
|
+
return { handled: true, output: pc6.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
5595
5822
|
}
|
|
5596
5823
|
}
|
|
5597
5824
|
if (action === "export") {
|
|
@@ -5599,7 +5826,7 @@ async function handleMemoryCommand(action, args, ctx) {
|
|
|
5599
5826
|
const format = args[0] === "json" ? "json" : "markdown";
|
|
5600
5827
|
const memories = memoryExport();
|
|
5601
5828
|
if (memories.length === 0) {
|
|
5602
|
-
return { handled: true, output:
|
|
5829
|
+
return { handled: true, output: pc6.dim("No memories to export.") };
|
|
5603
5830
|
}
|
|
5604
5831
|
if (format === "json") {
|
|
5605
5832
|
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 }));
|
|
@@ -5609,11 +5836,11 @@ async function handleMemoryCommand(action, args, ctx) {
|
|
|
5609
5836
|
for (const m of memories) {
|
|
5610
5837
|
const date = new Date(m.createdAt).toLocaleDateString();
|
|
5611
5838
|
const tags = m.tags.length > 0 ? ` [${m.tags.map((t) => `#${t}`).join(", ")}]` : "";
|
|
5612
|
-
lines.push(`- **[${m.type}]** ${m.content}${tags} ${
|
|
5839
|
+
lines.push(`- **[${m.type}]** ${m.content}${tags} ${pc6.dim(`(${date}, ${Math.round(m.confidence * 100)}%)`)}`);
|
|
5613
5840
|
}
|
|
5614
5841
|
return { handled: true, output: lines.join("\n") };
|
|
5615
5842
|
} catch (err) {
|
|
5616
|
-
return { handled: true, output:
|
|
5843
|
+
return { handled: true, output: pc6.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
5617
5844
|
}
|
|
5618
5845
|
}
|
|
5619
5846
|
if (action === "since") {
|
|
@@ -5628,60 +5855,60 @@ async function handleMemoryCommand(action, args, ctx) {
|
|
|
5628
5855
|
else if (unit === "d") hours = value * 24;
|
|
5629
5856
|
else if (unit === "w") hours = value * 24 * 7;
|
|
5630
5857
|
} else {
|
|
5631
|
-
return { handled: true, output:
|
|
5858
|
+
return { handled: true, output: pc6.yellow("Usage: /memory since <Nh|Nd|Nw> (e.g., 24h, 7d, 1w)") };
|
|
5632
5859
|
}
|
|
5633
5860
|
}
|
|
5634
5861
|
const memories = memorySince(hours);
|
|
5635
5862
|
if (memories.length === 0) {
|
|
5636
|
-
return { handled: true, output:
|
|
5863
|
+
return { handled: true, output: pc6.dim(`No memories in the last ${args[0] || "24h"}.`) };
|
|
5637
5864
|
}
|
|
5638
|
-
const lines = [
|
|
5865
|
+
const lines = [pc6.bold(`Memories since ${args[0] || "24h"} (${memories.length}):`), ""];
|
|
5639
5866
|
for (const m of memories) {
|
|
5640
5867
|
const age = Math.round((Date.now() - m.createdAt) / 36e5);
|
|
5641
5868
|
const ageStr = age < 1 ? "<1h ago" : `${age}h ago`;
|
|
5642
|
-
lines.push(` ${
|
|
5869
|
+
lines.push(` ${pc6.dim(ageStr.padEnd(10))} [${m.type}] ${m.content}`);
|
|
5643
5870
|
}
|
|
5644
5871
|
return { handled: true, output: lines.join("\n") };
|
|
5645
5872
|
} catch (err) {
|
|
5646
|
-
return { handled: true, output:
|
|
5873
|
+
return { handled: true, output: pc6.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
5647
5874
|
}
|
|
5648
5875
|
}
|
|
5649
5876
|
if (action === "fts") {
|
|
5650
5877
|
if (args.length < 1) {
|
|
5651
|
-
return { handled: true, output:
|
|
5878
|
+
return { handled: true, output: pc6.yellow("Usage: /memory fts <query...> \u2014 full-text search") };
|
|
5652
5879
|
}
|
|
5653
5880
|
try {
|
|
5654
5881
|
const query = args.join(" ");
|
|
5655
5882
|
const results = memorySearch(query, 20);
|
|
5656
5883
|
if (results.length === 0) {
|
|
5657
|
-
return { handled: true, output:
|
|
5884
|
+
return { handled: true, output: pc6.dim(`No results for full-text search: "${query}".`) };
|
|
5658
5885
|
}
|
|
5659
|
-
const lines = [
|
|
5886
|
+
const lines = [pc6.bold(`FTS results for "${query}" (${results.length}):`), ""];
|
|
5660
5887
|
for (const m of results) {
|
|
5661
|
-
const tags = m.tags.length > 0 ? ` ${
|
|
5888
|
+
const tags = m.tags.length > 0 ? ` ${pc6.dim(m.tags.map((t) => `#${t}`).join(" "))}` : "";
|
|
5662
5889
|
lines.push(` [${m.type}] ${m.content}${tags}`);
|
|
5663
5890
|
}
|
|
5664
5891
|
return { handled: true, output: lines.join("\n") };
|
|
5665
5892
|
} catch (err) {
|
|
5666
|
-
return { handled: true, output:
|
|
5893
|
+
return { handled: true, output: pc6.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
5667
5894
|
}
|
|
5668
5895
|
}
|
|
5669
5896
|
if (action === "help") {
|
|
5670
5897
|
return { handled: true, output: [
|
|
5671
|
-
|
|
5672
|
-
` ${
|
|
5673
|
-
` ${
|
|
5674
|
-
` ${
|
|
5675
|
-
` ${
|
|
5676
|
-
` ${
|
|
5677
|
-
` ${
|
|
5678
|
-
` ${
|
|
5679
|
-
` ${
|
|
5680
|
-
` ${
|
|
5681
|
-
` ${
|
|
5682
|
-
` ${
|
|
5683
|
-
` ${
|
|
5684
|
-
` ${
|
|
5898
|
+
pc6.bold("Memory commands:"),
|
|
5899
|
+
` ${pc6.cyan("/memory")} View recent context`,
|
|
5900
|
+
` ${pc6.cyan("/memory")} <topic> Context for a topic`,
|
|
5901
|
+
` ${pc6.cyan("/memory search")} <query> Search memories (semantic)`,
|
|
5902
|
+
` ${pc6.cyan("/memory fts")} <query> Full-text search (FTS5)`,
|
|
5903
|
+
` ${pc6.cyan("/memory since")} <Nh|Nd|Nw> Memories from time window`,
|
|
5904
|
+
` ${pc6.cyan("/memory stats")} Show memory statistics`,
|
|
5905
|
+
` ${pc6.cyan("/memory export")} [json] Export all memories`,
|
|
5906
|
+
` ${pc6.cyan("/memory timeline")} View memory timeline`,
|
|
5907
|
+
` ${pc6.cyan("/memory clear")} <query> Delete matching memories`,
|
|
5908
|
+
` ${pc6.cyan("/memory clear --type")} <type> Delete all of a type`,
|
|
5909
|
+
` ${pc6.cyan("/memory doctor")} Run memory diagnostics`,
|
|
5910
|
+
` ${pc6.cyan("/memory repair")} Dry-run repair (safe)`,
|
|
5911
|
+
` ${pc6.cyan("/memory config")} [key=value] View or update config (e.g. consolidation.maxStaleDays=60)`
|
|
5685
5912
|
].join("\n") };
|
|
5686
5913
|
}
|
|
5687
5914
|
if (action === "doctor") {
|
|
@@ -5701,7 +5928,7 @@ async function handleMemoryCommand(action, args, ctx) {
|
|
|
5701
5928
|
}
|
|
5702
5929
|
return { handled: true, output: lines.join("\n") };
|
|
5703
5930
|
} catch (err) {
|
|
5704
|
-
return { handled: true, output:
|
|
5931
|
+
return { handled: true, output: pc6.red(`Memory doctor error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
5705
5932
|
}
|
|
5706
5933
|
}
|
|
5707
5934
|
if (action === "repair") {
|
|
@@ -5723,7 +5950,7 @@ async function handleMemoryCommand(action, args, ctx) {
|
|
|
5723
5950
|
}
|
|
5724
5951
|
return { handled: true, output: lines.join("\n") };
|
|
5725
5952
|
} catch (err) {
|
|
5726
|
-
return { handled: true, output:
|
|
5953
|
+
return { handled: true, output: pc6.red(`Memory repair error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
5727
5954
|
}
|
|
5728
5955
|
}
|
|
5729
5956
|
if (action === "config") {
|
|
@@ -5734,7 +5961,7 @@ async function handleMemoryCommand(action, args, ctx) {
|
|
|
5734
5961
|
const key = kvArg.slice(0, eqIdx);
|
|
5735
5962
|
const rawVal = kvArg.slice(eqIdx + 1);
|
|
5736
5963
|
if (!rawVal) {
|
|
5737
|
-
return { handled: true, output:
|
|
5964
|
+
return { handled: true, output: pc6.yellow(`Usage: /memory config <key>=<value>`) };
|
|
5738
5965
|
}
|
|
5739
5966
|
const val = isNaN(Number(rawVal)) ? rawVal : Number(rawVal);
|
|
5740
5967
|
const update = buildNestedUpdate(key, val);
|
|
@@ -5755,14 +5982,14 @@ async function handleMemoryCommand(action, args, ctx) {
|
|
|
5755
5982
|
lines.push("```", "", "_Use `/memory config key=value` to change a setting._");
|
|
5756
5983
|
return { handled: true, output: lines.join("\n") };
|
|
5757
5984
|
} catch (err) {
|
|
5758
|
-
return { handled: true, output:
|
|
5985
|
+
return { handled: true, output: pc6.red(`Memory config error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
5759
5986
|
}
|
|
5760
5987
|
}
|
|
5761
5988
|
if (action === "reflect") {
|
|
5762
5989
|
try {
|
|
5763
5990
|
const report = await memoryReflect();
|
|
5764
5991
|
const lines = [
|
|
5765
|
-
|
|
5992
|
+
pc6.bold("Reflection complete"),
|
|
5766
5993
|
`Clusters: ${report.clusters.length}`,
|
|
5767
5994
|
`Contradictions: ${report.contradictions.length}`,
|
|
5768
5995
|
`Synthesis candidates: ${report.synthesisCandidates.length}`,
|
|
@@ -5772,7 +5999,7 @@ async function handleMemoryCommand(action, args, ctx) {
|
|
|
5772
5999
|
];
|
|
5773
6000
|
return { handled: true, output: lines.join("\n") };
|
|
5774
6001
|
} catch (err) {
|
|
5775
|
-
return { handled: true, output:
|
|
6002
|
+
return { handled: true, output: pc6.red(`Reflect error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
5776
6003
|
}
|
|
5777
6004
|
}
|
|
5778
6005
|
if (action === "consolidate") {
|
|
@@ -5780,7 +6007,7 @@ async function handleMemoryCommand(action, args, ctx) {
|
|
|
5780
6007
|
try {
|
|
5781
6008
|
const report = memoryConsolidate(!apply);
|
|
5782
6009
|
const lines = [
|
|
5783
|
-
apply ?
|
|
6010
|
+
apply ? pc6.bold("Consolidation applied") : pc6.bold("Consolidation dry-run"),
|
|
5784
6011
|
`Merged: ${report.merged}`,
|
|
5785
6012
|
`Pruned: ${report.pruned}`,
|
|
5786
6013
|
`Promoted: ${report.promoted}`,
|
|
@@ -5788,35 +6015,35 @@ async function handleMemoryCommand(action, args, ctx) {
|
|
|
5788
6015
|
`Health score: ${(report.healthScore * 100).toFixed(0)}%`,
|
|
5789
6016
|
`Before: ${report.before.total} \u2192 After: ${report.after.total}`
|
|
5790
6017
|
];
|
|
5791
|
-
if (!apply) lines.push(
|
|
6018
|
+
if (!apply) lines.push(pc6.dim("Run with --apply to execute."));
|
|
5792
6019
|
return { handled: true, output: lines.join("\n") };
|
|
5793
6020
|
} catch (err) {
|
|
5794
|
-
return { handled: true, output:
|
|
6021
|
+
return { handled: true, output: pc6.red(`Consolidate error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
5795
6022
|
}
|
|
5796
6023
|
}
|
|
5797
6024
|
if (action === "tier") {
|
|
5798
6025
|
const id = args[0];
|
|
5799
6026
|
const tier = args[1];
|
|
5800
6027
|
if (!id || !tier) {
|
|
5801
|
-
return { handled: true, output:
|
|
6028
|
+
return { handled: true, output: pc6.yellow("Usage: /memory tier <id> <core|working|archival>") };
|
|
5802
6029
|
}
|
|
5803
6030
|
const tierResult = memoryTier(id, tier);
|
|
5804
6031
|
if (!tierResult.ok) {
|
|
5805
|
-
return { handled: true, output:
|
|
6032
|
+
return { handled: true, output: pc6.red(`Tier error: ${tierResult.error}`) };
|
|
5806
6033
|
}
|
|
5807
6034
|
return { handled: true, output: `\u2705 Memory ${tierResult.id} moved to tier: ${tierResult.tier}` };
|
|
5808
6035
|
}
|
|
5809
6036
|
if (action === "detail") {
|
|
5810
6037
|
const id = args[0];
|
|
5811
6038
|
if (!id) {
|
|
5812
|
-
return { handled: true, output:
|
|
6039
|
+
return { handled: true, output: pc6.yellow("Usage: /memory detail <id>") };
|
|
5813
6040
|
}
|
|
5814
6041
|
const memory = memoryDetail(id);
|
|
5815
6042
|
if (!memory) {
|
|
5816
|
-
return { handled: true, output:
|
|
6043
|
+
return { handled: true, output: pc6.dim(`Memory not found: ${id}`) };
|
|
5817
6044
|
}
|
|
5818
6045
|
const lines = [
|
|
5819
|
-
|
|
6046
|
+
pc6.bold(`Memory: ${memory.id}`),
|
|
5820
6047
|
`Content: ${memory.content}`,
|
|
5821
6048
|
`Type: ${memory.type}`,
|
|
5822
6049
|
`Confidence: ${memory.confidence}`,
|
|
@@ -5830,37 +6057,37 @@ async function handleMemoryCommand(action, args, ctx) {
|
|
|
5830
6057
|
if (action === "relate") {
|
|
5831
6058
|
const [fromId, toId, relType, strengthStr] = args;
|
|
5832
6059
|
if (!fromId || !toId || !relType) {
|
|
5833
|
-
return { handled: true, output:
|
|
6060
|
+
return { handled: true, output: pc6.yellow("Usage: /memory relate <fromId> <toId> <type> [strength]") };
|
|
5834
6061
|
}
|
|
5835
6062
|
const strength = strengthStr !== void 0 ? parseFloat(strengthStr) : void 0;
|
|
5836
6063
|
const relResult = memoryRelate(fromId, toId, relType, strength);
|
|
5837
6064
|
if (!relResult.ok) {
|
|
5838
|
-
return { handled: true, output:
|
|
6065
|
+
return { handled: true, output: pc6.red(`Relate error: ${relResult.error}`) };
|
|
5839
6066
|
}
|
|
5840
6067
|
return { handled: true, output: `\u2705 Relation created: ${fromId} --[${relType}]--> ${toId} (id: ${relResult.relationId})` };
|
|
5841
6068
|
}
|
|
5842
6069
|
if (action === "expire") {
|
|
5843
6070
|
const id = args[0];
|
|
5844
6071
|
if (!id) {
|
|
5845
|
-
return { handled: true, output:
|
|
6072
|
+
return { handled: true, output: pc6.yellow("Usage: /memory expire <id> [reason]") };
|
|
5846
6073
|
}
|
|
5847
6074
|
const reason = args.slice(1).join(" ") || void 0;
|
|
5848
6075
|
const expireResult = memoryExpire(id, reason);
|
|
5849
6076
|
if (!expireResult.ok) {
|
|
5850
|
-
return { handled: true, output:
|
|
6077
|
+
return { handled: true, output: pc6.red(`Expire error: ${expireResult.error}`) };
|
|
5851
6078
|
}
|
|
5852
6079
|
return { handled: true, output: `\u2705 Memory ${expireResult.id} expired${reason ? `: ${reason}` : ""}` };
|
|
5853
6080
|
}
|
|
5854
6081
|
if (action === "versions") {
|
|
5855
6082
|
const id = args[0];
|
|
5856
6083
|
if (!id) {
|
|
5857
|
-
return { handled: true, output:
|
|
6084
|
+
return { handled: true, output: pc6.yellow("Usage: /memory versions <id>") };
|
|
5858
6085
|
}
|
|
5859
6086
|
const versions = memoryVersions(id);
|
|
5860
6087
|
if (!versions.length) {
|
|
5861
|
-
return { handled: true, output:
|
|
6088
|
+
return { handled: true, output: pc6.dim(`No version history for: ${id}`) };
|
|
5862
6089
|
}
|
|
5863
|
-
const lines = [
|
|
6090
|
+
const lines = [pc6.bold(`Version history for ${id}:`)];
|
|
5864
6091
|
for (const v of versions) {
|
|
5865
6092
|
lines.push(` [${new Date(v.editedAt).toISOString()}] ${v.content.slice(0, 80)}${v.content.length > 80 ? "\u2026" : ""}`);
|
|
5866
6093
|
}
|
|
@@ -5869,7 +6096,7 @@ async function handleMemoryCommand(action, args, ctx) {
|
|
|
5869
6096
|
if (action === "sync") {
|
|
5870
6097
|
const syncAction = args[0];
|
|
5871
6098
|
if (!syncAction) {
|
|
5872
|
-
return { handled: true, output:
|
|
6099
|
+
return { handled: true, output: pc6.yellow("Usage: /memory sync <import-claude|export-team|import-team|sync-copilot>") };
|
|
5873
6100
|
}
|
|
5874
6101
|
try {
|
|
5875
6102
|
const opts = {};
|
|
@@ -5883,64 +6110,64 @@ async function handleMemoryCommand(action, args, ctx) {
|
|
|
5883
6110
|
return { handled: true, output: `\u2705 Sync [${syncAction}] complete:
|
|
5884
6111
|
${JSON.stringify(result, null, 2)}` };
|
|
5885
6112
|
} catch (err) {
|
|
5886
|
-
return { handled: true, output:
|
|
6113
|
+
return { handled: true, output: pc6.red(`Sync error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
5887
6114
|
}
|
|
5888
6115
|
}
|
|
5889
|
-
return { handled: true, output:
|
|
6116
|
+
return { handled: true, output: pc6.yellow(`Unknown action: /memory ${action}. Try /memory --help`) };
|
|
5890
6117
|
}
|
|
5891
6118
|
function handleStatusCommand(ctx) {
|
|
5892
6119
|
const mcpToolCount = ctx.mcpManager ? ctx.mcpManager.getTools().length : 0;
|
|
5893
6120
|
const amemConnected = isMemoryInitialized();
|
|
5894
6121
|
const status = getEcosystemStatus(mcpToolCount, amemConnected);
|
|
5895
|
-
const lines = [
|
|
6122
|
+
const lines = [pc6.bold("Aman Ecosystem Dashboard"), ""];
|
|
5896
6123
|
for (const layer of status.layers) {
|
|
5897
|
-
const icon = layer.exists ?
|
|
5898
|
-
const name =
|
|
5899
|
-
const summary = layer.exists ? layer.summary :
|
|
6124
|
+
const icon = layer.exists ? pc6.green("\u25CF") : pc6.dim("\u25CB");
|
|
6125
|
+
const name = pc6.bold(layer.name.padEnd(12));
|
|
6126
|
+
const summary = layer.exists ? layer.summary : pc6.dim("not configured");
|
|
5900
6127
|
lines.push(` ${icon} ${name} ${summary}`);
|
|
5901
6128
|
}
|
|
5902
6129
|
lines.push("");
|
|
5903
|
-
lines.push(` ${status.mcpConnected ?
|
|
5904
|
-
lines.push(` ${status.amemConnected ?
|
|
6130
|
+
lines.push(` ${status.mcpConnected ? pc6.green("\u25CF") : pc6.dim("\u25CB")} ${pc6.bold("MCP".padEnd(12))} ${status.mcpConnected ? `${status.mcpToolCount} tools available` : pc6.dim("not connected")}`);
|
|
6131
|
+
lines.push(` ${status.amemConnected ? pc6.green("\u25CF") : pc6.dim("\u25CB")} ${pc6.bold("Memory".padEnd(12))} ${status.amemConnected ? "connected" : pc6.dim("not connected")}`);
|
|
5905
6132
|
return { handled: true, output: lines.join("\n") };
|
|
5906
6133
|
}
|
|
5907
6134
|
function handleDoctorCommand(ctx) {
|
|
5908
6135
|
const mcpToolCount = ctx.mcpManager ? ctx.mcpManager.getTools().length : 0;
|
|
5909
6136
|
const amemConnected = isMemoryInitialized();
|
|
5910
6137
|
const status = getEcosystemStatus(mcpToolCount, amemConnected);
|
|
5911
|
-
const lines = [
|
|
6138
|
+
const lines = [pc6.bold("Aman Health Check"), ""];
|
|
5912
6139
|
let healthy = 0;
|
|
5913
6140
|
let fixes = 0;
|
|
5914
6141
|
let suggestions = 0;
|
|
5915
6142
|
for (const layer of status.layers) {
|
|
5916
6143
|
if (layer.exists) {
|
|
5917
|
-
lines.push(` ${
|
|
6144
|
+
lines.push(` ${pc6.green("\u2713")} ${layer.name.padEnd(12)} ${pc6.green(layer.summary)}`);
|
|
5918
6145
|
healthy++;
|
|
5919
6146
|
} else {
|
|
5920
6147
|
const isRequired = ["identity", "rules"].includes(layer.name.toLowerCase());
|
|
5921
6148
|
if (isRequired) {
|
|
5922
|
-
lines.push(` ${
|
|
5923
|
-
lines.push(` ${
|
|
6149
|
+
lines.push(` ${pc6.red("\u2717")} ${layer.name.padEnd(12)} ${pc6.red("missing")}`);
|
|
6150
|
+
lines.push(` ${pc6.dim("\u2192 Fix: aman-agent init")}`);
|
|
5924
6151
|
fixes++;
|
|
5925
6152
|
} else {
|
|
5926
|
-
lines.push(` ${
|
|
6153
|
+
lines.push(` ${pc6.yellow("\u26A0")} ${layer.name.padEnd(12)} ${pc6.yellow("empty")}`);
|
|
5927
6154
|
const cmd = layer.name.toLowerCase() === "workflows" ? "/workflows add <name>" : layer.name.toLowerCase() === "tools" ? "/tools add <name> <type> <desc>" : layer.name.toLowerCase() === "skills" ? "/skills install <name>" : "";
|
|
5928
|
-
if (cmd) lines.push(` ${
|
|
6155
|
+
if (cmd) lines.push(` ${pc6.dim(`\u2192 Add with ${cmd}`)}`);
|
|
5929
6156
|
suggestions++;
|
|
5930
6157
|
}
|
|
5931
6158
|
}
|
|
5932
6159
|
}
|
|
5933
6160
|
lines.push("");
|
|
5934
|
-
lines.push(` ${status.mcpConnected ?
|
|
6161
|
+
lines.push(` ${status.mcpConnected ? pc6.green("\u2713") : pc6.red("\u2717")} ${"MCP".padEnd(12)} ${status.mcpConnected ? pc6.green(`${status.mcpToolCount} tools`) : pc6.red("not connected")}`);
|
|
5935
6162
|
if (!status.mcpConnected) {
|
|
5936
|
-
lines.push(` ${
|
|
6163
|
+
lines.push(` ${pc6.dim("\u2192 Fix: ensure npx is available and network is connected")}`);
|
|
5937
6164
|
fixes++;
|
|
5938
6165
|
} else {
|
|
5939
6166
|
healthy++;
|
|
5940
6167
|
}
|
|
5941
|
-
lines.push(` ${status.amemConnected ?
|
|
6168
|
+
lines.push(` ${status.amemConnected ? pc6.green("\u2713") : pc6.red("\u2717")} ${"Memory".padEnd(12)} ${status.amemConnected ? pc6.green("connected") : pc6.red("not connected")}`);
|
|
5942
6169
|
if (!status.amemConnected) {
|
|
5943
|
-
lines.push(` ${
|
|
6170
|
+
lines.push(` ${pc6.dim("\u2192 Fix: restart aman-agent (memory initializes automatically)")}`);
|
|
5944
6171
|
fixes++;
|
|
5945
6172
|
} else {
|
|
5946
6173
|
healthy++;
|
|
@@ -5954,36 +6181,36 @@ function handleHelp() {
|
|
|
5954
6181
|
return {
|
|
5955
6182
|
handled: true,
|
|
5956
6183
|
output: [
|
|
5957
|
-
|
|
5958
|
-
` ${
|
|
5959
|
-
` ${
|
|
5960
|
-
` ${
|
|
5961
|
-
` ${
|
|
5962
|
-
` ${
|
|
5963
|
-
` ${
|
|
5964
|
-
` ${
|
|
5965
|
-
` ${
|
|
5966
|
-
` ${
|
|
5967
|
-
` ${
|
|
5968
|
-
` ${
|
|
5969
|
-
` ${
|
|
5970
|
-
` ${
|
|
5971
|
-
` ${
|
|
5972
|
-
` ${
|
|
5973
|
-
` ${
|
|
5974
|
-
` ${
|
|
5975
|
-
` ${
|
|
5976
|
-
` ${
|
|
5977
|
-
` ${
|
|
5978
|
-
` ${
|
|
5979
|
-
` ${
|
|
5980
|
-
` ${
|
|
5981
|
-
` ${
|
|
5982
|
-
` ${
|
|
5983
|
-
` ${
|
|
5984
|
-
` ${
|
|
5985
|
-
` ${
|
|
5986
|
-
` ${
|
|
6184
|
+
pc6.bold("Commands:"),
|
|
6185
|
+
` ${pc6.cyan("/help")} Show this help`,
|
|
6186
|
+
` ${pc6.cyan("/identity")} View identity [update <section>]`,
|
|
6187
|
+
` ${pc6.cyan("/rules")} View rules [add|remove|toggle ...]`,
|
|
6188
|
+
` ${pc6.cyan("/workflows")} View workflows [add|remove ...]`,
|
|
6189
|
+
` ${pc6.cyan("/akit")} Manage tools [add|remove <tool>]`,
|
|
6190
|
+
` ${pc6.cyan("/skills")} View skills [install|uninstall|crystallize|list --auto]`,
|
|
6191
|
+
` ${pc6.cyan("/eval")} View evaluation [milestone ...]`,
|
|
6192
|
+
` ${pc6.cyan("/memory")} View recent memories [search|fts|since|stats|export|clear|timeline]`,
|
|
6193
|
+
` ${pc6.cyan("/reminder")} Manage reminders [set|check|done]`,
|
|
6194
|
+
` ${pc6.cyan("/status")} Ecosystem dashboard`,
|
|
6195
|
+
` ${pc6.cyan("/doctor")} Health check all layers`,
|
|
6196
|
+
` ${pc6.cyan("/decisions")} View decision log [<project>]`,
|
|
6197
|
+
` ${pc6.cyan("/export")} Export conversation to markdown`,
|
|
6198
|
+
` ${pc6.cyan("/debug")} Show debug log`,
|
|
6199
|
+
` ${pc6.cyan("/save")} Save conversation to memory`,
|
|
6200
|
+
` ${pc6.cyan("/model")} Show current LLM model`,
|
|
6201
|
+
` ${pc6.cyan("/plan")} Manage multi-step plans`,
|
|
6202
|
+
` ${pc6.cyan("/profile me")} View your profile`,
|
|
6203
|
+
` ${pc6.cyan("/profile edit")} Edit your profile`,
|
|
6204
|
+
` ${pc6.cyan("/profile")} List agent profiles`,
|
|
6205
|
+
` ${pc6.cyan("/showcase")} Browse & switch companion templates`,
|
|
6206
|
+
` ${pc6.cyan("/delegate")} Delegate tasks to sub-agents`,
|
|
6207
|
+
` ${pc6.cyan("/team")} Manage agent teams`,
|
|
6208
|
+
` ${pc6.cyan("/observe")} Session observation dashboard [pause|resume]`,
|
|
6209
|
+
` ${pc6.cyan("/postmortem")} Generate post-mortem [last|list|--since 7d]`,
|
|
6210
|
+
` ${pc6.cyan("/update")} Check for updates`,
|
|
6211
|
+
` ${pc6.cyan("/reset")} Full reset [all|memory|config|identity|rules]`,
|
|
6212
|
+
` ${pc6.cyan("/clear")} Clear conversation history`,
|
|
6213
|
+
` ${pc6.cyan("/quit")} Exit`
|
|
5987
6214
|
].join("\n")
|
|
5988
6215
|
};
|
|
5989
6216
|
}
|
|
@@ -5992,52 +6219,52 @@ function handleSave() {
|
|
|
5992
6219
|
}
|
|
5993
6220
|
function handleReset(action) {
|
|
5994
6221
|
const dirs = {
|
|
5995
|
-
config:
|
|
5996
|
-
memory:
|
|
5997
|
-
identity:
|
|
5998
|
-
rules:
|
|
6222
|
+
config: path18.join(os17.homedir(), ".aman-agent"),
|
|
6223
|
+
memory: path18.join(os17.homedir(), ".amem"),
|
|
6224
|
+
identity: path18.join(os17.homedir(), ".acore"),
|
|
6225
|
+
rules: path18.join(os17.homedir(), ".arules")
|
|
5999
6226
|
};
|
|
6000
6227
|
if (action === "help" || !action) {
|
|
6001
6228
|
return {
|
|
6002
6229
|
handled: true,
|
|
6003
6230
|
output: [
|
|
6004
|
-
|
|
6005
|
-
` ${
|
|
6006
|
-
` ${
|
|
6007
|
-
` ${
|
|
6008
|
-
` ${
|
|
6009
|
-
` ${
|
|
6231
|
+
pc6.bold("Reset options:"),
|
|
6232
|
+
` ${pc6.cyan("/reset all")} Full reset \u2014 config, memory, identity, rules`,
|
|
6233
|
+
` ${pc6.cyan("/reset memory")} Clear all memories only`,
|
|
6234
|
+
` ${pc6.cyan("/reset config")} Reset LLM config only`,
|
|
6235
|
+
` ${pc6.cyan("/reset identity")} Reset persona/identity only`,
|
|
6236
|
+
` ${pc6.cyan("/reset rules")} Reset guardrails only`,
|
|
6010
6237
|
"",
|
|
6011
|
-
|
|
6012
|
-
...Object.entries(dirs).map(([k, v]) => ` ${k}: ${
|
|
6238
|
+
pc6.dim("Directories:"),
|
|
6239
|
+
...Object.entries(dirs).map(([k, v]) => ` ${k}: ${pc6.dim(v)}`)
|
|
6013
6240
|
].join("\n")
|
|
6014
6241
|
};
|
|
6015
6242
|
}
|
|
6016
6243
|
const targets = action === "all" ? ["config", "memory", "identity", "rules"] : [action];
|
|
6017
6244
|
if (!targets.every((t) => t in dirs)) {
|
|
6018
|
-
return { handled: true, output:
|
|
6245
|
+
return { handled: true, output: pc6.red(`Unknown target: ${action}. Use /reset help`) };
|
|
6019
6246
|
}
|
|
6020
6247
|
const removed = [];
|
|
6021
6248
|
for (const target of targets) {
|
|
6022
6249
|
const dir = dirs[target];
|
|
6023
|
-
if (
|
|
6024
|
-
|
|
6250
|
+
if (fs18.existsSync(dir)) {
|
|
6251
|
+
fs18.rmSync(dir, { recursive: true, force: true });
|
|
6025
6252
|
removed.push(target);
|
|
6026
6253
|
}
|
|
6027
6254
|
}
|
|
6028
6255
|
if (targets.includes("config")) {
|
|
6029
6256
|
const configDir = dirs.config;
|
|
6030
|
-
|
|
6031
|
-
|
|
6257
|
+
fs18.mkdirSync(configDir, { recursive: true });
|
|
6258
|
+
fs18.writeFileSync(path18.join(configDir, ".reconfig"), "", "utf-8");
|
|
6032
6259
|
}
|
|
6033
6260
|
if (removed.length === 0) {
|
|
6034
|
-
return { handled: true, output:
|
|
6261
|
+
return { handled: true, output: pc6.dim("Nothing to reset \u2014 directories don't exist.") };
|
|
6035
6262
|
}
|
|
6036
6263
|
return {
|
|
6037
6264
|
handled: true,
|
|
6038
6265
|
quit: true,
|
|
6039
6266
|
output: [
|
|
6040
|
-
|
|
6267
|
+
pc6.green(`Reset complete: ${removed.join(", ")}`),
|
|
6041
6268
|
"Restart aman-agent to begin fresh."
|
|
6042
6269
|
].join("\n")
|
|
6043
6270
|
};
|
|
@@ -6045,20 +6272,20 @@ function handleReset(action) {
|
|
|
6045
6272
|
function handleUpdate() {
|
|
6046
6273
|
try {
|
|
6047
6274
|
const current = execFileSync3("npm", ["view", "@aman_asmuei/aman-agent", "version"], { encoding: "utf-8" }).trim();
|
|
6048
|
-
const local = true ? "0.
|
|
6275
|
+
const local = true ? "0.30.0" : "unknown";
|
|
6049
6276
|
if (current === local) {
|
|
6050
|
-
return { handled: true, output: `${
|
|
6277
|
+
return { handled: true, output: `${pc6.green("Up to date")} \u2014 v${local}` };
|
|
6051
6278
|
}
|
|
6052
6279
|
return {
|
|
6053
6280
|
handled: true,
|
|
6054
6281
|
output: [
|
|
6055
|
-
`${
|
|
6282
|
+
`${pc6.yellow("Update available:")} v${local} \u2192 v${current}`,
|
|
6056
6283
|
"",
|
|
6057
6284
|
`Run this in your terminal:`,
|
|
6058
|
-
` ${
|
|
6285
|
+
` ${pc6.bold("npm install -g @aman_asmuei/aman-agent@latest")}`,
|
|
6059
6286
|
"",
|
|
6060
6287
|
`Or use npx (always latest):`,
|
|
6061
|
-
` ${
|
|
6288
|
+
` ${pc6.bold("npx @aman_asmuei/aman-agent@latest")}`
|
|
6062
6289
|
].join("\n")
|
|
6063
6290
|
};
|
|
6064
6291
|
} catch {
|
|
@@ -6066,10 +6293,10 @@ function handleUpdate() {
|
|
|
6066
6293
|
handled: true,
|
|
6067
6294
|
output: [
|
|
6068
6295
|
`To update, run in your terminal:`,
|
|
6069
|
-
` ${
|
|
6296
|
+
` ${pc6.bold("npm install -g @aman_asmuei/aman-agent@latest")}`,
|
|
6070
6297
|
"",
|
|
6071
6298
|
`Or use npx (always latest):`,
|
|
6072
|
-
` ${
|
|
6299
|
+
` ${pc6.bold("npx @aman_asmuei/aman-agent@latest")}`
|
|
6073
6300
|
].join("\n")
|
|
6074
6301
|
};
|
|
6075
6302
|
}
|
|
@@ -6078,25 +6305,25 @@ async function handleDecisionsCommand(action, _args, _ctx) {
|
|
|
6078
6305
|
try {
|
|
6079
6306
|
const result = await memoryRecall("decision", { type: "decision", limit: 20 });
|
|
6080
6307
|
if (result.total === 0) {
|
|
6081
|
-
return { handled: true, output:
|
|
6308
|
+
return { handled: true, output: pc6.dim("No decisions recorded yet.") };
|
|
6082
6309
|
}
|
|
6083
|
-
return { handled: true, output:
|
|
6310
|
+
return { handled: true, output: pc6.bold("Decision Log:\n") + result.text };
|
|
6084
6311
|
} catch (err) {
|
|
6085
|
-
return { handled: true, output:
|
|
6312
|
+
return { handled: true, output: pc6.red(`Memory error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
6086
6313
|
}
|
|
6087
6314
|
}
|
|
6088
6315
|
function handleExportCommand() {
|
|
6089
6316
|
return { handled: true, exportConversation: true };
|
|
6090
6317
|
}
|
|
6091
6318
|
function handleDebugCommand() {
|
|
6092
|
-
const logPath =
|
|
6093
|
-
if (!
|
|
6094
|
-
return { handled: true, output:
|
|
6319
|
+
const logPath = path18.join(os17.homedir(), ".aman-agent", "debug.log");
|
|
6320
|
+
if (!fs18.existsSync(logPath)) {
|
|
6321
|
+
return { handled: true, output: pc6.dim("No debug log found.") };
|
|
6095
6322
|
}
|
|
6096
|
-
const content =
|
|
6323
|
+
const content = fs18.readFileSync(logPath, "utf-8");
|
|
6097
6324
|
const lines = content.trim().split("\n");
|
|
6098
6325
|
const last20 = lines.slice(-20).join("\n");
|
|
6099
|
-
return { handled: true, output:
|
|
6326
|
+
return { handled: true, output: pc6.bold("Debug Log (last 20 entries):\n") + pc6.dim(last20) };
|
|
6100
6327
|
}
|
|
6101
6328
|
async function handleTeamCommand(action, args, ctx) {
|
|
6102
6329
|
if (!action || action === "list") {
|
|
@@ -6104,12 +6331,12 @@ async function handleTeamCommand(action, args, ctx) {
|
|
|
6104
6331
|
if (teams.length === 0) {
|
|
6105
6332
|
return {
|
|
6106
6333
|
handled: true,
|
|
6107
|
-
output:
|
|
6334
|
+
output: pc6.dim("No teams yet. Create one:") + "\n /team create <name> Create from built-in template\n /team create Show available templates"
|
|
6108
6335
|
};
|
|
6109
6336
|
}
|
|
6110
6337
|
const lines = teams.map((t) => {
|
|
6111
6338
|
const members = t.members.map((m) => m.profile).join(", ");
|
|
6112
|
-
return ` ${
|
|
6339
|
+
return ` ${pc6.bold(t.name)} (${t.workflow}) \u2014 ${members}`;
|
|
6113
6340
|
});
|
|
6114
6341
|
return { handled: true, output: "Teams:\n" + lines.join("\n") };
|
|
6115
6342
|
}
|
|
@@ -6119,8 +6346,8 @@ async function handleTeamCommand(action, args, ctx) {
|
|
|
6119
6346
|
if (!name) {
|
|
6120
6347
|
const lines = BUILT_IN_TEAMS.map((t) => {
|
|
6121
6348
|
const members2 = t.members.map((m) => m.profile).join(" \u2192 ");
|
|
6122
|
-
return ` ${
|
|
6123
|
-
${
|
|
6349
|
+
return ` ${pc6.bold(t.name)} (${t.workflow}) \u2014 ${members2}
|
|
6350
|
+
${pc6.dim(t.goal)}`;
|
|
6124
6351
|
});
|
|
6125
6352
|
return {
|
|
6126
6353
|
handled: true,
|
|
@@ -6130,15 +6357,15 @@ async function handleTeamCommand(action, args, ctx) {
|
|
|
6130
6357
|
const builtIn = BUILT_IN_TEAMS.find((t) => t.name === name);
|
|
6131
6358
|
if (builtIn) {
|
|
6132
6359
|
createTeam(builtIn);
|
|
6133
|
-
return { handled: true, output:
|
|
6360
|
+
return { handled: true, output: pc6.green(`Team installed: ${builtIn.name}`) + "\n\n" + formatTeam(builtIn) };
|
|
6134
6361
|
}
|
|
6135
6362
|
const mode = args[1];
|
|
6136
6363
|
const membersStr = args[2];
|
|
6137
6364
|
if (!mode || !membersStr) {
|
|
6138
|
-
return { handled: true, output:
|
|
6365
|
+
return { handled: true, output: pc6.yellow("Usage: /team create <name> <pipeline|parallel|coordinator> <profile1:role>,<profile2:role>") };
|
|
6139
6366
|
}
|
|
6140
6367
|
if (!["pipeline", "parallel", "coordinator"].includes(mode)) {
|
|
6141
|
-
return { handled: true, output:
|
|
6368
|
+
return { handled: true, output: pc6.yellow("Mode must be: pipeline, parallel, or coordinator") };
|
|
6142
6369
|
}
|
|
6143
6370
|
const members = membersStr.split(",").map((m) => {
|
|
6144
6371
|
const [profile, ...roleParts] = m.trim().split(":");
|
|
@@ -6152,34 +6379,34 @@ async function handleTeamCommand(action, args, ctx) {
|
|
|
6152
6379
|
workflow: mode
|
|
6153
6380
|
};
|
|
6154
6381
|
createTeam(team);
|
|
6155
|
-
return { handled: true, output:
|
|
6382
|
+
return { handled: true, output: pc6.green(`Team created!`) + "\n\n" + formatTeam(team) };
|
|
6156
6383
|
}
|
|
6157
6384
|
case "run": {
|
|
6158
6385
|
const teamName = args[0];
|
|
6159
6386
|
const task = args.slice(1).join(" ");
|
|
6160
6387
|
if (!teamName || !task) {
|
|
6161
|
-
return { handled: true, output:
|
|
6388
|
+
return { handled: true, output: pc6.yellow("Usage: /team run <team-name> <task description>") };
|
|
6162
6389
|
}
|
|
6163
6390
|
const team = loadTeam(teamName);
|
|
6164
|
-
if (!team) return { handled: true, output:
|
|
6391
|
+
if (!team) return { handled: true, output: pc6.red(`Team not found: ${teamName}`) };
|
|
6165
6392
|
if (!ctx.llmClient || !ctx.mcpManager) {
|
|
6166
|
-
return { handled: true, output:
|
|
6393
|
+
return { handled: true, output: pc6.red("Team execution requires LLM client and MCP.") };
|
|
6167
6394
|
}
|
|
6168
6395
|
const result = await runTeam(team, task, ctx.llmClient, ctx.mcpManager, ctx.tools);
|
|
6169
6396
|
return { handled: true, output: formatTeamResult(result) };
|
|
6170
6397
|
}
|
|
6171
6398
|
case "show": {
|
|
6172
6399
|
const name = args[0];
|
|
6173
|
-
if (!name) return { handled: true, output:
|
|
6400
|
+
if (!name) return { handled: true, output: pc6.yellow("Usage: /team show <name>") };
|
|
6174
6401
|
const team = loadTeam(name);
|
|
6175
|
-
if (!team) return { handled: true, output:
|
|
6402
|
+
if (!team) return { handled: true, output: pc6.red(`Team not found: ${name}`) };
|
|
6176
6403
|
return { handled: true, output: formatTeam(team) };
|
|
6177
6404
|
}
|
|
6178
6405
|
case "delete": {
|
|
6179
6406
|
const name = args[0];
|
|
6180
|
-
if (!name) return { handled: true, output:
|
|
6181
|
-
if (!deleteTeam(name)) return { handled: true, output:
|
|
6182
|
-
return { handled: true, output:
|
|
6407
|
+
if (!name) return { handled: true, output: pc6.yellow("Usage: /team delete <name>") };
|
|
6408
|
+
if (!deleteTeam(name)) return { handled: true, output: pc6.red(`Team not found: ${name}`) };
|
|
6409
|
+
return { handled: true, output: pc6.dim(`Team deleted: ${name}`) };
|
|
6183
6410
|
}
|
|
6184
6411
|
case "help":
|
|
6185
6412
|
return { handled: true, output: `Team commands:
|
|
@@ -6202,7 +6429,7 @@ Examples:
|
|
|
6202
6429
|
/team create review-squad pipeline coder:implement,researcher:review
|
|
6203
6430
|
/team run review-squad Build a rate limiter in TypeScript` };
|
|
6204
6431
|
default:
|
|
6205
|
-
return { handled: true, output:
|
|
6432
|
+
return { handled: true, output: pc6.yellow(`Unknown team action: ${action}. Try /team help`) };
|
|
6206
6433
|
}
|
|
6207
6434
|
}
|
|
6208
6435
|
async function handleDelegateCommand(action, args, ctx) {
|
|
@@ -6231,13 +6458,13 @@ The pipeline mode passes each agent's output to the next:
|
|
|
6231
6458
|
writer drafts \u2192 researcher reviews \u2192 writer polishes` };
|
|
6232
6459
|
}
|
|
6233
6460
|
if (!ctx.llmClient || !ctx.mcpManager) {
|
|
6234
|
-
return { handled: true, output:
|
|
6461
|
+
return { handled: true, output: pc6.red("Delegation requires LLM client and MCP. Not available.") };
|
|
6235
6462
|
}
|
|
6236
6463
|
if (action === "pipeline") {
|
|
6237
6464
|
const profileList = args[0];
|
|
6238
6465
|
const task2 = args.slice(1).join(" ");
|
|
6239
6466
|
if (!profileList || !task2) {
|
|
6240
|
-
return { handled: true, output:
|
|
6467
|
+
return { handled: true, output: pc6.yellow("Usage: /delegate pipeline <profile1>,<profile2> <task>") };
|
|
6241
6468
|
}
|
|
6242
6469
|
const profiles = profileList.split(",").map((p4) => p4.trim());
|
|
6243
6470
|
const steps = profiles.map((profile2, i) => {
|
|
@@ -6248,7 +6475,7 @@ The pipeline mode passes each agent's output to the next:
|
|
|
6248
6475
|
|
|
6249
6476
|
{{input}}` };
|
|
6250
6477
|
});
|
|
6251
|
-
process.stdout.write(
|
|
6478
|
+
process.stdout.write(pc6.dim(`
|
|
6252
6479
|
Pipeline: ${profiles.join(" \u2192 ")}
|
|
6253
6480
|
`));
|
|
6254
6481
|
const results = await delegatePipeline(steps, task2, ctx.llmClient, ctx.mcpManager, { tools: ctx.tools });
|
|
@@ -6256,12 +6483,12 @@ The pipeline mode passes each agent's output to the next:
|
|
|
6256
6483
|
for (const r of results) {
|
|
6257
6484
|
if (r.success) {
|
|
6258
6485
|
output.push(`
|
|
6259
|
-
${
|
|
6486
|
+
${pc6.bold(`[${r.profile}]`)} ${pc6.green("\u2713")} (${r.turns} tool turns)`);
|
|
6260
6487
|
output.push(r.response.slice(0, 2e3));
|
|
6261
|
-
if (r.toolsUsed.length > 0) output.push(
|
|
6488
|
+
if (r.toolsUsed.length > 0) output.push(pc6.dim(` Tools: ${r.toolsUsed.join(", ")}`));
|
|
6262
6489
|
} else {
|
|
6263
6490
|
output.push(`
|
|
6264
|
-
${
|
|
6491
|
+
${pc6.bold(`[${r.profile}]`)} ${pc6.red("\u2717")} ${r.error}`);
|
|
6265
6492
|
}
|
|
6266
6493
|
}
|
|
6267
6494
|
return { handled: true, output: output.join("\n") };
|
|
@@ -6269,15 +6496,15 @@ ${pc5.bold(`[${r.profile}]`)} ${pc5.red("\u2717")} ${r.error}`);
|
|
|
6269
6496
|
const profile = action;
|
|
6270
6497
|
const task = args.join(" ");
|
|
6271
6498
|
if (!task) {
|
|
6272
|
-
return { handled: true, output:
|
|
6499
|
+
return { handled: true, output: pc6.yellow(`Usage: /delegate ${profile} <task description>`) };
|
|
6273
6500
|
}
|
|
6274
|
-
process.stdout.write(
|
|
6501
|
+
process.stdout.write(pc6.dim(`
|
|
6275
6502
|
[delegating to ${profile}...]
|
|
6276
6503
|
|
|
6277
6504
|
`));
|
|
6278
6505
|
const result = await delegateTask(task, profile, ctx.llmClient, ctx.mcpManager, { tools: ctx.tools });
|
|
6279
6506
|
if (!result.success) {
|
|
6280
|
-
return { handled: true, output:
|
|
6507
|
+
return { handled: true, output: pc6.red(`Delegation failed: ${result.error}`) };
|
|
6281
6508
|
}
|
|
6282
6509
|
const meta = [];
|
|
6283
6510
|
if (result.toolsUsed.length > 0) meta.push(`Tools: ${result.toolsUsed.join(", ")}`);
|
|
@@ -6285,31 +6512,31 @@ ${pc5.bold(`[${r.profile}]`)} ${pc5.red("\u2717")} ${r.error}`);
|
|
|
6285
6512
|
return {
|
|
6286
6513
|
handled: true,
|
|
6287
6514
|
output: `
|
|
6288
|
-
${
|
|
6515
|
+
${pc6.bold(`[${profile}]`)} ${pc6.green("\u2713")}${meta.length > 0 ? " " + pc6.dim(`(${meta.join(", ")})`) : ""}
|
|
6289
6516
|
|
|
6290
6517
|
${result.response}`
|
|
6291
6518
|
};
|
|
6292
6519
|
}
|
|
6293
6520
|
function handleProfileCommand(action, args) {
|
|
6294
|
-
const profilesDir =
|
|
6521
|
+
const profilesDir = path18.join(os17.homedir(), ".acore", "profiles");
|
|
6295
6522
|
if (action === "me") {
|
|
6296
6523
|
const user = loadUserIdentity();
|
|
6297
6524
|
if (!user) {
|
|
6298
|
-
return { handled: true, output:
|
|
6525
|
+
return { handled: true, output: pc6.dim("No user profile yet. Run /profile edit to set one up.") };
|
|
6299
6526
|
}
|
|
6300
6527
|
const lines = [
|
|
6301
|
-
` ${
|
|
6302
|
-
` ${
|
|
6303
|
-
` ${
|
|
6304
|
-
` ${
|
|
6528
|
+
` ${pc6.bold("Name:")} ${user.name}`,
|
|
6529
|
+
` ${pc6.bold("Role:")} ${user.roleLabel}`,
|
|
6530
|
+
` ${pc6.bold("Expertise:")} ${user.expertiseLabel}`,
|
|
6531
|
+
` ${pc6.bold("Style:")} ${user.styleLabel}`
|
|
6305
6532
|
];
|
|
6306
|
-
if (user.workingOn) lines.push(` ${
|
|
6307
|
-
if (user.notes) lines.push(` ${
|
|
6308
|
-
lines.push(` ${
|
|
6533
|
+
if (user.workingOn) lines.push(` ${pc6.bold("Working on:")} ${user.workingOn}`);
|
|
6534
|
+
if (user.notes) lines.push(` ${pc6.bold("Notes:")} ${user.notes}`);
|
|
6535
|
+
lines.push(` ${pc6.dim(`Updated: ${user.updatedAt}`)}`);
|
|
6309
6536
|
return { handled: true, output: `Your profile:
|
|
6310
6537
|
${lines.join("\n")}
|
|
6311
6538
|
|
|
6312
|
-
${
|
|
6539
|
+
${pc6.dim("Edit with: /profile edit")}` };
|
|
6313
6540
|
}
|
|
6314
6541
|
if (action === "edit") {
|
|
6315
6542
|
const current = loadUserIdentity();
|
|
@@ -6333,25 +6560,25 @@ ${pc5.dim("Edit with: /profile edit")}` };
|
|
|
6333
6560
|
if (!action || action === "list") {
|
|
6334
6561
|
const profiles = listProfiles();
|
|
6335
6562
|
const user = loadUserIdentity();
|
|
6336
|
-
const userLine = user ? `${
|
|
6563
|
+
const userLine = user ? `${pc6.bold("You:")} ${user.name} (${user.roleLabel}, ${user.expertiseLabel})
|
|
6337
6564
|
|
|
6338
|
-
` : `${
|
|
6565
|
+
` : `${pc6.dim("No user profile. Set up with: /profile edit")}
|
|
6339
6566
|
|
|
6340
6567
|
`;
|
|
6341
6568
|
if (profiles.length === 0) {
|
|
6342
|
-
return { handled: true, output: userLine +
|
|
6569
|
+
return { handled: true, output: userLine + pc6.dim("No agent profiles yet. Create one with: /profile create <name>") };
|
|
6343
6570
|
}
|
|
6344
6571
|
const lines = profiles.map(
|
|
6345
|
-
(p4) => ` ${
|
|
6572
|
+
(p4) => ` ${pc6.bold(p4.name)} \u2014 ${p4.aiName} (${pc6.dim(p4.personality)})`
|
|
6346
6573
|
);
|
|
6347
|
-
return { handled: true, output: userLine + "Agent profiles:\n" + lines.join("\n") + "\n\n" +
|
|
6574
|
+
return { handled: true, output: userLine + "Agent profiles:\n" + lines.join("\n") + "\n\n" + pc6.dim("Switch with: aman-agent --profile <name>") };
|
|
6348
6575
|
}
|
|
6349
6576
|
switch (action) {
|
|
6350
6577
|
case "create": {
|
|
6351
6578
|
const name = args[0];
|
|
6352
6579
|
if (!name) {
|
|
6353
6580
|
const lines = BUILT_IN_PROFILES.map(
|
|
6354
|
-
(t) => ` ${
|
|
6581
|
+
(t) => ` ${pc6.bold(t.name)} \u2014 ${t.label}: ${pc6.dim(t.description)}`
|
|
6355
6582
|
);
|
|
6356
6583
|
return {
|
|
6357
6584
|
handled: true,
|
|
@@ -6359,33 +6586,33 @@ ${pc5.dim("Edit with: /profile edit")}` };
|
|
|
6359
6586
|
};
|
|
6360
6587
|
}
|
|
6361
6588
|
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
6362
|
-
const profileDir =
|
|
6363
|
-
if (
|
|
6364
|
-
return { handled: true, output:
|
|
6589
|
+
const profileDir = path18.join(profilesDir, slug);
|
|
6590
|
+
if (fs18.existsSync(profileDir)) {
|
|
6591
|
+
return { handled: true, output: pc6.yellow(`Profile already exists: ${slug}`) };
|
|
6365
6592
|
}
|
|
6366
6593
|
const builtIn = BUILT_IN_PROFILES.find((t) => t.name === slug);
|
|
6367
6594
|
if (builtIn) {
|
|
6368
6595
|
const err = installProfileTemplate(slug);
|
|
6369
|
-
if (err) return { handled: true, output:
|
|
6596
|
+
if (err) return { handled: true, output: pc6.red(err) };
|
|
6370
6597
|
return {
|
|
6371
6598
|
handled: true,
|
|
6372
|
-
output:
|
|
6599
|
+
output: pc6.green(`Profile installed: ${builtIn.label}`) + `
|
|
6373
6600
|
AI name: ${builtIn.core.match(/^# (.+)/m)?.[1] || slug}
|
|
6374
|
-
${
|
|
6601
|
+
${pc6.dim(builtIn.description)}
|
|
6375
6602
|
|
|
6376
6603
|
Use: aman-agent --profile ${slug}`
|
|
6377
6604
|
};
|
|
6378
6605
|
}
|
|
6379
|
-
|
|
6380
|
-
const globalCore =
|
|
6381
|
-
if (
|
|
6382
|
-
let content =
|
|
6606
|
+
fs18.mkdirSync(profileDir, { recursive: true });
|
|
6607
|
+
const globalCore = path18.join(os17.homedir(), ".acore", "core.md");
|
|
6608
|
+
if (fs18.existsSync(globalCore)) {
|
|
6609
|
+
let content = fs18.readFileSync(globalCore, "utf-8");
|
|
6383
6610
|
const aiName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
6384
6611
|
content = content.replace(/^# .+$/m, `# ${aiName}`);
|
|
6385
|
-
|
|
6612
|
+
fs18.writeFileSync(path18.join(profileDir, "core.md"), content, "utf-8");
|
|
6386
6613
|
} else {
|
|
6387
6614
|
const aiName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
6388
|
-
|
|
6615
|
+
fs18.writeFileSync(path18.join(profileDir, "core.md"), `# ${aiName}
|
|
6389
6616
|
|
|
6390
6617
|
## Identity
|
|
6391
6618
|
- Role: ${aiName} is your AI companion
|
|
@@ -6397,58 +6624,58 @@ ${pc5.dim("Edit with: /profile edit")}` };
|
|
|
6397
6624
|
}
|
|
6398
6625
|
return {
|
|
6399
6626
|
handled: true,
|
|
6400
|
-
output:
|
|
6401
|
-
Edit: ${
|
|
6627
|
+
output: pc6.green(`Profile created: ${slug}`) + `
|
|
6628
|
+
Edit: ${path18.join(profileDir, "core.md")}
|
|
6402
6629
|
Use: aman-agent --profile ${slug}
|
|
6403
6630
|
|
|
6404
|
-
${
|
|
6631
|
+
${pc6.dim("Add rules.md or skills.md for profile-specific overrides.")}`
|
|
6405
6632
|
};
|
|
6406
6633
|
}
|
|
6407
6634
|
case "show": {
|
|
6408
6635
|
const name = args[0];
|
|
6409
|
-
if (!name) return { handled: true, output:
|
|
6410
|
-
const profileDir =
|
|
6411
|
-
if (!
|
|
6412
|
-
const files =
|
|
6636
|
+
if (!name) return { handled: true, output: pc6.yellow("Usage: /profile show <name>") };
|
|
6637
|
+
const profileDir = path18.join(profilesDir, name);
|
|
6638
|
+
if (!fs18.existsSync(profileDir)) return { handled: true, output: pc6.red(`Profile not found: ${name}`) };
|
|
6639
|
+
const files = fs18.readdirSync(profileDir).filter((f) => f.endsWith(".md"));
|
|
6413
6640
|
const lines = files.map((f) => ` ${f}`);
|
|
6414
|
-
return { handled: true, output: `Profile: ${
|
|
6641
|
+
return { handled: true, output: `Profile: ${pc6.bold(name)}
|
|
6415
6642
|
Files:
|
|
6416
6643
|
${lines.join("\n")}` };
|
|
6417
6644
|
}
|
|
6418
6645
|
case "delete": {
|
|
6419
6646
|
const name = args[0];
|
|
6420
|
-
if (!name) return { handled: true, output:
|
|
6421
|
-
const profileDir =
|
|
6422
|
-
if (!
|
|
6423
|
-
|
|
6424
|
-
return { handled: true, output:
|
|
6647
|
+
if (!name) return { handled: true, output: pc6.yellow("Usage: /profile delete <name>") };
|
|
6648
|
+
const profileDir = path18.join(profilesDir, name);
|
|
6649
|
+
if (!fs18.existsSync(profileDir)) return { handled: true, output: pc6.red(`Profile not found: ${name}`) };
|
|
6650
|
+
fs18.rmSync(profileDir, { recursive: true });
|
|
6651
|
+
return { handled: true, output: pc6.dim(`Profile deleted: ${name}`) };
|
|
6425
6652
|
}
|
|
6426
6653
|
case "help":
|
|
6427
6654
|
return { handled: true, output: `Profile commands:
|
|
6428
6655
|
|
|
6429
|
-
${
|
|
6656
|
+
${pc6.bold("Your profile:")}
|
|
6430
6657
|
/profile me View your profile
|
|
6431
6658
|
/profile edit Edit your profile
|
|
6432
6659
|
/profile setup Re-run full profile setup
|
|
6433
6660
|
|
|
6434
|
-
${
|
|
6661
|
+
${pc6.bold("Agent profiles:")}
|
|
6435
6662
|
/profile List all profiles
|
|
6436
6663
|
/profile create <n> Create new agent profile
|
|
6437
6664
|
/profile show <n> Show agent profile files
|
|
6438
6665
|
/profile delete <n> Delete an agent profile
|
|
6439
6666
|
|
|
6440
|
-
${
|
|
6667
|
+
${pc6.bold("Use agent profiles:")}
|
|
6441
6668
|
aman-agent --profile <name>
|
|
6442
6669
|
AMAN_PROFILE=<name> aman-agent` };
|
|
6443
6670
|
default:
|
|
6444
|
-
return { handled: true, output:
|
|
6671
|
+
return { handled: true, output: pc6.yellow(`Unknown profile action: ${action}. Try /profile help`) };
|
|
6445
6672
|
}
|
|
6446
6673
|
}
|
|
6447
6674
|
function handlePlanCommand(action, args, ctx) {
|
|
6448
6675
|
if (!action) {
|
|
6449
6676
|
const active = getActivePlan();
|
|
6450
6677
|
if (!active) {
|
|
6451
|
-
return { handled: true, output:
|
|
6678
|
+
return { handled: true, output: pc6.dim("No active plan. Create one with: /plan create <name> | <goal> | <step1>, <step2>, ...") };
|
|
6452
6679
|
}
|
|
6453
6680
|
return { handled: true, output: formatPlan(active) };
|
|
6454
6681
|
}
|
|
@@ -6457,22 +6684,22 @@ function handlePlanCommand(action, args, ctx) {
|
|
|
6457
6684
|
const fullArgs = args.join(" ");
|
|
6458
6685
|
const parts = fullArgs.split("|").map((p4) => p4.trim());
|
|
6459
6686
|
if (parts.length < 3) {
|
|
6460
|
-
return { handled: true, output:
|
|
6687
|
+
return { handled: true, output: pc6.yellow("Usage: /plan create <name> | <goal> | <step1>, <step2>, ...") };
|
|
6461
6688
|
}
|
|
6462
6689
|
const name = parts[0];
|
|
6463
6690
|
const goal = parts[1];
|
|
6464
6691
|
const steps = parts[2].split(",").map((s) => s.trim()).filter(Boolean);
|
|
6465
6692
|
if (steps.length === 0) {
|
|
6466
|
-
return { handled: true, output:
|
|
6693
|
+
return { handled: true, output: pc6.yellow("Need at least one step. Separate steps with commas.") };
|
|
6467
6694
|
}
|
|
6468
6695
|
const plan = createPlan(name, goal, steps);
|
|
6469
|
-
return { handled: true, output:
|
|
6696
|
+
return { handled: true, output: pc6.green(`Plan created!
|
|
6470
6697
|
|
|
6471
6698
|
`) + formatPlan(plan) };
|
|
6472
6699
|
}
|
|
6473
6700
|
case "done": {
|
|
6474
6701
|
const active = getActivePlan();
|
|
6475
|
-
if (!active) return { handled: true, output:
|
|
6702
|
+
if (!active) return { handled: true, output: pc6.yellow("No active plan.") };
|
|
6476
6703
|
const recordPlanMilestone = (stepIndex) => {
|
|
6477
6704
|
if (ctx?.observationSession) {
|
|
6478
6705
|
const step = active.steps[stepIndex];
|
|
@@ -6486,51 +6713,51 @@ function handlePlanCommand(action, args, ctx) {
|
|
|
6486
6713
|
if (args.length > 0) {
|
|
6487
6714
|
const stepNum = parseInt(args[0], 10);
|
|
6488
6715
|
if (isNaN(stepNum) || stepNum < 1 || stepNum > active.steps.length) {
|
|
6489
|
-
return { handled: true, output:
|
|
6716
|
+
return { handled: true, output: pc6.yellow(`Invalid step number. Range: 1-${active.steps.length}`) };
|
|
6490
6717
|
}
|
|
6491
6718
|
markStepDone(active, stepNum - 1);
|
|
6492
6719
|
recordPlanMilestone(stepNum - 1);
|
|
6493
|
-
return { handled: true, output:
|
|
6720
|
+
return { handled: true, output: pc6.green(`Step ${stepNum} done!`) + "\n\n" + formatPlan(active) };
|
|
6494
6721
|
}
|
|
6495
6722
|
const next = active.steps.findIndex((s) => !s.done);
|
|
6496
|
-
if (next < 0) return { handled: true, output:
|
|
6723
|
+
if (next < 0) return { handled: true, output: pc6.green("All steps already complete!") };
|
|
6497
6724
|
markStepDone(active, next);
|
|
6498
6725
|
recordPlanMilestone(next);
|
|
6499
|
-
return { handled: true, output:
|
|
6726
|
+
return { handled: true, output: pc6.green(`Step ${next + 1} done!`) + "\n\n" + formatPlan(active) };
|
|
6500
6727
|
}
|
|
6501
6728
|
case "undo": {
|
|
6502
6729
|
const active = getActivePlan();
|
|
6503
|
-
if (!active) return { handled: true, output:
|
|
6730
|
+
if (!active) return { handled: true, output: pc6.yellow("No active plan.") };
|
|
6504
6731
|
const stepNum = parseInt(args[0], 10);
|
|
6505
6732
|
if (isNaN(stepNum) || stepNum < 1 || stepNum > active.steps.length) {
|
|
6506
|
-
return { handled: true, output:
|
|
6733
|
+
return { handled: true, output: pc6.yellow(`Invalid step number. Range: 1-${active.steps.length}`) };
|
|
6507
6734
|
}
|
|
6508
6735
|
markStepUndone(active, stepNum - 1);
|
|
6509
|
-
return { handled: true, output:
|
|
6736
|
+
return { handled: true, output: pc6.dim(`Step ${stepNum} unmarked.`) + "\n\n" + formatPlan(active) };
|
|
6510
6737
|
}
|
|
6511
6738
|
case "list": {
|
|
6512
6739
|
const plans = listPlans();
|
|
6513
|
-
if (plans.length === 0) return { handled: true, output:
|
|
6740
|
+
if (plans.length === 0) return { handled: true, output: pc6.dim("No plans yet.") };
|
|
6514
6741
|
const lines = plans.map((p4) => {
|
|
6515
6742
|
const done = p4.steps.filter((s) => s.done).length;
|
|
6516
6743
|
const total = p4.steps.length;
|
|
6517
|
-
const status = p4.active ?
|
|
6744
|
+
const status = p4.active ? pc6.green("active") : pc6.dim("inactive");
|
|
6518
6745
|
return ` ${p4.name} \u2014 ${done}/${total} steps (${status})`;
|
|
6519
6746
|
});
|
|
6520
6747
|
return { handled: true, output: "Plans:\n" + lines.join("\n") };
|
|
6521
6748
|
}
|
|
6522
6749
|
case "switch": {
|
|
6523
6750
|
const name = args.join(" ");
|
|
6524
|
-
if (!name) return { handled: true, output:
|
|
6751
|
+
if (!name) return { handled: true, output: pc6.yellow("Usage: /plan switch <name>") };
|
|
6525
6752
|
const plan = setActivePlan(name);
|
|
6526
|
-
if (!plan) return { handled: true, output:
|
|
6527
|
-
return { handled: true, output:
|
|
6753
|
+
if (!plan) return { handled: true, output: pc6.red(`Plan not found: ${name}`) };
|
|
6754
|
+
return { handled: true, output: pc6.green(`Switched to: ${plan.name}`) + "\n\n" + formatPlan(plan) };
|
|
6528
6755
|
}
|
|
6529
6756
|
case "show": {
|
|
6530
6757
|
const name = args.join(" ");
|
|
6531
|
-
if (!name) return { handled: true, output:
|
|
6758
|
+
if (!name) return { handled: true, output: pc6.yellow("Usage: /plan show <name>") };
|
|
6532
6759
|
const plan = loadPlan(name);
|
|
6533
|
-
if (!plan) return { handled: true, output:
|
|
6760
|
+
if (!plan) return { handled: true, output: pc6.red(`Plan not found: ${name}`) };
|
|
6534
6761
|
return { handled: true, output: formatPlan(plan) };
|
|
6535
6762
|
}
|
|
6536
6763
|
case "help":
|
|
@@ -6543,27 +6770,27 @@ function handlePlanCommand(action, args, ctx) {
|
|
|
6543
6770
|
/plan switch <name> Switch active plan
|
|
6544
6771
|
/plan show <name> Show a specific plan` };
|
|
6545
6772
|
default:
|
|
6546
|
-
return { handled: true, output:
|
|
6773
|
+
return { handled: true, output: pc6.yellow(`Unknown plan action: ${action}. Try /plan help`) };
|
|
6547
6774
|
}
|
|
6548
6775
|
}
|
|
6549
6776
|
async function handleReminderCommand(action, args) {
|
|
6550
6777
|
if (!action || action === "list") {
|
|
6551
6778
|
try {
|
|
6552
6779
|
const reminders = reminderList();
|
|
6553
|
-
if (reminders.length === 0) return { handled: true, output:
|
|
6554
|
-
const lines = [
|
|
6780
|
+
if (reminders.length === 0) return { handled: true, output: pc6.dim("No reminders.") };
|
|
6781
|
+
const lines = [pc6.bold(`Reminders (${reminders.length}):`), ""];
|
|
6555
6782
|
for (const r of reminders) {
|
|
6556
|
-
const status = r.completed ?
|
|
6557
|
-
const due = r.dueAt ? ` ${
|
|
6558
|
-
lines.push(` ${status} ${r.content}${due} ${
|
|
6783
|
+
const status = r.completed ? pc6.green("[done]") : pc6.yellow("[todo]");
|
|
6784
|
+
const due = r.dueAt ? ` ${pc6.dim(`due: ${new Date(r.dueAt).toLocaleString()}`)}` : "";
|
|
6785
|
+
lines.push(` ${status} ${r.content}${due} ${pc6.dim(`(${r.id.slice(0, 8)})`)}`);
|
|
6559
6786
|
}
|
|
6560
6787
|
return { handled: true, output: lines.join("\n") };
|
|
6561
6788
|
} catch (err) {
|
|
6562
|
-
return { handled: true, output:
|
|
6789
|
+
return { handled: true, output: pc6.red(`Reminder error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
6563
6790
|
}
|
|
6564
6791
|
}
|
|
6565
6792
|
if (action === "set" || action === "add") {
|
|
6566
|
-
if (args.length === 0) return { handled: true, output:
|
|
6793
|
+
if (args.length === 0) return { handled: true, output: pc6.yellow("Usage: /reminder set <text> [--due <time>]\n Time formats: 1h, 2d, 1w, or ISO date (2026-04-10)") };
|
|
6567
6794
|
let dueAt;
|
|
6568
6795
|
const dueIdx = args.indexOf("--due");
|
|
6569
6796
|
let contentArgs = args;
|
|
@@ -6582,66 +6809,66 @@ async function handleReminderCommand(action, args) {
|
|
|
6582
6809
|
}
|
|
6583
6810
|
}
|
|
6584
6811
|
const content = contentArgs.join(" ");
|
|
6585
|
-
if (!content) return { handled: true, output:
|
|
6812
|
+
if (!content) return { handled: true, output: pc6.yellow("Usage: /reminder set <text> [--due <time>]") };
|
|
6586
6813
|
try {
|
|
6587
6814
|
const id = reminderSet(content, dueAt);
|
|
6588
6815
|
const dueInfo = dueAt ? ` (due: ${new Date(dueAt).toLocaleDateString()})` : "";
|
|
6589
|
-
return { handled: true, output:
|
|
6816
|
+
return { handled: true, output: pc6.green(`Reminder set: "${content}"${dueInfo} (ID: ${id.slice(0, 8)})`) };
|
|
6590
6817
|
} catch (err) {
|
|
6591
|
-
return { handled: true, output:
|
|
6818
|
+
return { handled: true, output: pc6.red(`Reminder error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
6592
6819
|
}
|
|
6593
6820
|
}
|
|
6594
6821
|
if (action === "done" || action === "complete") {
|
|
6595
|
-
if (!args[0]) return { handled: true, output:
|
|
6822
|
+
if (!args[0]) return { handled: true, output: pc6.yellow("Usage: /reminder done <id>") };
|
|
6596
6823
|
try {
|
|
6597
6824
|
const result = reminderComplete(args[0]);
|
|
6598
|
-
return { handled: true, output: result ?
|
|
6825
|
+
return { handled: true, output: result ? pc6.green("Reminder completed.") : pc6.yellow("Reminder not found.") };
|
|
6599
6826
|
} catch (err) {
|
|
6600
|
-
return { handled: true, output:
|
|
6827
|
+
return { handled: true, output: pc6.red(`Reminder error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
6601
6828
|
}
|
|
6602
6829
|
}
|
|
6603
6830
|
if (action === "check") {
|
|
6604
6831
|
try {
|
|
6605
6832
|
const reminders = reminderCheck();
|
|
6606
|
-
if (reminders.length === 0) return { handled: true, output:
|
|
6607
|
-
const lines = [
|
|
6833
|
+
if (reminders.length === 0) return { handled: true, output: pc6.dim("No pending reminders.") };
|
|
6834
|
+
const lines = [pc6.bold("Pending Reminders:"), ""];
|
|
6608
6835
|
for (const r of reminders) {
|
|
6609
|
-
const icon = r.status === "overdue" ?
|
|
6610
|
-
const due = r.dueAt ? ` ${
|
|
6611
|
-
lines.push(` ${icon} ${r.content}${due} ${
|
|
6836
|
+
const icon = r.status === "overdue" ? pc6.red("!!!") : r.status === "today" ? pc6.yellow("(!)") : pc6.dim("( )");
|
|
6837
|
+
const due = r.dueAt ? ` ${pc6.dim(`due: ${new Date(r.dueAt).toLocaleString()}`)}` : "";
|
|
6838
|
+
lines.push(` ${icon} ${r.content}${due} ${pc6.dim(`[${r.status}]`)}`);
|
|
6612
6839
|
}
|
|
6613
6840
|
return { handled: true, output: lines.join("\n") };
|
|
6614
6841
|
} catch (err) {
|
|
6615
|
-
return { handled: true, output:
|
|
6842
|
+
return { handled: true, output: pc6.red(`Reminder error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
6616
6843
|
}
|
|
6617
6844
|
}
|
|
6618
6845
|
if (action === "help") {
|
|
6619
6846
|
return { handled: true, output: [
|
|
6620
|
-
|
|
6621
|
-
` ${
|
|
6622
|
-
` ${
|
|
6623
|
-
` ${
|
|
6624
|
-
` ${
|
|
6847
|
+
pc6.bold("Reminder commands:"),
|
|
6848
|
+
` ${pc6.cyan("/reminder")} List all reminders`,
|
|
6849
|
+
` ${pc6.cyan("/reminder set")} <text> Create a reminder [--due 1h|2d|1w|date]`,
|
|
6850
|
+
` ${pc6.cyan("/reminder check")} Show overdue/upcoming`,
|
|
6851
|
+
` ${pc6.cyan("/reminder done")} <id> Mark as completed`
|
|
6625
6852
|
].join("\n") };
|
|
6626
6853
|
}
|
|
6627
|
-
return { handled: true, output:
|
|
6854
|
+
return { handled: true, output: pc6.yellow(`Unknown action: /reminder ${action}. Try /reminder --help`) };
|
|
6628
6855
|
}
|
|
6629
6856
|
function handleShowcaseCommand(action, args) {
|
|
6630
6857
|
const showcases = loadShowcaseManifest();
|
|
6631
6858
|
if (showcases.length === 0) {
|
|
6632
6859
|
return {
|
|
6633
6860
|
handled: true,
|
|
6634
|
-
output:
|
|
6861
|
+
output: pc6.dim("No showcase templates found.") + `
|
|
6635
6862
|
|
|
6636
6863
|
Install aman-showcase to get 13 pre-built companion personalities:
|
|
6637
|
-
${
|
|
6864
|
+
${pc6.bold("npm install -g @aman_asmuei/aman-showcase")}
|
|
6638
6865
|
Or place it as a sibling directory to aman-agent.`
|
|
6639
6866
|
};
|
|
6640
6867
|
}
|
|
6641
|
-
const corePath =
|
|
6868
|
+
const corePath = path18.join(os17.homedir(), ".acore", "core.md");
|
|
6642
6869
|
let currentShowcase = null;
|
|
6643
|
-
if (
|
|
6644
|
-
const content =
|
|
6870
|
+
if (fs18.existsSync(corePath)) {
|
|
6871
|
+
const content = fs18.readFileSync(corePath, "utf-8");
|
|
6645
6872
|
const nameMatch = content.match(/^# (.+)/m);
|
|
6646
6873
|
if (nameMatch) {
|
|
6647
6874
|
const coreName = nameMatch[1].trim().toLowerCase();
|
|
@@ -6651,12 +6878,12 @@ function handleShowcaseCommand(action, args) {
|
|
|
6651
6878
|
}
|
|
6652
6879
|
if (!action || action === "list") {
|
|
6653
6880
|
const lines = showcases.map((s) => {
|
|
6654
|
-
const active = s.name === currentShowcase ?
|
|
6881
|
+
const active = s.name === currentShowcase ? pc6.green(" \u2190 active") : "";
|
|
6655
6882
|
const langBadge = s.language === "ms" ? " [BM]" : s.language === "en+ms" ? " [EN/BM]" : "";
|
|
6656
|
-
return ` ${
|
|
6883
|
+
return ` ${pc6.bold(s.name.padEnd(12))} ${s.title}${langBadge}${active}`;
|
|
6657
6884
|
});
|
|
6658
6885
|
const currentLine = currentShowcase ? `
|
|
6659
|
-
Current: ${
|
|
6886
|
+
Current: ${pc6.bold(currentShowcase)}
|
|
6660
6887
|
` : `
|
|
6661
6888
|
No showcase active (using default personality)
|
|
6662
6889
|
`;
|
|
@@ -6666,49 +6893,49 @@ No showcase active (using default personality)
|
|
|
6666
6893
|
|
|
6667
6894
|
${lines.join("\n")}
|
|
6668
6895
|
${currentLine}
|
|
6669
|
-
${
|
|
6896
|
+
${pc6.dim("Switch with: /showcase install <name>")}`
|
|
6670
6897
|
};
|
|
6671
6898
|
}
|
|
6672
6899
|
if (action === "install" || action === "switch" || action === "use") {
|
|
6673
6900
|
const name = args[0];
|
|
6674
6901
|
if (!name) {
|
|
6675
|
-
return { handled: true, output:
|
|
6902
|
+
return { handled: true, output: pc6.yellow("Usage: /showcase install <name>\n\nRun /showcase list to see available templates.") };
|
|
6676
6903
|
}
|
|
6677
6904
|
const entry = showcases.find((s) => s.name === name);
|
|
6678
6905
|
if (!entry) {
|
|
6679
|
-
return { handled: true, output:
|
|
6906
|
+
return { handled: true, output: pc6.red(`Showcase not found: ${name}`) + `
|
|
6680
6907
|
|
|
6681
6908
|
Available: ${showcases.map((s) => s.name).join(", ")}` };
|
|
6682
6909
|
}
|
|
6683
6910
|
if (name === currentShowcase) {
|
|
6684
|
-
return { handled: true, output:
|
|
6911
|
+
return { handled: true, output: pc6.dim(`${entry.title} is already active.`) };
|
|
6685
6912
|
}
|
|
6686
6913
|
try {
|
|
6687
6914
|
const result = installShowcaseTemplate(name);
|
|
6688
|
-
const lines = [
|
|
6915
|
+
const lines = [pc6.green(`Installed ${pc6.bold(entry.title)}`)];
|
|
6689
6916
|
for (const f of result.installed) {
|
|
6690
|
-
lines.push(
|
|
6917
|
+
lines.push(pc6.dim(` ${f}`));
|
|
6691
6918
|
}
|
|
6692
6919
|
if (result.backed_up.length > 0) {
|
|
6693
|
-
lines.push(
|
|
6920
|
+
lines.push(pc6.dim(`
|
|
6694
6921
|
Backed up ${result.backed_up.length} existing file(s) (.bak)`));
|
|
6695
6922
|
}
|
|
6696
6923
|
lines.push("");
|
|
6697
|
-
lines.push(
|
|
6698
|
-
lines.push(
|
|
6924
|
+
lines.push(pc6.yellow("Restart aman-agent to use the new personality."));
|
|
6925
|
+
lines.push(pc6.dim("Your user profile (/profile me) is unchanged \u2014 only the AI personality switched."));
|
|
6699
6926
|
return { handled: true, output: lines.join("\n") };
|
|
6700
6927
|
} catch (err) {
|
|
6701
|
-
return { handled: true, output:
|
|
6928
|
+
return { handled: true, output: pc6.red(`Failed to install: ${err instanceof Error ? err.message : String(err)}`) };
|
|
6702
6929
|
}
|
|
6703
6930
|
}
|
|
6704
6931
|
if (action === "current") {
|
|
6705
6932
|
if (currentShowcase) {
|
|
6706
6933
|
const entry = showcases.find((s) => s.name === currentShowcase);
|
|
6707
|
-
return { handled: true, output: `Active showcase: ${
|
|
6708
|
-
${
|
|
6934
|
+
return { handled: true, output: `Active showcase: ${pc6.bold(entry?.title || currentShowcase)}
|
|
6935
|
+
${pc6.dim(entry?.description || "")}` };
|
|
6709
6936
|
}
|
|
6710
|
-
return { handled: true, output:
|
|
6711
|
-
${
|
|
6937
|
+
return { handled: true, output: pc6.dim("No showcase active \u2014 using default personality.") + `
|
|
6938
|
+
${pc6.dim("Install one with: /showcase install <name>")}` };
|
|
6712
6939
|
}
|
|
6713
6940
|
if (action === "help") {
|
|
6714
6941
|
return { handled: true, output: `Showcase commands:
|
|
@@ -6717,70 +6944,70 @@ ${pc5.dim("Install one with: /showcase install <name>")}` };
|
|
|
6717
6944
|
/showcase install <n> Install/switch to a template
|
|
6718
6945
|
/showcase current Show active template
|
|
6719
6946
|
|
|
6720
|
-
${
|
|
6721
|
-
${
|
|
6722
|
-
${
|
|
6947
|
+
${pc6.dim("Showcase templates replace your AI's personality, workflows, rules, and skills.")}
|
|
6948
|
+
${pc6.dim("Your user profile (/profile me) stays unchanged \u2014 only the AI personality switches.")}
|
|
6949
|
+
${pc6.dim("Existing files are backed up (.bak) before overwriting.")}` };
|
|
6723
6950
|
}
|
|
6724
|
-
return { handled: true, output:
|
|
6951
|
+
return { handled: true, output: pc6.yellow(`Unknown action: /showcase ${action}. Try /showcase help`) };
|
|
6725
6952
|
}
|
|
6726
6953
|
async function handleFileCommand(action, args) {
|
|
6727
6954
|
if (!action) {
|
|
6728
6955
|
return {
|
|
6729
6956
|
handled: true,
|
|
6730
6957
|
output: [
|
|
6731
|
-
|
|
6732
|
-
` ${
|
|
6733
|
-
` ${
|
|
6734
|
-
` ${
|
|
6958
|
+
pc6.bold("File commands:"),
|
|
6959
|
+
` ${pc6.cyan("/file read")} <path> Read a text file (max 50 KB)`,
|
|
6960
|
+
` ${pc6.cyan("/file convert")} <path> Attempt to read binary file as text`,
|
|
6961
|
+
` ${pc6.cyan("/file list")} <path> [--recursive] List directory contents`
|
|
6735
6962
|
].join("\n")
|
|
6736
6963
|
};
|
|
6737
6964
|
}
|
|
6738
6965
|
if (action === "read" || action === "convert") {
|
|
6739
6966
|
const filePath = args[0];
|
|
6740
6967
|
if (!filePath) {
|
|
6741
|
-
return { handled: true, output:
|
|
6968
|
+
return { handled: true, output: pc6.yellow(`Usage: /file ${action} <path>`) };
|
|
6742
6969
|
}
|
|
6743
6970
|
try {
|
|
6744
6971
|
const result = await readFile(filePath);
|
|
6745
6972
|
const lines = [
|
|
6746
|
-
|
|
6973
|
+
pc6.bold(`\u{1F4C4} ${result.path}`) + pc6.dim(` (${(result.size / 1024).toFixed(1)} KB)`),
|
|
6747
6974
|
"",
|
|
6748
6975
|
result.content
|
|
6749
6976
|
];
|
|
6750
6977
|
if (result.truncated) {
|
|
6751
|
-
lines.push("",
|
|
6978
|
+
lines.push("", pc6.yellow(`\u26A0 File truncated at 50 KB. Use a text editor for the full file.`));
|
|
6752
6979
|
}
|
|
6753
6980
|
return { handled: true, output: lines.join("\n") };
|
|
6754
6981
|
} catch (err) {
|
|
6755
|
-
return { handled: true, output:
|
|
6982
|
+
return { handled: true, output: pc6.red(`File error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
6756
6983
|
}
|
|
6757
6984
|
}
|
|
6758
6985
|
if (action === "list") {
|
|
6759
6986
|
const dirPath = args.find((a) => !a.startsWith("-"));
|
|
6760
6987
|
if (!dirPath) {
|
|
6761
|
-
return { handled: true, output:
|
|
6988
|
+
return { handled: true, output: pc6.yellow(`Usage: /file list <path> [--recursive]`) };
|
|
6762
6989
|
}
|
|
6763
6990
|
const recursive = args.includes("--recursive") || args.includes("-r");
|
|
6764
6991
|
try {
|
|
6765
6992
|
const result = await listFiles(dirPath, { recursive });
|
|
6766
6993
|
const lines = [
|
|
6767
|
-
|
|
6994
|
+
pc6.bold(`\u{1F4C1} ${result.path}`) + pc6.dim(` (${result.total} items)`),
|
|
6768
6995
|
""
|
|
6769
6996
|
];
|
|
6770
6997
|
for (const entry of result.entries) {
|
|
6771
6998
|
if (entry.type === "dir") {
|
|
6772
|
-
lines.push(` ${
|
|
6999
|
+
lines.push(` ${pc6.cyan(entry.name + "/")}`);
|
|
6773
7000
|
} else {
|
|
6774
|
-
const kb = entry.size > 0 ?
|
|
7001
|
+
const kb = entry.size > 0 ? pc6.dim(` ${(entry.size / 1024).toFixed(1)} KB`) : "";
|
|
6775
7002
|
lines.push(` ${entry.name}${kb}`);
|
|
6776
7003
|
}
|
|
6777
7004
|
}
|
|
6778
7005
|
return { handled: true, output: lines.join("\n") };
|
|
6779
7006
|
} catch (err) {
|
|
6780
|
-
return { handled: true, output:
|
|
7007
|
+
return { handled: true, output: pc6.red(`File error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
6781
7008
|
}
|
|
6782
7009
|
}
|
|
6783
|
-
return { handled: true, output:
|
|
7010
|
+
return { handled: true, output: pc6.yellow(`Unknown /file subcommand: ${action}. Try /file for help.`) };
|
|
6784
7011
|
}
|
|
6785
7012
|
var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
|
|
6786
7013
|
"quit",
|
|
@@ -6820,16 +7047,16 @@ async function handleObserveCommand(action, ctx) {
|
|
|
6820
7047
|
if (!ctx.observationSession) {
|
|
6821
7048
|
return {
|
|
6822
7049
|
handled: true,
|
|
6823
|
-
output:
|
|
7050
|
+
output: pc6.dim("Observation is disabled. Enable with recordObservations: true in config.")
|
|
6824
7051
|
};
|
|
6825
7052
|
}
|
|
6826
7053
|
switch (action) {
|
|
6827
7054
|
case "pause":
|
|
6828
7055
|
pauseObservation(ctx.observationSession);
|
|
6829
|
-
return { handled: true, output:
|
|
7056
|
+
return { handled: true, output: pc6.dim("Observation paused. Use /observe resume to continue.") };
|
|
6830
7057
|
case "resume":
|
|
6831
7058
|
resumeObservation(ctx.observationSession);
|
|
6832
|
-
return { handled: true, output:
|
|
7059
|
+
return { handled: true, output: pc6.dim("Observation resumed.") };
|
|
6833
7060
|
default:
|
|
6834
7061
|
return { handled: true, output: getSessionStats(ctx.observationSession) };
|
|
6835
7062
|
}
|
|
@@ -6838,13 +7065,13 @@ async function handlePostmortemCommand(action, args, ctx) {
|
|
|
6838
7065
|
switch (action) {
|
|
6839
7066
|
case "last": {
|
|
6840
7067
|
const files = await listPostmortems();
|
|
6841
|
-
if (files.length === 0) return { handled: true, output:
|
|
7068
|
+
if (files.length === 0) return { handled: true, output: pc6.dim("No post-mortems found.") };
|
|
6842
7069
|
const content = await readPostmortem(files[0]);
|
|
6843
|
-
return { handled: true, output: content ??
|
|
7070
|
+
return { handled: true, output: content ?? pc6.red("Could not read post-mortem.") };
|
|
6844
7071
|
}
|
|
6845
7072
|
case "list": {
|
|
6846
7073
|
const files = await listPostmortems();
|
|
6847
|
-
if (files.length === 0) return { handled: true, output:
|
|
7074
|
+
if (files.length === 0) return { handled: true, output: pc6.dim("No post-mortems found.") };
|
|
6848
7075
|
return { handled: true, output: "Post-mortems:\n" + files.map((f) => ` ${f}`).join("\n") };
|
|
6849
7076
|
}
|
|
6850
7077
|
default: {
|
|
@@ -6854,15 +7081,15 @@ async function handlePostmortemCommand(action, args, ctx) {
|
|
|
6854
7081
|
const daysStr = allArgs[sinceIdx + 1];
|
|
6855
7082
|
const days = parseInt(daysStr.replace("d", ""), 10) || 7;
|
|
6856
7083
|
if (!ctx.llmClient) {
|
|
6857
|
-
return { handled: true, output:
|
|
7084
|
+
return { handled: true, output: pc6.red("LLM client not available for analysis.") };
|
|
6858
7085
|
}
|
|
6859
7086
|
const analysis = await analyzePostmortemRange(days, ctx.llmClient);
|
|
6860
|
-
return { handled: true, output: analysis ??
|
|
7087
|
+
return { handled: true, output: analysis ?? pc6.red("Could not analyze post-mortems.") };
|
|
6861
7088
|
}
|
|
6862
7089
|
if (!ctx.observationSession || !ctx.llmClient || !ctx.messages) {
|
|
6863
7090
|
return {
|
|
6864
7091
|
handled: true,
|
|
6865
|
-
output:
|
|
7092
|
+
output: pc6.dim("Cannot generate post-mortem: missing session context.")
|
|
6866
7093
|
};
|
|
6867
7094
|
}
|
|
6868
7095
|
const report = await generatePostmortemReport(
|
|
@@ -6871,13 +7098,13 @@ async function handlePostmortemCommand(action, args, ctx) {
|
|
|
6871
7098
|
ctx.observationSession,
|
|
6872
7099
|
ctx.llmClient
|
|
6873
7100
|
);
|
|
6874
|
-
if (!report) return { handled: true, output:
|
|
7101
|
+
if (!report) return { handled: true, output: pc6.red("Could not generate post-mortem.") };
|
|
6875
7102
|
const filePath = await savePostmortem(report);
|
|
6876
7103
|
return {
|
|
6877
7104
|
handled: true,
|
|
6878
7105
|
output: formatPostmortemMarkdown(report) + `
|
|
6879
7106
|
|
|
6880
|
-
${
|
|
7107
|
+
${pc6.dim(`Saved \u2192 ${filePath}`)}`
|
|
6881
7108
|
};
|
|
6882
7109
|
}
|
|
6883
7110
|
}
|
|
@@ -6895,9 +7122,9 @@ async function handleCommand(input, ctx) {
|
|
|
6895
7122
|
case "help":
|
|
6896
7123
|
return handleHelp();
|
|
6897
7124
|
case "clear":
|
|
6898
|
-
return { handled: true, output:
|
|
7125
|
+
return { handled: true, output: pc6.dim("Conversation cleared."), clearHistory: true };
|
|
6899
7126
|
case "model":
|
|
6900
|
-
return { handled: true, output: ctx.model ? `Model: ${
|
|
7127
|
+
return { handled: true, output: ctx.model ? `Model: ${pc6.bold(ctx.model)}` : "Model: unknown" };
|
|
6901
7128
|
case "identity":
|
|
6902
7129
|
return handleIdentityCommand(action, args, ctx);
|
|
6903
7130
|
case "rules":
|
|
@@ -7028,10 +7255,10 @@ ${summaryParts.slice(0, 20).join("\n")}
|
|
|
7028
7255
|
}
|
|
7029
7256
|
|
|
7030
7257
|
// src/skill-engine.ts
|
|
7031
|
-
import
|
|
7258
|
+
import fs19 from "fs";
|
|
7032
7259
|
import fsp from "fs/promises";
|
|
7033
|
-
import
|
|
7034
|
-
import
|
|
7260
|
+
import path19 from "path";
|
|
7261
|
+
import os18 from "os";
|
|
7035
7262
|
var SKILL_TRIGGERS = {
|
|
7036
7263
|
testing: ["test", "spec", "coverage", "tdd", "jest", "vitest", "mocha", "assert", "mock", "stub", "fixture", "e2e", "integration test", "unit test"],
|
|
7037
7264
|
"api-design": ["api", "endpoint", "rest", "graphql", "route", "controller", "middleware", "http", "request", "response", "status code", "pagination"],
|
|
@@ -7060,20 +7287,20 @@ async function loadRuntimeTriggers(skillsMdPath) {
|
|
|
7060
7287
|
return /* @__PURE__ */ new Map();
|
|
7061
7288
|
}
|
|
7062
7289
|
}
|
|
7063
|
-
var LEVEL_FILE =
|
|
7290
|
+
var LEVEL_FILE = path19.join(os18.homedir(), ".aman-agent", "skill-levels.json");
|
|
7064
7291
|
function loadSkillLevels() {
|
|
7065
7292
|
try {
|
|
7066
|
-
if (
|
|
7067
|
-
return JSON.parse(
|
|
7293
|
+
if (fs19.existsSync(LEVEL_FILE)) {
|
|
7294
|
+
return JSON.parse(fs19.readFileSync(LEVEL_FILE, "utf-8"));
|
|
7068
7295
|
}
|
|
7069
7296
|
} catch {
|
|
7070
7297
|
}
|
|
7071
7298
|
return {};
|
|
7072
7299
|
}
|
|
7073
7300
|
function saveSkillLevels(levels) {
|
|
7074
|
-
const dir =
|
|
7075
|
-
if (!
|
|
7076
|
-
|
|
7301
|
+
const dir = path19.dirname(LEVEL_FILE);
|
|
7302
|
+
if (!fs19.existsSync(dir)) fs19.mkdirSync(dir, { recursive: true });
|
|
7303
|
+
fs19.writeFileSync(LEVEL_FILE, JSON.stringify(levels, null, 2), "utf-8");
|
|
7077
7304
|
}
|
|
7078
7305
|
function computeLevel(activations) {
|
|
7079
7306
|
if (activations >= 50) return { level: 5, label: "Expert" };
|
|
@@ -7300,7 +7527,7 @@ async function autoTriggerSkills(userInput, mcpManager) {
|
|
|
7300
7527
|
const result = await mcpManager.callTool("skill_list", {});
|
|
7301
7528
|
const skills = JSON.parse(result);
|
|
7302
7529
|
const installed = skills.filter((s) => s.installed).map((s) => s.name);
|
|
7303
|
-
const skillsMdPath =
|
|
7530
|
+
const skillsMdPath = path19.join(os18.homedir(), ".askill", "skills.md");
|
|
7304
7531
|
const runtimeTriggers = await loadRuntimeTriggers(skillsMdPath);
|
|
7305
7532
|
if (installed.length === 0 && runtimeTriggers.size === 0) return "";
|
|
7306
7533
|
const matched = matchSkillsSemantic(userInput, installed, runtimeTriggers);
|
|
@@ -7575,7 +7802,7 @@ function matchKnowledge(userInput) {
|
|
|
7575
7802
|
}
|
|
7576
7803
|
|
|
7577
7804
|
// src/memory-extractor.ts
|
|
7578
|
-
import { reflect as reflect2, isReflectionDue as isReflectionDue2 } from "@aman_asmuei/amem-core";
|
|
7805
|
+
import { reflect as reflect2, isReflectionDue as isReflectionDue2, autoRelateMemory } from "@aman_asmuei/amem-core";
|
|
7579
7806
|
var VALID_TYPES = /* @__PURE__ */ new Set(["preference", "fact", "pattern", "topology", "decision", "correction"]);
|
|
7580
7807
|
var MIN_RESPONSE_LENGTH = 50;
|
|
7581
7808
|
var MIN_TURNS_BETWEEN_EMPTY = 3;
|
|
@@ -7703,6 +7930,10 @@ Assistant: ${assistantResponse.slice(0, 2e3)}`;
|
|
|
7703
7930
|
if (storeResult.action !== "private") {
|
|
7704
7931
|
stored++;
|
|
7705
7932
|
log.debug("extractor", "Stored " + candidate.type + ": " + candidate.content);
|
|
7933
|
+
try {
|
|
7934
|
+
autoRelateMemory(getDb(), storeResult.id);
|
|
7935
|
+
} catch {
|
|
7936
|
+
}
|
|
7706
7937
|
if (candidate.type === "pattern" || candidate.type === "preference") {
|
|
7707
7938
|
const skillMatch = matchPatternToSkill(candidate.content, candidate.tags);
|
|
7708
7939
|
if (skillMatch) {
|
|
@@ -7729,147 +7960,6 @@ Assistant: ${assistantResponse.slice(0, 2e3)}`;
|
|
|
7729
7960
|
}
|
|
7730
7961
|
}
|
|
7731
7962
|
|
|
7732
|
-
// src/background.ts
|
|
7733
|
-
import pc6 from "picocolors";
|
|
7734
|
-
var BACKGROUND_ELIGIBLE = /* @__PURE__ */ new Set([
|
|
7735
|
-
"run_tests",
|
|
7736
|
-
"npm_test",
|
|
7737
|
-
"build",
|
|
7738
|
-
"npm_build",
|
|
7739
|
-
"file_search",
|
|
7740
|
-
"code_search",
|
|
7741
|
-
"grep_search",
|
|
7742
|
-
"git_clone",
|
|
7743
|
-
"docker_build",
|
|
7744
|
-
"docker_run"
|
|
7745
|
-
]);
|
|
7746
|
-
var NEVER_BACKGROUND = /* @__PURE__ */ new Set([
|
|
7747
|
-
"memory_recall",
|
|
7748
|
-
"memory_store",
|
|
7749
|
-
"memory_log",
|
|
7750
|
-
"memory_context",
|
|
7751
|
-
"memory_detail",
|
|
7752
|
-
"identity_read",
|
|
7753
|
-
"identity_summary",
|
|
7754
|
-
"identity_update_session",
|
|
7755
|
-
"identity_update_dynamics",
|
|
7756
|
-
"rules_check",
|
|
7757
|
-
"rules_list",
|
|
7758
|
-
"workflow_list",
|
|
7759
|
-
"workflow_get",
|
|
7760
|
-
"skill_list",
|
|
7761
|
-
"skill_search",
|
|
7762
|
-
"eval_status",
|
|
7763
|
-
"eval_log",
|
|
7764
|
-
"reminder_check",
|
|
7765
|
-
"reminder_set",
|
|
7766
|
-
"file_read",
|
|
7767
|
-
"doc_convert",
|
|
7768
|
-
"file_list",
|
|
7769
|
-
"avatar_prompt"
|
|
7770
|
-
]);
|
|
7771
|
-
function shouldRunInBackground(toolName) {
|
|
7772
|
-
if (NEVER_BACKGROUND.has(toolName)) return false;
|
|
7773
|
-
if (BACKGROUND_ELIGIBLE.has(toolName)) return true;
|
|
7774
|
-
return false;
|
|
7775
|
-
}
|
|
7776
|
-
var BackgroundTaskManager = class {
|
|
7777
|
-
tasks = /* @__PURE__ */ new Map();
|
|
7778
|
-
taskCounter = 0;
|
|
7779
|
-
/**
|
|
7780
|
-
* Launch a tool call in the background.
|
|
7781
|
-
*/
|
|
7782
|
-
launch(toolName, toolUseId, mcpManager, toolInput) {
|
|
7783
|
-
const id = `bg-${++this.taskCounter}`;
|
|
7784
|
-
const task = {
|
|
7785
|
-
id,
|
|
7786
|
-
toolName,
|
|
7787
|
-
toolUseId,
|
|
7788
|
-
startedAt: Date.now(),
|
|
7789
|
-
done: false,
|
|
7790
|
-
promise: mcpManager.callTool(toolName, toolInput).then(
|
|
7791
|
-
(result) => {
|
|
7792
|
-
task.result = result;
|
|
7793
|
-
task.done = true;
|
|
7794
|
-
return result;
|
|
7795
|
-
},
|
|
7796
|
-
(error) => {
|
|
7797
|
-
task.error = error instanceof Error ? error.message : String(error);
|
|
7798
|
-
task.done = true;
|
|
7799
|
-
return `Error: ${task.error}`;
|
|
7800
|
-
}
|
|
7801
|
-
)
|
|
7802
|
-
};
|
|
7803
|
-
this.tasks.set(id, task);
|
|
7804
|
-
process.stdout.write(pc6.dim(` [${toolName} running in background (${id})...]
|
|
7805
|
-
`));
|
|
7806
|
-
return task;
|
|
7807
|
-
}
|
|
7808
|
-
/**
|
|
7809
|
-
* Check for completed background tasks and return their results.
|
|
7810
|
-
*/
|
|
7811
|
-
collectCompleted() {
|
|
7812
|
-
const completed = [];
|
|
7813
|
-
for (const [id, task] of this.tasks) {
|
|
7814
|
-
if (task.done) {
|
|
7815
|
-
completed.push(task);
|
|
7816
|
-
this.tasks.delete(id);
|
|
7817
|
-
}
|
|
7818
|
-
}
|
|
7819
|
-
return completed;
|
|
7820
|
-
}
|
|
7821
|
-
/**
|
|
7822
|
-
* Display completed background task results to the user.
|
|
7823
|
-
*/
|
|
7824
|
-
displayCompleted() {
|
|
7825
|
-
const completed = this.collectCompleted();
|
|
7826
|
-
const outputs = [];
|
|
7827
|
-
for (const task of completed) {
|
|
7828
|
-
const elapsed = ((Date.now() - task.startedAt) / 1e3).toFixed(1);
|
|
7829
|
-
if (task.error) {
|
|
7830
|
-
process.stdout.write(pc6.yellow(`
|
|
7831
|
-
[${task.id}] ${task.toolName} failed after ${elapsed}s: ${task.error}
|
|
7832
|
-
`));
|
|
7833
|
-
outputs.push(`[Background task ${task.toolName} failed: ${task.error}]`);
|
|
7834
|
-
} else {
|
|
7835
|
-
process.stdout.write(pc6.green(`
|
|
7836
|
-
[${task.id}] ${task.toolName} completed in ${elapsed}s
|
|
7837
|
-
`));
|
|
7838
|
-
const preview = (task.result || "").slice(0, 200);
|
|
7839
|
-
if (preview) {
|
|
7840
|
-
process.stdout.write(pc6.dim(` ${preview}${(task.result || "").length > 200 ? "..." : ""}
|
|
7841
|
-
`));
|
|
7842
|
-
}
|
|
7843
|
-
outputs.push(`[Background task ${task.toolName} completed: ${task.result}]`);
|
|
7844
|
-
}
|
|
7845
|
-
}
|
|
7846
|
-
return outputs;
|
|
7847
|
-
}
|
|
7848
|
-
/**
|
|
7849
|
-
* Wait for all pending background tasks to complete.
|
|
7850
|
-
*/
|
|
7851
|
-
async waitAll() {
|
|
7852
|
-
const pending = [...this.tasks.values()].filter((t) => !t.done);
|
|
7853
|
-
if (pending.length === 0) return;
|
|
7854
|
-
process.stdout.write(pc6.dim(`
|
|
7855
|
-
Waiting for ${pending.length} background task(s)...
|
|
7856
|
-
`));
|
|
7857
|
-
await Promise.allSettled(pending.map((t) => t.promise));
|
|
7858
|
-
}
|
|
7859
|
-
/**
|
|
7860
|
-
* Number of currently running tasks.
|
|
7861
|
-
*/
|
|
7862
|
-
get pendingCount() {
|
|
7863
|
-
return [...this.tasks.values()].filter((t) => !t.done).length;
|
|
7864
|
-
}
|
|
7865
|
-
/**
|
|
7866
|
-
* Check if any tasks have completed (non-blocking).
|
|
7867
|
-
*/
|
|
7868
|
-
get hasCompleted() {
|
|
7869
|
-
return [...this.tasks.values()].some((t) => t.done);
|
|
7870
|
-
}
|
|
7871
|
-
};
|
|
7872
|
-
|
|
7873
7963
|
// src/errors.ts
|
|
7874
7964
|
var ERROR_MAPPINGS = [
|
|
7875
7965
|
{ pattern: /rate.?limit|429/i, message: "Rate limited. I'll retry automatically." },
|
|
@@ -7891,9 +7981,9 @@ function humanizeError(message) {
|
|
|
7891
7981
|
}
|
|
7892
7982
|
|
|
7893
7983
|
// src/hints.ts
|
|
7894
|
-
import
|
|
7895
|
-
import
|
|
7896
|
-
import
|
|
7984
|
+
import fs20 from "fs";
|
|
7985
|
+
import path20 from "path";
|
|
7986
|
+
import os19 from "os";
|
|
7897
7987
|
var HINTS = [
|
|
7898
7988
|
{
|
|
7899
7989
|
id: "eval",
|
|
@@ -7931,11 +8021,11 @@ function getHint(state, ctx) {
|
|
|
7931
8021
|
}
|
|
7932
8022
|
return null;
|
|
7933
8023
|
}
|
|
7934
|
-
var HINTS_FILE =
|
|
8024
|
+
var HINTS_FILE = path20.join(os19.homedir(), ".aman-agent", "hints-seen.json");
|
|
7935
8025
|
function loadShownHints() {
|
|
7936
8026
|
try {
|
|
7937
|
-
if (
|
|
7938
|
-
const data = JSON.parse(
|
|
8027
|
+
if (fs20.existsSync(HINTS_FILE)) {
|
|
8028
|
+
const data = JSON.parse(fs20.readFileSync(HINTS_FILE, "utf-8"));
|
|
7939
8029
|
return new Set(Array.isArray(data) ? data : []);
|
|
7940
8030
|
}
|
|
7941
8031
|
} catch {
|
|
@@ -7944,9 +8034,9 @@ function loadShownHints() {
|
|
|
7944
8034
|
}
|
|
7945
8035
|
function saveShownHints(shown) {
|
|
7946
8036
|
try {
|
|
7947
|
-
const dir =
|
|
7948
|
-
|
|
7949
|
-
|
|
8037
|
+
const dir = path20.dirname(HINTS_FILE);
|
|
8038
|
+
fs20.mkdirSync(dir, { recursive: true });
|
|
8039
|
+
fs20.writeFileSync(HINTS_FILE, JSON.stringify([...shown]), "utf-8");
|
|
7950
8040
|
} catch {
|
|
7951
8041
|
}
|
|
7952
8042
|
}
|
|
@@ -8213,9 +8303,9 @@ ${task.result}`
|
|
|
8213
8303
|
}
|
|
8214
8304
|
if (cmdResult.exportConversation) {
|
|
8215
8305
|
try {
|
|
8216
|
-
const exportDir =
|
|
8217
|
-
|
|
8218
|
-
const exportPath =
|
|
8306
|
+
const exportDir = path21.join(os20.homedir(), ".aman-agent", "exports");
|
|
8307
|
+
fs21.mkdirSync(exportDir, { recursive: true });
|
|
8308
|
+
const exportPath = path21.join(exportDir, `${sessionId}.md`);
|
|
8219
8309
|
const lines = [
|
|
8220
8310
|
`# Conversation \u2014 ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
|
|
8221
8311
|
`**Model:** ${model}`,
|
|
@@ -8229,7 +8319,7 @@ ${task.result}`
|
|
|
8229
8319
|
lines.push(`${label} ${msg.content}`, "");
|
|
8230
8320
|
}
|
|
8231
8321
|
}
|
|
8232
|
-
|
|
8322
|
+
fs21.writeFileSync(exportPath, lines.join("\n"), "utf-8");
|
|
8233
8323
|
console.log(pc7.green(`Exported to ${exportPath}`));
|
|
8234
8324
|
} catch {
|
|
8235
8325
|
console.log(pc7.red("Failed to export conversation."));
|
|
@@ -8355,25 +8445,25 @@ ${knowledgeItem.content}
|
|
|
8355
8445
|
for (const match of filePathMatches) {
|
|
8356
8446
|
let filePath = match[1];
|
|
8357
8447
|
if (filePath.startsWith("~/")) {
|
|
8358
|
-
filePath =
|
|
8448
|
+
filePath = path21.join(os20.homedir(), filePath.slice(2));
|
|
8359
8449
|
}
|
|
8360
|
-
if (!
|
|
8361
|
-
const ext =
|
|
8450
|
+
if (!fs21.existsSync(filePath) || !fs21.statSync(filePath).isFile()) continue;
|
|
8451
|
+
const ext = path21.extname(filePath).toLowerCase();
|
|
8362
8452
|
if (imageExts.has(ext)) {
|
|
8363
8453
|
try {
|
|
8364
|
-
const stat =
|
|
8454
|
+
const stat = fs21.statSync(filePath);
|
|
8365
8455
|
if (stat.size > maxImageBytes) {
|
|
8366
|
-
process.stdout.write(pc7.yellow(` [skipped: ${
|
|
8456
|
+
process.stdout.write(pc7.yellow(` [skipped: ${path21.basename(filePath)} \u2014 exceeds 20MB limit]
|
|
8367
8457
|
`));
|
|
8368
8458
|
continue;
|
|
8369
8459
|
}
|
|
8370
|
-
const data =
|
|
8460
|
+
const data = fs21.readFileSync(filePath).toString("base64");
|
|
8371
8461
|
const mediaType = mimeMap[ext] || "image/png";
|
|
8372
8462
|
imageBlocks.push({
|
|
8373
8463
|
type: "image",
|
|
8374
8464
|
source: { type: "base64", media_type: mediaType, data }
|
|
8375
8465
|
});
|
|
8376
|
-
process.stdout.write(pc7.dim(` [attached image: ${
|
|
8466
|
+
process.stdout.write(pc7.dim(` [attached image: ${path21.basename(filePath)} (${(stat.size / 1024).toFixed(1)}KB)]
|
|
8377
8467
|
`));
|
|
8378
8468
|
} catch {
|
|
8379
8469
|
process.stdout.write(pc7.dim(` [could not read image: ${filePath}]
|
|
@@ -8381,7 +8471,7 @@ ${knowledgeItem.content}
|
|
|
8381
8471
|
}
|
|
8382
8472
|
} else if (textExts.has(ext) || ext === "") {
|
|
8383
8473
|
try {
|
|
8384
|
-
const content =
|
|
8474
|
+
const content = fs21.readFileSync(filePath, "utf-8");
|
|
8385
8475
|
const maxChars = 5e4;
|
|
8386
8476
|
const trimmed = content.length > maxChars ? content.slice(0, maxChars) + `
|
|
8387
8477
|
|
|
@@ -8391,7 +8481,7 @@ ${knowledgeItem.content}
|
|
|
8391
8481
|
<file path="${filePath}" size="${content.length} chars">
|
|
8392
8482
|
${trimmed}
|
|
8393
8483
|
</file>`;
|
|
8394
|
-
process.stdout.write(pc7.dim(` [attached: ${
|
|
8484
|
+
process.stdout.write(pc7.dim(` [attached: ${path21.basename(filePath)} (${(content.length / 1024).toFixed(1)}KB)]
|
|
8395
8485
|
`));
|
|
8396
8486
|
} catch {
|
|
8397
8487
|
process.stdout.write(pc7.dim(` [could not read: ${filePath}]
|
|
@@ -8400,7 +8490,7 @@ ${trimmed}
|
|
|
8400
8490
|
} else if (docExts.has(ext)) {
|
|
8401
8491
|
if (mcpManager) {
|
|
8402
8492
|
try {
|
|
8403
|
-
process.stdout.write(pc7.dim(` [converting: ${
|
|
8493
|
+
process.stdout.write(pc7.dim(` [converting: ${path21.basename(filePath)}...]
|
|
8404
8494
|
`));
|
|
8405
8495
|
const converted = await mcpManager.callTool("doc_convert", { path: filePath });
|
|
8406
8496
|
if (converted && !converted.startsWith("Error") && !converted.includes("Could not convert")) {
|
|
@@ -8409,7 +8499,7 @@ ${trimmed}
|
|
|
8409
8499
|
<file path="${filePath}" format="${ext}">
|
|
8410
8500
|
${converted.slice(0, 5e4)}
|
|
8411
8501
|
</file>`;
|
|
8412
|
-
process.stdout.write(pc7.dim(` [attached: ${
|
|
8502
|
+
process.stdout.write(pc7.dim(` [attached: ${path21.basename(filePath)} (converted from ${ext})]
|
|
8413
8503
|
`));
|
|
8414
8504
|
} else {
|
|
8415
8505
|
textContent += `
|
|
@@ -8421,7 +8511,7 @@ ${converted}
|
|
|
8421
8511
|
`));
|
|
8422
8512
|
}
|
|
8423
8513
|
} catch {
|
|
8424
|
-
process.stdout.write(pc7.dim(` [could not convert: ${
|
|
8514
|
+
process.stdout.write(pc7.dim(` [could not convert: ${path21.basename(filePath)}]
|
|
8425
8515
|
`));
|
|
8426
8516
|
}
|
|
8427
8517
|
} else {
|
|
@@ -8645,6 +8735,20 @@ ${preemptive.join("\n")}
|
|
|
8645
8735
|
}
|
|
8646
8736
|
if (toolUse.name === "delegate_task" && mcpManager) {
|
|
8647
8737
|
const input2 = toolUse.input;
|
|
8738
|
+
const confirmed = await new Promise((resolve) => {
|
|
8739
|
+
rl.question(
|
|
8740
|
+
pc7.cyan(` Delegate to ${pc7.bold(input2.profile)}? `) + pc7.dim(`"${input2.task.slice(0, 80)}${input2.task.length > 80 ? "..." : ""}" (y/N) `),
|
|
8741
|
+
(answer) => resolve(answer.toLowerCase() === "y")
|
|
8742
|
+
);
|
|
8743
|
+
});
|
|
8744
|
+
if (!confirmed) {
|
|
8745
|
+
return {
|
|
8746
|
+
type: "tool_result",
|
|
8747
|
+
tool_use_id: toolUse.id,
|
|
8748
|
+
content: "User declined delegation.",
|
|
8749
|
+
is_error: true
|
|
8750
|
+
};
|
|
8751
|
+
}
|
|
8648
8752
|
process.stdout.write(pc7.dim(`
|
|
8649
8753
|
[delegating to ${input2.profile}...]
|
|
8650
8754
|
|
|
@@ -8661,6 +8765,20 @@ ${result2.response}` : `[${input2.profile}] failed: ${result2.error}`;
|
|
|
8661
8765
|
}
|
|
8662
8766
|
if (toolUse.name === "team_run" && mcpManager) {
|
|
8663
8767
|
const input2 = toolUse.input;
|
|
8768
|
+
const confirmed = await new Promise((resolve) => {
|
|
8769
|
+
rl.question(
|
|
8770
|
+
pc7.cyan(` Run team ${pc7.bold(input2.team)}? `) + pc7.dim(`"${input2.task.slice(0, 80)}${input2.task.length > 80 ? "..." : ""}" (y/N) `),
|
|
8771
|
+
(answer) => resolve(answer.toLowerCase() === "y")
|
|
8772
|
+
);
|
|
8773
|
+
});
|
|
8774
|
+
if (!confirmed) {
|
|
8775
|
+
return {
|
|
8776
|
+
type: "tool_result",
|
|
8777
|
+
tool_use_id: toolUse.id,
|
|
8778
|
+
content: "User declined team execution.",
|
|
8779
|
+
is_error: true
|
|
8780
|
+
};
|
|
8781
|
+
}
|
|
8664
8782
|
const team = loadTeam(input2.team);
|
|
8665
8783
|
if (!team) {
|
|
8666
8784
|
return {
|
|
@@ -8785,7 +8903,7 @@ ${result2.response}` : `[${input2.profile}] failed: ${result2.error}`;
|
|
|
8785
8903
|
}
|
|
8786
8904
|
if (hooksConfig?.featureHints) {
|
|
8787
8905
|
hintState.turnCount++;
|
|
8788
|
-
const hasWorkflows =
|
|
8906
|
+
const hasWorkflows = fs21.existsSync(path21.join(os20.homedir(), ".aflow", "flow.md"));
|
|
8789
8907
|
const memoryCount = memoryTokens > 0 ? Math.floor(memoryTokens / 5) : 0;
|
|
8790
8908
|
const hint = getHint(hintState, { hasWorkflows, memoryCount });
|
|
8791
8909
|
if (hint) {
|
|
@@ -8831,9 +8949,9 @@ async function saveConversationToMemory(messages, sessionId) {
|
|
|
8831
8949
|
}
|
|
8832
8950
|
|
|
8833
8951
|
// src/index.ts
|
|
8834
|
-
import
|
|
8835
|
-
import
|
|
8836
|
-
import
|
|
8952
|
+
import fs22 from "fs";
|
|
8953
|
+
import path22 from "path";
|
|
8954
|
+
import os21 from "os";
|
|
8837
8955
|
|
|
8838
8956
|
// src/presets.ts
|
|
8839
8957
|
var PRESETS = {
|
|
@@ -8942,9 +9060,9 @@ ${wfSections}`;
|
|
|
8942
9060
|
|
|
8943
9061
|
// src/index.ts
|
|
8944
9062
|
async function autoDetectConfig() {
|
|
8945
|
-
const reconfigMarker =
|
|
8946
|
-
if (
|
|
8947
|
-
|
|
9063
|
+
const reconfigMarker = path22.join(os21.homedir(), ".aman-agent", ".reconfig");
|
|
9064
|
+
if (fs22.existsSync(reconfigMarker)) {
|
|
9065
|
+
fs22.unlinkSync(reconfigMarker);
|
|
8948
9066
|
return null;
|
|
8949
9067
|
}
|
|
8950
9068
|
const anthropicKey = process.env.ANTHROPIC_API_KEY;
|
|
@@ -8973,11 +9091,11 @@ async function autoDetectConfig() {
|
|
|
8973
9091
|
return null;
|
|
8974
9092
|
}
|
|
8975
9093
|
function bootstrapEcosystem() {
|
|
8976
|
-
const home2 =
|
|
8977
|
-
const corePath =
|
|
8978
|
-
if (
|
|
8979
|
-
|
|
8980
|
-
|
|
9094
|
+
const home2 = os21.homedir();
|
|
9095
|
+
const corePath = path22.join(home2, ".acore", "core.md");
|
|
9096
|
+
if (fs22.existsSync(corePath)) return false;
|
|
9097
|
+
fs22.mkdirSync(path22.join(home2, ".acore"), { recursive: true });
|
|
9098
|
+
fs22.writeFileSync(corePath, [
|
|
8981
9099
|
"# Aman",
|
|
8982
9100
|
"",
|
|
8983
9101
|
"## Personality",
|
|
@@ -8989,11 +9107,11 @@ function bootstrapEcosystem() {
|
|
|
8989
9107
|
"## Session",
|
|
8990
9108
|
"_New companion \u2014 no prior sessions._"
|
|
8991
9109
|
].join("\n"), "utf-8");
|
|
8992
|
-
const rulesDir =
|
|
8993
|
-
const rulesPath =
|
|
8994
|
-
if (!
|
|
8995
|
-
|
|
8996
|
-
|
|
9110
|
+
const rulesDir = path22.join(home2, ".arules");
|
|
9111
|
+
const rulesPath = path22.join(rulesDir, "rules.md");
|
|
9112
|
+
if (!fs22.existsSync(rulesPath)) {
|
|
9113
|
+
fs22.mkdirSync(rulesDir, { recursive: true });
|
|
9114
|
+
fs22.writeFileSync(rulesPath, [
|
|
8997
9115
|
"# Guardrails",
|
|
8998
9116
|
"",
|
|
8999
9117
|
"## safety",
|
|
@@ -9005,22 +9123,22 @@ function bootstrapEcosystem() {
|
|
|
9005
9123
|
"- Respect the user's preferences stored in memory"
|
|
9006
9124
|
].join("\n"), "utf-8");
|
|
9007
9125
|
}
|
|
9008
|
-
const flowDir =
|
|
9009
|
-
const flowPath =
|
|
9010
|
-
if (!
|
|
9011
|
-
|
|
9012
|
-
|
|
9126
|
+
const flowDir = path22.join(home2, ".aflow");
|
|
9127
|
+
const flowPath = path22.join(flowDir, "flow.md");
|
|
9128
|
+
if (!fs22.existsSync(flowPath)) {
|
|
9129
|
+
fs22.mkdirSync(flowDir, { recursive: true });
|
|
9130
|
+
fs22.writeFileSync(flowPath, "# Workflows\n\n_No workflows defined yet. Use /workflows add to create one._\n", "utf-8");
|
|
9013
9131
|
}
|
|
9014
|
-
const skillDir =
|
|
9015
|
-
const skillPath =
|
|
9016
|
-
if (!
|
|
9017
|
-
|
|
9018
|
-
|
|
9132
|
+
const skillDir = path22.join(home2, ".askill");
|
|
9133
|
+
const skillPath = path22.join(skillDir, "skills.md");
|
|
9134
|
+
if (!fs22.existsSync(skillPath)) {
|
|
9135
|
+
fs22.mkdirSync(skillDir, { recursive: true });
|
|
9136
|
+
fs22.writeFileSync(skillPath, "# Skills\n\n_No skills installed yet. Use /skills install to add domain expertise._\n", "utf-8");
|
|
9019
9137
|
}
|
|
9020
9138
|
return true;
|
|
9021
9139
|
}
|
|
9022
9140
|
var program = new Command();
|
|
9023
|
-
program.name("aman-agent").description("Your AI companion, running locally").version("0.
|
|
9141
|
+
program.name("aman-agent").description("Your AI companion, running locally").version("0.30.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) => {
|
|
9024
9142
|
p3.intro(pc8.bold("aman agent") + pc8.dim(" \u2014 your AI companion"));
|
|
9025
9143
|
let config = loadConfig();
|
|
9026
9144
|
if (!config) {
|
|
@@ -9372,19 +9490,19 @@ program.command("init").description("Set up your AI companion with a guided wiza
|
|
|
9372
9490
|
});
|
|
9373
9491
|
if (p3.isCancel(preset)) process.exit(0);
|
|
9374
9492
|
const result = applyPreset(preset, name || "Aman");
|
|
9375
|
-
const home2 =
|
|
9376
|
-
|
|
9377
|
-
|
|
9493
|
+
const home2 = os21.homedir();
|
|
9494
|
+
fs22.mkdirSync(path22.join(home2, ".acore"), { recursive: true });
|
|
9495
|
+
fs22.writeFileSync(path22.join(home2, ".acore", "core.md"), result.coreMd, "utf-8");
|
|
9378
9496
|
p3.log.success(`Identity created \u2014 ${PRESETS[preset].identity.personality.split(".")[0].toLowerCase()}`);
|
|
9379
9497
|
if (result.rulesMd) {
|
|
9380
|
-
|
|
9381
|
-
|
|
9498
|
+
fs22.mkdirSync(path22.join(home2, ".arules"), { recursive: true });
|
|
9499
|
+
fs22.writeFileSync(path22.join(home2, ".arules", "rules.md"), result.rulesMd, "utf-8");
|
|
9382
9500
|
const ruleCount = (result.rulesMd.match(/^- /gm) || []).length;
|
|
9383
9501
|
p3.log.success(`${ruleCount} rules set`);
|
|
9384
9502
|
}
|
|
9385
9503
|
if (result.flowMd) {
|
|
9386
|
-
|
|
9387
|
-
|
|
9504
|
+
fs22.mkdirSync(path22.join(home2, ".aflow"), { recursive: true });
|
|
9505
|
+
fs22.writeFileSync(path22.join(home2, ".aflow", "flow.md"), result.flowMd, "utf-8");
|
|
9388
9506
|
const wfCount = (result.flowMd.match(/^## /gm) || []).length;
|
|
9389
9507
|
p3.log.success(`${wfCount} workflow${wfCount > 1 ? "s" : ""} added`);
|
|
9390
9508
|
}
|