@aman_asmuei/aman-agent 0.32.0 → 0.33.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -8,6 +8,65 @@ 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
71
  import fs5 from "fs";
13
72
  import path5 from "path";
@@ -600,6 +659,476 @@ 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
+ if (typeof item !== "string" || !item) continue;
813
+ const tokens = estimateTokens(item);
814
+ if (total + tokens > maxTokens) break;
815
+ result.push(item);
816
+ total += tokens;
817
+ }
818
+ return result;
819
+ }
820
+ async function buildContext2(stack, opts) {
821
+ const conventions = [];
822
+ const decisions = [];
823
+ const corrections = [];
824
+ const preferences = [];
825
+ const rules = [];
826
+ let memoriesUsed = 0;
827
+ try {
828
+ const amemDir = process.env.AMEM_DIR ?? path25.join(os22.homedir(), ".amem");
829
+ const dbPath = process.env.AMEM_DB ?? path25.join(amemDir, "memory.db");
830
+ const db2 = createDatabase2(dbPath);
831
+ const query = [stack.projectName, ...stack.languages, ...stack.frameworks].join(" ");
832
+ const result = await recall2(db2, { query, limit: 20 });
833
+ for (const mem of result.memories) {
834
+ const content = mem.content;
835
+ if (typeof content !== "string" || !content) continue;
836
+ switch (mem.type) {
837
+ case "pattern":
838
+ conventions.push(content);
839
+ break;
840
+ case "decision":
841
+ decisions.push(content);
842
+ break;
843
+ case "correction":
844
+ corrections.push(content);
845
+ break;
846
+ case "preference":
847
+ preferences.push(content);
848
+ break;
849
+ }
850
+ memoriesUsed++;
851
+ }
852
+ } catch {
853
+ }
854
+ try {
855
+ const identity = await acoreGetIdentity2(AGENT_SCOPE2);
856
+ if (identity?.content) {
857
+ const lines = identity.content.split("\n").filter(
858
+ (l) => l.startsWith("- ") && (l.toLowerCase().includes("prefer") || l.toLowerCase().includes("style") || l.toLowerCase().includes("convention"))
859
+ );
860
+ for (const line of lines) {
861
+ const text3 = line.replace(/^-\s*/, "").trim();
862
+ if (text3 && !preferences.includes(text3)) preferences.push(text3);
863
+ }
864
+ }
865
+ } catch {
866
+ }
867
+ try {
868
+ const categories = await arulesListCategories2(AGENT_SCOPE2);
869
+ for (const cat of categories) {
870
+ for (const ruleText of cat.rules) {
871
+ rules.push(ruleText);
872
+ }
873
+ }
874
+ } catch {
875
+ }
876
+ if (opts?.smart && opts.llmClient) {
877
+ try {
878
+ const client = opts.llmClient;
879
+ const rawData = [
880
+ `Project: ${stack.projectName}`,
881
+ `Stack: ${stack.languages.join(", ")} + ${stack.frameworks.join(", ")}`,
882
+ `Databases: ${stack.databases.join(", ") || "none detected"}`,
883
+ "",
884
+ conventions.length > 0 ? `Conventions:
885
+ ${conventions.map((c) => `- ${c}`).join("\n")}` : "",
886
+ decisions.length > 0 ? `Decisions:
887
+ ${decisions.map((d) => `- ${d}`).join("\n")}` : "",
888
+ corrections.length > 0 ? `Corrections:
889
+ ${corrections.map((c) => `- ${c}`).join("\n")}` : "",
890
+ preferences.length > 0 ? `Preferences:
891
+ ${preferences.map((p5) => `- ${p5}`).join("\n")}` : "",
892
+ rules.length > 0 ? `Rules:
893
+ ${rules.map((r) => `- ${r}`).join("\n")}` : ""
894
+ ].filter(Boolean).join("\n\n");
895
+ const response = await client.chat(
896
+ "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.",
897
+ [{ role: "user", content: rawData }],
898
+ () => {
899
+ }
900
+ );
901
+ const text3 = typeof response.message.content === "string" ? response.message.content : response.message.content.map((b) => b.text ?? "").join("");
902
+ const extractSection = (sectionName) => {
903
+ const regex = new RegExp(`##?\\s*${sectionName}[\\s\\S]*?(?=##|$)`, "i");
904
+ const match = text3.match(regex);
905
+ if (!match) return [];
906
+ return match[0].split("\n").filter((l) => l.startsWith("- ")).map((l) => l.replace(/^-\s*/, "").trim());
907
+ };
908
+ const smartConventions = extractSection("Conventions");
909
+ const smartDecisions = extractSection("Decisions");
910
+ const smartCorrections = extractSection("Corrections");
911
+ const smartPreferences = extractSection("Preferences");
912
+ const smartRules = extractSection("Rules");
913
+ return {
914
+ stack,
915
+ conventions: trimToTokenBudget(smartConventions.length > 0 ? smartConventions : conventions, TOKEN_LIMITS.conventions),
916
+ decisions: trimToTokenBudget(smartDecisions.length > 0 ? smartDecisions : decisions, TOKEN_LIMITS.decisions),
917
+ corrections: trimToTokenBudget(smartCorrections.length > 0 ? smartCorrections : corrections, TOKEN_LIMITS.corrections),
918
+ preferences: trimToTokenBudget(smartPreferences.length > 0 ? smartPreferences : preferences, TOKEN_LIMITS.preferences),
919
+ rules: trimToTokenBudget(smartRules.length > 0 ? smartRules : rules, TOKEN_LIMITS.rules),
920
+ metadata: {
921
+ generatedAt: Date.now(),
922
+ mode: "smart",
923
+ memoriesUsed
924
+ }
925
+ };
926
+ } catch {
927
+ }
928
+ }
929
+ return {
930
+ stack,
931
+ conventions: trimToTokenBudget(conventions, TOKEN_LIMITS.conventions),
932
+ decisions: trimToTokenBudget(decisions, TOKEN_LIMITS.decisions),
933
+ corrections: trimToTokenBudget(corrections, TOKEN_LIMITS.corrections),
934
+ preferences: trimToTokenBudget(preferences, TOKEN_LIMITS.preferences),
935
+ rules: trimToTokenBudget(rules, TOKEN_LIMITS.rules),
936
+ metadata: {
937
+ generatedAt: Date.now(),
938
+ mode: "template",
939
+ memoriesUsed
940
+ }
941
+ };
942
+ }
943
+ var AGENT_SCOPE2, TOKEN_LIMITS;
944
+ var init_context_builder = __esm({
945
+ "src/dev/context-builder.ts"() {
946
+ "use strict";
947
+ init_token_budget();
948
+ AGENT_SCOPE2 = process.env.AMAN_AGENT_SCOPE ?? "dev:agent";
949
+ TOKEN_LIMITS = {
950
+ conventions: 1500,
951
+ decisions: 1200,
952
+ corrections: 800,
953
+ preferences: 500,
954
+ rules: 800
955
+ };
956
+ }
957
+ });
958
+
959
+ // src/dev/claude-md-writer.ts
960
+ import fs25 from "fs";
961
+ import path26 from "path";
962
+ function formatStack(stack) {
963
+ const parts = [];
964
+ const goFrameworks = ["fiber", "gin", "chi", "echo"];
965
+ const jsFrameworks = ["next", "react", "remix", "express", "fastify", "hono", "nestjs", "vue", "svelte", "nuxt"];
966
+ const pyFrameworks = ["django", "fastapi", "flask"];
967
+ for (const lang of stack.languages) {
968
+ const fw = stack.frameworks.filter((f) => {
969
+ if (lang === "go" && goFrameworks.includes(f)) return true;
970
+ if ((lang === "typescript" || lang === "javascript") && jsFrameworks.includes(f)) return true;
971
+ if (lang === "python" && pyFrameworks.includes(f)) return true;
972
+ if (lang === "dart" && f === "flutter") return true;
973
+ return false;
974
+ });
975
+ const name = lang.charAt(0).toUpperCase() + lang.slice(1);
976
+ if (fw.length > 0) {
977
+ parts.push(`${name} (${fw.map((f) => f.charAt(0).toUpperCase() + f.slice(1)).join(", ")})`);
978
+ } else {
979
+ parts.push(name);
980
+ }
981
+ }
982
+ if (stack.databases.length > 0) {
983
+ parts.push(...stack.databases.map((d) => d.charAt(0).toUpperCase() + d.slice(1)));
984
+ }
985
+ return parts.join(" + ");
986
+ }
987
+ function renderToString(ctx) {
988
+ const lines = [];
989
+ const ts = new Date(ctx.metadata.generatedAt).toISOString();
990
+ lines.push(`# Project: ${ctx.stack.projectName}`);
991
+ lines.push(`<!-- aman-agent:dev generated=${ts} memories=${ctx.metadata.memoriesUsed} mode=${ctx.metadata.mode} -->`);
992
+ lines.push("");
993
+ const stackLine = formatStack(ctx.stack);
994
+ if (stackLine || ctx.stack.infra.length > 0) {
995
+ lines.push("## Stack");
996
+ if (stackLine) lines.push(`- ${stackLine}`);
997
+ if (ctx.stack.infra.length > 0) {
998
+ lines.push(`- Infra: ${ctx.stack.infra.join(", ")}`);
999
+ }
1000
+ if (ctx.stack.isMonorepo) {
1001
+ lines.push("- Monorepo");
1002
+ }
1003
+ lines.push("");
1004
+ }
1005
+ if (ctx.conventions.length > 0) {
1006
+ lines.push("## Conventions");
1007
+ for (const c of ctx.conventions) lines.push(`- ${c}`);
1008
+ lines.push("");
1009
+ }
1010
+ if (ctx.decisions.length > 0) {
1011
+ lines.push("## Past Decisions");
1012
+ for (const d of ctx.decisions) lines.push(`- ${d}`);
1013
+ lines.push("");
1014
+ }
1015
+ if (ctx.corrections.length > 0) {
1016
+ lines.push("## Corrections");
1017
+ for (const c of ctx.corrections) lines.push(`- ${c}`);
1018
+ lines.push("");
1019
+ }
1020
+ if (ctx.preferences.length > 0) {
1021
+ lines.push("## Developer Preferences");
1022
+ for (const p5 of ctx.preferences) lines.push(`- ${p5}`);
1023
+ lines.push("");
1024
+ }
1025
+ if (ctx.rules.length > 0) {
1026
+ lines.push("## Rules");
1027
+ for (const r of ctx.rules) lines.push(`- ${r}`);
1028
+ lines.push("");
1029
+ }
1030
+ return lines.join("\n");
1031
+ }
1032
+ function parseMarker(content) {
1033
+ const match = content.match(
1034
+ /<!--\s*aman-agent:dev\s+generated=(\S+)\s+memories=(\d+)\s+mode=(\S+)\s*-->/
1035
+ );
1036
+ if (!match) return null;
1037
+ return {
1038
+ generatedAt: new Date(match[1]),
1039
+ memories: parseInt(match[2], 10),
1040
+ mode: match[3]
1041
+ };
1042
+ }
1043
+ function checkStaleness(projectPath) {
1044
+ const claudeMdPath = path26.join(projectPath, "CLAUDE.md");
1045
+ if (!fs25.existsSync(claudeMdPath)) {
1046
+ return { status: "missing" };
1047
+ }
1048
+ const content = fs25.readFileSync(claudeMdPath, "utf-8");
1049
+ const marker = parseMarker(content);
1050
+ if (!marker) {
1051
+ return { status: "no-marker" };
1052
+ }
1053
+ return { status: "fresh", generatedAt: marker.generatedAt };
1054
+ }
1055
+ function writeClaudeMd(ctx, projectPath) {
1056
+ const claudeMdPath = path26.join(projectPath, "CLAUDE.md");
1057
+ let backedUp = false;
1058
+ if (fs25.existsSync(claudeMdPath)) {
1059
+ const content = fs25.readFileSync(claudeMdPath, "utf-8");
1060
+ const marker = parseMarker(content);
1061
+ if (!marker) {
1062
+ fs25.copyFileSync(claudeMdPath, `${claudeMdPath}.bak`);
1063
+ backedUp = true;
1064
+ }
1065
+ }
1066
+ const md = renderToString(ctx);
1067
+ fs25.writeFileSync(claudeMdPath, md, "utf-8");
1068
+ return { written: true, backedUp, path: claudeMdPath };
1069
+ }
1070
+ var init_claude_md_writer = __esm({
1071
+ "src/dev/claude-md-writer.ts"() {
1072
+ "use strict";
1073
+ }
1074
+ });
1075
+
1076
+ // src/dev/dev-command.ts
1077
+ var dev_command_exports = {};
1078
+ __export(dev_command_exports, {
1079
+ runDev: () => runDev
1080
+ });
1081
+ import fs26 from "fs";
1082
+ import path27 from "path";
1083
+ function ensureGitignore(projectPath) {
1084
+ const gitignorePath = path27.join(projectPath, ".gitignore");
1085
+ if (!fs26.existsSync(gitignorePath)) return;
1086
+ const content = fs26.readFileSync(gitignorePath, "utf-8");
1087
+ if (content.includes("CLAUDE.md")) return;
1088
+ fs26.appendFileSync(gitignorePath, "\n# Generated by aman-agent dev\nCLAUDE.md\n");
1089
+ }
1090
+ async function runDev(projectPath, flags = {}, precomputedStack) {
1091
+ const resolved = path27.resolve(projectPath);
1092
+ if (!fs26.existsSync(resolved)) {
1093
+ return { success: false, generated: false, error: `Directory not found: ${resolved}` };
1094
+ }
1095
+ const stack = precomputedStack ?? scanStack(resolved);
1096
+ if (flags.diff) {
1097
+ const ctx2 = await buildContext2(stack, { smart: flags.smart });
1098
+ const newContent = renderToString(ctx2);
1099
+ const existingPath = path27.join(resolved, "CLAUDE.md");
1100
+ const existing = fs26.existsSync(existingPath) ? fs26.readFileSync(existingPath, "utf-8") : "";
1101
+ return {
1102
+ success: true,
1103
+ generated: false,
1104
+ diff: existing === newContent ? "(no changes)" : newContent,
1105
+ context: ctx2
1106
+ };
1107
+ }
1108
+ if (!flags.force) {
1109
+ const staleness = checkStaleness(resolved);
1110
+ if (staleness.status === "fresh") {
1111
+ return { success: true, generated: false, skippedReason: "fresh" };
1112
+ }
1113
+ }
1114
+ const ctx = await buildContext2(stack, { smart: flags.smart });
1115
+ const writeResult = writeClaudeMd(ctx, resolved);
1116
+ ensureGitignore(resolved);
1117
+ return {
1118
+ success: true,
1119
+ generated: writeResult.written,
1120
+ context: ctx
1121
+ };
1122
+ }
1123
+ var init_dev_command = __esm({
1124
+ "src/dev/dev-command.ts"() {
1125
+ "use strict";
1126
+ init_stack_detector();
1127
+ init_context_builder();
1128
+ init_claude_md_writer();
1129
+ }
1130
+ });
1131
+
603
1132
  // src/index.ts
604
1133
  import { Command } from "commander";
605
1134
  import * as p4 from "@clack/prompts";
@@ -696,63 +1225,11 @@ function migrateIfNeeded() {
696
1225
  }
697
1226
 
698
1227
  // src/prompt.ts
1228
+ init_token_budget();
699
1229
  import fs4 from "fs";
700
1230
  import path4 from "path";
701
1231
  import os3 from "os";
702
1232
 
703
- // src/token-budget.ts
704
- function estimateTokens(text3) {
705
- return Math.round(text3.split(/\s+/).filter(Boolean).length * 1.3);
706
- }
707
- var PRIORITIES = [
708
- "identity",
709
- // core.md — always include
710
- "user",
711
- // user.md — user profile, always include
712
- "guardrails",
713
- // rules.md — safety critical
714
- "workflows",
715
- // flow.md — behavioral
716
- "tools",
717
- // kit.md — capabilities
718
- "skills"
719
- // skills.md — can be truncated
720
- ];
721
- function buildBudgetedPrompt(components, maxTokens = 8e3) {
722
- const included = [];
723
- const truncated = [];
724
- const parts = [];
725
- let totalTokens = 0;
726
- const sorted = [...components].sort((a, b) => {
727
- const aPri = PRIORITIES.indexOf(a.name);
728
- const bPri = PRIORITIES.indexOf(b.name);
729
- return (aPri === -1 ? 99 : aPri) - (bPri === -1 ? 99 : bPri);
730
- });
731
- for (const comp of sorted) {
732
- if (totalTokens + comp.tokens <= maxTokens) {
733
- parts.push(comp.content);
734
- included.push(comp.name);
735
- totalTokens += comp.tokens;
736
- } else {
737
- const halfContent = comp.content.slice(0, Math.floor(comp.content.length / 2));
738
- const halfTokens = estimateTokens(halfContent);
739
- if (totalTokens + halfTokens <= maxTokens) {
740
- parts.push(halfContent + "\n\n[... truncated for context budget ...]");
741
- included.push(comp.name + " (partial)");
742
- totalTokens += halfTokens;
743
- } else {
744
- truncated.push(comp.name);
745
- }
746
- }
747
- }
748
- return {
749
- prompt: parts.join("\n\n---\n\n"),
750
- included,
751
- truncated,
752
- totalTokens
753
- };
754
- }
755
-
756
1233
  // src/user-identity.ts
757
1234
  import fs3 from "fs";
758
1235
  import path3 from "path";
@@ -4574,12 +5051,12 @@ You are being delegated a specific task by the primary agent. Complete this task
4574
5051
  </delegation>`;
4575
5052
  let finalDelegationPrompt = delegationPrompt;
4576
5053
  try {
4577
- const recall2 = await memoryRecall(task, { limit: 3, compact: true });
4578
- if (recall2.total > 0) {
5054
+ const recall3 = await memoryRecall(task, { limit: 3, compact: true });
5055
+ if (recall3.total > 0) {
4579
5056
  finalDelegationPrompt += `
4580
5057
 
4581
5058
  <relevant-memories>
4582
- ${recall2.text}
5059
+ ${recall3.text}
4583
5060
  </relevant-memories>`;
4584
5061
  }
4585
5062
  } catch {
@@ -6604,7 +7081,7 @@ function handleReset(action) {
6604
7081
  function handleUpdate() {
6605
7082
  try {
6606
7083
  const current = execFileSync3("npm", ["view", "@aman_asmuei/aman-agent", "version"], { encoding: "utf-8" }).trim();
6607
- const local = true ? "0.32.0" : "unknown";
7084
+ const local = true ? "0.33.1" : "unknown";
6608
7085
  if (current === local) {
6609
7086
  return { handled: true, output: `${pc6.green("Up to date")} \u2014 v${local}` };
6610
7087
  }
@@ -8381,6 +8858,9 @@ Assistant: ${assistantResponse.slice(0, 2e3)}`;
8381
8858
  }
8382
8859
  }
8383
8860
 
8861
+ // src/agent.ts
8862
+ init_token_budget();
8863
+
8384
8864
  // src/errors.ts
8385
8865
  var ERROR_MAPPINGS = [
8386
8866
  { pattern: /rate.?limit|429/i, message: "Rate limited. I'll retry automatically." },
@@ -8988,10 +9468,10 @@ ${converted}
8988
9468
  let augmentedSystemPrompt = activeSystemPrompt;
8989
9469
  let memoryTokens = 0;
8990
9470
  {
8991
- const recall2 = await recallForMessage(input);
8992
- if (recall2) {
8993
- augmentedSystemPrompt = activeSystemPrompt + recall2.text;
8994
- memoryTokens = recall2.tokenEstimate;
9471
+ const recall3 = await recallForMessage(input);
9472
+ if (recall3) {
9473
+ augmentedSystemPrompt = activeSystemPrompt + recall3.text;
9474
+ memoryTokens = recall3.tokenEstimate;
8995
9475
  }
8996
9476
  }
8997
9477
  const userTurnCount = messages.filter((m) => m.role === "user").length;
@@ -9370,8 +9850,8 @@ async function saveConversationToMemory(messages, sessionId) {
9370
9850
  }
9371
9851
 
9372
9852
  // src/index.ts
9373
- import fs24 from "fs";
9374
- import path24 from "path";
9853
+ import fs27 from "fs";
9854
+ import path28 from "path";
9375
9855
 
9376
9856
  // src/presets.ts
9377
9857
  var PRESETS = {
@@ -9585,7 +10065,7 @@ var Inbox = class {
9585
10065
  // package.json
9586
10066
  var package_default = {
9587
10067
  name: "@aman_asmuei/aman-agent",
9588
- version: "0.32.0",
10068
+ version: "0.33.1",
9589
10069
  description: "Your AI companion, running locally \u2014 powered by the aman ecosystem",
9590
10070
  type: "module",
9591
10071
  engines: {
@@ -9878,9 +10358,9 @@ async function runServe(opts) {
9878
10358
 
9879
10359
  // src/index.ts
9880
10360
  async function autoDetectConfig() {
9881
- const reconfigMarker = path24.join(homeDir(), ".reconfig");
9882
- if (fs24.existsSync(reconfigMarker)) {
9883
- fs24.unlinkSync(reconfigMarker);
10361
+ const reconfigMarker = path28.join(homeDir(), ".reconfig");
10362
+ if (fs27.existsSync(reconfigMarker)) {
10363
+ fs27.unlinkSync(reconfigMarker);
9884
10364
  return null;
9885
10365
  }
9886
10366
  const anthropicKey = process.env.ANTHROPIC_API_KEY;
@@ -9909,10 +10389,10 @@ async function autoDetectConfig() {
9909
10389
  return null;
9910
10390
  }
9911
10391
  function bootstrapEcosystem() {
9912
- const corePath = path24.join(identityDir(), "core.md");
9913
- if (fs24.existsSync(corePath)) return false;
9914
- fs24.mkdirSync(identityDir(), { recursive: true });
9915
- fs24.writeFileSync(corePath, [
10392
+ const corePath = path28.join(identityDir(), "core.md");
10393
+ if (fs27.existsSync(corePath)) return false;
10394
+ fs27.mkdirSync(identityDir(), { recursive: true });
10395
+ fs27.writeFileSync(corePath, [
9916
10396
  "# Aman",
9917
10397
  "",
9918
10398
  "## Personality",
@@ -9924,10 +10404,10 @@ function bootstrapEcosystem() {
9924
10404
  "## Session",
9925
10405
  "_New companion \u2014 no prior sessions._"
9926
10406
  ].join("\n"), "utf-8");
9927
- const rulesPath = path24.join(rulesDir(), "rules.md");
9928
- if (!fs24.existsSync(rulesPath)) {
9929
- fs24.mkdirSync(rulesDir(), { recursive: true });
9930
- fs24.writeFileSync(rulesPath, [
10407
+ const rulesPath = path28.join(rulesDir(), "rules.md");
10408
+ if (!fs27.existsSync(rulesPath)) {
10409
+ fs27.mkdirSync(rulesDir(), { recursive: true });
10410
+ fs27.writeFileSync(rulesPath, [
9931
10411
  "# Guardrails",
9932
10412
  "",
9933
10413
  "## safety",
@@ -9939,20 +10419,20 @@ function bootstrapEcosystem() {
9939
10419
  "- Respect the user's preferences stored in memory"
9940
10420
  ].join("\n"), "utf-8");
9941
10421
  }
9942
- const flowPath = path24.join(workflowsDir(), "flow.md");
9943
- if (!fs24.existsSync(flowPath)) {
9944
- fs24.mkdirSync(workflowsDir(), { recursive: true });
9945
- fs24.writeFileSync(flowPath, "# Workflows\n\n_No workflows defined yet. Use /workflows add to create one._\n", "utf-8");
10422
+ const flowPath = path28.join(workflowsDir(), "flow.md");
10423
+ if (!fs27.existsSync(flowPath)) {
10424
+ fs27.mkdirSync(workflowsDir(), { recursive: true });
10425
+ fs27.writeFileSync(flowPath, "# Workflows\n\n_No workflows defined yet. Use /workflows add to create one._\n", "utf-8");
9946
10426
  }
9947
- const skillPath = path24.join(skillsDir(), "skills.md");
9948
- if (!fs24.existsSync(skillPath)) {
9949
- fs24.mkdirSync(skillsDir(), { recursive: true });
9950
- fs24.writeFileSync(skillPath, "# Skills\n\n_No skills installed yet. Use /skills install to add domain expertise._\n", "utf-8");
10427
+ const skillPath = path28.join(skillsDir(), "skills.md");
10428
+ if (!fs27.existsSync(skillPath)) {
10429
+ fs27.mkdirSync(skillsDir(), { recursive: true });
10430
+ fs27.writeFileSync(skillPath, "# Skills\n\n_No skills installed yet. Use /skills install to add domain expertise._\n", "utf-8");
9951
10431
  }
9952
10432
  return true;
9953
10433
  }
9954
10434
  var program = new Command();
9955
- program.name("aman-agent").description("Your AI companion, running locally").version("0.32.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) => {
10435
+ program.name("aman-agent").description("Your AI companion, running locally").version("0.33.1").option("--model <model>", "Override LLM model").option("--budget <tokens>", "Token budget for system prompt (default: 8000)", parseInt).option("--profile <name>", "Use a specific agent profile (e.g., coder, writer, researcher)").action(async (options) => {
9956
10436
  p4.intro(pc9.bold("aman agent") + pc9.dim(" \u2014 your AI companion"));
9957
10437
  let config = loadConfig();
9958
10438
  if (!config) {
@@ -10307,18 +10787,18 @@ program.command("init").description("Set up your AI companion with a guided wiza
10307
10787
  });
10308
10788
  if (p4.isCancel(preset)) process.exit(0);
10309
10789
  const result = applyPreset(preset, name || "Aman");
10310
- fs24.mkdirSync(identityDir(), { recursive: true });
10311
- fs24.writeFileSync(path24.join(identityDir(), "core.md"), result.coreMd, "utf-8");
10790
+ fs27.mkdirSync(identityDir(), { recursive: true });
10791
+ fs27.writeFileSync(path28.join(identityDir(), "core.md"), result.coreMd, "utf-8");
10312
10792
  p4.log.success(`Identity created \u2014 ${PRESETS[preset].identity.personality.split(".")[0].toLowerCase()}`);
10313
10793
  if (result.rulesMd) {
10314
- fs24.mkdirSync(rulesDir(), { recursive: true });
10315
- fs24.writeFileSync(path24.join(rulesDir(), "rules.md"), result.rulesMd, "utf-8");
10794
+ fs27.mkdirSync(rulesDir(), { recursive: true });
10795
+ fs27.writeFileSync(path28.join(rulesDir(), "rules.md"), result.rulesMd, "utf-8");
10316
10796
  const ruleCount = (result.rulesMd.match(/^- /gm) || []).length;
10317
10797
  p4.log.success(`${ruleCount} rules set`);
10318
10798
  }
10319
10799
  if (result.flowMd) {
10320
- fs24.mkdirSync(workflowsDir(), { recursive: true });
10321
- fs24.writeFileSync(path24.join(workflowsDir(), "flow.md"), result.flowMd, "utf-8");
10800
+ fs27.mkdirSync(workflowsDir(), { recursive: true });
10801
+ fs27.writeFileSync(path28.join(workflowsDir(), "flow.md"), result.flowMd, "utf-8");
10322
10802
  const wfCount = (result.flowMd.match(/^## /gm) || []).length;
10323
10803
  p4.log.success(`${wfCount} workflow${wfCount > 1 ? "s" : ""} added`);
10324
10804
  }
@@ -10347,18 +10827,78 @@ program.command("serve").description("Run aman-agent as a local MCP server other
10347
10827
  process.exit(1);
10348
10828
  }
10349
10829
  });
10830
+ 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) => {
10831
+ const { runDev: runDev2 } = await Promise.resolve().then(() => (init_dev_command(), dev_command_exports));
10832
+ const { scanStack: scanStack2 } = await Promise.resolve().then(() => (init_stack_detector(), stack_detector_exports));
10833
+ const targetPath = projectPath ?? process.cwd();
10834
+ const stack = scanStack2(targetPath);
10835
+ const stackParts = stack.languages.map((l) => l.charAt(0).toUpperCase() + l.slice(1));
10836
+ if (stack.frameworks.length > 0) {
10837
+ stackParts.push(`(${stack.frameworks.map((f) => f.charAt(0).toUpperCase() + f.slice(1)).join(", ")})`);
10838
+ }
10839
+ if (stack.databases.length > 0) {
10840
+ stackParts.push(...stack.databases.map((d) => d.charAt(0).toUpperCase() + d.slice(1)));
10841
+ }
10842
+ if (stack.infra.length > 0) {
10843
+ stackParts.push(...stack.infra.map((i) => i.charAt(0).toUpperCase() + i.slice(1)));
10844
+ }
10845
+ if (stack.languages.length > 0) {
10846
+ console.log(`
10847
+ ${pc9.cyan("Detected:")} ${stackParts.join(" + ")}`);
10848
+ } else {
10849
+ console.log(`
10850
+ ${pc9.dim("No stack detected \u2014 generating minimal CLAUDE.md")}`);
10851
+ }
10852
+ const result = await runDev2(targetPath, {
10853
+ smart: opts.smart,
10854
+ noLaunch: opts.launch === false,
10855
+ force: opts.force,
10856
+ diff: opts.diff
10857
+ }, stack);
10858
+ if (!result.success) {
10859
+ console.error(` ${pc9.red("Error:")} ${result.error}`);
10860
+ process.exit(1);
10861
+ }
10862
+ if (result.diff) {
10863
+ console.log(`
10864
+ ${result.diff}`);
10865
+ return;
10866
+ }
10867
+ if (result.generated) {
10868
+ const mode = opts.smart ? "smart" : "template";
10869
+ const memCount = result.context?.metadata.memoriesUsed ?? 0;
10870
+ console.log(` ${pc9.cyan("Recalled:")} ${memCount} memories`);
10871
+ console.log(` ${pc9.green("\u2713")} CLAUDE.md written (${mode} mode)
10872
+ `);
10873
+ } else if (result.skippedReason === "fresh") {
10874
+ console.log(` ${pc9.green("\u2713")} CLAUDE.md is up to date
10875
+ `);
10876
+ }
10877
+ if (opts.launch !== false && !opts.diff) {
10878
+ const { execFileSync: execFileSync4 } = await import("child_process");
10879
+ try {
10880
+ execFileSync4("which", ["claude"], { stdio: "ignore" });
10881
+ } catch {
10882
+ console.log(` ${pc9.yellow("Claude Code not found.")} Install: npm install -g @anthropic-ai/claude-code`);
10883
+ process.exit(1);
10884
+ }
10885
+ console.log(` ${pc9.cyan("Launching Claude Code...")}
10886
+ `);
10887
+ execFileSync4("claude", [], { cwd: targetPath, stdio: "inherit" });
10888
+ }
10889
+ });
10350
10890
  program.command("setup").description("Run the full configuration wizard (provider, identity, presets)").action(async () => {
10351
10891
  p4.intro(pc9.bold("aman agent setup") + pc9.dim(" \u2014 full configuration wizard"));
10352
- const reconfigPath = path24.join(homeDir(), ".reconfig");
10353
- fs24.mkdirSync(homeDir(), { recursive: true });
10354
- fs24.writeFileSync(reconfigPath, "", "utf-8");
10892
+ const reconfigPath = path28.join(homeDir(), ".reconfig");
10893
+ fs27.mkdirSync(homeDir(), { recursive: true });
10894
+ fs27.writeFileSync(reconfigPath, "", "utf-8");
10355
10895
  p4.log.info("Configuration reset. Restart aman-agent to complete setup.");
10356
10896
  });
10357
10897
  program.command("update").description("Update aman-agent to the latest version").action(async () => {
10358
10898
  const { execFileSync: execFileSync4 } = await import("child_process");
10359
- const isVendored = process.execPath.includes(path24.join(".aman-agent", "node"));
10899
+ const isVendored = process.execPath.includes(path28.join(".aman-agent", "node"));
10360
10900
  if (isVendored) {
10361
- const npmPath = path24.join(homeDir(), "node", "bin", "npm");
10901
+ const npmPath = path28.join(homeDir(), "node", "bin", "npm");
10362
10902
  console.log("Updating aman-agent...");
10363
10903
  try {
10364
10904
  execFileSync4(npmPath, ["install", "-g", "@aman_asmuei/aman-agent@latest"], {
@@ -10386,7 +10926,7 @@ program.command("update").description("Update aman-agent to the latest version")
10386
10926
  program.command("uninstall").description("Remove aman-agent and all its data").action(async () => {
10387
10927
  const home2 = homeDir();
10388
10928
  if (!process.stdin.isTTY) {
10389
- fs24.rmSync(home2, { recursive: true, force: true });
10929
+ fs27.rmSync(home2, { recursive: true, force: true });
10390
10930
  console.log("\u2713 Removed " + home2);
10391
10931
  return;
10392
10932
  }
@@ -10397,7 +10937,7 @@ program.command("uninstall").description("Remove aman-agent and all its data").a
10397
10937
  console.log("Cancelled.");
10398
10938
  return;
10399
10939
  }
10400
- fs24.rmSync(home2, { recursive: true, force: true });
10940
+ fs27.rmSync(home2, { recursive: true, force: true });
10401
10941
  console.log("\u2713 Removed " + home2);
10402
10942
  console.log("");
10403
10943
  console.log("To complete uninstall, remove the PATH line from your shell config:");