@aman_asmuei/aman-agent 0.31.0 → 0.33.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 +166 -37
- package/dist/delegate.js +61 -49
- package/dist/delegate.js.map +1 -1
- package/dist/index.js +1076 -428
- package/dist/index.js.map +1 -1
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -8,23 +8,82 @@ var __export = (target, all) => {
|
|
|
8
8
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
+
// src/token-budget.ts
|
|
12
|
+
function estimateTokens(text3) {
|
|
13
|
+
return Math.round(text3.split(/\s+/).filter(Boolean).length * 1.3);
|
|
14
|
+
}
|
|
15
|
+
function buildBudgetedPrompt(components, maxTokens = 8e3) {
|
|
16
|
+
const included = [];
|
|
17
|
+
const truncated = [];
|
|
18
|
+
const parts = [];
|
|
19
|
+
let totalTokens = 0;
|
|
20
|
+
const sorted = [...components].sort((a, b) => {
|
|
21
|
+
const aPri = PRIORITIES.indexOf(a.name);
|
|
22
|
+
const bPri = PRIORITIES.indexOf(b.name);
|
|
23
|
+
return (aPri === -1 ? 99 : aPri) - (bPri === -1 ? 99 : bPri);
|
|
24
|
+
});
|
|
25
|
+
for (const comp of sorted) {
|
|
26
|
+
if (totalTokens + comp.tokens <= maxTokens) {
|
|
27
|
+
parts.push(comp.content);
|
|
28
|
+
included.push(comp.name);
|
|
29
|
+
totalTokens += comp.tokens;
|
|
30
|
+
} else {
|
|
31
|
+
const halfContent = comp.content.slice(0, Math.floor(comp.content.length / 2));
|
|
32
|
+
const halfTokens = estimateTokens(halfContent);
|
|
33
|
+
if (totalTokens + halfTokens <= maxTokens) {
|
|
34
|
+
parts.push(halfContent + "\n\n[... truncated for context budget ...]");
|
|
35
|
+
included.push(comp.name + " (partial)");
|
|
36
|
+
totalTokens += halfTokens;
|
|
37
|
+
} else {
|
|
38
|
+
truncated.push(comp.name);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
prompt: parts.join("\n\n---\n\n"),
|
|
44
|
+
included,
|
|
45
|
+
truncated,
|
|
46
|
+
totalTokens
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
var PRIORITIES;
|
|
50
|
+
var init_token_budget = __esm({
|
|
51
|
+
"src/token-budget.ts"() {
|
|
52
|
+
"use strict";
|
|
53
|
+
PRIORITIES = [
|
|
54
|
+
"identity",
|
|
55
|
+
// core.md — always include
|
|
56
|
+
"user",
|
|
57
|
+
// user.md — user profile, always include
|
|
58
|
+
"guardrails",
|
|
59
|
+
// rules.md — safety critical
|
|
60
|
+
"workflows",
|
|
61
|
+
// flow.md — behavioral
|
|
62
|
+
"tools",
|
|
63
|
+
// kit.md — capabilities
|
|
64
|
+
"skills"
|
|
65
|
+
// skills.md — can be truncated
|
|
66
|
+
];
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
11
70
|
// src/logger.ts
|
|
12
|
-
import
|
|
13
|
-
import
|
|
71
|
+
import fs5 from "fs";
|
|
72
|
+
import path5 from "path";
|
|
14
73
|
import os4 from "os";
|
|
15
74
|
function ensureDir() {
|
|
16
|
-
if (!
|
|
17
|
-
|
|
75
|
+
if (!fs5.existsSync(LOG_DIR)) {
|
|
76
|
+
fs5.mkdirSync(LOG_DIR, { recursive: true });
|
|
18
77
|
}
|
|
19
78
|
}
|
|
20
79
|
function maybeRotate() {
|
|
21
80
|
try {
|
|
22
|
-
if (!
|
|
23
|
-
const stat =
|
|
81
|
+
if (!fs5.existsSync(LOG_PATH)) return;
|
|
82
|
+
const stat = fs5.statSync(LOG_PATH);
|
|
24
83
|
if (stat.size >= MAX_LOG_SIZE) {
|
|
25
84
|
const backupPath = LOG_PATH + ".1";
|
|
26
|
-
if (
|
|
27
|
-
|
|
85
|
+
if (fs5.existsSync(backupPath)) fs5.unlinkSync(backupPath);
|
|
86
|
+
fs5.renameSync(LOG_PATH, backupPath);
|
|
28
87
|
}
|
|
29
88
|
} catch {
|
|
30
89
|
}
|
|
@@ -42,7 +101,7 @@ function write(level, module, message, data) {
|
|
|
42
101
|
if (data !== void 0) {
|
|
43
102
|
entry.data = data instanceof Error ? data.message : String(data);
|
|
44
103
|
}
|
|
45
|
-
|
|
104
|
+
fs5.appendFileSync(LOG_PATH, JSON.stringify(entry) + "\n");
|
|
46
105
|
} catch {
|
|
47
106
|
}
|
|
48
107
|
}
|
|
@@ -50,8 +109,8 @@ var LOG_DIR, LOG_PATH, MAX_LOG_SIZE, log;
|
|
|
50
109
|
var init_logger = __esm({
|
|
51
110
|
"src/logger.ts"() {
|
|
52
111
|
"use strict";
|
|
53
|
-
LOG_DIR =
|
|
54
|
-
LOG_PATH =
|
|
112
|
+
LOG_DIR = path5.join(os4.homedir(), ".aman-agent");
|
|
113
|
+
LOG_PATH = path5.join(LOG_DIR, "debug.log");
|
|
55
114
|
MAX_LOG_SIZE = 1048576;
|
|
56
115
|
log = {
|
|
57
116
|
debug: (module, message, data) => write("debug", module, message, data),
|
|
@@ -73,11 +132,11 @@ __export(user_model_exports, {
|
|
|
73
132
|
predictBurnout: () => predictBurnout,
|
|
74
133
|
saveUserModel: () => saveUserModel
|
|
75
134
|
});
|
|
76
|
-
import
|
|
77
|
-
import
|
|
135
|
+
import fs14 from "fs/promises";
|
|
136
|
+
import path14 from "path";
|
|
78
137
|
import os12 from "os";
|
|
79
138
|
function defaultModelPath() {
|
|
80
|
-
return
|
|
139
|
+
return path14.join(os12.homedir(), ".acore", "user-model.json");
|
|
81
140
|
}
|
|
82
141
|
function createEmptyModel() {
|
|
83
142
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -109,7 +168,7 @@ function emptyProfile() {
|
|
|
109
168
|
async function loadUserModel(filePath) {
|
|
110
169
|
const fp = filePath ?? defaultModelPath();
|
|
111
170
|
try {
|
|
112
|
-
const raw = await
|
|
171
|
+
const raw = await fs14.readFile(fp, "utf-8");
|
|
113
172
|
const parsed = JSON.parse(raw);
|
|
114
173
|
if (parsed?.version !== 1) return null;
|
|
115
174
|
return parsed;
|
|
@@ -119,11 +178,11 @@ async function loadUserModel(filePath) {
|
|
|
119
178
|
}
|
|
120
179
|
async function saveUserModel(model, filePath) {
|
|
121
180
|
const fp = filePath ?? defaultModelPath();
|
|
122
|
-
const dir =
|
|
123
|
-
await
|
|
181
|
+
const dir = path14.dirname(fp);
|
|
182
|
+
await fs14.mkdir(dir, { recursive: true });
|
|
124
183
|
const tmp = fp + `.tmp-${Date.now()}`;
|
|
125
|
-
await
|
|
126
|
-
await
|
|
184
|
+
await fs14.writeFile(tmp, JSON.stringify(model, null, 2), "utf-8");
|
|
185
|
+
await fs14.rename(tmp, fp);
|
|
127
186
|
}
|
|
128
187
|
function aggregateSession(model, snapshot) {
|
|
129
188
|
const sessions = [...model.sessions, snapshot];
|
|
@@ -386,21 +445,21 @@ var init_user_model = __esm({
|
|
|
386
445
|
});
|
|
387
446
|
|
|
388
447
|
// src/server/registry.ts
|
|
389
|
-
import
|
|
390
|
-
import
|
|
448
|
+
import fs16 from "fs/promises";
|
|
449
|
+
import path16 from "path";
|
|
391
450
|
import os14 from "os";
|
|
392
451
|
function amanAgentHome() {
|
|
393
|
-
return process.env.AMAN_AGENT_HOME ||
|
|
452
|
+
return process.env.AMAN_AGENT_HOME || path16.join(os14.homedir(), ".aman-agent");
|
|
394
453
|
}
|
|
395
454
|
function registryPath() {
|
|
396
|
-
return
|
|
455
|
+
return path16.join(amanAgentHome(), "registry.json");
|
|
397
456
|
}
|
|
398
457
|
async function ensureHome() {
|
|
399
|
-
await
|
|
458
|
+
await fs16.mkdir(amanAgentHome(), { recursive: true });
|
|
400
459
|
}
|
|
401
460
|
async function readRaw() {
|
|
402
461
|
try {
|
|
403
|
-
const buf = await
|
|
462
|
+
const buf = await fs16.readFile(registryPath(), "utf-8");
|
|
404
463
|
const parsed = JSON.parse(buf);
|
|
405
464
|
return Array.isArray(parsed) ? parsed : [];
|
|
406
465
|
} catch (err) {
|
|
@@ -414,10 +473,10 @@ async function readRaw() {
|
|
|
414
473
|
async function writeAtomic(entries) {
|
|
415
474
|
await ensureHome();
|
|
416
475
|
const tmp = registryPath() + ".tmp";
|
|
417
|
-
await
|
|
418
|
-
await
|
|
476
|
+
await fs16.writeFile(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
|
|
477
|
+
await fs16.rename(tmp, registryPath());
|
|
419
478
|
try {
|
|
420
|
-
await
|
|
479
|
+
await fs16.chmod(registryPath(), 384);
|
|
421
480
|
} catch {
|
|
422
481
|
}
|
|
423
482
|
}
|
|
@@ -600,6 +659,473 @@ var init_delegate_remote = __esm({
|
|
|
600
659
|
}
|
|
601
660
|
});
|
|
602
661
|
|
|
662
|
+
// src/dev/stack-detector.ts
|
|
663
|
+
var stack_detector_exports = {};
|
|
664
|
+
__export(stack_detector_exports, {
|
|
665
|
+
scanStack: () => scanStack
|
|
666
|
+
});
|
|
667
|
+
import fs24 from "fs";
|
|
668
|
+
import path24 from "path";
|
|
669
|
+
function scanStack(projectPath) {
|
|
670
|
+
const languages = [];
|
|
671
|
+
const frameworks = [];
|
|
672
|
+
const databases = [];
|
|
673
|
+
const infra = [];
|
|
674
|
+
let isMonorepo = false;
|
|
675
|
+
let projectName = path24.basename(projectPath);
|
|
676
|
+
const goModPath = path24.join(projectPath, "go.mod");
|
|
677
|
+
if (fs24.existsSync(goModPath)) {
|
|
678
|
+
languages.push("go");
|
|
679
|
+
const content = fs24.readFileSync(goModPath, "utf-8");
|
|
680
|
+
const moduleMatch = content.match(/^module\s+(.+)$/m);
|
|
681
|
+
if (moduleMatch) {
|
|
682
|
+
const parts = moduleMatch[1].trim().split("/");
|
|
683
|
+
projectName = parts[parts.length - 1];
|
|
684
|
+
}
|
|
685
|
+
if (content.includes("gofiber/fiber")) frameworks.push("fiber");
|
|
686
|
+
if (content.includes("gin-gonic/gin")) frameworks.push("gin");
|
|
687
|
+
if (content.includes("go-chi/chi")) frameworks.push("chi");
|
|
688
|
+
if (content.includes("labstack/echo")) frameworks.push("echo");
|
|
689
|
+
}
|
|
690
|
+
const pkgPath = path24.join(projectPath, "package.json");
|
|
691
|
+
const hasTsConfig = fs24.existsSync(path24.join(projectPath, "tsconfig.json"));
|
|
692
|
+
if (fs24.existsSync(pkgPath)) {
|
|
693
|
+
try {
|
|
694
|
+
const pkg = JSON.parse(fs24.readFileSync(pkgPath, "utf-8"));
|
|
695
|
+
if (pkg.name) projectName = pkg.name;
|
|
696
|
+
if (hasTsConfig) {
|
|
697
|
+
languages.push("typescript");
|
|
698
|
+
} else {
|
|
699
|
+
languages.push("javascript");
|
|
700
|
+
}
|
|
701
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
702
|
+
for (const [dep, fwName] of Object.entries(FRAMEWORK_MAP)) {
|
|
703
|
+
if (allDeps?.[dep]) frameworks.push(fwName);
|
|
704
|
+
}
|
|
705
|
+
if (pkg.workspaces) isMonorepo = true;
|
|
706
|
+
} catch {
|
|
707
|
+
if (hasTsConfig) languages.push("typescript");
|
|
708
|
+
}
|
|
709
|
+
} else if (hasTsConfig) {
|
|
710
|
+
languages.push("typescript");
|
|
711
|
+
}
|
|
712
|
+
const cargoPath = path24.join(projectPath, "Cargo.toml");
|
|
713
|
+
if (fs24.existsSync(cargoPath)) {
|
|
714
|
+
languages.push("rust");
|
|
715
|
+
const content = fs24.readFileSync(cargoPath, "utf-8");
|
|
716
|
+
if (content.includes("[workspace]")) isMonorepo = true;
|
|
717
|
+
const nameMatch = content.match(/^\s*name\s*=\s*"([^"]+)"/m);
|
|
718
|
+
if (nameMatch && !isMonorepo) projectName = nameMatch[1];
|
|
719
|
+
}
|
|
720
|
+
const pyprojectPath = path24.join(projectPath, "pyproject.toml");
|
|
721
|
+
if (fs24.existsSync(pyprojectPath)) {
|
|
722
|
+
languages.push("python");
|
|
723
|
+
const content = fs24.readFileSync(pyprojectPath, "utf-8");
|
|
724
|
+
if (content.includes("django")) frameworks.push("django");
|
|
725
|
+
if (content.includes("fastapi")) frameworks.push("fastapi");
|
|
726
|
+
if (content.includes("flask")) frameworks.push("flask");
|
|
727
|
+
}
|
|
728
|
+
if (fs24.existsSync(path24.join(projectPath, "pubspec.yaml"))) {
|
|
729
|
+
languages.push("dart");
|
|
730
|
+
frameworks.push("flutter");
|
|
731
|
+
}
|
|
732
|
+
if (fs24.existsSync(path24.join(projectPath, "Dockerfile"))) {
|
|
733
|
+
infra.push("docker");
|
|
734
|
+
}
|
|
735
|
+
const composeNames = ["docker-compose.yml", "docker-compose.yaml", "compose.yml", "compose.yaml"];
|
|
736
|
+
for (const name of composeNames) {
|
|
737
|
+
const composePath = path24.join(projectPath, name);
|
|
738
|
+
if (fs24.existsSync(composePath)) {
|
|
739
|
+
if (!infra.includes("docker")) infra.push("docker");
|
|
740
|
+
const content = fs24.readFileSync(composePath, "utf-8");
|
|
741
|
+
for (const [pattern, dbName] of Object.entries(DB_IMAGE_MAP)) {
|
|
742
|
+
if (content.includes(pattern) && !databases.includes(dbName)) {
|
|
743
|
+
databases.push(dbName);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
break;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
if (fs24.existsSync(path24.join(projectPath, ".github", "workflows"))) {
|
|
750
|
+
infra.push("github-actions");
|
|
751
|
+
}
|
|
752
|
+
for (const dir of ["k3s", "k8s", "deploy"]) {
|
|
753
|
+
if (fs24.existsSync(path24.join(projectPath, dir))) {
|
|
754
|
+
infra.push("kubernetes");
|
|
755
|
+
break;
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
if (fs24.existsSync(path24.join(projectPath, "Makefile"))) {
|
|
759
|
+
infra.push("make");
|
|
760
|
+
}
|
|
761
|
+
return {
|
|
762
|
+
projectName,
|
|
763
|
+
languages,
|
|
764
|
+
frameworks,
|
|
765
|
+
databases,
|
|
766
|
+
infra,
|
|
767
|
+
isMonorepo,
|
|
768
|
+
detectedAt: Date.now()
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
var FRAMEWORK_MAP, DB_IMAGE_MAP;
|
|
772
|
+
var init_stack_detector = __esm({
|
|
773
|
+
"src/dev/stack-detector.ts"() {
|
|
774
|
+
"use strict";
|
|
775
|
+
FRAMEWORK_MAP = {
|
|
776
|
+
next: "next",
|
|
777
|
+
react: "react",
|
|
778
|
+
remix: "remix",
|
|
779
|
+
express: "express",
|
|
780
|
+
fastify: "fastify",
|
|
781
|
+
hono: "hono",
|
|
782
|
+
"@nestjs/core": "nestjs",
|
|
783
|
+
vue: "vue",
|
|
784
|
+
svelte: "svelte",
|
|
785
|
+
nuxt: "nuxt"
|
|
786
|
+
};
|
|
787
|
+
DB_IMAGE_MAP = {
|
|
788
|
+
postgres: "postgresql",
|
|
789
|
+
mysql: "mysql",
|
|
790
|
+
mariadb: "mariadb",
|
|
791
|
+
mongo: "mongodb",
|
|
792
|
+
redis: "redis",
|
|
793
|
+
timescaledb: "timescaledb"
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
});
|
|
797
|
+
|
|
798
|
+
// src/dev/context-builder.ts
|
|
799
|
+
import path25 from "path";
|
|
800
|
+
import os22 from "os";
|
|
801
|
+
import { createDatabase as createDatabase2, recall as recall2 } from "@aman_asmuei/amem-core";
|
|
802
|
+
import {
|
|
803
|
+
getIdentity as acoreGetIdentity2
|
|
804
|
+
} from "@aman_asmuei/acore-core";
|
|
805
|
+
import {
|
|
806
|
+
listRuleCategories as arulesListCategories2
|
|
807
|
+
} from "@aman_asmuei/arules-core";
|
|
808
|
+
function trimToTokenBudget(items, maxTokens) {
|
|
809
|
+
const result = [];
|
|
810
|
+
let total = 0;
|
|
811
|
+
for (const item of items) {
|
|
812
|
+
const tokens = estimateTokens(item);
|
|
813
|
+
if (total + tokens > maxTokens) break;
|
|
814
|
+
result.push(item);
|
|
815
|
+
total += tokens;
|
|
816
|
+
}
|
|
817
|
+
return result;
|
|
818
|
+
}
|
|
819
|
+
async function buildContext2(stack, opts) {
|
|
820
|
+
const conventions = [];
|
|
821
|
+
const decisions = [];
|
|
822
|
+
const corrections = [];
|
|
823
|
+
const preferences = [];
|
|
824
|
+
const rules = [];
|
|
825
|
+
let memoriesUsed = 0;
|
|
826
|
+
try {
|
|
827
|
+
const amemDir = process.env.AMEM_DIR ?? path25.join(os22.homedir(), ".amem");
|
|
828
|
+
const dbPath = process.env.AMEM_DB ?? path25.join(amemDir, "memory.db");
|
|
829
|
+
const db2 = createDatabase2(dbPath);
|
|
830
|
+
const query = [stack.projectName, ...stack.languages, ...stack.frameworks].join(" ");
|
|
831
|
+
const result = await recall2(db2, { query, limit: 20 });
|
|
832
|
+
for (const mem of result.memories) {
|
|
833
|
+
switch (mem.type) {
|
|
834
|
+
case "pattern":
|
|
835
|
+
conventions.push(mem.content);
|
|
836
|
+
break;
|
|
837
|
+
case "decision":
|
|
838
|
+
decisions.push(mem.content);
|
|
839
|
+
break;
|
|
840
|
+
case "correction":
|
|
841
|
+
corrections.push(mem.content);
|
|
842
|
+
break;
|
|
843
|
+
case "preference":
|
|
844
|
+
preferences.push(mem.content);
|
|
845
|
+
break;
|
|
846
|
+
}
|
|
847
|
+
memoriesUsed++;
|
|
848
|
+
}
|
|
849
|
+
} catch {
|
|
850
|
+
}
|
|
851
|
+
try {
|
|
852
|
+
const identity = await acoreGetIdentity2(AGENT_SCOPE2);
|
|
853
|
+
if (identity?.content) {
|
|
854
|
+
const lines = identity.content.split("\n").filter(
|
|
855
|
+
(l) => l.startsWith("- ") && (l.toLowerCase().includes("prefer") || l.toLowerCase().includes("style") || l.toLowerCase().includes("convention"))
|
|
856
|
+
);
|
|
857
|
+
for (const line of lines) {
|
|
858
|
+
const text3 = line.replace(/^-\s*/, "").trim();
|
|
859
|
+
if (text3 && !preferences.includes(text3)) preferences.push(text3);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
} catch {
|
|
863
|
+
}
|
|
864
|
+
try {
|
|
865
|
+
const categories = await arulesListCategories2(AGENT_SCOPE2);
|
|
866
|
+
for (const cat of categories) {
|
|
867
|
+
for (const ruleText of cat.rules) {
|
|
868
|
+
rules.push(ruleText);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
} catch {
|
|
872
|
+
}
|
|
873
|
+
if (opts?.smart && opts.llmClient) {
|
|
874
|
+
try {
|
|
875
|
+
const client = opts.llmClient;
|
|
876
|
+
const rawData = [
|
|
877
|
+
`Project: ${stack.projectName}`,
|
|
878
|
+
`Stack: ${stack.languages.join(", ")} + ${stack.frameworks.join(", ")}`,
|
|
879
|
+
`Databases: ${stack.databases.join(", ") || "none detected"}`,
|
|
880
|
+
"",
|
|
881
|
+
conventions.length > 0 ? `Conventions:
|
|
882
|
+
${conventions.map((c) => `- ${c}`).join("\n")}` : "",
|
|
883
|
+
decisions.length > 0 ? `Decisions:
|
|
884
|
+
${decisions.map((d) => `- ${d}`).join("\n")}` : "",
|
|
885
|
+
corrections.length > 0 ? `Corrections:
|
|
886
|
+
${corrections.map((c) => `- ${c}`).join("\n")}` : "",
|
|
887
|
+
preferences.length > 0 ? `Preferences:
|
|
888
|
+
${preferences.map((p5) => `- ${p5}`).join("\n")}` : "",
|
|
889
|
+
rules.length > 0 ? `Rules:
|
|
890
|
+
${rules.map((r) => `- ${r}`).join("\n")}` : ""
|
|
891
|
+
].filter(Boolean).join("\n\n");
|
|
892
|
+
const response = await client.chat(
|
|
893
|
+
"You are a developer context assembler. Given raw developer history, output a merged, deduplicated set of conventions and decisions as markdown bullet lists. Group by: Conventions, Decisions, Corrections, Preferences, Rules. Be specific, not generic. Max 3000 tokens.",
|
|
894
|
+
[{ role: "user", content: rawData }],
|
|
895
|
+
() => {
|
|
896
|
+
}
|
|
897
|
+
);
|
|
898
|
+
const text3 = typeof response.message.content === "string" ? response.message.content : response.message.content.map((b) => b.text ?? "").join("");
|
|
899
|
+
const extractSection = (sectionName) => {
|
|
900
|
+
const regex = new RegExp(`##?\\s*${sectionName}[\\s\\S]*?(?=##|$)`, "i");
|
|
901
|
+
const match = text3.match(regex);
|
|
902
|
+
if (!match) return [];
|
|
903
|
+
return match[0].split("\n").filter((l) => l.startsWith("- ")).map((l) => l.replace(/^-\s*/, "").trim());
|
|
904
|
+
};
|
|
905
|
+
const smartConventions = extractSection("Conventions");
|
|
906
|
+
const smartDecisions = extractSection("Decisions");
|
|
907
|
+
const smartCorrections = extractSection("Corrections");
|
|
908
|
+
const smartPreferences = extractSection("Preferences");
|
|
909
|
+
const smartRules = extractSection("Rules");
|
|
910
|
+
return {
|
|
911
|
+
stack,
|
|
912
|
+
conventions: trimToTokenBudget(smartConventions.length > 0 ? smartConventions : conventions, TOKEN_LIMITS.conventions),
|
|
913
|
+
decisions: trimToTokenBudget(smartDecisions.length > 0 ? smartDecisions : decisions, TOKEN_LIMITS.decisions),
|
|
914
|
+
corrections: trimToTokenBudget(smartCorrections.length > 0 ? smartCorrections : corrections, TOKEN_LIMITS.corrections),
|
|
915
|
+
preferences: trimToTokenBudget(smartPreferences.length > 0 ? smartPreferences : preferences, TOKEN_LIMITS.preferences),
|
|
916
|
+
rules: trimToTokenBudget(smartRules.length > 0 ? smartRules : rules, TOKEN_LIMITS.rules),
|
|
917
|
+
metadata: {
|
|
918
|
+
generatedAt: Date.now(),
|
|
919
|
+
mode: "smart",
|
|
920
|
+
memoriesUsed
|
|
921
|
+
}
|
|
922
|
+
};
|
|
923
|
+
} catch {
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
return {
|
|
927
|
+
stack,
|
|
928
|
+
conventions: trimToTokenBudget(conventions, TOKEN_LIMITS.conventions),
|
|
929
|
+
decisions: trimToTokenBudget(decisions, TOKEN_LIMITS.decisions),
|
|
930
|
+
corrections: trimToTokenBudget(corrections, TOKEN_LIMITS.corrections),
|
|
931
|
+
preferences: trimToTokenBudget(preferences, TOKEN_LIMITS.preferences),
|
|
932
|
+
rules: trimToTokenBudget(rules, TOKEN_LIMITS.rules),
|
|
933
|
+
metadata: {
|
|
934
|
+
generatedAt: Date.now(),
|
|
935
|
+
mode: "template",
|
|
936
|
+
memoriesUsed
|
|
937
|
+
}
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
var AGENT_SCOPE2, TOKEN_LIMITS;
|
|
941
|
+
var init_context_builder = __esm({
|
|
942
|
+
"src/dev/context-builder.ts"() {
|
|
943
|
+
"use strict";
|
|
944
|
+
init_token_budget();
|
|
945
|
+
AGENT_SCOPE2 = process.env.AMAN_AGENT_SCOPE ?? "dev:agent";
|
|
946
|
+
TOKEN_LIMITS = {
|
|
947
|
+
conventions: 1500,
|
|
948
|
+
decisions: 1200,
|
|
949
|
+
corrections: 800,
|
|
950
|
+
preferences: 500,
|
|
951
|
+
rules: 800
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
});
|
|
955
|
+
|
|
956
|
+
// src/dev/claude-md-writer.ts
|
|
957
|
+
import fs25 from "fs";
|
|
958
|
+
import path26 from "path";
|
|
959
|
+
function formatStack(stack) {
|
|
960
|
+
const parts = [];
|
|
961
|
+
const goFrameworks = ["fiber", "gin", "chi", "echo"];
|
|
962
|
+
const jsFrameworks = ["next", "react", "remix", "express", "fastify", "hono", "nestjs", "vue", "svelte", "nuxt"];
|
|
963
|
+
const pyFrameworks = ["django", "fastapi", "flask"];
|
|
964
|
+
for (const lang of stack.languages) {
|
|
965
|
+
const fw = stack.frameworks.filter((f) => {
|
|
966
|
+
if (lang === "go" && goFrameworks.includes(f)) return true;
|
|
967
|
+
if ((lang === "typescript" || lang === "javascript") && jsFrameworks.includes(f)) return true;
|
|
968
|
+
if (lang === "python" && pyFrameworks.includes(f)) return true;
|
|
969
|
+
if (lang === "dart" && f === "flutter") return true;
|
|
970
|
+
return false;
|
|
971
|
+
});
|
|
972
|
+
const name = lang.charAt(0).toUpperCase() + lang.slice(1);
|
|
973
|
+
if (fw.length > 0) {
|
|
974
|
+
parts.push(`${name} (${fw.map((f) => f.charAt(0).toUpperCase() + f.slice(1)).join(", ")})`);
|
|
975
|
+
} else {
|
|
976
|
+
parts.push(name);
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
if (stack.databases.length > 0) {
|
|
980
|
+
parts.push(...stack.databases.map((d) => d.charAt(0).toUpperCase() + d.slice(1)));
|
|
981
|
+
}
|
|
982
|
+
return parts.join(" + ");
|
|
983
|
+
}
|
|
984
|
+
function renderToString(ctx) {
|
|
985
|
+
const lines = [];
|
|
986
|
+
const ts = new Date(ctx.metadata.generatedAt).toISOString();
|
|
987
|
+
lines.push(`# Project: ${ctx.stack.projectName}`);
|
|
988
|
+
lines.push(`<!-- aman-agent:dev generated=${ts} memories=${ctx.metadata.memoriesUsed} mode=${ctx.metadata.mode} -->`);
|
|
989
|
+
lines.push("");
|
|
990
|
+
const stackLine = formatStack(ctx.stack);
|
|
991
|
+
if (stackLine || ctx.stack.infra.length > 0) {
|
|
992
|
+
lines.push("## Stack");
|
|
993
|
+
if (stackLine) lines.push(`- ${stackLine}`);
|
|
994
|
+
if (ctx.stack.infra.length > 0) {
|
|
995
|
+
lines.push(`- Infra: ${ctx.stack.infra.join(", ")}`);
|
|
996
|
+
}
|
|
997
|
+
if (ctx.stack.isMonorepo) {
|
|
998
|
+
lines.push("- Monorepo");
|
|
999
|
+
}
|
|
1000
|
+
lines.push("");
|
|
1001
|
+
}
|
|
1002
|
+
if (ctx.conventions.length > 0) {
|
|
1003
|
+
lines.push("## Conventions");
|
|
1004
|
+
for (const c of ctx.conventions) lines.push(`- ${c}`);
|
|
1005
|
+
lines.push("");
|
|
1006
|
+
}
|
|
1007
|
+
if (ctx.decisions.length > 0) {
|
|
1008
|
+
lines.push("## Past Decisions");
|
|
1009
|
+
for (const d of ctx.decisions) lines.push(`- ${d}`);
|
|
1010
|
+
lines.push("");
|
|
1011
|
+
}
|
|
1012
|
+
if (ctx.corrections.length > 0) {
|
|
1013
|
+
lines.push("## Corrections");
|
|
1014
|
+
for (const c of ctx.corrections) lines.push(`- ${c}`);
|
|
1015
|
+
lines.push("");
|
|
1016
|
+
}
|
|
1017
|
+
if (ctx.preferences.length > 0) {
|
|
1018
|
+
lines.push("## Developer Preferences");
|
|
1019
|
+
for (const p5 of ctx.preferences) lines.push(`- ${p5}`);
|
|
1020
|
+
lines.push("");
|
|
1021
|
+
}
|
|
1022
|
+
if (ctx.rules.length > 0) {
|
|
1023
|
+
lines.push("## Rules");
|
|
1024
|
+
for (const r of ctx.rules) lines.push(`- ${r}`);
|
|
1025
|
+
lines.push("");
|
|
1026
|
+
}
|
|
1027
|
+
return lines.join("\n");
|
|
1028
|
+
}
|
|
1029
|
+
function parseMarker(content) {
|
|
1030
|
+
const match = content.match(
|
|
1031
|
+
/<!--\s*aman-agent:dev\s+generated=(\S+)\s+memories=(\d+)\s+mode=(\S+)\s*-->/
|
|
1032
|
+
);
|
|
1033
|
+
if (!match) return null;
|
|
1034
|
+
return {
|
|
1035
|
+
generatedAt: new Date(match[1]),
|
|
1036
|
+
memories: parseInt(match[2], 10),
|
|
1037
|
+
mode: match[3]
|
|
1038
|
+
};
|
|
1039
|
+
}
|
|
1040
|
+
function checkStaleness(projectPath) {
|
|
1041
|
+
const claudeMdPath = path26.join(projectPath, "CLAUDE.md");
|
|
1042
|
+
if (!fs25.existsSync(claudeMdPath)) {
|
|
1043
|
+
return { status: "missing" };
|
|
1044
|
+
}
|
|
1045
|
+
const content = fs25.readFileSync(claudeMdPath, "utf-8");
|
|
1046
|
+
const marker = parseMarker(content);
|
|
1047
|
+
if (!marker) {
|
|
1048
|
+
return { status: "no-marker" };
|
|
1049
|
+
}
|
|
1050
|
+
return { status: "fresh", generatedAt: marker.generatedAt };
|
|
1051
|
+
}
|
|
1052
|
+
function writeClaudeMd(ctx, projectPath) {
|
|
1053
|
+
const claudeMdPath = path26.join(projectPath, "CLAUDE.md");
|
|
1054
|
+
let backedUp = false;
|
|
1055
|
+
if (fs25.existsSync(claudeMdPath)) {
|
|
1056
|
+
const content = fs25.readFileSync(claudeMdPath, "utf-8");
|
|
1057
|
+
const marker = parseMarker(content);
|
|
1058
|
+
if (!marker) {
|
|
1059
|
+
fs25.copyFileSync(claudeMdPath, `${claudeMdPath}.bak`);
|
|
1060
|
+
backedUp = true;
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
const md = renderToString(ctx);
|
|
1064
|
+
fs25.writeFileSync(claudeMdPath, md, "utf-8");
|
|
1065
|
+
return { written: true, backedUp, path: claudeMdPath };
|
|
1066
|
+
}
|
|
1067
|
+
var init_claude_md_writer = __esm({
|
|
1068
|
+
"src/dev/claude-md-writer.ts"() {
|
|
1069
|
+
"use strict";
|
|
1070
|
+
}
|
|
1071
|
+
});
|
|
1072
|
+
|
|
1073
|
+
// src/dev/dev-command.ts
|
|
1074
|
+
var dev_command_exports = {};
|
|
1075
|
+
__export(dev_command_exports, {
|
|
1076
|
+
runDev: () => runDev
|
|
1077
|
+
});
|
|
1078
|
+
import fs26 from "fs";
|
|
1079
|
+
import path27 from "path";
|
|
1080
|
+
function ensureGitignore(projectPath) {
|
|
1081
|
+
const gitignorePath = path27.join(projectPath, ".gitignore");
|
|
1082
|
+
if (!fs26.existsSync(gitignorePath)) return;
|
|
1083
|
+
const content = fs26.readFileSync(gitignorePath, "utf-8");
|
|
1084
|
+
if (content.includes("CLAUDE.md")) return;
|
|
1085
|
+
fs26.appendFileSync(gitignorePath, "\n# Generated by aman-agent dev\nCLAUDE.md\n");
|
|
1086
|
+
}
|
|
1087
|
+
async function runDev(projectPath, flags = {}, precomputedStack) {
|
|
1088
|
+
const resolved = path27.resolve(projectPath);
|
|
1089
|
+
if (!fs26.existsSync(resolved)) {
|
|
1090
|
+
return { success: false, generated: false, error: `Directory not found: ${resolved}` };
|
|
1091
|
+
}
|
|
1092
|
+
const stack = precomputedStack ?? scanStack(resolved);
|
|
1093
|
+
if (flags.diff) {
|
|
1094
|
+
const ctx2 = await buildContext2(stack, { smart: flags.smart });
|
|
1095
|
+
const newContent = renderToString(ctx2);
|
|
1096
|
+
const existingPath = path27.join(resolved, "CLAUDE.md");
|
|
1097
|
+
const existing = fs26.existsSync(existingPath) ? fs26.readFileSync(existingPath, "utf-8") : "";
|
|
1098
|
+
return {
|
|
1099
|
+
success: true,
|
|
1100
|
+
generated: false,
|
|
1101
|
+
diff: existing === newContent ? "(no changes)" : newContent,
|
|
1102
|
+
context: ctx2
|
|
1103
|
+
};
|
|
1104
|
+
}
|
|
1105
|
+
if (!flags.force) {
|
|
1106
|
+
const staleness = checkStaleness(resolved);
|
|
1107
|
+
if (staleness.status === "fresh") {
|
|
1108
|
+
return { success: true, generated: false, skippedReason: "fresh" };
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
const ctx = await buildContext2(stack, { smart: flags.smart });
|
|
1112
|
+
const writeResult = writeClaudeMd(ctx, resolved);
|
|
1113
|
+
ensureGitignore(resolved);
|
|
1114
|
+
return {
|
|
1115
|
+
success: true,
|
|
1116
|
+
generated: writeResult.written,
|
|
1117
|
+
context: ctx
|
|
1118
|
+
};
|
|
1119
|
+
}
|
|
1120
|
+
var init_dev_command = __esm({
|
|
1121
|
+
"src/dev/dev-command.ts"() {
|
|
1122
|
+
"use strict";
|
|
1123
|
+
init_stack_detector();
|
|
1124
|
+
init_context_builder();
|
|
1125
|
+
init_claude_md_writer();
|
|
1126
|
+
}
|
|
1127
|
+
});
|
|
1128
|
+
|
|
603
1129
|
// src/index.ts
|
|
604
1130
|
import { Command } from "commander";
|
|
605
1131
|
import * as p4 from "@clack/prompts";
|
|
@@ -620,8 +1146,26 @@ var DEFAULT_HOOKS = {
|
|
|
620
1146
|
featureHints: true,
|
|
621
1147
|
personalityAdapt: true
|
|
622
1148
|
};
|
|
1149
|
+
function homeDir() {
|
|
1150
|
+
return process.env.AMAN_HOME || process.env.AMAN_AGENT_HOME || path.join(os.homedir(), ".aman-agent");
|
|
1151
|
+
}
|
|
1152
|
+
function identityDir() {
|
|
1153
|
+
return path.join(homeDir(), "identity");
|
|
1154
|
+
}
|
|
1155
|
+
function rulesDir() {
|
|
1156
|
+
return path.join(homeDir(), "rules");
|
|
1157
|
+
}
|
|
1158
|
+
function memoryDir() {
|
|
1159
|
+
return path.join(homeDir(), "memory");
|
|
1160
|
+
}
|
|
1161
|
+
function workflowsDir() {
|
|
1162
|
+
return path.join(homeDir(), "workflows");
|
|
1163
|
+
}
|
|
1164
|
+
function skillsDir() {
|
|
1165
|
+
return path.join(homeDir(), "skills");
|
|
1166
|
+
}
|
|
623
1167
|
function configDir() {
|
|
624
|
-
return
|
|
1168
|
+
return homeDir();
|
|
625
1169
|
}
|
|
626
1170
|
function configPath() {
|
|
627
1171
|
return path.join(configDir(), "config.json");
|
|
@@ -646,76 +1190,54 @@ function saveConfig(config) {
|
|
|
646
1190
|
);
|
|
647
1191
|
}
|
|
648
1192
|
|
|
649
|
-
// src/
|
|
650
|
-
import
|
|
651
|
-
import
|
|
652
|
-
import
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
"
|
|
660
|
-
// core.md — always include
|
|
661
|
-
"user",
|
|
662
|
-
// user.md — user profile, always include
|
|
663
|
-
"guardrails",
|
|
664
|
-
// rules.md — safety critical
|
|
665
|
-
"workflows",
|
|
666
|
-
// flow.md — behavioral
|
|
667
|
-
"tools",
|
|
668
|
-
// kit.md — capabilities
|
|
669
|
-
"skills"
|
|
670
|
-
// skills.md — can be truncated
|
|
1193
|
+
// src/migrate.ts
|
|
1194
|
+
import fs2 from "fs";
|
|
1195
|
+
import path2 from "path";
|
|
1196
|
+
import os2 from "os";
|
|
1197
|
+
var MIGRATION_MAP = [
|
|
1198
|
+
{ oldName: ".acore", newSubdir: "identity" },
|
|
1199
|
+
{ oldName: ".arules", newSubdir: "rules" },
|
|
1200
|
+
{ oldName: ".aflow", newSubdir: "workflows" },
|
|
1201
|
+
{ oldName: ".askill", newSubdir: "skills" },
|
|
1202
|
+
{ oldName: ".amem", newSubdir: "memory" },
|
|
1203
|
+
{ oldName: ".aeval", newSubdir: "eval" }
|
|
671
1204
|
];
|
|
672
|
-
function
|
|
673
|
-
const
|
|
674
|
-
const
|
|
675
|
-
const
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
const
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
parts.push(comp.content);
|
|
685
|
-
included.push(comp.name);
|
|
686
|
-
totalTokens += comp.tokens;
|
|
687
|
-
} else {
|
|
688
|
-
const halfContent = comp.content.slice(0, Math.floor(comp.content.length / 2));
|
|
689
|
-
const halfTokens = estimateTokens(halfContent);
|
|
690
|
-
if (totalTokens + halfTokens <= maxTokens) {
|
|
691
|
-
parts.push(halfContent + "\n\n[... truncated for context budget ...]");
|
|
692
|
-
included.push(comp.name + " (partial)");
|
|
693
|
-
totalTokens += halfTokens;
|
|
694
|
-
} else {
|
|
695
|
-
truncated.push(comp.name);
|
|
696
|
-
}
|
|
1205
|
+
function migrateIfNeeded() {
|
|
1206
|
+
const home2 = os2.homedir();
|
|
1207
|
+
const target = homeDir();
|
|
1208
|
+
const migrated = [];
|
|
1209
|
+
for (const { oldName, newSubdir } of MIGRATION_MAP) {
|
|
1210
|
+
const oldDir = path2.join(home2, oldName);
|
|
1211
|
+
const newDir = path2.join(target, newSubdir);
|
|
1212
|
+
if (!fs2.existsSync(oldDir)) continue;
|
|
1213
|
+
if (fs2.existsSync(newDir) && fs2.readdirSync(newDir).length > 0) continue;
|
|
1214
|
+
fs2.mkdirSync(newDir, { recursive: true });
|
|
1215
|
+
for (const entry of fs2.readdirSync(oldDir)) {
|
|
1216
|
+
fs2.renameSync(path2.join(oldDir, entry), path2.join(newDir, entry));
|
|
697
1217
|
}
|
|
1218
|
+
fs2.rmSync(oldDir, { recursive: true, force: true });
|
|
1219
|
+
migrated.push(newSubdir);
|
|
698
1220
|
}
|
|
699
|
-
return {
|
|
700
|
-
prompt: parts.join("\n\n---\n\n"),
|
|
701
|
-
included,
|
|
702
|
-
truncated,
|
|
703
|
-
totalTokens
|
|
704
|
-
};
|
|
1221
|
+
return { migrated };
|
|
705
1222
|
}
|
|
706
1223
|
|
|
1224
|
+
// src/prompt.ts
|
|
1225
|
+
init_token_budget();
|
|
1226
|
+
import fs4 from "fs";
|
|
1227
|
+
import path4 from "path";
|
|
1228
|
+
import os3 from "os";
|
|
1229
|
+
|
|
707
1230
|
// src/user-identity.ts
|
|
708
|
-
import
|
|
709
|
-
import
|
|
710
|
-
|
|
711
|
-
var USER_FILE = path2.join(os2.homedir(), ".acore", "user.md");
|
|
1231
|
+
import fs3 from "fs";
|
|
1232
|
+
import path3 from "path";
|
|
1233
|
+
var USER_FILE = path3.join(identityDir(), "user.md");
|
|
712
1234
|
function hasUserIdentity() {
|
|
713
|
-
return
|
|
1235
|
+
return fs3.existsSync(USER_FILE);
|
|
714
1236
|
}
|
|
715
1237
|
function loadUserIdentity() {
|
|
716
|
-
if (!
|
|
1238
|
+
if (!fs3.existsSync(USER_FILE)) return null;
|
|
717
1239
|
try {
|
|
718
|
-
const content =
|
|
1240
|
+
const content = fs3.readFileSync(USER_FILE, "utf-8");
|
|
719
1241
|
const get = (key) => {
|
|
720
1242
|
const match = content.match(new RegExp(`^- ${key}:\\s*(.+)$`, "m"));
|
|
721
1243
|
return match?.[1]?.trim() ?? "";
|
|
@@ -746,8 +1268,8 @@ function loadUserIdentity() {
|
|
|
746
1268
|
}
|
|
747
1269
|
}
|
|
748
1270
|
function saveUserIdentity(user) {
|
|
749
|
-
const dir =
|
|
750
|
-
if (!
|
|
1271
|
+
const dir = path3.dirname(USER_FILE);
|
|
1272
|
+
if (!fs3.existsSync(dir)) fs3.mkdirSync(dir, { recursive: true });
|
|
751
1273
|
const lines = [
|
|
752
1274
|
"# User Profile",
|
|
753
1275
|
"",
|
|
@@ -772,7 +1294,7 @@ function saveUserIdentity(user) {
|
|
|
772
1294
|
`- Created: ${user.createdAt}`,
|
|
773
1295
|
`- Updated: ${user.updatedAt}`
|
|
774
1296
|
);
|
|
775
|
-
|
|
1297
|
+
fs3.writeFileSync(USER_FILE, lines.join("\n") + "\n", "utf-8");
|
|
776
1298
|
}
|
|
777
1299
|
function formatUserContext(user) {
|
|
778
1300
|
const parts = [
|
|
@@ -834,19 +1356,19 @@ var ECOSYSTEM_FILES = [
|
|
|
834
1356
|
];
|
|
835
1357
|
function resolveLayerPath(entry, home2, profile) {
|
|
836
1358
|
if (profile && entry.profileOverridable) {
|
|
837
|
-
const profilePath =
|
|
838
|
-
if (
|
|
1359
|
+
const profilePath = path4.join(home2, ".acore", "profiles", profile, entry.file);
|
|
1360
|
+
if (fs4.existsSync(profilePath)) return profilePath;
|
|
839
1361
|
if (entry.name === "guardrails") {
|
|
840
|
-
const altPath =
|
|
841
|
-
if (
|
|
1362
|
+
const altPath = path4.join(home2, ".acore", "profiles", profile, "rules.md");
|
|
1363
|
+
if (fs4.existsSync(altPath)) return altPath;
|
|
842
1364
|
}
|
|
843
1365
|
if (entry.name === "skills") {
|
|
844
|
-
const altPath =
|
|
845
|
-
if (
|
|
1366
|
+
const altPath = path4.join(home2, ".acore", "profiles", profile, "skills.md");
|
|
1367
|
+
if (fs4.existsSync(altPath)) return altPath;
|
|
846
1368
|
}
|
|
847
1369
|
}
|
|
848
|
-
const globalPath =
|
|
849
|
-
if (
|
|
1370
|
+
const globalPath = path4.join(home2, entry.dir, entry.file);
|
|
1371
|
+
if (fs4.existsSync(globalPath)) return globalPath;
|
|
850
1372
|
return null;
|
|
851
1373
|
}
|
|
852
1374
|
function assembleSystemPrompt(maxTokens, profile) {
|
|
@@ -855,7 +1377,7 @@ function assembleSystemPrompt(maxTokens, profile) {
|
|
|
855
1377
|
for (const entry of ECOSYSTEM_FILES) {
|
|
856
1378
|
const filePath = resolveLayerPath(entry, home2, profile);
|
|
857
1379
|
if (filePath) {
|
|
858
|
-
const content =
|
|
1380
|
+
const content = fs4.readFileSync(filePath, "utf-8").trim();
|
|
859
1381
|
components.push({
|
|
860
1382
|
name: entry.name,
|
|
861
1383
|
content,
|
|
@@ -863,9 +1385,9 @@ function assembleSystemPrompt(maxTokens, profile) {
|
|
|
863
1385
|
});
|
|
864
1386
|
}
|
|
865
1387
|
}
|
|
866
|
-
const contextPath =
|
|
867
|
-
if (
|
|
868
|
-
const content =
|
|
1388
|
+
const contextPath = path4.join(process.cwd(), ".acore", "context.md");
|
|
1389
|
+
if (fs4.existsSync(contextPath)) {
|
|
1390
|
+
const content = fs4.readFileSync(contextPath, "utf-8").trim();
|
|
869
1391
|
components.push({
|
|
870
1392
|
name: "context",
|
|
871
1393
|
content,
|
|
@@ -891,14 +1413,14 @@ function assembleSystemPrompt(maxTokens, profile) {
|
|
|
891
1413
|
};
|
|
892
1414
|
}
|
|
893
1415
|
function listProfiles() {
|
|
894
|
-
const profilesDir =
|
|
895
|
-
if (!
|
|
1416
|
+
const profilesDir = path4.join(os3.homedir(), ".acore", "profiles");
|
|
1417
|
+
if (!fs4.existsSync(profilesDir)) return [];
|
|
896
1418
|
const profiles = [];
|
|
897
|
-
for (const entry of
|
|
1419
|
+
for (const entry of fs4.readdirSync(profilesDir, { withFileTypes: true })) {
|
|
898
1420
|
if (!entry.isDirectory()) continue;
|
|
899
|
-
const corePath =
|
|
900
|
-
if (!
|
|
901
|
-
const content =
|
|
1421
|
+
const corePath = path4.join(profilesDir, entry.name, "core.md");
|
|
1422
|
+
if (!fs4.existsSync(corePath)) continue;
|
|
1423
|
+
const content = fs4.readFileSync(corePath, "utf-8");
|
|
902
1424
|
const nameMatch = content.match(/^# (.+)/m);
|
|
903
1425
|
const personalityMatch = content.match(/- Personality:\s*(.+)/);
|
|
904
1426
|
profiles.push({
|
|
@@ -913,13 +1435,13 @@ function getProfileAiName(profile) {
|
|
|
913
1435
|
const home2 = os3.homedir();
|
|
914
1436
|
let corePath;
|
|
915
1437
|
if (profile) {
|
|
916
|
-
const profileCorePath =
|
|
917
|
-
corePath =
|
|
1438
|
+
const profileCorePath = path4.join(home2, ".acore", "profiles", profile, "core.md");
|
|
1439
|
+
corePath = fs4.existsSync(profileCorePath) ? profileCorePath : path4.join(home2, ".acore", "core.md");
|
|
918
1440
|
} else {
|
|
919
|
-
corePath =
|
|
1441
|
+
corePath = path4.join(home2, ".acore", "core.md");
|
|
920
1442
|
}
|
|
921
|
-
if (!
|
|
922
|
-
const content =
|
|
1443
|
+
if (!fs4.existsSync(corePath)) return "Assistant";
|
|
1444
|
+
const content = fs4.readFileSync(corePath, "utf-8");
|
|
923
1445
|
const match = content.match(/^# (.+)$/m);
|
|
924
1446
|
return match?.[1]?.trim() || "Assistant";
|
|
925
1447
|
}
|
|
@@ -1976,8 +2498,8 @@ var McpManager = class {
|
|
|
1976
2498
|
|
|
1977
2499
|
// src/agent.ts
|
|
1978
2500
|
import * as readline from "readline";
|
|
1979
|
-
import
|
|
1980
|
-
import
|
|
2501
|
+
import fs23 from "fs";
|
|
2502
|
+
import path23 from "path";
|
|
1981
2503
|
import os21 from "os";
|
|
1982
2504
|
import pc7 from "picocolors";
|
|
1983
2505
|
import { marked } from "marked";
|
|
@@ -1985,15 +2507,15 @@ import { markedTerminal } from "marked-terminal";
|
|
|
1985
2507
|
import logUpdate from "log-update";
|
|
1986
2508
|
|
|
1987
2509
|
// src/commands.ts
|
|
1988
|
-
import
|
|
1989
|
-
import
|
|
2510
|
+
import fs20 from "fs";
|
|
2511
|
+
import path20 from "path";
|
|
1990
2512
|
import os18 from "os";
|
|
1991
2513
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
1992
2514
|
import pc6 from "picocolors";
|
|
1993
2515
|
|
|
1994
2516
|
// src/layers/parsers.ts
|
|
1995
|
-
import
|
|
1996
|
-
import
|
|
2517
|
+
import fs6 from "fs";
|
|
2518
|
+
import path6 from "path";
|
|
1997
2519
|
import os5 from "os";
|
|
1998
2520
|
var home = os5.homedir();
|
|
1999
2521
|
var LAYER_FILES = [
|
|
@@ -2031,11 +2553,11 @@ function getLayerSummary(name, content) {
|
|
|
2031
2553
|
}
|
|
2032
2554
|
function getEcosystemStatus(mcpToolCount, amemConnected) {
|
|
2033
2555
|
const layers = LAYER_FILES.map((entry) => {
|
|
2034
|
-
const filePath =
|
|
2035
|
-
const exists =
|
|
2556
|
+
const filePath = path6.join(home, entry.dir, entry.file);
|
|
2557
|
+
const exists = fs6.existsSync(filePath);
|
|
2036
2558
|
let summary = "not configured";
|
|
2037
2559
|
if (exists) {
|
|
2038
|
-
const content =
|
|
2560
|
+
const content = fs6.readFileSync(filePath, "utf-8");
|
|
2039
2561
|
summary = getLayerSummary(entry.name, content);
|
|
2040
2562
|
}
|
|
2041
2563
|
return { name: entry.name, exists, path: filePath, summary };
|
|
@@ -2073,25 +2595,25 @@ import {
|
|
|
2073
2595
|
importFromTeam,
|
|
2074
2596
|
syncToCopilot
|
|
2075
2597
|
} from "@aman_asmuei/amem-core";
|
|
2076
|
-
import
|
|
2598
|
+
import path7 from "path";
|
|
2077
2599
|
import os6 from "os";
|
|
2078
|
-
import
|
|
2600
|
+
import fs7 from "fs";
|
|
2079
2601
|
var db = null;
|
|
2080
2602
|
var currentProject = "global";
|
|
2081
2603
|
async function initMemory(project) {
|
|
2082
2604
|
if (db) return db;
|
|
2083
|
-
const amemDir = process.env.AMEM_DIR ??
|
|
2084
|
-
if (!
|
|
2085
|
-
const dbPath = process.env.AMEM_DB ??
|
|
2605
|
+
const amemDir = process.env.AMEM_DIR ?? path7.join(os6.homedir(), ".amem");
|
|
2606
|
+
if (!fs7.existsSync(amemDir)) fs7.mkdirSync(amemDir, { recursive: true });
|
|
2607
|
+
const dbPath = process.env.AMEM_DB ?? path7.join(amemDir, "memory.db");
|
|
2086
2608
|
try {
|
|
2087
2609
|
db = createDatabase(dbPath);
|
|
2088
2610
|
} catch (err) {
|
|
2089
2611
|
const backupPath = `${dbPath}.corrupt.${Date.now()}`;
|
|
2090
2612
|
try {
|
|
2091
|
-
if (
|
|
2092
|
-
|
|
2093
|
-
if (
|
|
2094
|
-
if (
|
|
2613
|
+
if (fs7.existsSync(dbPath)) {
|
|
2614
|
+
fs7.renameSync(dbPath, backupPath);
|
|
2615
|
+
if (fs7.existsSync(`${dbPath}-wal`)) fs7.unlinkSync(`${dbPath}-wal`);
|
|
2616
|
+
if (fs7.existsSync(`${dbPath}-shm`)) fs7.unlinkSync(`${dbPath}-shm`);
|
|
2095
2617
|
console.error(`[amem] Database corrupted \u2014 backed up to ${backupPath}`);
|
|
2096
2618
|
console.error("[amem] Creating fresh database. Previous memories are in the backup file.");
|
|
2097
2619
|
db = createDatabase(dbPath);
|
|
@@ -2240,7 +2762,7 @@ async function memoryRepair(opts = {}) {
|
|
|
2240
2762
|
actions: diag.issues.map((issue) => `Would fix: ${issue.suggestion}`)
|
|
2241
2763
|
};
|
|
2242
2764
|
}
|
|
2243
|
-
const dbPath = process.env.AMEM_DB ??
|
|
2765
|
+
const dbPath = process.env.AMEM_DB ?? path7.join(os6.homedir(), ".amem", "memory.db");
|
|
2244
2766
|
const result = repairDatabase(dbPath);
|
|
2245
2767
|
return {
|
|
2246
2768
|
dryRun: false,
|
|
@@ -2336,8 +2858,8 @@ async function memorySync(action, opts = {}) {
|
|
|
2336
2858
|
}
|
|
2337
2859
|
|
|
2338
2860
|
// src/profile-templates.ts
|
|
2339
|
-
import
|
|
2340
|
-
import
|
|
2861
|
+
import fs8 from "fs";
|
|
2862
|
+
import path8 from "path";
|
|
2341
2863
|
import os7 from "os";
|
|
2342
2864
|
var BUILT_IN_PROFILES = [
|
|
2343
2865
|
{
|
|
@@ -2431,9 +2953,9 @@ var BUILT_IN_PROFILES = [
|
|
|
2431
2953
|
function installProfileTemplate(templateName, userName) {
|
|
2432
2954
|
const template = BUILT_IN_PROFILES.find((t) => t.name === templateName);
|
|
2433
2955
|
if (!template) return null;
|
|
2434
|
-
const profileDir =
|
|
2435
|
-
if (
|
|
2436
|
-
|
|
2956
|
+
const profileDir = path8.join(os7.homedir(), ".acore", "profiles", template.name);
|
|
2957
|
+
if (fs8.existsSync(profileDir)) return `Profile already exists: ${template.name}`;
|
|
2958
|
+
fs8.mkdirSync(profileDir, { recursive: true });
|
|
2437
2959
|
let core = template.core;
|
|
2438
2960
|
if (userName) {
|
|
2439
2961
|
core += `
|
|
@@ -2447,12 +2969,12 @@ function installProfileTemplate(templateName, userName) {
|
|
|
2447
2969
|
- Detail level: balanced
|
|
2448
2970
|
`;
|
|
2449
2971
|
}
|
|
2450
|
-
|
|
2972
|
+
fs8.writeFileSync(path8.join(profileDir, "core.md"), core, "utf-8");
|
|
2451
2973
|
if (template.rules) {
|
|
2452
|
-
|
|
2974
|
+
fs8.writeFileSync(path8.join(profileDir, "rules.md"), template.rules, "utf-8");
|
|
2453
2975
|
}
|
|
2454
2976
|
if (template.skills) {
|
|
2455
|
-
|
|
2977
|
+
fs8.writeFileSync(path8.join(profileDir, "skills.md"), template.skills, "utf-8");
|
|
2456
2978
|
}
|
|
2457
2979
|
return null;
|
|
2458
2980
|
}
|
|
@@ -2463,21 +2985,21 @@ import pc from "picocolors";
|
|
|
2463
2985
|
|
|
2464
2986
|
// src/showcase-bridge.ts
|
|
2465
2987
|
init_logger();
|
|
2466
|
-
import
|
|
2467
|
-
import
|
|
2988
|
+
import fs9 from "fs";
|
|
2989
|
+
import path9 from "path";
|
|
2468
2990
|
import os8 from "os";
|
|
2469
2991
|
var cachedManifest = null;
|
|
2470
2992
|
var cachedShowcaseRoot = null;
|
|
2471
2993
|
function findShowcaseRoot() {
|
|
2472
2994
|
const candidates = [
|
|
2473
2995
|
// Sibling in monorepo
|
|
2474
|
-
|
|
2475
|
-
|
|
2996
|
+
path9.join(os8.homedir(), "project-aman", "aman-showcase"),
|
|
2997
|
+
path9.join(process.cwd(), "..", "aman-showcase"),
|
|
2476
2998
|
// npm global install
|
|
2477
|
-
|
|
2999
|
+
path9.join(process.cwd(), "node_modules", "@aman_asmuei", "aman-showcase")
|
|
2478
3000
|
];
|
|
2479
3001
|
for (const candidate of candidates) {
|
|
2480
|
-
if (
|
|
3002
|
+
if (fs9.existsSync(path9.join(candidate, "src", "manifest.ts")) || fs9.existsSync(path9.join(candidate, "dist", "index.js"))) {
|
|
2481
3003
|
return candidate;
|
|
2482
3004
|
}
|
|
2483
3005
|
}
|
|
@@ -2507,10 +3029,10 @@ function loadShowcaseManifest() {
|
|
|
2507
3029
|
return cachedManifest;
|
|
2508
3030
|
}
|
|
2509
3031
|
cachedShowcaseRoot = root;
|
|
2510
|
-
const manifestSrc =
|
|
2511
|
-
if (
|
|
3032
|
+
const manifestSrc = path9.join(root, "src", "manifest.ts");
|
|
3033
|
+
if (fs9.existsSync(manifestSrc)) {
|
|
2512
3034
|
try {
|
|
2513
|
-
const content =
|
|
3035
|
+
const content = fs9.readFileSync(manifestSrc, "utf-8");
|
|
2514
3036
|
const parsed = parseManifestSource(content);
|
|
2515
3037
|
if (parsed.length > 0) {
|
|
2516
3038
|
cachedManifest = parsed;
|
|
@@ -2521,7 +3043,7 @@ function loadShowcaseManifest() {
|
|
|
2521
3043
|
}
|
|
2522
3044
|
}
|
|
2523
3045
|
try {
|
|
2524
|
-
const dirs =
|
|
3046
|
+
const dirs = fs9.readdirSync(root, { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith(".") && !["node_modules", "dist", "src", "bin", "docs"].includes(d.name)).filter((d) => fs9.existsSync(path9.join(root, d.name, "identity")));
|
|
2525
3047
|
cachedManifest = dirs.map((d) => ({
|
|
2526
3048
|
name: d.name,
|
|
2527
3049
|
title: d.name.charAt(0).toUpperCase() + d.name.slice(1),
|
|
@@ -2540,69 +3062,69 @@ function installShowcaseTemplate(name) {
|
|
|
2540
3062
|
if (!root) {
|
|
2541
3063
|
throw new Error("aman-showcase package not found. Install it or check the path.");
|
|
2542
3064
|
}
|
|
2543
|
-
const showcaseDir =
|
|
2544
|
-
if (!
|
|
3065
|
+
const showcaseDir = path9.join(root, name);
|
|
3066
|
+
if (!fs9.existsSync(showcaseDir) || !fs9.existsSync(path9.join(showcaseDir, "identity"))) {
|
|
2545
3067
|
throw new Error(`Showcase "${name}" not found in ${root}`);
|
|
2546
3068
|
}
|
|
2547
3069
|
const result = { installed: [], backed_up: [], env_example: "" };
|
|
2548
3070
|
const home2 = os8.homedir();
|
|
2549
3071
|
const copies = [
|
|
2550
3072
|
{
|
|
2551
|
-
src:
|
|
2552
|
-
dest:
|
|
3073
|
+
src: path9.join(showcaseDir, "identity", "core.md"),
|
|
3074
|
+
dest: path9.join(home2, ".acore", "core.md"),
|
|
2553
3075
|
label: "~/.acore/core.md (identity)"
|
|
2554
3076
|
},
|
|
2555
3077
|
{
|
|
2556
|
-
src:
|
|
2557
|
-
dest:
|
|
3078
|
+
src: path9.join(showcaseDir, "workflows", "flow.md"),
|
|
3079
|
+
dest: path9.join(home2, ".aflow", "flow.md"),
|
|
2558
3080
|
label: "~/.aflow/flow.md (workflows)"
|
|
2559
3081
|
},
|
|
2560
3082
|
{
|
|
2561
|
-
src:
|
|
2562
|
-
dest:
|
|
3083
|
+
src: path9.join(showcaseDir, "rules", "rules.md"),
|
|
3084
|
+
dest: path9.join(home2, ".arules", "rules.md"),
|
|
2563
3085
|
label: "~/.arules/rules.md (guardrails)"
|
|
2564
3086
|
}
|
|
2565
3087
|
];
|
|
2566
|
-
const skillsSrc =
|
|
2567
|
-
if (
|
|
2568
|
-
const skillFiles =
|
|
3088
|
+
const skillsSrc = path9.join(showcaseDir, "skills");
|
|
3089
|
+
if (fs9.existsSync(skillsSrc)) {
|
|
3090
|
+
const skillFiles = fs9.readdirSync(skillsSrc).filter((f) => f.endsWith(".md"));
|
|
2569
3091
|
if (skillFiles.length > 0) {
|
|
2570
3092
|
const skillParts = [];
|
|
2571
3093
|
for (const skillFile of skillFiles) {
|
|
2572
|
-
const content =
|
|
3094
|
+
const content = fs9.readFileSync(path9.join(skillsSrc, skillFile), "utf-8").trim();
|
|
2573
3095
|
if (content) skillParts.push(content);
|
|
2574
3096
|
}
|
|
2575
3097
|
if (skillParts.length > 0) {
|
|
2576
|
-
const skillsDest =
|
|
3098
|
+
const skillsDest = path9.join(home2, ".askill", "skills.md");
|
|
2577
3099
|
const consolidated = `# Skills
|
|
2578
3100
|
|
|
2579
3101
|
${skillParts.join("\n\n---\n\n")}
|
|
2580
3102
|
`;
|
|
2581
|
-
if (
|
|
2582
|
-
|
|
3103
|
+
if (fs9.existsSync(skillsDest)) {
|
|
3104
|
+
fs9.copyFileSync(skillsDest, `${skillsDest}.bak`);
|
|
2583
3105
|
result.backed_up.push("~/.askill/skills.md (skills)");
|
|
2584
3106
|
}
|
|
2585
|
-
|
|
2586
|
-
|
|
3107
|
+
fs9.mkdirSync(path9.dirname(skillsDest), { recursive: true });
|
|
3108
|
+
fs9.writeFileSync(skillsDest, consolidated, "utf-8");
|
|
2587
3109
|
result.installed.push(`~/.askill/skills.md (${skillFiles.length} skill${skillFiles.length > 1 ? "s" : ""} consolidated)`);
|
|
2588
3110
|
}
|
|
2589
3111
|
}
|
|
2590
3112
|
}
|
|
2591
3113
|
for (const { src, dest, label } of copies) {
|
|
2592
|
-
if (!
|
|
2593
|
-
if (
|
|
3114
|
+
if (!fs9.existsSync(src)) continue;
|
|
3115
|
+
if (fs9.existsSync(dest)) {
|
|
2594
3116
|
const backup = `${dest}.bak`;
|
|
2595
|
-
|
|
3117
|
+
fs9.copyFileSync(dest, backup);
|
|
2596
3118
|
result.backed_up.push(label);
|
|
2597
3119
|
}
|
|
2598
|
-
|
|
2599
|
-
|
|
3120
|
+
fs9.mkdirSync(path9.dirname(dest), { recursive: true });
|
|
3121
|
+
fs9.copyFileSync(src, dest);
|
|
2600
3122
|
result.installed.push(label);
|
|
2601
3123
|
}
|
|
2602
|
-
const envExample =
|
|
2603
|
-
if (
|
|
2604
|
-
const destEnv =
|
|
2605
|
-
|
|
3124
|
+
const envExample = path9.join(showcaseDir, "config", "telegram.env.example");
|
|
3125
|
+
if (fs9.existsSync(envExample)) {
|
|
3126
|
+
const destEnv = path9.join(process.cwd(), ".env.example");
|
|
3127
|
+
fs9.copyFileSync(envExample, destEnv);
|
|
2606
3128
|
result.env_example = destEnv;
|
|
2607
3129
|
}
|
|
2608
3130
|
log.debug("showcase", `Installed showcase: ${name} (${result.installed.length} files)`);
|
|
@@ -2862,31 +3384,31 @@ async function editProfile(current) {
|
|
|
2862
3384
|
}
|
|
2863
3385
|
|
|
2864
3386
|
// src/files.ts
|
|
2865
|
-
import
|
|
2866
|
-
import
|
|
3387
|
+
import fs10 from "fs";
|
|
3388
|
+
import path10 from "path";
|
|
2867
3389
|
import os9 from "os";
|
|
2868
3390
|
var MAX_READ_BYTES = 5e4;
|
|
2869
|
-
var HOME =
|
|
2870
|
-
var TMPDIR =
|
|
2871
|
-
var CWD =
|
|
3391
|
+
var HOME = fs10.realpathSync(os9.homedir());
|
|
3392
|
+
var TMPDIR = fs10.realpathSync(os9.tmpdir());
|
|
3393
|
+
var CWD = fs10.realpathSync(process.cwd());
|
|
2872
3394
|
function realOrBest(p5) {
|
|
2873
|
-
const parts = p5.split(
|
|
3395
|
+
const parts = p5.split(path10.sep);
|
|
2874
3396
|
for (let i = parts.length; i > 0; i--) {
|
|
2875
|
-
const candidate = parts.slice(0, i).join(
|
|
3397
|
+
const candidate = parts.slice(0, i).join(path10.sep) || path10.sep;
|
|
2876
3398
|
try {
|
|
2877
|
-
const real =
|
|
2878
|
-
const remainder = parts.slice(i).join(
|
|
2879
|
-
return remainder ? `${real}${
|
|
3399
|
+
const real = fs10.realpathSync(candidate);
|
|
3400
|
+
const remainder = parts.slice(i).join(path10.sep);
|
|
3401
|
+
return remainder ? `${real}${path10.sep}${remainder}` : real;
|
|
2880
3402
|
} catch {
|
|
2881
3403
|
}
|
|
2882
3404
|
}
|
|
2883
3405
|
return p5;
|
|
2884
3406
|
}
|
|
2885
3407
|
function isUnderDir(real, dir) {
|
|
2886
|
-
return real === dir || real.startsWith(dir +
|
|
3408
|
+
return real === dir || real.startsWith(dir + path10.sep);
|
|
2887
3409
|
}
|
|
2888
3410
|
function assertSafePath(filePath) {
|
|
2889
|
-
const resolved =
|
|
3411
|
+
const resolved = path10.resolve(filePath);
|
|
2890
3412
|
const real = realOrBest(resolved);
|
|
2891
3413
|
if (!isUnderDir(real, HOME) && !isUnderDir(real, CWD) && !isUnderDir(real, TMPDIR)) {
|
|
2892
3414
|
throw new Error(`Path is outside allowed directories (home or cwd): ${real}`);
|
|
@@ -2895,20 +3417,20 @@ function assertSafePath(filePath) {
|
|
|
2895
3417
|
}
|
|
2896
3418
|
async function readFile(filePath) {
|
|
2897
3419
|
const resolved = assertSafePath(filePath);
|
|
2898
|
-
if (!
|
|
3420
|
+
if (!fs10.existsSync(resolved)) {
|
|
2899
3421
|
throw new Error(`File not found: ${resolved}`);
|
|
2900
3422
|
}
|
|
2901
|
-
const stat =
|
|
3423
|
+
const stat = fs10.statSync(resolved);
|
|
2902
3424
|
if (stat.isDirectory()) {
|
|
2903
3425
|
throw new Error(`Path is a directory, not a file: ${resolved}. Use /file list instead.`);
|
|
2904
3426
|
}
|
|
2905
3427
|
const size = stat.size;
|
|
2906
3428
|
const buf = Buffer.alloc(Math.min(size, MAX_READ_BYTES));
|
|
2907
|
-
const fd =
|
|
3429
|
+
const fd = fs10.openSync(resolved, "r");
|
|
2908
3430
|
try {
|
|
2909
|
-
|
|
3431
|
+
fs10.readSync(fd, buf, 0, buf.length, 0);
|
|
2910
3432
|
} finally {
|
|
2911
|
-
|
|
3433
|
+
fs10.closeSync(fd);
|
|
2912
3434
|
}
|
|
2913
3435
|
return {
|
|
2914
3436
|
path: resolved,
|
|
@@ -2920,23 +3442,23 @@ async function readFile(filePath) {
|
|
|
2920
3442
|
}
|
|
2921
3443
|
async function listFiles(dirPath, opts = {}) {
|
|
2922
3444
|
const resolved = assertSafePath(dirPath);
|
|
2923
|
-
if (!
|
|
3445
|
+
if (!fs10.existsSync(resolved)) {
|
|
2924
3446
|
throw new Error(`Directory not found: ${resolved}`);
|
|
2925
3447
|
}
|
|
2926
|
-
const stat =
|
|
3448
|
+
const stat = fs10.statSync(resolved);
|
|
2927
3449
|
if (!stat.isDirectory()) {
|
|
2928
3450
|
throw new Error(`Path is a file, not a directory: ${resolved}. Use /file read instead.`);
|
|
2929
3451
|
}
|
|
2930
3452
|
const entries = [];
|
|
2931
3453
|
function walk(dir, prefix) {
|
|
2932
|
-
const items =
|
|
3454
|
+
const items = fs10.readdirSync(dir, { withFileTypes: true });
|
|
2933
3455
|
for (const item of items) {
|
|
2934
3456
|
const rel = prefix ? `${prefix}/${item.name}` : item.name;
|
|
2935
3457
|
if (item.isDirectory()) {
|
|
2936
3458
|
entries.push({ name: rel, type: "dir", size: 0 });
|
|
2937
|
-
if (opts.recursive) walk(
|
|
3459
|
+
if (opts.recursive) walk(path10.join(dir, item.name), rel);
|
|
2938
3460
|
} else {
|
|
2939
|
-
const s =
|
|
3461
|
+
const s = fs10.statSync(path10.join(dir, item.name));
|
|
2940
3462
|
entries.push({ name: rel, type: "file", size: s.size });
|
|
2941
3463
|
}
|
|
2942
3464
|
}
|
|
@@ -2953,8 +3475,8 @@ init_logger();
|
|
|
2953
3475
|
init_logger();
|
|
2954
3476
|
import pc2 from "picocolors";
|
|
2955
3477
|
import * as p2 from "@clack/prompts";
|
|
2956
|
-
import
|
|
2957
|
-
import
|
|
3478
|
+
import fs15 from "fs";
|
|
3479
|
+
import path15 from "path";
|
|
2958
3480
|
import os13 from "os";
|
|
2959
3481
|
|
|
2960
3482
|
// src/personality.ts
|
|
@@ -3149,13 +3671,13 @@ async function syncPersonalityToCore(state, mcpManager, modelMetrics) {
|
|
|
3149
3671
|
}
|
|
3150
3672
|
|
|
3151
3673
|
// src/postmortem.ts
|
|
3152
|
-
import
|
|
3153
|
-
import
|
|
3674
|
+
import fs12 from "fs/promises";
|
|
3675
|
+
import path12 from "path";
|
|
3154
3676
|
import os11 from "os";
|
|
3155
3677
|
|
|
3156
3678
|
// src/observation.ts
|
|
3157
|
-
import
|
|
3158
|
-
import
|
|
3679
|
+
import fs11 from "fs/promises";
|
|
3680
|
+
import path11 from "path";
|
|
3159
3681
|
import os10 from "os";
|
|
3160
3682
|
var STAT_MAP = {
|
|
3161
3683
|
tool_call: "toolCalls",
|
|
@@ -3166,7 +3688,7 @@ var STAT_MAP = {
|
|
|
3166
3688
|
file_change: "fileChanges"
|
|
3167
3689
|
};
|
|
3168
3690
|
function defaultObservationsDir() {
|
|
3169
|
-
return
|
|
3691
|
+
return path11.join(os10.homedir(), ".acore", "observations");
|
|
3170
3692
|
}
|
|
3171
3693
|
function createObservationSession(sessionId) {
|
|
3172
3694
|
return {
|
|
@@ -3202,17 +3724,17 @@ function resumeObservation(session) {
|
|
|
3202
3724
|
async function flushEvents(session, dir) {
|
|
3203
3725
|
if (session.events.length === 0) return;
|
|
3204
3726
|
const obsDir = dir ?? defaultObservationsDir();
|
|
3205
|
-
await
|
|
3206
|
-
const filePath =
|
|
3727
|
+
await fs11.mkdir(obsDir, { recursive: true });
|
|
3728
|
+
const filePath = path11.join(obsDir, `${session.sessionId}.jsonl`);
|
|
3207
3729
|
const lines = session.events.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
3208
|
-
await
|
|
3730
|
+
await fs11.appendFile(filePath, lines, "utf-8");
|
|
3209
3731
|
session.events.length = 0;
|
|
3210
3732
|
}
|
|
3211
3733
|
async function readObservationEvents(sessionId, dir) {
|
|
3212
3734
|
const obsDir = dir ?? defaultObservationsDir();
|
|
3213
|
-
const filePath =
|
|
3735
|
+
const filePath = path11.join(obsDir, `${sessionId}.jsonl`);
|
|
3214
3736
|
try {
|
|
3215
|
-
const content = await
|
|
3737
|
+
const content = await fs11.readFile(filePath, "utf-8");
|
|
3216
3738
|
return content.trim().split("\n").filter((line) => line.length > 0).map((line) => JSON.parse(line));
|
|
3217
3739
|
} catch {
|
|
3218
3740
|
return [];
|
|
@@ -3235,14 +3757,14 @@ function getSessionStats(session) {
|
|
|
3235
3757
|
async function cleanupOldObservations(dir, maxAgeDays = 30) {
|
|
3236
3758
|
const obsDir = dir ?? defaultObservationsDir();
|
|
3237
3759
|
try {
|
|
3238
|
-
const files = await
|
|
3760
|
+
const files = await fs11.readdir(obsDir);
|
|
3239
3761
|
const cutoff = Date.now() - maxAgeDays * 24 * 60 * 60 * 1e3;
|
|
3240
3762
|
for (const file of files) {
|
|
3241
3763
|
if (!file.endsWith(".jsonl")) continue;
|
|
3242
|
-
const filePath =
|
|
3243
|
-
const stat = await
|
|
3764
|
+
const filePath = path11.join(obsDir, file);
|
|
3765
|
+
const stat = await fs11.stat(filePath);
|
|
3244
3766
|
if (stat.mtimeMs < cutoff) {
|
|
3245
|
-
await
|
|
3767
|
+
await fs11.unlink(filePath);
|
|
3246
3768
|
}
|
|
3247
3769
|
}
|
|
3248
3770
|
} catch {
|
|
@@ -3269,10 +3791,10 @@ function detectTopicShift(recentMessages, previousMessages) {
|
|
|
3269
3791
|
// src/postmortem.ts
|
|
3270
3792
|
init_logger();
|
|
3271
3793
|
function defaultPostmortemsDir() {
|
|
3272
|
-
return
|
|
3794
|
+
return path12.join(os11.homedir(), ".acore", "postmortems");
|
|
3273
3795
|
}
|
|
3274
3796
|
function defaultObservationsDir2() {
|
|
3275
|
-
return
|
|
3797
|
+
return path12.join(os11.homedir(), ".acore", "observations");
|
|
3276
3798
|
}
|
|
3277
3799
|
function shouldAutoPostmortem(session, messages) {
|
|
3278
3800
|
if (messages.length < 6) return false;
|
|
@@ -3491,15 +4013,15 @@ function formatPostmortemMarkdown(report) {
|
|
|
3491
4013
|
}
|
|
3492
4014
|
async function savePostmortem(report, dir) {
|
|
3493
4015
|
const pmDir = dir ?? defaultPostmortemsDir();
|
|
3494
|
-
await
|
|
4016
|
+
await fs12.mkdir(pmDir, { recursive: true });
|
|
3495
4017
|
const shortId = report.sessionId.slice(0, 4);
|
|
3496
4018
|
const fileName = `${report.date}-${shortId}.md`;
|
|
3497
|
-
const filePath =
|
|
4019
|
+
const filePath = path12.join(pmDir, fileName);
|
|
3498
4020
|
const markdown = formatPostmortemMarkdown(report);
|
|
3499
|
-
await
|
|
4021
|
+
await fs12.writeFile(filePath, markdown, "utf-8");
|
|
3500
4022
|
const jsonPath = filePath.replace(/\.md$/, ".json");
|
|
3501
4023
|
try {
|
|
3502
|
-
await
|
|
4024
|
+
await fs12.writeFile(jsonPath, JSON.stringify(report, null, 2), "utf-8");
|
|
3503
4025
|
} catch (err) {
|
|
3504
4026
|
log.debug("postmortem", "JSON sidecar write failed", err);
|
|
3505
4027
|
}
|
|
@@ -3508,7 +4030,7 @@ async function savePostmortem(report, dir) {
|
|
|
3508
4030
|
async function listPostmortems(dir) {
|
|
3509
4031
|
const pmDir = dir ?? defaultPostmortemsDir();
|
|
3510
4032
|
try {
|
|
3511
|
-
const files = await
|
|
4033
|
+
const files = await fs12.readdir(pmDir);
|
|
3512
4034
|
return files.filter((f) => f.endsWith(".md")).sort().reverse();
|
|
3513
4035
|
} catch {
|
|
3514
4036
|
return [];
|
|
@@ -3518,7 +4040,7 @@ async function readPostmortem(name, dir) {
|
|
|
3518
4040
|
const pmDir = dir ?? defaultPostmortemsDir();
|
|
3519
4041
|
const fileName = name.endsWith(".md") ? name : `${name}.md`;
|
|
3520
4042
|
try {
|
|
3521
|
-
return await
|
|
4043
|
+
return await fs12.readFile(path12.join(pmDir, fileName), "utf-8");
|
|
3522
4044
|
} catch {
|
|
3523
4045
|
return null;
|
|
3524
4046
|
}
|
|
@@ -3565,8 +4087,8 @@ ${contents.join("\n\n---\n\n")}`
|
|
|
3565
4087
|
|
|
3566
4088
|
// src/crystallization.ts
|
|
3567
4089
|
init_logger();
|
|
3568
|
-
import
|
|
3569
|
-
import
|
|
4090
|
+
import fs13 from "fs/promises";
|
|
4091
|
+
import path13 from "path";
|
|
3570
4092
|
var STOPWORDS = /* @__PURE__ */ new Set([
|
|
3571
4093
|
"the",
|
|
3572
4094
|
"and",
|
|
@@ -3731,10 +4253,10 @@ function findCollision(name, triggers, existing) {
|
|
|
3731
4253
|
}
|
|
3732
4254
|
async function writeSkillToFile(candidate, skillsMdPath, postmortemFilename) {
|
|
3733
4255
|
try {
|
|
3734
|
-
await
|
|
4256
|
+
await fs13.mkdir(path13.dirname(skillsMdPath), { recursive: true });
|
|
3735
4257
|
let existingContent = "";
|
|
3736
4258
|
try {
|
|
3737
|
-
existingContent = await
|
|
4259
|
+
existingContent = await fs13.readFile(skillsMdPath, "utf-8");
|
|
3738
4260
|
} catch {
|
|
3739
4261
|
existingContent = "# Skills\n\n";
|
|
3740
4262
|
}
|
|
@@ -3755,7 +4277,7 @@ async function writeSkillToFile(candidate, skillsMdPath, postmortemFilename) {
|
|
|
3755
4277
|
}
|
|
3756
4278
|
const skillMarkdown = formatSkillMarkdown(candidate, postmortemFilename);
|
|
3757
4279
|
const separator = existingContent.endsWith("\n\n") ? "" : existingContent.endsWith("\n") ? "\n" : "\n\n";
|
|
3758
|
-
await
|
|
4280
|
+
await fs13.writeFile(
|
|
3759
4281
|
skillsMdPath,
|
|
3760
4282
|
existingContent + separator + skillMarkdown,
|
|
3761
4283
|
"utf-8"
|
|
@@ -3777,7 +4299,7 @@ async function writeSkillToFile(candidate, skillsMdPath, postmortemFilename) {
|
|
|
3777
4299
|
}
|
|
3778
4300
|
async function mergeSkillInFile(candidate, existingName, skillsMdPath, postmortemFilename) {
|
|
3779
4301
|
try {
|
|
3780
|
-
const content = await
|
|
4302
|
+
const content = await fs13.readFile(skillsMdPath, "utf-8");
|
|
3781
4303
|
const lines = content.split("\n");
|
|
3782
4304
|
const heading = toTitleCase(existingName);
|
|
3783
4305
|
let startIdx = -1;
|
|
@@ -3818,7 +4340,7 @@ async function mergeSkillInFile(candidate, existingName, skillsMdPath, postmorte
|
|
|
3818
4340
|
const before = lines.slice(0, startIdx);
|
|
3819
4341
|
const after = lines.slice(endIdx);
|
|
3820
4342
|
const merged = [...before, ...oldBlock, "", newSkillMarkdown, ...after].join("\n");
|
|
3821
|
-
await
|
|
4343
|
+
await fs13.writeFile(skillsMdPath, merged, "utf-8");
|
|
3822
4344
|
return {
|
|
3823
4345
|
written: true,
|
|
3824
4346
|
filePath: skillsMdPath,
|
|
@@ -3837,27 +4359,27 @@ async function mergeSkillInFile(candidate, existingName, skillsMdPath, postmorte
|
|
|
3837
4359
|
}
|
|
3838
4360
|
async function appendCrystallizationLog(entry, logPath) {
|
|
3839
4361
|
try {
|
|
3840
|
-
await
|
|
4362
|
+
await fs13.mkdir(path13.dirname(logPath), { recursive: true });
|
|
3841
4363
|
let existing = [];
|
|
3842
4364
|
try {
|
|
3843
|
-
const content = await
|
|
4365
|
+
const content = await fs13.readFile(logPath, "utf-8");
|
|
3844
4366
|
existing = JSON.parse(content);
|
|
3845
4367
|
if (!Array.isArray(existing)) existing = [];
|
|
3846
4368
|
} catch {
|
|
3847
4369
|
existing = [];
|
|
3848
4370
|
}
|
|
3849
4371
|
existing.push(entry);
|
|
3850
|
-
await
|
|
4372
|
+
await fs13.writeFile(logPath, JSON.stringify(existing, null, 2), "utf-8");
|
|
3851
4373
|
} catch (err) {
|
|
3852
4374
|
log.debug("crystallization", "appendCrystallizationLog failed", err);
|
|
3853
4375
|
}
|
|
3854
4376
|
}
|
|
3855
4377
|
async function appendRejection(candidate, postmortemFilename, rejectionsPath) {
|
|
3856
4378
|
try {
|
|
3857
|
-
await
|
|
4379
|
+
await fs13.mkdir(path13.dirname(rejectionsPath), { recursive: true });
|
|
3858
4380
|
let existing = [];
|
|
3859
4381
|
try {
|
|
3860
|
-
const content = await
|
|
4382
|
+
const content = await fs13.readFile(rejectionsPath, "utf-8");
|
|
3861
4383
|
existing = JSON.parse(content);
|
|
3862
4384
|
if (!Array.isArray(existing)) existing = [];
|
|
3863
4385
|
} catch {
|
|
@@ -3872,14 +4394,14 @@ async function appendRejection(candidate, postmortemFilename, rejectionsPath) {
|
|
|
3872
4394
|
while (existing.length > MAX_REJECTIONS) {
|
|
3873
4395
|
existing.shift();
|
|
3874
4396
|
}
|
|
3875
|
-
await
|
|
4397
|
+
await fs13.writeFile(rejectionsPath, JSON.stringify(existing, null, 2), "utf-8");
|
|
3876
4398
|
} catch (err) {
|
|
3877
4399
|
log.debug("crystallization", "appendRejection failed", err);
|
|
3878
4400
|
}
|
|
3879
4401
|
}
|
|
3880
4402
|
async function loadRejectedNames(rejectionsPath) {
|
|
3881
4403
|
try {
|
|
3882
|
-
const content = await
|
|
4404
|
+
const content = await fs13.readFile(rejectionsPath, "utf-8");
|
|
3883
4405
|
const entries = JSON.parse(content);
|
|
3884
4406
|
if (!Array.isArray(entries)) return [];
|
|
3885
4407
|
return [...new Set(entries.map((e) => e.name))];
|
|
@@ -3889,7 +4411,7 @@ async function loadRejectedNames(rejectionsPath) {
|
|
|
3889
4411
|
}
|
|
3890
4412
|
async function loadSuggestionCounts(suggestionsPath) {
|
|
3891
4413
|
try {
|
|
3892
|
-
const content = await
|
|
4414
|
+
const content = await fs13.readFile(suggestionsPath, "utf-8");
|
|
3893
4415
|
const parsed = JSON.parse(content);
|
|
3894
4416
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return {};
|
|
3895
4417
|
return parsed;
|
|
@@ -3899,10 +4421,10 @@ async function loadSuggestionCounts(suggestionsPath) {
|
|
|
3899
4421
|
}
|
|
3900
4422
|
async function incrementSuggestionCount(name, suggestionsPath) {
|
|
3901
4423
|
try {
|
|
3902
|
-
await
|
|
4424
|
+
await fs13.mkdir(path13.dirname(suggestionsPath), { recursive: true });
|
|
3903
4425
|
const counts = await loadSuggestionCounts(suggestionsPath);
|
|
3904
4426
|
counts[name] = (counts[name] || 0) + 1;
|
|
3905
|
-
await
|
|
4427
|
+
await fs13.writeFile(suggestionsPath, JSON.stringify(counts, null, 2), "utf-8");
|
|
3906
4428
|
return counts[name];
|
|
3907
4429
|
} catch (err) {
|
|
3908
4430
|
log.debug("crystallization", "incrementSuggestionCount failed", err);
|
|
@@ -4213,10 +4735,10 @@ async function onSessionEnd(ctx, messages, sessionId, observationSession) {
|
|
|
4213
4735
|
}
|
|
4214
4736
|
console.log(pc2.dim(` Saved ${textMessages.length} messages (session: ${sessionId})`));
|
|
4215
4737
|
}
|
|
4216
|
-
const projectContextPath =
|
|
4217
|
-
if (
|
|
4738
|
+
const projectContextPath = path15.join(process.cwd(), ".acore", "context.md");
|
|
4739
|
+
if (fs15.existsSync(projectContextPath) && messages.length > 2) {
|
|
4218
4740
|
try {
|
|
4219
|
-
let contextContent =
|
|
4741
|
+
let contextContent = fs15.readFileSync(projectContextPath, "utf-8");
|
|
4220
4742
|
const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
4221
4743
|
let lastUserMsg = "";
|
|
4222
4744
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
@@ -4234,7 +4756,7 @@ async function onSessionEnd(ctx, messages, sessionId, observationSession) {
|
|
|
4234
4756
|
- Recent decisions: [see memory]
|
|
4235
4757
|
- Temp notes: [cleared]`;
|
|
4236
4758
|
contextContent = contextContent.replace(sessionPattern, newSession);
|
|
4237
|
-
|
|
4759
|
+
fs15.writeFileSync(projectContextPath, contextContent, "utf-8");
|
|
4238
4760
|
log.debug("hooks", `Updated project context: ${projectContextPath}`);
|
|
4239
4761
|
}
|
|
4240
4762
|
} catch (err) {
|
|
@@ -4338,7 +4860,7 @@ async function onSessionEnd(ctx, messages, sessionId, observationSession) {
|
|
|
4338
4860
|
try {
|
|
4339
4861
|
const client = ctx.llmClient;
|
|
4340
4862
|
if (client) {
|
|
4341
|
-
const rejectionsPath =
|
|
4863
|
+
const rejectionsPath = path15.join(
|
|
4342
4864
|
os13.homedir(),
|
|
4343
4865
|
".aman-agent",
|
|
4344
4866
|
"crystallization-rejections.json"
|
|
@@ -4368,18 +4890,18 @@ async function onSessionEnd(ctx, messages, sessionId, observationSession) {
|
|
|
4368
4890
|
}
|
|
4369
4891
|
}
|
|
4370
4892
|
if (report.crystallizationCandidates && report.crystallizationCandidates.length > 0) {
|
|
4371
|
-
const skillsMdPath =
|
|
4372
|
-
const logPath =
|
|
4893
|
+
const skillsMdPath = path15.join(os13.homedir(), ".askill", "skills.md");
|
|
4894
|
+
const logPath = path15.join(
|
|
4373
4895
|
os13.homedir(),
|
|
4374
4896
|
".aman-agent",
|
|
4375
4897
|
"crystallization-log.json"
|
|
4376
4898
|
);
|
|
4377
|
-
const rejectionsPath2 =
|
|
4899
|
+
const rejectionsPath2 = path15.join(
|
|
4378
4900
|
os13.homedir(),
|
|
4379
4901
|
".aman-agent",
|
|
4380
4902
|
"crystallization-rejections.json"
|
|
4381
4903
|
);
|
|
4382
|
-
const suggestionsPath =
|
|
4904
|
+
const suggestionsPath = path15.join(
|
|
4383
4905
|
os13.homedir(),
|
|
4384
4906
|
".aman-agent",
|
|
4385
4907
|
"crystallization-suggestions.json"
|
|
@@ -4526,12 +5048,12 @@ You are being delegated a specific task by the primary agent. Complete this task
|
|
|
4526
5048
|
</delegation>`;
|
|
4527
5049
|
let finalDelegationPrompt = delegationPrompt;
|
|
4528
5050
|
try {
|
|
4529
|
-
const
|
|
4530
|
-
if (
|
|
5051
|
+
const recall3 = await memoryRecall(task, { limit: 3, compact: true });
|
|
5052
|
+
if (recall3.total > 0) {
|
|
4531
5053
|
finalDelegationPrompt += `
|
|
4532
5054
|
|
|
4533
5055
|
<relevant-memories>
|
|
4534
|
-
${
|
|
5056
|
+
${recall3.text}
|
|
4535
5057
|
</relevant-memories>`;
|
|
4536
5058
|
}
|
|
4537
5059
|
} catch {
|
|
@@ -4658,43 +5180,43 @@ import { StreamableHTTPClientTransport as StreamableHTTPClientTransport2 } from
|
|
|
4658
5180
|
import { Client as Client3 } from "@modelcontextprotocol/sdk/client/index.js";
|
|
4659
5181
|
|
|
4660
5182
|
// src/teams.ts
|
|
4661
|
-
import
|
|
4662
|
-
import
|
|
5183
|
+
import fs17 from "fs";
|
|
5184
|
+
import path17 from "path";
|
|
4663
5185
|
import os15 from "os";
|
|
4664
5186
|
import pc4 from "picocolors";
|
|
4665
5187
|
function getTeamsDir() {
|
|
4666
|
-
return
|
|
5188
|
+
return path17.join(os15.homedir(), ".acore", "teams");
|
|
4667
5189
|
}
|
|
4668
5190
|
function ensureTeamsDir() {
|
|
4669
5191
|
const dir = getTeamsDir();
|
|
4670
|
-
if (!
|
|
5192
|
+
if (!fs17.existsSync(dir)) fs17.mkdirSync(dir, { recursive: true });
|
|
4671
5193
|
return dir;
|
|
4672
5194
|
}
|
|
4673
5195
|
function teamPath(name) {
|
|
4674
5196
|
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
4675
|
-
return
|
|
5197
|
+
return path17.join(ensureTeamsDir(), `${slug}.json`);
|
|
4676
5198
|
}
|
|
4677
5199
|
function createTeam(team) {
|
|
4678
5200
|
const fp = teamPath(team.name);
|
|
4679
|
-
|
|
5201
|
+
fs17.writeFileSync(fp, JSON.stringify(team, null, 2), "utf-8");
|
|
4680
5202
|
}
|
|
4681
5203
|
function loadTeam(name) {
|
|
4682
5204
|
const fp = teamPath(name);
|
|
4683
|
-
if (!
|
|
5205
|
+
if (!fs17.existsSync(fp)) return null;
|
|
4684
5206
|
try {
|
|
4685
|
-
return JSON.parse(
|
|
5207
|
+
return JSON.parse(fs17.readFileSync(fp, "utf-8"));
|
|
4686
5208
|
} catch {
|
|
4687
5209
|
return null;
|
|
4688
5210
|
}
|
|
4689
5211
|
}
|
|
4690
5212
|
function listTeams() {
|
|
4691
5213
|
const dir = getTeamsDir();
|
|
4692
|
-
if (!
|
|
5214
|
+
if (!fs17.existsSync(dir)) return [];
|
|
4693
5215
|
const teams = [];
|
|
4694
|
-
for (const file of
|
|
5216
|
+
for (const file of fs17.readdirSync(dir)) {
|
|
4695
5217
|
if (!file.endsWith(".json")) continue;
|
|
4696
5218
|
try {
|
|
4697
|
-
const content =
|
|
5219
|
+
const content = fs17.readFileSync(path17.join(dir, file), "utf-8");
|
|
4698
5220
|
teams.push(JSON.parse(content));
|
|
4699
5221
|
} catch {
|
|
4700
5222
|
}
|
|
@@ -4703,8 +5225,8 @@ function listTeams() {
|
|
|
4703
5225
|
}
|
|
4704
5226
|
function deleteTeam(name) {
|
|
4705
5227
|
const fp = teamPath(name);
|
|
4706
|
-
if (!
|
|
4707
|
-
|
|
5228
|
+
if (!fs17.existsSync(fp)) return false;
|
|
5229
|
+
fs17.unlinkSync(fp);
|
|
4708
5230
|
return true;
|
|
4709
5231
|
}
|
|
4710
5232
|
async function runTeam(team, task, client, mcpManager, tools) {
|
|
@@ -4931,23 +5453,23 @@ var BUILT_IN_TEAMS = [
|
|
|
4931
5453
|
|
|
4932
5454
|
// src/plans.ts
|
|
4933
5455
|
init_logger();
|
|
4934
|
-
import
|
|
4935
|
-
import
|
|
5456
|
+
import fs18 from "fs";
|
|
5457
|
+
import path18 from "path";
|
|
4936
5458
|
import os16 from "os";
|
|
4937
5459
|
function getPlansDir() {
|
|
4938
|
-
const localDir =
|
|
4939
|
-
const localAcore =
|
|
4940
|
-
if (
|
|
4941
|
-
return
|
|
5460
|
+
const localDir = path18.join(process.cwd(), ".acore", "plans");
|
|
5461
|
+
const localAcore = path18.join(process.cwd(), ".acore");
|
|
5462
|
+
if (fs18.existsSync(localAcore)) return localDir;
|
|
5463
|
+
return path18.join(os16.homedir(), ".acore", "plans");
|
|
4942
5464
|
}
|
|
4943
5465
|
function ensurePlansDir() {
|
|
4944
5466
|
const dir = getPlansDir();
|
|
4945
|
-
if (!
|
|
5467
|
+
if (!fs18.existsSync(dir)) fs18.mkdirSync(dir, { recursive: true });
|
|
4946
5468
|
return dir;
|
|
4947
5469
|
}
|
|
4948
5470
|
function planPath(name) {
|
|
4949
5471
|
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
4950
|
-
return
|
|
5472
|
+
return path18.join(ensurePlansDir(), `${slug}.md`);
|
|
4951
5473
|
}
|
|
4952
5474
|
function serializePlan(plan) {
|
|
4953
5475
|
const lines = [];
|
|
@@ -4973,7 +5495,7 @@ function parsePlan(content, filePath) {
|
|
|
4973
5495
|
const createdMatch = content.match(/\*\*Created:\*\*\s*(.+)/);
|
|
4974
5496
|
const updatedMatch = content.match(/\*\*Updated:\*\*\s*(.+)/);
|
|
4975
5497
|
const activeMatch = content.match(/\*\*Active:\*\*\s*(.+)/);
|
|
4976
|
-
const name = nameMatch?.[1]?.trim() ||
|
|
5498
|
+
const name = nameMatch?.[1]?.trim() || path18.basename(filePath, ".md");
|
|
4977
5499
|
const goal = goalMatch?.[1]?.trim() || "";
|
|
4978
5500
|
const createdAt = createdMatch?.[1]?.trim() || "";
|
|
4979
5501
|
const updatedAt = updatedMatch?.[1]?.trim() || "";
|
|
@@ -5015,22 +5537,22 @@ function createPlan(name, goal, steps) {
|
|
|
5015
5537
|
}
|
|
5016
5538
|
function savePlan(plan) {
|
|
5017
5539
|
const fp = planPath(plan.name);
|
|
5018
|
-
|
|
5540
|
+
fs18.writeFileSync(fp, serializePlan(plan), "utf-8");
|
|
5019
5541
|
}
|
|
5020
5542
|
function loadPlan(name) {
|
|
5021
5543
|
const fp = planPath(name);
|
|
5022
|
-
if (!
|
|
5023
|
-
const content =
|
|
5544
|
+
if (!fs18.existsSync(fp)) return null;
|
|
5545
|
+
const content = fs18.readFileSync(fp, "utf-8");
|
|
5024
5546
|
return parsePlan(content, fp);
|
|
5025
5547
|
}
|
|
5026
5548
|
function listPlans() {
|
|
5027
5549
|
const dir = getPlansDir();
|
|
5028
|
-
if (!
|
|
5550
|
+
if (!fs18.existsSync(dir)) return [];
|
|
5029
5551
|
const plans = [];
|
|
5030
|
-
for (const file of
|
|
5552
|
+
for (const file of fs18.readdirSync(dir)) {
|
|
5031
5553
|
if (!file.endsWith(".md")) continue;
|
|
5032
|
-
const fp =
|
|
5033
|
-
const content =
|
|
5554
|
+
const fp = path18.join(dir, file);
|
|
5555
|
+
const content = fs18.readFileSync(fp, "utf-8");
|
|
5034
5556
|
const plan = parsePlan(content, fp);
|
|
5035
5557
|
if (plan) plans.push(plan);
|
|
5036
5558
|
}
|
|
@@ -5129,8 +5651,8 @@ init_user_model();
|
|
|
5129
5651
|
|
|
5130
5652
|
// src/background.ts
|
|
5131
5653
|
init_logger();
|
|
5132
|
-
import
|
|
5133
|
-
import
|
|
5654
|
+
import fs19 from "fs";
|
|
5655
|
+
import path19 from "path";
|
|
5134
5656
|
import os17 from "os";
|
|
5135
5657
|
import pc5 from "picocolors";
|
|
5136
5658
|
var BACKGROUND_ELIGIBLE = /* @__PURE__ */ new Set([
|
|
@@ -5170,13 +5692,13 @@ var NEVER_BACKGROUND = /* @__PURE__ */ new Set([
|
|
|
5170
5692
|
"file_list",
|
|
5171
5693
|
"avatar_prompt"
|
|
5172
5694
|
]);
|
|
5173
|
-
var TASK_LOG_DIR =
|
|
5174
|
-
var TASK_LOG_FILE =
|
|
5695
|
+
var TASK_LOG_DIR = path19.join(os17.homedir(), ".aman-agent");
|
|
5696
|
+
var TASK_LOG_FILE = path19.join(TASK_LOG_DIR, "bg-tasks.json");
|
|
5175
5697
|
var MAX_LOG_ENTRIES = 50;
|
|
5176
5698
|
function loadTaskLog() {
|
|
5177
5699
|
try {
|
|
5178
|
-
if (!
|
|
5179
|
-
const raw =
|
|
5700
|
+
if (!fs19.existsSync(TASK_LOG_FILE)) return [];
|
|
5701
|
+
const raw = fs19.readFileSync(TASK_LOG_FILE, "utf-8");
|
|
5180
5702
|
return JSON.parse(raw);
|
|
5181
5703
|
} catch {
|
|
5182
5704
|
return [];
|
|
@@ -5184,9 +5706,9 @@ function loadTaskLog() {
|
|
|
5184
5706
|
}
|
|
5185
5707
|
function saveTaskLog(entries) {
|
|
5186
5708
|
try {
|
|
5187
|
-
if (!
|
|
5709
|
+
if (!fs19.existsSync(TASK_LOG_DIR)) fs19.mkdirSync(TASK_LOG_DIR, { recursive: true });
|
|
5188
5710
|
const trimmed = entries.slice(-MAX_LOG_ENTRIES);
|
|
5189
|
-
|
|
5711
|
+
fs19.writeFileSync(TASK_LOG_FILE, JSON.stringify(trimmed, null, 2));
|
|
5190
5712
|
} catch (err) {
|
|
5191
5713
|
log.debug("background", "Failed to save task log", err);
|
|
5192
5714
|
}
|
|
@@ -5335,10 +5857,10 @@ import {
|
|
|
5335
5857
|
} from "@aman_asmuei/arules-core";
|
|
5336
5858
|
var AGENT_SCOPE = process.env.AMAN_AGENT_SCOPE ?? "dev:agent";
|
|
5337
5859
|
function readEcosystemFile(filePath, label) {
|
|
5338
|
-
if (!
|
|
5860
|
+
if (!fs20.existsSync(filePath)) {
|
|
5339
5861
|
return pc6.dim(`No ${label} file found at ${filePath}`);
|
|
5340
5862
|
}
|
|
5341
|
-
return
|
|
5863
|
+
return fs20.readFileSync(filePath, "utf-8").trim();
|
|
5342
5864
|
}
|
|
5343
5865
|
function parseCommand(input) {
|
|
5344
5866
|
const trimmed = input.trim();
|
|
@@ -5423,8 +5945,8 @@ async function handleIdentityCommand(action, args, _ctx) {
|
|
|
5423
5945
|
}
|
|
5424
5946
|
if (args.includes("--reset")) {
|
|
5425
5947
|
const modelPath = defaultModelPath();
|
|
5426
|
-
if (
|
|
5427
|
-
|
|
5948
|
+
if (fs20.existsSync(modelPath)) {
|
|
5949
|
+
fs20.unlinkSync(modelPath);
|
|
5428
5950
|
return { handled: true, output: pc6.green("User model reset. Starting fresh.") };
|
|
5429
5951
|
}
|
|
5430
5952
|
return { handled: true, output: pc6.dim("No user model to reset.") };
|
|
@@ -5670,7 +6192,7 @@ ${result.violations.map((v) => ` - ${v}`).join("\n")}`)
|
|
|
5670
6192
|
async function handleWorkflowsCommand(action, args, ctx) {
|
|
5671
6193
|
const home2 = os18.homedir();
|
|
5672
6194
|
if (!action) {
|
|
5673
|
-
const content = readEcosystemFile(
|
|
6195
|
+
const content = readEcosystemFile(path20.join(home2, ".aflow", "flow.md"), "workflows (aflow)");
|
|
5674
6196
|
return { handled: true, output: content };
|
|
5675
6197
|
}
|
|
5676
6198
|
if (action === "add") {
|
|
@@ -5692,7 +6214,7 @@ async function handleWorkflowsCommand(action, args, ctx) {
|
|
|
5692
6214
|
return { handled: true, output: pc6.yellow("Usage: /workflows get <name>") };
|
|
5693
6215
|
}
|
|
5694
6216
|
const name = args.join(" ").toLowerCase();
|
|
5695
|
-
const raw = readEcosystemFile(
|
|
6217
|
+
const raw = readEcosystemFile(path20.join(home2, ".aflow", "flow.md"), "workflows (aflow)");
|
|
5696
6218
|
if (raw.startsWith("No ")) {
|
|
5697
6219
|
return { handled: true, output: raw };
|
|
5698
6220
|
}
|
|
@@ -5752,11 +6274,11 @@ async function handleToolsCommand(action, args, _ctx) {
|
|
|
5752
6274
|
}
|
|
5753
6275
|
const query = args.join(" ").toLowerCase();
|
|
5754
6276
|
const home2 = os18.homedir();
|
|
5755
|
-
const toolsFile =
|
|
5756
|
-
if (!
|
|
6277
|
+
const toolsFile = path20.join(home2, ".akit", "tools.md");
|
|
6278
|
+
if (!fs20.existsSync(toolsFile)) {
|
|
5757
6279
|
return { handled: true, output: pc6.dim(`No tools file found. Use 'npx @aman_asmuei/akit search ${args.join(" ")}' to search the registry.`) };
|
|
5758
6280
|
}
|
|
5759
|
-
const raw =
|
|
6281
|
+
const raw = fs20.readFileSync(toolsFile, "utf-8").trim();
|
|
5760
6282
|
const lines = raw.split("\n");
|
|
5761
6283
|
const matches = lines.filter((l) => l.toLowerCase().includes(query));
|
|
5762
6284
|
if (matches.length === 0) {
|
|
@@ -5769,7 +6291,7 @@ async function handleToolsCommand(action, args, _ctx) {
|
|
|
5769
6291
|
async function handleSkillsCommand(action, args, ctx) {
|
|
5770
6292
|
const home2 = os18.homedir();
|
|
5771
6293
|
if (!action) {
|
|
5772
|
-
const content = readEcosystemFile(
|
|
6294
|
+
const content = readEcosystemFile(path20.join(home2, ".askill", "skills.md"), "skills (askill)");
|
|
5773
6295
|
return { handled: true, output: content };
|
|
5774
6296
|
}
|
|
5775
6297
|
if (action === "install") {
|
|
@@ -5792,7 +6314,7 @@ async function handleSkillsCommand(action, args, ctx) {
|
|
|
5792
6314
|
}
|
|
5793
6315
|
const query = args.join(" ").toLowerCase();
|
|
5794
6316
|
const home3 = os18.homedir();
|
|
5795
|
-
const raw = readEcosystemFile(
|
|
6317
|
+
const raw = readEcosystemFile(path20.join(home3, ".askill", "skills.md"), "skills (askill)");
|
|
5796
6318
|
if (raw.startsWith("No ")) {
|
|
5797
6319
|
return { handled: true, output: raw };
|
|
5798
6320
|
}
|
|
@@ -5806,23 +6328,23 @@ async function handleSkillsCommand(action, args, ctx) {
|
|
|
5806
6328
|
if (action === "list") {
|
|
5807
6329
|
const autoOnly = args.includes("--auto");
|
|
5808
6330
|
if (autoOnly) {
|
|
5809
|
-
const logPath =
|
|
6331
|
+
const logPath = path20.join(os18.homedir(), ".aman-agent", "crystallization-log.json");
|
|
5810
6332
|
try {
|
|
5811
|
-
const content2 =
|
|
6333
|
+
const content2 = fs20.readFileSync(logPath, "utf-8");
|
|
5812
6334
|
const entries = JSON.parse(content2);
|
|
5813
6335
|
if (entries.length === 0) {
|
|
5814
6336
|
return { handled: true, output: pc6.dim("No crystallized skills yet.") };
|
|
5815
6337
|
}
|
|
5816
|
-
const suggestionsPath =
|
|
6338
|
+
const suggestionsPath = path20.join(os18.homedir(), ".aman-agent", "crystallization-suggestions.json");
|
|
5817
6339
|
let sugCounts = {};
|
|
5818
6340
|
try {
|
|
5819
|
-
const sc =
|
|
6341
|
+
const sc = fs20.readFileSync(suggestionsPath, "utf-8");
|
|
5820
6342
|
sugCounts = JSON.parse(sc);
|
|
5821
6343
|
} catch {
|
|
5822
6344
|
}
|
|
5823
6345
|
let versionCounts = {};
|
|
5824
6346
|
try {
|
|
5825
|
-
const skillsContent =
|
|
6347
|
+
const skillsContent = fs20.readFileSync(path20.join(os18.homedir(), ".askill", "skills.md"), "utf-8");
|
|
5826
6348
|
const versionRe = /^# (.+)\.v(\d+)$/gm;
|
|
5827
6349
|
let vMatch;
|
|
5828
6350
|
while ((vMatch = versionRe.exec(skillsContent)) !== null) {
|
|
@@ -5847,13 +6369,13 @@ async function handleSkillsCommand(action, args, ctx) {
|
|
|
5847
6369
|
return { handled: true, output: pc6.dim("No crystallized skills yet.") };
|
|
5848
6370
|
}
|
|
5849
6371
|
}
|
|
5850
|
-
const content = readEcosystemFile(
|
|
6372
|
+
const content = readEcosystemFile(path20.join(home2, ".askill", "skills.md"), "skills (askill)");
|
|
5851
6373
|
return { handled: true, output: content };
|
|
5852
6374
|
}
|
|
5853
6375
|
if (action === "crystallize") {
|
|
5854
|
-
const pmDir =
|
|
6376
|
+
const pmDir = path20.join(os18.homedir(), ".acore", "postmortems");
|
|
5855
6377
|
try {
|
|
5856
|
-
const files =
|
|
6378
|
+
const files = fs20.readdirSync(pmDir);
|
|
5857
6379
|
const jsonFiles = files.filter((f) => f.endsWith(".json")).sort().reverse();
|
|
5858
6380
|
if (jsonFiles.length === 0) {
|
|
5859
6381
|
return {
|
|
@@ -5862,7 +6384,7 @@ async function handleSkillsCommand(action, args, ctx) {
|
|
|
5862
6384
|
};
|
|
5863
6385
|
}
|
|
5864
6386
|
const latest = jsonFiles[0];
|
|
5865
|
-
const content =
|
|
6387
|
+
const content = fs20.readFileSync(path20.join(pmDir, latest), "utf-8");
|
|
5866
6388
|
const report = JSON.parse(content);
|
|
5867
6389
|
if (!report.crystallizationCandidates || report.crystallizationCandidates.length === 0) {
|
|
5868
6390
|
return {
|
|
@@ -5870,8 +6392,8 @@ async function handleSkillsCommand(action, args, ctx) {
|
|
|
5870
6392
|
output: pc6.dim(`No crystallization candidates in the most recent post-mortem (${latest}). Run a longer session or wait for the next auto-postmortem.`)
|
|
5871
6393
|
};
|
|
5872
6394
|
}
|
|
5873
|
-
const skillsMdPath =
|
|
5874
|
-
const logPath =
|
|
6395
|
+
const skillsMdPath = path20.join(os18.homedir(), ".askill", "skills.md");
|
|
6396
|
+
const logPath = path20.join(os18.homedir(), ".aman-agent", "crystallization-log.json");
|
|
5875
6397
|
const postmortemFilename = latest.replace(/\.json$/, ".md");
|
|
5876
6398
|
const lines = [
|
|
5877
6399
|
pc6.bold(`Found ${report.crystallizationCandidates.length} candidate(s) in ${latest}:`)
|
|
@@ -5930,7 +6452,7 @@ async function handleSkillsCommand(action, args, ctx) {
|
|
|
5930
6452
|
async function handleEvalCommand(action, args, ctx) {
|
|
5931
6453
|
const home2 = os18.homedir();
|
|
5932
6454
|
if (!action) {
|
|
5933
|
-
const content = readEcosystemFile(
|
|
6455
|
+
const content = readEcosystemFile(path20.join(home2, ".aeval", "eval.md"), "evaluation (aeval)");
|
|
5934
6456
|
return { handled: true, output: content };
|
|
5935
6457
|
}
|
|
5936
6458
|
if (action === "milestone") {
|
|
@@ -5942,10 +6464,10 @@ async function handleEvalCommand(action, args, ctx) {
|
|
|
5942
6464
|
return { handled: true, output };
|
|
5943
6465
|
}
|
|
5944
6466
|
if (action === "report") {
|
|
5945
|
-
const evalFile =
|
|
6467
|
+
const evalFile = path20.join(home2, ".aeval", "eval.md");
|
|
5946
6468
|
const lines = [pc6.bold("\u{1F4CA} Eval Report")];
|
|
5947
|
-
if (
|
|
5948
|
-
lines.push("",
|
|
6469
|
+
if (fs20.existsSync(evalFile)) {
|
|
6470
|
+
lines.push("", fs20.readFileSync(evalFile, "utf-8").trim());
|
|
5949
6471
|
} else {
|
|
5950
6472
|
lines.push("", pc6.dim("No eval log yet. Use /eval milestone <text> to start."));
|
|
5951
6473
|
}
|
|
@@ -6503,10 +7025,10 @@ function handleSave() {
|
|
|
6503
7025
|
}
|
|
6504
7026
|
function handleReset(action) {
|
|
6505
7027
|
const dirs = {
|
|
6506
|
-
config:
|
|
6507
|
-
memory:
|
|
6508
|
-
identity:
|
|
6509
|
-
rules:
|
|
7028
|
+
config: path20.join(os18.homedir(), ".aman-agent"),
|
|
7029
|
+
memory: path20.join(os18.homedir(), ".amem"),
|
|
7030
|
+
identity: path20.join(os18.homedir(), ".acore"),
|
|
7031
|
+
rules: path20.join(os18.homedir(), ".arules")
|
|
6510
7032
|
};
|
|
6511
7033
|
if (action === "help" || !action) {
|
|
6512
7034
|
return {
|
|
@@ -6531,15 +7053,15 @@ function handleReset(action) {
|
|
|
6531
7053
|
const removed = [];
|
|
6532
7054
|
for (const target of targets) {
|
|
6533
7055
|
const dir = dirs[target];
|
|
6534
|
-
if (
|
|
6535
|
-
|
|
7056
|
+
if (fs20.existsSync(dir)) {
|
|
7057
|
+
fs20.rmSync(dir, { recursive: true, force: true });
|
|
6536
7058
|
removed.push(target);
|
|
6537
7059
|
}
|
|
6538
7060
|
}
|
|
6539
7061
|
if (targets.includes("config")) {
|
|
6540
7062
|
const configDir2 = dirs.config;
|
|
6541
|
-
|
|
6542
|
-
|
|
7063
|
+
fs20.mkdirSync(configDir2, { recursive: true });
|
|
7064
|
+
fs20.writeFileSync(path20.join(configDir2, ".reconfig"), "", "utf-8");
|
|
6543
7065
|
}
|
|
6544
7066
|
if (removed.length === 0) {
|
|
6545
7067
|
return { handled: true, output: pc6.dim("Nothing to reset \u2014 directories don't exist.") };
|
|
@@ -6556,20 +7078,19 @@ function handleReset(action) {
|
|
|
6556
7078
|
function handleUpdate() {
|
|
6557
7079
|
try {
|
|
6558
7080
|
const current = execFileSync3("npm", ["view", "@aman_asmuei/aman-agent", "version"], { encoding: "utf-8" }).trim();
|
|
6559
|
-
const local = true ? "0.
|
|
7081
|
+
const local = true ? "0.33.0" : "unknown";
|
|
6560
7082
|
if (current === local) {
|
|
6561
7083
|
return { handled: true, output: `${pc6.green("Up to date")} \u2014 v${local}` };
|
|
6562
7084
|
}
|
|
7085
|
+
const isVendored = process.execPath.includes(path20.join(".aman-agent", "node"));
|
|
7086
|
+
const updateCmd = isVendored ? "aman-agent update" : "npm install -g @aman_asmuei/aman-agent@latest";
|
|
6563
7087
|
return {
|
|
6564
7088
|
handled: true,
|
|
6565
7089
|
output: [
|
|
6566
7090
|
`${pc6.yellow("Update available:")} v${local} \u2192 v${current}`,
|
|
6567
7091
|
"",
|
|
6568
7092
|
`Run this in your terminal:`,
|
|
6569
|
-
` ${pc6.bold(
|
|
6570
|
-
"",
|
|
6571
|
-
`Or use npx (always latest):`,
|
|
6572
|
-
` ${pc6.bold("npx @aman_asmuei/aman-agent@latest")}`
|
|
7093
|
+
` ${pc6.bold(updateCmd)}`
|
|
6573
7094
|
].join("\n")
|
|
6574
7095
|
};
|
|
6575
7096
|
} catch {
|
|
@@ -6577,10 +7098,7 @@ function handleUpdate() {
|
|
|
6577
7098
|
handled: true,
|
|
6578
7099
|
output: [
|
|
6579
7100
|
`To update, run in your terminal:`,
|
|
6580
|
-
` ${pc6.bold("npm install -g @aman_asmuei/aman-agent@latest")}
|
|
6581
|
-
"",
|
|
6582
|
-
`Or use npx (always latest):`,
|
|
6583
|
-
` ${pc6.bold("npx @aman_asmuei/aman-agent@latest")}`
|
|
7101
|
+
` ${pc6.bold("npm install -g @aman_asmuei/aman-agent@latest")}`
|
|
6584
7102
|
].join("\n")
|
|
6585
7103
|
};
|
|
6586
7104
|
}
|
|
@@ -6600,11 +7118,11 @@ function handleExportCommand() {
|
|
|
6600
7118
|
return { handled: true, exportConversation: true };
|
|
6601
7119
|
}
|
|
6602
7120
|
function handleDebugCommand() {
|
|
6603
|
-
const logPath =
|
|
6604
|
-
if (!
|
|
7121
|
+
const logPath = path20.join(os18.homedir(), ".aman-agent", "debug.log");
|
|
7122
|
+
if (!fs20.existsSync(logPath)) {
|
|
6605
7123
|
return { handled: true, output: pc6.dim("No debug log found.") };
|
|
6606
7124
|
}
|
|
6607
|
-
const content =
|
|
7125
|
+
const content = fs20.readFileSync(logPath, "utf-8");
|
|
6608
7126
|
const lines = content.trim().split("\n");
|
|
6609
7127
|
const last20 = lines.slice(-20).join("\n");
|
|
6610
7128
|
return { handled: true, output: pc6.bold("Debug Log (last 20 entries):\n") + pc6.dim(last20) };
|
|
@@ -6884,7 +7402,7 @@ ${text3}` };
|
|
|
6884
7402
|
};
|
|
6885
7403
|
}
|
|
6886
7404
|
function handleProfileCommand(action, args) {
|
|
6887
|
-
const profilesDir =
|
|
7405
|
+
const profilesDir = path20.join(os18.homedir(), ".acore", "profiles");
|
|
6888
7406
|
if (action === "me") {
|
|
6889
7407
|
const user = loadUserIdentity();
|
|
6890
7408
|
if (!user) {
|
|
@@ -6952,8 +7470,8 @@ ${pc6.dim("Edit with: /profile edit")}` };
|
|
|
6952
7470
|
};
|
|
6953
7471
|
}
|
|
6954
7472
|
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
6955
|
-
const profileDir =
|
|
6956
|
-
if (
|
|
7473
|
+
const profileDir = path20.join(profilesDir, slug);
|
|
7474
|
+
if (fs20.existsSync(profileDir)) {
|
|
6957
7475
|
return { handled: true, output: pc6.yellow(`Profile already exists: ${slug}`) };
|
|
6958
7476
|
}
|
|
6959
7477
|
const builtIn = BUILT_IN_PROFILES.find((t) => t.name === slug);
|
|
@@ -6969,16 +7487,16 @@ ${pc6.dim("Edit with: /profile edit")}` };
|
|
|
6969
7487
|
Use: aman-agent --profile ${slug}`
|
|
6970
7488
|
};
|
|
6971
7489
|
}
|
|
6972
|
-
|
|
6973
|
-
const globalCore =
|
|
6974
|
-
if (
|
|
6975
|
-
let content =
|
|
7490
|
+
fs20.mkdirSync(profileDir, { recursive: true });
|
|
7491
|
+
const globalCore = path20.join(os18.homedir(), ".acore", "core.md");
|
|
7492
|
+
if (fs20.existsSync(globalCore)) {
|
|
7493
|
+
let content = fs20.readFileSync(globalCore, "utf-8");
|
|
6976
7494
|
const aiName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
6977
7495
|
content = content.replace(/^# .+$/m, `# ${aiName}`);
|
|
6978
|
-
|
|
7496
|
+
fs20.writeFileSync(path20.join(profileDir, "core.md"), content, "utf-8");
|
|
6979
7497
|
} else {
|
|
6980
7498
|
const aiName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
6981
|
-
|
|
7499
|
+
fs20.writeFileSync(path20.join(profileDir, "core.md"), `# ${aiName}
|
|
6982
7500
|
|
|
6983
7501
|
## Identity
|
|
6984
7502
|
- Role: ${aiName} is your AI companion
|
|
@@ -6991,7 +7509,7 @@ ${pc6.dim("Edit with: /profile edit")}` };
|
|
|
6991
7509
|
return {
|
|
6992
7510
|
handled: true,
|
|
6993
7511
|
output: pc6.green(`Profile created: ${slug}`) + `
|
|
6994
|
-
Edit: ${
|
|
7512
|
+
Edit: ${path20.join(profileDir, "core.md")}
|
|
6995
7513
|
Use: aman-agent --profile ${slug}
|
|
6996
7514
|
|
|
6997
7515
|
${pc6.dim("Add rules.md or skills.md for profile-specific overrides.")}`
|
|
@@ -7000,9 +7518,9 @@ ${pc6.dim("Edit with: /profile edit")}` };
|
|
|
7000
7518
|
case "show": {
|
|
7001
7519
|
const name = args[0];
|
|
7002
7520
|
if (!name) return { handled: true, output: pc6.yellow("Usage: /profile show <name>") };
|
|
7003
|
-
const profileDir =
|
|
7004
|
-
if (!
|
|
7005
|
-
const files =
|
|
7521
|
+
const profileDir = path20.join(profilesDir, name);
|
|
7522
|
+
if (!fs20.existsSync(profileDir)) return { handled: true, output: pc6.red(`Profile not found: ${name}`) };
|
|
7523
|
+
const files = fs20.readdirSync(profileDir).filter((f) => f.endsWith(".md"));
|
|
7006
7524
|
const lines = files.map((f) => ` ${f}`);
|
|
7007
7525
|
return { handled: true, output: `Profile: ${pc6.bold(name)}
|
|
7008
7526
|
Files:
|
|
@@ -7011,9 +7529,9 @@ ${lines.join("\n")}` };
|
|
|
7011
7529
|
case "delete": {
|
|
7012
7530
|
const name = args[0];
|
|
7013
7531
|
if (!name) return { handled: true, output: pc6.yellow("Usage: /profile delete <name>") };
|
|
7014
|
-
const profileDir =
|
|
7015
|
-
if (!
|
|
7016
|
-
|
|
7532
|
+
const profileDir = path20.join(profilesDir, name);
|
|
7533
|
+
if (!fs20.existsSync(profileDir)) return { handled: true, output: pc6.red(`Profile not found: ${name}`) };
|
|
7534
|
+
fs20.rmSync(profileDir, { recursive: true });
|
|
7017
7535
|
return { handled: true, output: pc6.dim(`Profile deleted: ${name}`) };
|
|
7018
7536
|
}
|
|
7019
7537
|
case "help":
|
|
@@ -7231,10 +7749,10 @@ function handleShowcaseCommand(action, args) {
|
|
|
7231
7749
|
Or place it as a sibling directory to aman-agent.`
|
|
7232
7750
|
};
|
|
7233
7751
|
}
|
|
7234
|
-
const corePath =
|
|
7752
|
+
const corePath = path20.join(os18.homedir(), ".acore", "core.md");
|
|
7235
7753
|
let currentShowcase = null;
|
|
7236
|
-
if (
|
|
7237
|
-
const content =
|
|
7754
|
+
if (fs20.existsSync(corePath)) {
|
|
7755
|
+
const content = fs20.readFileSync(corePath, "utf-8");
|
|
7238
7756
|
const nameMatch = content.match(/^# (.+)/m);
|
|
7239
7757
|
if (nameMatch) {
|
|
7240
7758
|
const coreName = nameMatch[1].trim().toLowerCase();
|
|
@@ -7632,9 +8150,9 @@ init_logger();
|
|
|
7632
8150
|
|
|
7633
8151
|
// src/skill-engine.ts
|
|
7634
8152
|
init_logger();
|
|
7635
|
-
import
|
|
8153
|
+
import fs21 from "fs";
|
|
7636
8154
|
import fsp from "fs/promises";
|
|
7637
|
-
import
|
|
8155
|
+
import path21 from "path";
|
|
7638
8156
|
import os19 from "os";
|
|
7639
8157
|
var SKILL_TRIGGERS = {
|
|
7640
8158
|
testing: ["test", "spec", "coverage", "tdd", "jest", "vitest", "mocha", "assert", "mock", "stub", "fixture", "e2e", "integration test", "unit test"],
|
|
@@ -7664,20 +8182,20 @@ async function loadRuntimeTriggers(skillsMdPath) {
|
|
|
7664
8182
|
return /* @__PURE__ */ new Map();
|
|
7665
8183
|
}
|
|
7666
8184
|
}
|
|
7667
|
-
var LEVEL_FILE =
|
|
8185
|
+
var LEVEL_FILE = path21.join(os19.homedir(), ".aman-agent", "skill-levels.json");
|
|
7668
8186
|
function loadSkillLevels() {
|
|
7669
8187
|
try {
|
|
7670
|
-
if (
|
|
7671
|
-
return JSON.parse(
|
|
8188
|
+
if (fs21.existsSync(LEVEL_FILE)) {
|
|
8189
|
+
return JSON.parse(fs21.readFileSync(LEVEL_FILE, "utf-8"));
|
|
7672
8190
|
}
|
|
7673
8191
|
} catch {
|
|
7674
8192
|
}
|
|
7675
8193
|
return {};
|
|
7676
8194
|
}
|
|
7677
8195
|
function saveSkillLevels(levels) {
|
|
7678
|
-
const dir =
|
|
7679
|
-
if (!
|
|
7680
|
-
|
|
8196
|
+
const dir = path21.dirname(LEVEL_FILE);
|
|
8197
|
+
if (!fs21.existsSync(dir)) fs21.mkdirSync(dir, { recursive: true });
|
|
8198
|
+
fs21.writeFileSync(LEVEL_FILE, JSON.stringify(levels, null, 2), "utf-8");
|
|
7681
8199
|
}
|
|
7682
8200
|
function computeLevel(activations) {
|
|
7683
8201
|
if (activations >= 50) return { level: 5, label: "Expert" };
|
|
@@ -7904,7 +8422,7 @@ async function autoTriggerSkills(userInput, mcpManager) {
|
|
|
7904
8422
|
const result = await mcpManager.callTool("skill_list", {});
|
|
7905
8423
|
const skills = JSON.parse(result);
|
|
7906
8424
|
const installed = skills.filter((s) => s.installed).map((s) => s.name);
|
|
7907
|
-
const skillsMdPath =
|
|
8425
|
+
const skillsMdPath = path21.join(os19.homedir(), ".askill", "skills.md");
|
|
7908
8426
|
const runtimeTriggers = await loadRuntimeTriggers(skillsMdPath);
|
|
7909
8427
|
if (installed.length === 0 && runtimeTriggers.size === 0) return "";
|
|
7910
8428
|
const matched = matchSkillsSemantic(userInput, installed, runtimeTriggers);
|
|
@@ -8337,6 +8855,9 @@ Assistant: ${assistantResponse.slice(0, 2e3)}`;
|
|
|
8337
8855
|
}
|
|
8338
8856
|
}
|
|
8339
8857
|
|
|
8858
|
+
// src/agent.ts
|
|
8859
|
+
init_token_budget();
|
|
8860
|
+
|
|
8340
8861
|
// src/errors.ts
|
|
8341
8862
|
var ERROR_MAPPINGS = [
|
|
8342
8863
|
{ pattern: /rate.?limit|429/i, message: "Rate limited. I'll retry automatically." },
|
|
@@ -8358,8 +8879,8 @@ function humanizeError(message) {
|
|
|
8358
8879
|
}
|
|
8359
8880
|
|
|
8360
8881
|
// src/hints.ts
|
|
8361
|
-
import
|
|
8362
|
-
import
|
|
8882
|
+
import fs22 from "fs";
|
|
8883
|
+
import path22 from "path";
|
|
8363
8884
|
import os20 from "os";
|
|
8364
8885
|
var HINTS = [
|
|
8365
8886
|
{
|
|
@@ -8398,11 +8919,11 @@ function getHint(state, ctx) {
|
|
|
8398
8919
|
}
|
|
8399
8920
|
return null;
|
|
8400
8921
|
}
|
|
8401
|
-
var HINTS_FILE =
|
|
8922
|
+
var HINTS_FILE = path22.join(os20.homedir(), ".aman-agent", "hints-seen.json");
|
|
8402
8923
|
function loadShownHints() {
|
|
8403
8924
|
try {
|
|
8404
|
-
if (
|
|
8405
|
-
const data = JSON.parse(
|
|
8925
|
+
if (fs22.existsSync(HINTS_FILE)) {
|
|
8926
|
+
const data = JSON.parse(fs22.readFileSync(HINTS_FILE, "utf-8"));
|
|
8406
8927
|
return new Set(Array.isArray(data) ? data : []);
|
|
8407
8928
|
}
|
|
8408
8929
|
} catch {
|
|
@@ -8411,9 +8932,9 @@ function loadShownHints() {
|
|
|
8411
8932
|
}
|
|
8412
8933
|
function saveShownHints(shown) {
|
|
8413
8934
|
try {
|
|
8414
|
-
const dir =
|
|
8415
|
-
|
|
8416
|
-
|
|
8935
|
+
const dir = path22.dirname(HINTS_FILE);
|
|
8936
|
+
fs22.mkdirSync(dir, { recursive: true });
|
|
8937
|
+
fs22.writeFileSync(HINTS_FILE, JSON.stringify([...shown]), "utf-8");
|
|
8417
8938
|
} catch {
|
|
8418
8939
|
}
|
|
8419
8940
|
}
|
|
@@ -8680,9 +9201,9 @@ ${task.result}`
|
|
|
8680
9201
|
}
|
|
8681
9202
|
if (cmdResult.exportConversation) {
|
|
8682
9203
|
try {
|
|
8683
|
-
const exportDir =
|
|
8684
|
-
|
|
8685
|
-
const exportPath =
|
|
9204
|
+
const exportDir = path23.join(os21.homedir(), ".aman-agent", "exports");
|
|
9205
|
+
fs23.mkdirSync(exportDir, { recursive: true });
|
|
9206
|
+
const exportPath = path23.join(exportDir, `${sessionId}.md`);
|
|
8686
9207
|
const lines = [
|
|
8687
9208
|
`# Conversation \u2014 ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
|
|
8688
9209
|
`**Model:** ${model}`,
|
|
@@ -8696,7 +9217,7 @@ ${task.result}`
|
|
|
8696
9217
|
lines.push(`${label} ${msg.content}`, "");
|
|
8697
9218
|
}
|
|
8698
9219
|
}
|
|
8699
|
-
|
|
9220
|
+
fs23.writeFileSync(exportPath, lines.join("\n"), "utf-8");
|
|
8700
9221
|
console.log(pc7.green(`Exported to ${exportPath}`));
|
|
8701
9222
|
} catch {
|
|
8702
9223
|
console.log(pc7.red("Failed to export conversation."));
|
|
@@ -8822,25 +9343,25 @@ ${knowledgeItem.content}
|
|
|
8822
9343
|
for (const match of filePathMatches) {
|
|
8823
9344
|
let filePath = match[1];
|
|
8824
9345
|
if (filePath.startsWith("~/")) {
|
|
8825
|
-
filePath =
|
|
9346
|
+
filePath = path23.join(os21.homedir(), filePath.slice(2));
|
|
8826
9347
|
}
|
|
8827
|
-
if (!
|
|
8828
|
-
const ext =
|
|
9348
|
+
if (!fs23.existsSync(filePath) || !fs23.statSync(filePath).isFile()) continue;
|
|
9349
|
+
const ext = path23.extname(filePath).toLowerCase();
|
|
8829
9350
|
if (imageExts.has(ext)) {
|
|
8830
9351
|
try {
|
|
8831
|
-
const stat =
|
|
9352
|
+
const stat = fs23.statSync(filePath);
|
|
8832
9353
|
if (stat.size > maxImageBytes) {
|
|
8833
|
-
process.stdout.write(pc7.yellow(` [skipped: ${
|
|
9354
|
+
process.stdout.write(pc7.yellow(` [skipped: ${path23.basename(filePath)} \u2014 exceeds 20MB limit]
|
|
8834
9355
|
`));
|
|
8835
9356
|
continue;
|
|
8836
9357
|
}
|
|
8837
|
-
const data =
|
|
9358
|
+
const data = fs23.readFileSync(filePath).toString("base64");
|
|
8838
9359
|
const mediaType = mimeMap[ext] || "image/png";
|
|
8839
9360
|
imageBlocks.push({
|
|
8840
9361
|
type: "image",
|
|
8841
9362
|
source: { type: "base64", media_type: mediaType, data }
|
|
8842
9363
|
});
|
|
8843
|
-
process.stdout.write(pc7.dim(` [attached image: ${
|
|
9364
|
+
process.stdout.write(pc7.dim(` [attached image: ${path23.basename(filePath)} (${(stat.size / 1024).toFixed(1)}KB)]
|
|
8844
9365
|
`));
|
|
8845
9366
|
} catch {
|
|
8846
9367
|
process.stdout.write(pc7.dim(` [could not read image: ${filePath}]
|
|
@@ -8848,7 +9369,7 @@ ${knowledgeItem.content}
|
|
|
8848
9369
|
}
|
|
8849
9370
|
} else if (textExts.has(ext) || ext === "") {
|
|
8850
9371
|
try {
|
|
8851
|
-
const content =
|
|
9372
|
+
const content = fs23.readFileSync(filePath, "utf-8");
|
|
8852
9373
|
const maxChars = 5e4;
|
|
8853
9374
|
const trimmed = content.length > maxChars ? content.slice(0, maxChars) + `
|
|
8854
9375
|
|
|
@@ -8858,7 +9379,7 @@ ${knowledgeItem.content}
|
|
|
8858
9379
|
<file path="${filePath}" size="${content.length} chars">
|
|
8859
9380
|
${trimmed}
|
|
8860
9381
|
</file>`;
|
|
8861
|
-
process.stdout.write(pc7.dim(` [attached: ${
|
|
9382
|
+
process.stdout.write(pc7.dim(` [attached: ${path23.basename(filePath)} (${(content.length / 1024).toFixed(1)}KB)]
|
|
8862
9383
|
`));
|
|
8863
9384
|
} catch {
|
|
8864
9385
|
process.stdout.write(pc7.dim(` [could not read: ${filePath}]
|
|
@@ -8867,7 +9388,7 @@ ${trimmed}
|
|
|
8867
9388
|
} else if (docExts.has(ext)) {
|
|
8868
9389
|
if (mcpManager) {
|
|
8869
9390
|
try {
|
|
8870
|
-
process.stdout.write(pc7.dim(` [converting: ${
|
|
9391
|
+
process.stdout.write(pc7.dim(` [converting: ${path23.basename(filePath)}...]
|
|
8871
9392
|
`));
|
|
8872
9393
|
const converted = await mcpManager.callTool("doc_convert", { path: filePath });
|
|
8873
9394
|
if (converted && !converted.startsWith("Error") && !converted.includes("Could not convert")) {
|
|
@@ -8876,7 +9397,7 @@ ${trimmed}
|
|
|
8876
9397
|
<file path="${filePath}" format="${ext}">
|
|
8877
9398
|
${converted.slice(0, 5e4)}
|
|
8878
9399
|
</file>`;
|
|
8879
|
-
process.stdout.write(pc7.dim(` [attached: ${
|
|
9400
|
+
process.stdout.write(pc7.dim(` [attached: ${path23.basename(filePath)} (converted from ${ext})]
|
|
8880
9401
|
`));
|
|
8881
9402
|
} else {
|
|
8882
9403
|
textContent += `
|
|
@@ -8888,7 +9409,7 @@ ${converted}
|
|
|
8888
9409
|
`));
|
|
8889
9410
|
}
|
|
8890
9411
|
} catch {
|
|
8891
|
-
process.stdout.write(pc7.dim(` [could not convert: ${
|
|
9412
|
+
process.stdout.write(pc7.dim(` [could not convert: ${path23.basename(filePath)}]
|
|
8892
9413
|
`));
|
|
8893
9414
|
}
|
|
8894
9415
|
} else {
|
|
@@ -8944,10 +9465,10 @@ ${converted}
|
|
|
8944
9465
|
let augmentedSystemPrompt = activeSystemPrompt;
|
|
8945
9466
|
let memoryTokens = 0;
|
|
8946
9467
|
{
|
|
8947
|
-
const
|
|
8948
|
-
if (
|
|
8949
|
-
augmentedSystemPrompt = activeSystemPrompt +
|
|
8950
|
-
memoryTokens =
|
|
9468
|
+
const recall3 = await recallForMessage(input);
|
|
9469
|
+
if (recall3) {
|
|
9470
|
+
augmentedSystemPrompt = activeSystemPrompt + recall3.text;
|
|
9471
|
+
memoryTokens = recall3.tokenEstimate;
|
|
8951
9472
|
}
|
|
8952
9473
|
}
|
|
8953
9474
|
const userTurnCount = messages.filter((m) => m.role === "user").length;
|
|
@@ -9280,7 +9801,7 @@ ${result2.response}` : `[${input2.profile}] failed: ${result2.error}`;
|
|
|
9280
9801
|
}
|
|
9281
9802
|
if (hooksConfig?.featureHints) {
|
|
9282
9803
|
hintState.turnCount++;
|
|
9283
|
-
const hasWorkflows =
|
|
9804
|
+
const hasWorkflows = fs23.existsSync(path23.join(os21.homedir(), ".aflow", "flow.md"));
|
|
9284
9805
|
const memoryCount = memoryTokens > 0 ? Math.floor(memoryTokens / 5) : 0;
|
|
9285
9806
|
const hint = getHint(hintState, { hasWorkflows, memoryCount });
|
|
9286
9807
|
if (hint) {
|
|
@@ -9326,9 +9847,8 @@ async function saveConversationToMemory(messages, sessionId) {
|
|
|
9326
9847
|
}
|
|
9327
9848
|
|
|
9328
9849
|
// src/index.ts
|
|
9329
|
-
import
|
|
9330
|
-
import
|
|
9331
|
-
import os22 from "os";
|
|
9850
|
+
import fs27 from "fs";
|
|
9851
|
+
import path28 from "path";
|
|
9332
9852
|
|
|
9333
9853
|
// src/presets.ts
|
|
9334
9854
|
var PRESETS = {
|
|
@@ -9542,9 +10062,12 @@ var Inbox = class {
|
|
|
9542
10062
|
// package.json
|
|
9543
10063
|
var package_default = {
|
|
9544
10064
|
name: "@aman_asmuei/aman-agent",
|
|
9545
|
-
version: "0.
|
|
10065
|
+
version: "0.33.0",
|
|
9546
10066
|
description: "Your AI companion, running locally \u2014 powered by the aman ecosystem",
|
|
9547
10067
|
type: "module",
|
|
10068
|
+
engines: {
|
|
10069
|
+
node: ">=18.0.0"
|
|
10070
|
+
},
|
|
9548
10071
|
bin: {
|
|
9549
10072
|
"aman-agent": "./bin/aman-agent.js"
|
|
9550
10073
|
},
|
|
@@ -9832,9 +10355,9 @@ async function runServe(opts) {
|
|
|
9832
10355
|
|
|
9833
10356
|
// src/index.ts
|
|
9834
10357
|
async function autoDetectConfig() {
|
|
9835
|
-
const reconfigMarker =
|
|
9836
|
-
if (
|
|
9837
|
-
|
|
10358
|
+
const reconfigMarker = path28.join(homeDir(), ".reconfig");
|
|
10359
|
+
if (fs27.existsSync(reconfigMarker)) {
|
|
10360
|
+
fs27.unlinkSync(reconfigMarker);
|
|
9838
10361
|
return null;
|
|
9839
10362
|
}
|
|
9840
10363
|
const anthropicKey = process.env.ANTHROPIC_API_KEY;
|
|
@@ -9863,11 +10386,10 @@ async function autoDetectConfig() {
|
|
|
9863
10386
|
return null;
|
|
9864
10387
|
}
|
|
9865
10388
|
function bootstrapEcosystem() {
|
|
9866
|
-
const
|
|
9867
|
-
|
|
9868
|
-
|
|
9869
|
-
|
|
9870
|
-
fs23.writeFileSync(corePath, [
|
|
10389
|
+
const corePath = path28.join(identityDir(), "core.md");
|
|
10390
|
+
if (fs27.existsSync(corePath)) return false;
|
|
10391
|
+
fs27.mkdirSync(identityDir(), { recursive: true });
|
|
10392
|
+
fs27.writeFileSync(corePath, [
|
|
9871
10393
|
"# Aman",
|
|
9872
10394
|
"",
|
|
9873
10395
|
"## Personality",
|
|
@@ -9879,11 +10401,10 @@ function bootstrapEcosystem() {
|
|
|
9879
10401
|
"## Session",
|
|
9880
10402
|
"_New companion \u2014 no prior sessions._"
|
|
9881
10403
|
].join("\n"), "utf-8");
|
|
9882
|
-
const
|
|
9883
|
-
|
|
9884
|
-
|
|
9885
|
-
|
|
9886
|
-
fs23.writeFileSync(rulesPath, [
|
|
10404
|
+
const rulesPath = path28.join(rulesDir(), "rules.md");
|
|
10405
|
+
if (!fs27.existsSync(rulesPath)) {
|
|
10406
|
+
fs27.mkdirSync(rulesDir(), { recursive: true });
|
|
10407
|
+
fs27.writeFileSync(rulesPath, [
|
|
9887
10408
|
"# Guardrails",
|
|
9888
10409
|
"",
|
|
9889
10410
|
"## safety",
|
|
@@ -9895,22 +10416,20 @@ function bootstrapEcosystem() {
|
|
|
9895
10416
|
"- Respect the user's preferences stored in memory"
|
|
9896
10417
|
].join("\n"), "utf-8");
|
|
9897
10418
|
}
|
|
9898
|
-
const
|
|
9899
|
-
|
|
9900
|
-
|
|
9901
|
-
|
|
9902
|
-
fs23.writeFileSync(flowPath, "# Workflows\n\n_No workflows defined yet. Use /workflows add to create one._\n", "utf-8");
|
|
10419
|
+
const flowPath = path28.join(workflowsDir(), "flow.md");
|
|
10420
|
+
if (!fs27.existsSync(flowPath)) {
|
|
10421
|
+
fs27.mkdirSync(workflowsDir(), { recursive: true });
|
|
10422
|
+
fs27.writeFileSync(flowPath, "# Workflows\n\n_No workflows defined yet. Use /workflows add to create one._\n", "utf-8");
|
|
9903
10423
|
}
|
|
9904
|
-
const
|
|
9905
|
-
|
|
9906
|
-
|
|
9907
|
-
|
|
9908
|
-
fs23.writeFileSync(skillPath, "# Skills\n\n_No skills installed yet. Use /skills install to add domain expertise._\n", "utf-8");
|
|
10424
|
+
const skillPath = path28.join(skillsDir(), "skills.md");
|
|
10425
|
+
if (!fs27.existsSync(skillPath)) {
|
|
10426
|
+
fs27.mkdirSync(skillsDir(), { recursive: true });
|
|
10427
|
+
fs27.writeFileSync(skillPath, "# Skills\n\n_No skills installed yet. Use /skills install to add domain expertise._\n", "utf-8");
|
|
9909
10428
|
}
|
|
9910
10429
|
return true;
|
|
9911
10430
|
}
|
|
9912
10431
|
var program = new Command();
|
|
9913
|
-
program.name("aman-agent").description("Your AI companion, running locally").version("0.
|
|
10432
|
+
program.name("aman-agent").description("Your AI companion, running locally").version("0.33.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) => {
|
|
9914
10433
|
p4.intro(pc9.bold("aman agent") + pc9.dim(" \u2014 your AI companion"));
|
|
9915
10434
|
let config = loadConfig();
|
|
9916
10435
|
if (!config) {
|
|
@@ -9922,6 +10441,11 @@ program.name("aman-agent").description("Your AI companion, running locally").ver
|
|
|
9922
10441
|
p4.log.info(pc9.dim("Change anytime with /reset config"));
|
|
9923
10442
|
saveConfig(config);
|
|
9924
10443
|
} else {
|
|
10444
|
+
if (!process.stdin.isTTY) {
|
|
10445
|
+
console.error("Error: No LLM provider configured.");
|
|
10446
|
+
console.error("Set ANTHROPIC_API_KEY or OPENAI_API_KEY, or run interactively: aman-agent");
|
|
10447
|
+
process.exit(1);
|
|
10448
|
+
}
|
|
9925
10449
|
p4.log.info("First-time setup \u2014 configure your LLM connection.");
|
|
9926
10450
|
const provider = await p4.select({
|
|
9927
10451
|
message: "LLM provider",
|
|
@@ -10134,6 +10658,15 @@ program.name("aman-agent").description("Your AI companion, running locally").ver
|
|
|
10134
10658
|
const model = options.model || config.model;
|
|
10135
10659
|
const s = p4.spinner();
|
|
10136
10660
|
s.start("Loading ecosystem");
|
|
10661
|
+
const migration = migrateIfNeeded();
|
|
10662
|
+
if (migration.migrated.length > 0) {
|
|
10663
|
+
for (const dir of migration.migrated) {
|
|
10664
|
+
p4.log.info(`Migrated \u2192 ~/.aman-agent/${dir}/`);
|
|
10665
|
+
}
|
|
10666
|
+
}
|
|
10667
|
+
process.env.ACORE_HOME = identityDir();
|
|
10668
|
+
process.env.ARULES_HOME = rulesDir();
|
|
10669
|
+
process.env.AMEM_DIR = memoryDir();
|
|
10137
10670
|
const isFirstRun = bootstrapEcosystem();
|
|
10138
10671
|
if (!hasUserIdentity()) {
|
|
10139
10672
|
s.stop("Ecosystem loaded");
|
|
@@ -10251,19 +10784,18 @@ program.command("init").description("Set up your AI companion with a guided wiza
|
|
|
10251
10784
|
});
|
|
10252
10785
|
if (p4.isCancel(preset)) process.exit(0);
|
|
10253
10786
|
const result = applyPreset(preset, name || "Aman");
|
|
10254
|
-
|
|
10255
|
-
|
|
10256
|
-
fs23.writeFileSync(path23.join(home2, ".acore", "core.md"), result.coreMd, "utf-8");
|
|
10787
|
+
fs27.mkdirSync(identityDir(), { recursive: true });
|
|
10788
|
+
fs27.writeFileSync(path28.join(identityDir(), "core.md"), result.coreMd, "utf-8");
|
|
10257
10789
|
p4.log.success(`Identity created \u2014 ${PRESETS[preset].identity.personality.split(".")[0].toLowerCase()}`);
|
|
10258
10790
|
if (result.rulesMd) {
|
|
10259
|
-
|
|
10260
|
-
|
|
10791
|
+
fs27.mkdirSync(rulesDir(), { recursive: true });
|
|
10792
|
+
fs27.writeFileSync(path28.join(rulesDir(), "rules.md"), result.rulesMd, "utf-8");
|
|
10261
10793
|
const ruleCount = (result.rulesMd.match(/^- /gm) || []).length;
|
|
10262
10794
|
p4.log.success(`${ruleCount} rules set`);
|
|
10263
10795
|
}
|
|
10264
10796
|
if (result.flowMd) {
|
|
10265
|
-
|
|
10266
|
-
|
|
10797
|
+
fs27.mkdirSync(workflowsDir(), { recursive: true });
|
|
10798
|
+
fs27.writeFileSync(path28.join(workflowsDir(), "flow.md"), result.flowMd, "utf-8");
|
|
10267
10799
|
const wfCount = (result.flowMd.match(/^## /gm) || []).length;
|
|
10268
10800
|
p4.log.success(`${wfCount} workflow${wfCount > 1 ? "s" : ""} added`);
|
|
10269
10801
|
}
|
|
@@ -10292,5 +10824,121 @@ program.command("serve").description("Run aman-agent as a local MCP server other
|
|
|
10292
10824
|
process.exit(1);
|
|
10293
10825
|
}
|
|
10294
10826
|
});
|
|
10827
|
+
program.command("dev [path]").description("Set up project context and start Claude Code").option("--smart", "Use LLM to generate CLAUDE.md").option("--no-launch", "Generate CLAUDE.md only, don't start claude").option("--force", "Regenerate even if CLAUDE.md is fresh").option("--diff", "Show what would change without writing").action(async (projectPath, opts) => {
|
|
10828
|
+
const { runDev: runDev2 } = await Promise.resolve().then(() => (init_dev_command(), dev_command_exports));
|
|
10829
|
+
const { scanStack: scanStack2 } = await Promise.resolve().then(() => (init_stack_detector(), stack_detector_exports));
|
|
10830
|
+
const targetPath = projectPath ?? process.cwd();
|
|
10831
|
+
const stack = scanStack2(targetPath);
|
|
10832
|
+
const stackParts = stack.languages.map((l) => l.charAt(0).toUpperCase() + l.slice(1));
|
|
10833
|
+
if (stack.frameworks.length > 0) {
|
|
10834
|
+
stackParts.push(`(${stack.frameworks.map((f) => f.charAt(0).toUpperCase() + f.slice(1)).join(", ")})`);
|
|
10835
|
+
}
|
|
10836
|
+
if (stack.databases.length > 0) {
|
|
10837
|
+
stackParts.push(...stack.databases.map((d) => d.charAt(0).toUpperCase() + d.slice(1)));
|
|
10838
|
+
}
|
|
10839
|
+
if (stack.infra.length > 0) {
|
|
10840
|
+
stackParts.push(...stack.infra.map((i) => i.charAt(0).toUpperCase() + i.slice(1)));
|
|
10841
|
+
}
|
|
10842
|
+
if (stack.languages.length > 0) {
|
|
10843
|
+
console.log(`
|
|
10844
|
+
${pc9.cyan("Detected:")} ${stackParts.join(" + ")}`);
|
|
10845
|
+
} else {
|
|
10846
|
+
console.log(`
|
|
10847
|
+
${pc9.dim("No stack detected \u2014 generating minimal CLAUDE.md")}`);
|
|
10848
|
+
}
|
|
10849
|
+
const result = await runDev2(targetPath, {
|
|
10850
|
+
smart: opts.smart,
|
|
10851
|
+
noLaunch: opts.launch === false,
|
|
10852
|
+
force: opts.force,
|
|
10853
|
+
diff: opts.diff
|
|
10854
|
+
}, stack);
|
|
10855
|
+
if (!result.success) {
|
|
10856
|
+
console.error(` ${pc9.red("Error:")} ${result.error}`);
|
|
10857
|
+
process.exit(1);
|
|
10858
|
+
}
|
|
10859
|
+
if (result.diff) {
|
|
10860
|
+
console.log(`
|
|
10861
|
+
${result.diff}`);
|
|
10862
|
+
return;
|
|
10863
|
+
}
|
|
10864
|
+
if (result.generated) {
|
|
10865
|
+
const mode = opts.smart ? "smart" : "template";
|
|
10866
|
+
const memCount = result.context?.metadata.memoriesUsed ?? 0;
|
|
10867
|
+
console.log(` ${pc9.cyan("Recalled:")} ${memCount} memories`);
|
|
10868
|
+
console.log(` ${pc9.green("\u2713")} CLAUDE.md written (${mode} mode)
|
|
10869
|
+
`);
|
|
10870
|
+
} else if (result.skippedReason === "fresh") {
|
|
10871
|
+
console.log(` ${pc9.green("\u2713")} CLAUDE.md is up to date
|
|
10872
|
+
`);
|
|
10873
|
+
}
|
|
10874
|
+
if (opts.launch !== false && !opts.diff) {
|
|
10875
|
+
const { execFileSync: execFileSync4 } = await import("child_process");
|
|
10876
|
+
try {
|
|
10877
|
+
execFileSync4("which", ["claude"], { stdio: "ignore" });
|
|
10878
|
+
} catch {
|
|
10879
|
+
console.log(` ${pc9.yellow("Claude Code not found.")} Install: npm install -g @anthropic-ai/claude-code`);
|
|
10880
|
+
process.exit(1);
|
|
10881
|
+
}
|
|
10882
|
+
console.log(` ${pc9.cyan("Launching Claude Code...")}
|
|
10883
|
+
`);
|
|
10884
|
+
execFileSync4("claude", [], { cwd: targetPath, stdio: "inherit" });
|
|
10885
|
+
}
|
|
10886
|
+
});
|
|
10887
|
+
program.command("setup").description("Run the full configuration wizard (provider, identity, presets)").action(async () => {
|
|
10888
|
+
p4.intro(pc9.bold("aman agent setup") + pc9.dim(" \u2014 full configuration wizard"));
|
|
10889
|
+
const reconfigPath = path28.join(homeDir(), ".reconfig");
|
|
10890
|
+
fs27.mkdirSync(homeDir(), { recursive: true });
|
|
10891
|
+
fs27.writeFileSync(reconfigPath, "", "utf-8");
|
|
10892
|
+
p4.log.info("Configuration reset. Restart aman-agent to complete setup.");
|
|
10893
|
+
});
|
|
10894
|
+
program.command("update").description("Update aman-agent to the latest version").action(async () => {
|
|
10895
|
+
const { execFileSync: execFileSync4 } = await import("child_process");
|
|
10896
|
+
const isVendored = process.execPath.includes(path28.join(".aman-agent", "node"));
|
|
10897
|
+
if (isVendored) {
|
|
10898
|
+
const npmPath = path28.join(homeDir(), "node", "bin", "npm");
|
|
10899
|
+
console.log("Updating aman-agent...");
|
|
10900
|
+
try {
|
|
10901
|
+
execFileSync4(npmPath, ["install", "-g", "@aman_asmuei/aman-agent@latest"], {
|
|
10902
|
+
stdio: "inherit",
|
|
10903
|
+
env: { ...process.env, PREFIX: homeDir() }
|
|
10904
|
+
});
|
|
10905
|
+
console.log("\u2713 Updated successfully.");
|
|
10906
|
+
} catch {
|
|
10907
|
+
console.error("Update failed. Try manually: npm install -g @aman_asmuei/aman-agent@latest");
|
|
10908
|
+
process.exit(1);
|
|
10909
|
+
}
|
|
10910
|
+
} else {
|
|
10911
|
+
console.log("Updating via npm...");
|
|
10912
|
+
try {
|
|
10913
|
+
execFileSync4("npm", ["install", "-g", "@aman_asmuei/aman-agent@latest"], {
|
|
10914
|
+
stdio: "inherit"
|
|
10915
|
+
});
|
|
10916
|
+
console.log("\u2713 Updated successfully.");
|
|
10917
|
+
} catch {
|
|
10918
|
+
console.error("Update failed. Try manually: npm install -g @aman_asmuei/aman-agent@latest");
|
|
10919
|
+
process.exit(1);
|
|
10920
|
+
}
|
|
10921
|
+
}
|
|
10922
|
+
});
|
|
10923
|
+
program.command("uninstall").description("Remove aman-agent and all its data").action(async () => {
|
|
10924
|
+
const home2 = homeDir();
|
|
10925
|
+
if (!process.stdin.isTTY) {
|
|
10926
|
+
fs27.rmSync(home2, { recursive: true, force: true });
|
|
10927
|
+
console.log("\u2713 Removed " + home2);
|
|
10928
|
+
return;
|
|
10929
|
+
}
|
|
10930
|
+
const confirm3 = await p4.confirm({
|
|
10931
|
+
message: `This will delete ${home2} and all your data (memory, identity, config). Continue?`
|
|
10932
|
+
});
|
|
10933
|
+
if (!confirm3 || p4.isCancel(confirm3)) {
|
|
10934
|
+
console.log("Cancelled.");
|
|
10935
|
+
return;
|
|
10936
|
+
}
|
|
10937
|
+
fs27.rmSync(home2, { recursive: true, force: true });
|
|
10938
|
+
console.log("\u2713 Removed " + home2);
|
|
10939
|
+
console.log("");
|
|
10940
|
+
console.log("To complete uninstall, remove the PATH line from your shell config:");
|
|
10941
|
+
console.log(' Remove: export PATH="$HOME/.aman-agent/bin:$PATH"');
|
|
10942
|
+
});
|
|
10295
10943
|
program.parse();
|
|
10296
10944
|
//# sourceMappingURL=index.js.map
|