@aman_asmuei/aman-agent 0.32.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/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,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";
@@ -696,63 +1222,11 @@ function migrateIfNeeded() {
696
1222
  }
697
1223
 
698
1224
  // src/prompt.ts
1225
+ init_token_budget();
699
1226
  import fs4 from "fs";
700
1227
  import path4 from "path";
701
1228
  import os3 from "os";
702
1229
 
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
1230
  // src/user-identity.ts
757
1231
  import fs3 from "fs";
758
1232
  import path3 from "path";
@@ -4574,12 +5048,12 @@ You are being delegated a specific task by the primary agent. Complete this task
4574
5048
  </delegation>`;
4575
5049
  let finalDelegationPrompt = delegationPrompt;
4576
5050
  try {
4577
- const recall2 = await memoryRecall(task, { limit: 3, compact: true });
4578
- if (recall2.total > 0) {
5051
+ const recall3 = await memoryRecall(task, { limit: 3, compact: true });
5052
+ if (recall3.total > 0) {
4579
5053
  finalDelegationPrompt += `
4580
5054
 
4581
5055
  <relevant-memories>
4582
- ${recall2.text}
5056
+ ${recall3.text}
4583
5057
  </relevant-memories>`;
4584
5058
  }
4585
5059
  } catch {
@@ -6604,7 +7078,7 @@ function handleReset(action) {
6604
7078
  function handleUpdate() {
6605
7079
  try {
6606
7080
  const current = execFileSync3("npm", ["view", "@aman_asmuei/aman-agent", "version"], { encoding: "utf-8" }).trim();
6607
- const local = true ? "0.32.0" : "unknown";
7081
+ const local = true ? "0.33.0" : "unknown";
6608
7082
  if (current === local) {
6609
7083
  return { handled: true, output: `${pc6.green("Up to date")} \u2014 v${local}` };
6610
7084
  }
@@ -8381,6 +8855,9 @@ Assistant: ${assistantResponse.slice(0, 2e3)}`;
8381
8855
  }
8382
8856
  }
8383
8857
 
8858
+ // src/agent.ts
8859
+ init_token_budget();
8860
+
8384
8861
  // src/errors.ts
8385
8862
  var ERROR_MAPPINGS = [
8386
8863
  { pattern: /rate.?limit|429/i, message: "Rate limited. I'll retry automatically." },
@@ -8988,10 +9465,10 @@ ${converted}
8988
9465
  let augmentedSystemPrompt = activeSystemPrompt;
8989
9466
  let memoryTokens = 0;
8990
9467
  {
8991
- const recall2 = await recallForMessage(input);
8992
- if (recall2) {
8993
- augmentedSystemPrompt = activeSystemPrompt + recall2.text;
8994
- memoryTokens = recall2.tokenEstimate;
9468
+ const recall3 = await recallForMessage(input);
9469
+ if (recall3) {
9470
+ augmentedSystemPrompt = activeSystemPrompt + recall3.text;
9471
+ memoryTokens = recall3.tokenEstimate;
8995
9472
  }
8996
9473
  }
8997
9474
  const userTurnCount = messages.filter((m) => m.role === "user").length;
@@ -9370,8 +9847,8 @@ async function saveConversationToMemory(messages, sessionId) {
9370
9847
  }
9371
9848
 
9372
9849
  // src/index.ts
9373
- import fs24 from "fs";
9374
- import path24 from "path";
9850
+ import fs27 from "fs";
9851
+ import path28 from "path";
9375
9852
 
9376
9853
  // src/presets.ts
9377
9854
  var PRESETS = {
@@ -9585,7 +10062,7 @@ var Inbox = class {
9585
10062
  // package.json
9586
10063
  var package_default = {
9587
10064
  name: "@aman_asmuei/aman-agent",
9588
- version: "0.32.0",
10065
+ version: "0.33.0",
9589
10066
  description: "Your AI companion, running locally \u2014 powered by the aman ecosystem",
9590
10067
  type: "module",
9591
10068
  engines: {
@@ -9878,9 +10355,9 @@ async function runServe(opts) {
9878
10355
 
9879
10356
  // src/index.ts
9880
10357
  async function autoDetectConfig() {
9881
- const reconfigMarker = path24.join(homeDir(), ".reconfig");
9882
- if (fs24.existsSync(reconfigMarker)) {
9883
- fs24.unlinkSync(reconfigMarker);
10358
+ const reconfigMarker = path28.join(homeDir(), ".reconfig");
10359
+ if (fs27.existsSync(reconfigMarker)) {
10360
+ fs27.unlinkSync(reconfigMarker);
9884
10361
  return null;
9885
10362
  }
9886
10363
  const anthropicKey = process.env.ANTHROPIC_API_KEY;
@@ -9909,10 +10386,10 @@ async function autoDetectConfig() {
9909
10386
  return null;
9910
10387
  }
9911
10388
  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, [
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, [
9916
10393
  "# Aman",
9917
10394
  "",
9918
10395
  "## Personality",
@@ -9924,10 +10401,10 @@ function bootstrapEcosystem() {
9924
10401
  "## Session",
9925
10402
  "_New companion \u2014 no prior sessions._"
9926
10403
  ].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, [
10404
+ const rulesPath = path28.join(rulesDir(), "rules.md");
10405
+ if (!fs27.existsSync(rulesPath)) {
10406
+ fs27.mkdirSync(rulesDir(), { recursive: true });
10407
+ fs27.writeFileSync(rulesPath, [
9931
10408
  "# Guardrails",
9932
10409
  "",
9933
10410
  "## safety",
@@ -9939,20 +10416,20 @@ function bootstrapEcosystem() {
9939
10416
  "- Respect the user's preferences stored in memory"
9940
10417
  ].join("\n"), "utf-8");
9941
10418
  }
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");
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");
9946
10423
  }
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");
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");
9951
10428
  }
9952
10429
  return true;
9953
10430
  }
9954
10431
  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) => {
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) => {
9956
10433
  p4.intro(pc9.bold("aman agent") + pc9.dim(" \u2014 your AI companion"));
9957
10434
  let config = loadConfig();
9958
10435
  if (!config) {
@@ -10307,18 +10784,18 @@ program.command("init").description("Set up your AI companion with a guided wiza
10307
10784
  });
10308
10785
  if (p4.isCancel(preset)) process.exit(0);
10309
10786
  const result = applyPreset(preset, name || "Aman");
10310
- fs24.mkdirSync(identityDir(), { recursive: true });
10311
- fs24.writeFileSync(path24.join(identityDir(), "core.md"), result.coreMd, "utf-8");
10787
+ fs27.mkdirSync(identityDir(), { recursive: true });
10788
+ fs27.writeFileSync(path28.join(identityDir(), "core.md"), result.coreMd, "utf-8");
10312
10789
  p4.log.success(`Identity created \u2014 ${PRESETS[preset].identity.personality.split(".")[0].toLowerCase()}`);
10313
10790
  if (result.rulesMd) {
10314
- fs24.mkdirSync(rulesDir(), { recursive: true });
10315
- fs24.writeFileSync(path24.join(rulesDir(), "rules.md"), result.rulesMd, "utf-8");
10791
+ fs27.mkdirSync(rulesDir(), { recursive: true });
10792
+ fs27.writeFileSync(path28.join(rulesDir(), "rules.md"), result.rulesMd, "utf-8");
10316
10793
  const ruleCount = (result.rulesMd.match(/^- /gm) || []).length;
10317
10794
  p4.log.success(`${ruleCount} rules set`);
10318
10795
  }
10319
10796
  if (result.flowMd) {
10320
- fs24.mkdirSync(workflowsDir(), { recursive: true });
10321
- fs24.writeFileSync(path24.join(workflowsDir(), "flow.md"), result.flowMd, "utf-8");
10797
+ fs27.mkdirSync(workflowsDir(), { recursive: true });
10798
+ fs27.writeFileSync(path28.join(workflowsDir(), "flow.md"), result.flowMd, "utf-8");
10322
10799
  const wfCount = (result.flowMd.match(/^## /gm) || []).length;
10323
10800
  p4.log.success(`${wfCount} workflow${wfCount > 1 ? "s" : ""} added`);
10324
10801
  }
@@ -10347,18 +10824,78 @@ program.command("serve").description("Run aman-agent as a local MCP server other
10347
10824
  process.exit(1);
10348
10825
  }
10349
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
+ });
10350
10887
  program.command("setup").description("Run the full configuration wizard (provider, identity, presets)").action(async () => {
10351
10888
  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");
10889
+ const reconfigPath = path28.join(homeDir(), ".reconfig");
10890
+ fs27.mkdirSync(homeDir(), { recursive: true });
10891
+ fs27.writeFileSync(reconfigPath, "", "utf-8");
10355
10892
  p4.log.info("Configuration reset. Restart aman-agent to complete setup.");
10356
10893
  });
10357
10894
  program.command("update").description("Update aman-agent to the latest version").action(async () => {
10358
10895
  const { execFileSync: execFileSync4 } = await import("child_process");
10359
- const isVendored = process.execPath.includes(path24.join(".aman-agent", "node"));
10896
+ const isVendored = process.execPath.includes(path28.join(".aman-agent", "node"));
10360
10897
  if (isVendored) {
10361
- const npmPath = path24.join(homeDir(), "node", "bin", "npm");
10898
+ const npmPath = path28.join(homeDir(), "node", "bin", "npm");
10362
10899
  console.log("Updating aman-agent...");
10363
10900
  try {
10364
10901
  execFileSync4(npmPath, ["install", "-g", "@aman_asmuei/aman-agent@latest"], {
@@ -10386,7 +10923,7 @@ program.command("update").description("Update aman-agent to the latest version")
10386
10923
  program.command("uninstall").description("Remove aman-agent and all its data").action(async () => {
10387
10924
  const home2 = homeDir();
10388
10925
  if (!process.stdin.isTTY) {
10389
- fs24.rmSync(home2, { recursive: true, force: true });
10926
+ fs27.rmSync(home2, { recursive: true, force: true });
10390
10927
  console.log("\u2713 Removed " + home2);
10391
10928
  return;
10392
10929
  }
@@ -10397,7 +10934,7 @@ program.command("uninstall").description("Remove aman-agent and all its data").a
10397
10934
  console.log("Cancelled.");
10398
10935
  return;
10399
10936
  }
10400
- fs24.rmSync(home2, { recursive: true, force: true });
10937
+ fs27.rmSync(home2, { recursive: true, force: true });
10401
10938
  console.log("\u2713 Removed " + home2);
10402
10939
  console.log("");
10403
10940
  console.log("To complete uninstall, remove the PATH line from your shell config:");