@aman_asmuei/aman-agent 0.34.0 → 0.40.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 +227 -26
- package/dist/delegate.js.map +1 -1
- package/dist/index.js +1251 -242
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -659,24 +659,247 @@ var init_delegate_remote = __esm({
|
|
|
659
659
|
}
|
|
660
660
|
});
|
|
661
661
|
|
|
662
|
+
// src/orchestrator/types.ts
|
|
663
|
+
import { z } from "zod";
|
|
664
|
+
var ModelTierEnum, TaskNodeSchema, PhaseGateTypeEnum, PhaseGateSchema, TaskDAGSchema, OrchestrationStatusEnum, TaskStatusEnum, OrchestrationConfigSchema;
|
|
665
|
+
var init_types = __esm({
|
|
666
|
+
"src/orchestrator/types.ts"() {
|
|
667
|
+
"use strict";
|
|
668
|
+
ModelTierEnum = z.enum(["fast", "standard", "advanced"]);
|
|
669
|
+
TaskNodeSchema = z.object({
|
|
670
|
+
id: z.string().min(1),
|
|
671
|
+
name: z.string().min(1),
|
|
672
|
+
description: z.string().optional(),
|
|
673
|
+
profile: z.string().min(1),
|
|
674
|
+
tier: ModelTierEnum,
|
|
675
|
+
dependencies: z.array(z.string()).default([]),
|
|
676
|
+
phase: z.string().optional(),
|
|
677
|
+
context: z.string().optional(),
|
|
678
|
+
metadata: z.record(z.unknown()).optional()
|
|
679
|
+
});
|
|
680
|
+
PhaseGateTypeEnum = z.enum([
|
|
681
|
+
"approval",
|
|
682
|
+
"ci_pass",
|
|
683
|
+
"test_pass",
|
|
684
|
+
"custom"
|
|
685
|
+
]);
|
|
686
|
+
PhaseGateSchema = z.object({
|
|
687
|
+
id: z.string().min(1),
|
|
688
|
+
name: z.string().min(1),
|
|
689
|
+
type: PhaseGateTypeEnum,
|
|
690
|
+
afterNodes: z.array(z.string()),
|
|
691
|
+
beforeNodes: z.array(z.string()),
|
|
692
|
+
metadata: z.record(z.unknown()).optional()
|
|
693
|
+
});
|
|
694
|
+
TaskDAGSchema = z.object({
|
|
695
|
+
id: z.string().min(1),
|
|
696
|
+
name: z.string().min(1),
|
|
697
|
+
goal: z.string().min(1),
|
|
698
|
+
nodes: z.array(TaskNodeSchema).min(1),
|
|
699
|
+
gates: z.array(PhaseGateSchema).default([]),
|
|
700
|
+
metadata: z.record(z.unknown()).optional()
|
|
701
|
+
});
|
|
702
|
+
OrchestrationStatusEnum = z.enum([
|
|
703
|
+
"pending",
|
|
704
|
+
"running",
|
|
705
|
+
"awaiting_approval",
|
|
706
|
+
"approved",
|
|
707
|
+
"paused",
|
|
708
|
+
"completed",
|
|
709
|
+
"failed",
|
|
710
|
+
"cancelled"
|
|
711
|
+
]);
|
|
712
|
+
TaskStatusEnum = z.enum([
|
|
713
|
+
"pending",
|
|
714
|
+
"ready",
|
|
715
|
+
"running",
|
|
716
|
+
"completed",
|
|
717
|
+
"failed",
|
|
718
|
+
"skipped",
|
|
719
|
+
"blocked"
|
|
720
|
+
]);
|
|
721
|
+
OrchestrationConfigSchema = z.object({
|
|
722
|
+
maxParallelTasks: z.number().int().positive().default(4),
|
|
723
|
+
defaultTier: ModelTierEnum.default("standard"),
|
|
724
|
+
requireApprovalForPhaseTransition: z.boolean().default(true),
|
|
725
|
+
taskTimeoutMs: z.number().int().positive().default(3e5),
|
|
726
|
+
orchestrationTimeoutMs: z.number().int().positive().default(36e5)
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
// src/orchestrator/dag.ts
|
|
732
|
+
function validateDAG(dag) {
|
|
733
|
+
const nodeIds = /* @__PURE__ */ new Set();
|
|
734
|
+
for (const node of dag.nodes) {
|
|
735
|
+
if (nodeIds.has(node.id)) {
|
|
736
|
+
throw new DAGValidationError(`Duplicate node id: "${node.id}"`);
|
|
737
|
+
}
|
|
738
|
+
nodeIds.add(node.id);
|
|
739
|
+
}
|
|
740
|
+
for (const node of dag.nodes) {
|
|
741
|
+
for (const dep of node.dependencies) {
|
|
742
|
+
if (!nodeIds.has(dep)) {
|
|
743
|
+
throw new DAGValidationError(
|
|
744
|
+
`Node "${node.id}" depends on nonexistent node "${dep}"`
|
|
745
|
+
);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
for (const gate of dag.gates) {
|
|
750
|
+
for (const id of gate.afterNodes) {
|
|
751
|
+
if (!nodeIds.has(id)) {
|
|
752
|
+
throw new DAGValidationError(
|
|
753
|
+
`Gate "${gate.id}" references nonexistent afterNode "${id}"`
|
|
754
|
+
);
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
for (const id of gate.beforeNodes) {
|
|
758
|
+
if (!nodeIds.has(id)) {
|
|
759
|
+
throw new DAGValidationError(
|
|
760
|
+
`Gate "${gate.id}" references nonexistent beforeNode "${id}"`
|
|
761
|
+
);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
const inDegree = /* @__PURE__ */ new Map();
|
|
766
|
+
const adj = /* @__PURE__ */ new Map();
|
|
767
|
+
for (const node of dag.nodes) {
|
|
768
|
+
inDegree.set(node.id, 0);
|
|
769
|
+
adj.set(node.id, []);
|
|
770
|
+
}
|
|
771
|
+
for (const node of dag.nodes) {
|
|
772
|
+
for (const dep of node.dependencies) {
|
|
773
|
+
adj.get(dep).push(node.id);
|
|
774
|
+
inDegree.set(node.id, inDegree.get(node.id) + 1);
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
const queue = [];
|
|
778
|
+
for (const [id, deg] of inDegree) {
|
|
779
|
+
if (deg === 0) queue.push(id);
|
|
780
|
+
}
|
|
781
|
+
let visited = 0;
|
|
782
|
+
while (queue.length > 0) {
|
|
783
|
+
const current = queue.shift();
|
|
784
|
+
visited++;
|
|
785
|
+
for (const neighbor of adj.get(current)) {
|
|
786
|
+
const newDeg = inDegree.get(neighbor) - 1;
|
|
787
|
+
inDegree.set(neighbor, newDeg);
|
|
788
|
+
if (newDeg === 0) queue.push(neighbor);
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
if (visited !== dag.nodes.length) {
|
|
792
|
+
throw new DAGValidationError(
|
|
793
|
+
"DAG contains a cycle \u2014 not all nodes were reachable via topological ordering"
|
|
794
|
+
);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
var DAGValidationError;
|
|
798
|
+
var init_dag = __esm({
|
|
799
|
+
"src/orchestrator/dag.ts"() {
|
|
800
|
+
"use strict";
|
|
801
|
+
DAGValidationError = class extends Error {
|
|
802
|
+
constructor(message) {
|
|
803
|
+
super(message);
|
|
804
|
+
this.name = "DAGValidationError";
|
|
805
|
+
}
|
|
806
|
+
};
|
|
807
|
+
}
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
// src/orchestrator/decompose.ts
|
|
811
|
+
function parseDecompositionResponse(response) {
|
|
812
|
+
let jsonStr;
|
|
813
|
+
const codeBlockMatch = response.match(/```(?:json)?\s*\n([\s\S]*?)\n```/);
|
|
814
|
+
if (codeBlockMatch) {
|
|
815
|
+
jsonStr = codeBlockMatch[1];
|
|
816
|
+
} else {
|
|
817
|
+
jsonStr = response;
|
|
818
|
+
}
|
|
819
|
+
let raw;
|
|
820
|
+
try {
|
|
821
|
+
raw = JSON.parse(jsonStr);
|
|
822
|
+
} catch {
|
|
823
|
+
throw new Error(
|
|
824
|
+
`Failed to parse decomposition response as JSON: ${jsonStr.slice(0, 200)}`
|
|
825
|
+
);
|
|
826
|
+
}
|
|
827
|
+
const parsed = TaskDAGSchema.parse(raw);
|
|
828
|
+
validateDAG(parsed);
|
|
829
|
+
return parsed;
|
|
830
|
+
}
|
|
831
|
+
async function decomposeRequirement(requirement, client) {
|
|
832
|
+
const response = await client.chat(
|
|
833
|
+
DECOMPOSITION_SYSTEM_PROMPT,
|
|
834
|
+
[{ role: "user", content: requirement }],
|
|
835
|
+
() => {
|
|
836
|
+
}
|
|
837
|
+
// stream chunks are unused; we read the final message
|
|
838
|
+
);
|
|
839
|
+
const text3 = typeof response.message.content === "string" ? response.message.content : response.message.content.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
840
|
+
return parseDecompositionResponse(text3);
|
|
841
|
+
}
|
|
842
|
+
var DECOMPOSITION_SYSTEM_PROMPT;
|
|
843
|
+
var init_decompose = __esm({
|
|
844
|
+
"src/orchestrator/decompose.ts"() {
|
|
845
|
+
"use strict";
|
|
846
|
+
init_types();
|
|
847
|
+
init_dag();
|
|
848
|
+
DECOMPOSITION_SYSTEM_PROMPT = `You are a software project decomposer. Given a requirement, break it into a task DAG for parallel agent execution.
|
|
849
|
+
|
|
850
|
+
Return ONLY valid JSON matching this schema:
|
|
851
|
+
{
|
|
852
|
+
"id": "orch-<short-id>",
|
|
853
|
+
"name": "<short name>",
|
|
854
|
+
"goal": "<one-line goal>",
|
|
855
|
+
"nodes": [
|
|
856
|
+
{
|
|
857
|
+
"id": "<unique-id>",
|
|
858
|
+
"name": "<task name>",
|
|
859
|
+
"description": "<what to do>",
|
|
860
|
+
"profile": "<architect|coder|tester|reviewer|security>",
|
|
861
|
+
"tier": "<fast|standard|advanced>",
|
|
862
|
+
"dependencies": ["<prerequisite task ids>"]
|
|
863
|
+
}
|
|
864
|
+
],
|
|
865
|
+
"gates": [
|
|
866
|
+
{
|
|
867
|
+
"id": "<gate-id>",
|
|
868
|
+
"name": "<gate description>",
|
|
869
|
+
"type": "approval",
|
|
870
|
+
"afterNodes": ["<completed before gate>"],
|
|
871
|
+
"beforeNodes": ["<blocked until gate resolves>"]
|
|
872
|
+
}
|
|
873
|
+
]
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
Rules:
|
|
877
|
+
- architect profile = tier advanced
|
|
878
|
+
- coder/tester/reviewer = tier standard
|
|
879
|
+
- Maximize parallelism
|
|
880
|
+
- Add approval gate before destructive actions
|
|
881
|
+
- 3-12 tasks for most features`;
|
|
882
|
+
}
|
|
883
|
+
});
|
|
884
|
+
|
|
662
885
|
// src/dev/stack-detector.ts
|
|
663
886
|
var stack_detector_exports = {};
|
|
664
887
|
__export(stack_detector_exports, {
|
|
665
888
|
scanStack: () => scanStack
|
|
666
889
|
});
|
|
667
|
-
import
|
|
668
|
-
import
|
|
890
|
+
import fs17 from "fs";
|
|
891
|
+
import path17 from "path";
|
|
669
892
|
function scanStack(projectPath) {
|
|
670
893
|
const languages = [];
|
|
671
894
|
const frameworks = [];
|
|
672
895
|
const databases = [];
|
|
673
896
|
const infra = [];
|
|
674
897
|
let isMonorepo = false;
|
|
675
|
-
let projectName =
|
|
676
|
-
const goModPath =
|
|
677
|
-
if (
|
|
898
|
+
let projectName = path17.basename(projectPath);
|
|
899
|
+
const goModPath = path17.join(projectPath, "go.mod");
|
|
900
|
+
if (fs17.existsSync(goModPath)) {
|
|
678
901
|
languages.push("go");
|
|
679
|
-
const content =
|
|
902
|
+
const content = fs17.readFileSync(goModPath, "utf-8");
|
|
680
903
|
const moduleMatch = content.match(/^module\s+(.+)$/m);
|
|
681
904
|
if (moduleMatch) {
|
|
682
905
|
const parts = moduleMatch[1].trim().split("/");
|
|
@@ -687,11 +910,11 @@ function scanStack(projectPath) {
|
|
|
687
910
|
if (content.includes("go-chi/chi")) frameworks.push("chi");
|
|
688
911
|
if (content.includes("labstack/echo")) frameworks.push("echo");
|
|
689
912
|
}
|
|
690
|
-
const pkgPath =
|
|
691
|
-
const hasTsConfig =
|
|
692
|
-
if (
|
|
913
|
+
const pkgPath = path17.join(projectPath, "package.json");
|
|
914
|
+
const hasTsConfig = fs17.existsSync(path17.join(projectPath, "tsconfig.json"));
|
|
915
|
+
if (fs17.existsSync(pkgPath)) {
|
|
693
916
|
try {
|
|
694
|
-
const pkg = JSON.parse(
|
|
917
|
+
const pkg = JSON.parse(fs17.readFileSync(pkgPath, "utf-8"));
|
|
695
918
|
if (pkg.name) projectName = pkg.name;
|
|
696
919
|
if (hasTsConfig) {
|
|
697
920
|
languages.push("typescript");
|
|
@@ -709,35 +932,35 @@ function scanStack(projectPath) {
|
|
|
709
932
|
} else if (hasTsConfig) {
|
|
710
933
|
languages.push("typescript");
|
|
711
934
|
}
|
|
712
|
-
const cargoPath =
|
|
713
|
-
if (
|
|
935
|
+
const cargoPath = path17.join(projectPath, "Cargo.toml");
|
|
936
|
+
if (fs17.existsSync(cargoPath)) {
|
|
714
937
|
languages.push("rust");
|
|
715
|
-
const content =
|
|
938
|
+
const content = fs17.readFileSync(cargoPath, "utf-8");
|
|
716
939
|
if (content.includes("[workspace]")) isMonorepo = true;
|
|
717
940
|
const nameMatch = content.match(/^\s*name\s*=\s*"([^"]+)"/m);
|
|
718
941
|
if (nameMatch && !isMonorepo) projectName = nameMatch[1];
|
|
719
942
|
}
|
|
720
|
-
const pyprojectPath =
|
|
721
|
-
if (
|
|
943
|
+
const pyprojectPath = path17.join(projectPath, "pyproject.toml");
|
|
944
|
+
if (fs17.existsSync(pyprojectPath)) {
|
|
722
945
|
languages.push("python");
|
|
723
|
-
const content =
|
|
946
|
+
const content = fs17.readFileSync(pyprojectPath, "utf-8");
|
|
724
947
|
if (content.includes("django")) frameworks.push("django");
|
|
725
948
|
if (content.includes("fastapi")) frameworks.push("fastapi");
|
|
726
949
|
if (content.includes("flask")) frameworks.push("flask");
|
|
727
950
|
}
|
|
728
|
-
if (
|
|
951
|
+
if (fs17.existsSync(path17.join(projectPath, "pubspec.yaml"))) {
|
|
729
952
|
languages.push("dart");
|
|
730
953
|
frameworks.push("flutter");
|
|
731
954
|
}
|
|
732
|
-
if (
|
|
955
|
+
if (fs17.existsSync(path17.join(projectPath, "Dockerfile"))) {
|
|
733
956
|
infra.push("docker");
|
|
734
957
|
}
|
|
735
958
|
const composeNames = ["docker-compose.yml", "docker-compose.yaml", "compose.yml", "compose.yaml"];
|
|
736
959
|
for (const name of composeNames) {
|
|
737
|
-
const composePath =
|
|
738
|
-
if (
|
|
960
|
+
const composePath = path17.join(projectPath, name);
|
|
961
|
+
if (fs17.existsSync(composePath)) {
|
|
739
962
|
if (!infra.includes("docker")) infra.push("docker");
|
|
740
|
-
const content =
|
|
963
|
+
const content = fs17.readFileSync(composePath, "utf-8");
|
|
741
964
|
for (const [pattern, dbName] of Object.entries(DB_IMAGE_MAP)) {
|
|
742
965
|
if (content.includes(pattern) && !databases.includes(dbName)) {
|
|
743
966
|
databases.push(dbName);
|
|
@@ -746,16 +969,16 @@ function scanStack(projectPath) {
|
|
|
746
969
|
break;
|
|
747
970
|
}
|
|
748
971
|
}
|
|
749
|
-
if (
|
|
972
|
+
if (fs17.existsSync(path17.join(projectPath, ".github", "workflows"))) {
|
|
750
973
|
infra.push("github-actions");
|
|
751
974
|
}
|
|
752
975
|
for (const dir of ["k3s", "k8s", "deploy"]) {
|
|
753
|
-
if (
|
|
976
|
+
if (fs17.existsSync(path17.join(projectPath, dir))) {
|
|
754
977
|
infra.push("kubernetes");
|
|
755
978
|
break;
|
|
756
979
|
}
|
|
757
980
|
}
|
|
758
|
-
if (
|
|
981
|
+
if (fs17.existsSync(path17.join(projectPath, "Makefile"))) {
|
|
759
982
|
infra.push("make");
|
|
760
983
|
}
|
|
761
984
|
return {
|
|
@@ -795,10 +1018,475 @@ var init_stack_detector = __esm({
|
|
|
795
1018
|
}
|
|
796
1019
|
});
|
|
797
1020
|
|
|
1021
|
+
// src/github/types.ts
|
|
1022
|
+
import { z as z2 } from "zod";
|
|
1023
|
+
var GitHubIssueSchema, GitHubPRSchema, WorkflowRunSchema, CheckStatusSchema, GhResultSchema;
|
|
1024
|
+
var init_types2 = __esm({
|
|
1025
|
+
"src/github/types.ts"() {
|
|
1026
|
+
"use strict";
|
|
1027
|
+
GitHubIssueSchema = z2.object({
|
|
1028
|
+
number: z2.number().int().positive(),
|
|
1029
|
+
title: z2.string().min(1),
|
|
1030
|
+
body: z2.string().nullable().default(null),
|
|
1031
|
+
state: z2.enum(["OPEN", "CLOSED"]),
|
|
1032
|
+
url: z2.string().url(),
|
|
1033
|
+
labels: z2.array(z2.object({ name: z2.string() })).default([]),
|
|
1034
|
+
assignees: z2.array(z2.object({ login: z2.string() })).default([]),
|
|
1035
|
+
author: z2.object({ login: z2.string() }).optional(),
|
|
1036
|
+
createdAt: z2.string(),
|
|
1037
|
+
updatedAt: z2.string()
|
|
1038
|
+
});
|
|
1039
|
+
GitHubPRSchema = z2.object({
|
|
1040
|
+
number: z2.number().int().positive(),
|
|
1041
|
+
title: z2.string().min(1),
|
|
1042
|
+
body: z2.string().nullable().default(null),
|
|
1043
|
+
state: z2.enum(["OPEN", "CLOSED", "MERGED"]),
|
|
1044
|
+
url: z2.string().url(),
|
|
1045
|
+
headRefName: z2.string(),
|
|
1046
|
+
baseRefName: z2.string(),
|
|
1047
|
+
isDraft: z2.boolean().default(false),
|
|
1048
|
+
mergeable: z2.enum(["MERGEABLE", "CONFLICTING", "UNKNOWN"]).default("UNKNOWN"),
|
|
1049
|
+
labels: z2.array(z2.object({ name: z2.string() })).default([]),
|
|
1050
|
+
author: z2.object({ login: z2.string() }).optional(),
|
|
1051
|
+
createdAt: z2.string(),
|
|
1052
|
+
updatedAt: z2.string()
|
|
1053
|
+
});
|
|
1054
|
+
WorkflowRunSchema = z2.object({
|
|
1055
|
+
databaseId: z2.number().int().positive(),
|
|
1056
|
+
name: z2.string(),
|
|
1057
|
+
workflowName: z2.string().optional(),
|
|
1058
|
+
status: z2.enum([
|
|
1059
|
+
"queued",
|
|
1060
|
+
"in_progress",
|
|
1061
|
+
"completed",
|
|
1062
|
+
"waiting",
|
|
1063
|
+
"requested",
|
|
1064
|
+
"pending"
|
|
1065
|
+
]),
|
|
1066
|
+
conclusion: z2.enum([
|
|
1067
|
+
"success",
|
|
1068
|
+
"failure",
|
|
1069
|
+
"cancelled",
|
|
1070
|
+
"skipped",
|
|
1071
|
+
"timed_out",
|
|
1072
|
+
"action_required",
|
|
1073
|
+
"neutral",
|
|
1074
|
+
"stale",
|
|
1075
|
+
""
|
|
1076
|
+
]).nullable().default(null),
|
|
1077
|
+
url: z2.string().url(),
|
|
1078
|
+
headBranch: z2.string(),
|
|
1079
|
+
event: z2.string(),
|
|
1080
|
+
createdAt: z2.string(),
|
|
1081
|
+
updatedAt: z2.string()
|
|
1082
|
+
});
|
|
1083
|
+
CheckStatusSchema = z2.object({
|
|
1084
|
+
passed: z2.boolean(),
|
|
1085
|
+
pending: z2.boolean(),
|
|
1086
|
+
failing: z2.boolean(),
|
|
1087
|
+
total: z2.number().int().nonnegative(),
|
|
1088
|
+
details: z2.array(
|
|
1089
|
+
z2.object({
|
|
1090
|
+
name: z2.string(),
|
|
1091
|
+
status: z2.string(),
|
|
1092
|
+
conclusion: z2.string().nullable()
|
|
1093
|
+
})
|
|
1094
|
+
).default([])
|
|
1095
|
+
});
|
|
1096
|
+
GhResultSchema = z2.object({
|
|
1097
|
+
success: z2.boolean(),
|
|
1098
|
+
stdout: z2.string(),
|
|
1099
|
+
stderr: z2.string(),
|
|
1100
|
+
exitCode: z2.number().int()
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
});
|
|
1104
|
+
|
|
1105
|
+
// src/github/cli.ts
|
|
1106
|
+
var cli_exports = {};
|
|
1107
|
+
__export(cli_exports, {
|
|
1108
|
+
GhError: () => GhError,
|
|
1109
|
+
gh: () => gh,
|
|
1110
|
+
ghAvailable: () => ghAvailable,
|
|
1111
|
+
ghCurrentRepo: () => ghCurrentRepo,
|
|
1112
|
+
ghJson: () => ghJson
|
|
1113
|
+
});
|
|
1114
|
+
import { execFile } from "child_process";
|
|
1115
|
+
import { promisify } from "util";
|
|
1116
|
+
async function gh(args, options) {
|
|
1117
|
+
const ghBin = options?.env?.GH_PATH ?? process.env.GH_PATH ?? "gh";
|
|
1118
|
+
const timeout = options?.timeoutMs ?? 3e4;
|
|
1119
|
+
const execOpts = {
|
|
1120
|
+
timeout,
|
|
1121
|
+
...options?.cwd ? { cwd: options.cwd } : {},
|
|
1122
|
+
...options?.env ? { env: { ...process.env, ...options.env } } : {}
|
|
1123
|
+
};
|
|
1124
|
+
try {
|
|
1125
|
+
const { stdout, stderr } = await execFileAsync(ghBin, args, execOpts);
|
|
1126
|
+
return { success: true, stdout, stderr, exitCode: 0 };
|
|
1127
|
+
} catch (err) {
|
|
1128
|
+
const e = err;
|
|
1129
|
+
const exitCode = typeof e.code === "number" ? e.code : 1;
|
|
1130
|
+
return {
|
|
1131
|
+
success: false,
|
|
1132
|
+
stdout: e.stdout ?? "",
|
|
1133
|
+
stderr: e.stderr ?? "",
|
|
1134
|
+
exitCode
|
|
1135
|
+
};
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
async function ghJson(args, options) {
|
|
1139
|
+
const result = await gh(args, options);
|
|
1140
|
+
if (!result.success) {
|
|
1141
|
+
throw new GhError(
|
|
1142
|
+
`gh command failed: ${result.stderr}`,
|
|
1143
|
+
result.exitCode,
|
|
1144
|
+
result.stderr
|
|
1145
|
+
);
|
|
1146
|
+
}
|
|
1147
|
+
try {
|
|
1148
|
+
return JSON.parse(result.stdout);
|
|
1149
|
+
} catch {
|
|
1150
|
+
throw new GhError(
|
|
1151
|
+
`Failed to parse JSON from gh output: ${result.stdout.slice(0, 200)}`,
|
|
1152
|
+
0,
|
|
1153
|
+
result.stderr
|
|
1154
|
+
);
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
async function ghAvailable() {
|
|
1158
|
+
const result = await gh(["auth", "status"]);
|
|
1159
|
+
return result.success;
|
|
1160
|
+
}
|
|
1161
|
+
async function ghCurrentRepo() {
|
|
1162
|
+
try {
|
|
1163
|
+
const data = await ghJson(
|
|
1164
|
+
["repo", "view", "--json", "owner,name"]
|
|
1165
|
+
);
|
|
1166
|
+
return { owner: data.owner.login, name: data.name };
|
|
1167
|
+
} catch {
|
|
1168
|
+
return null;
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
var execFileAsync, GhError;
|
|
1172
|
+
var init_cli = __esm({
|
|
1173
|
+
"src/github/cli.ts"() {
|
|
1174
|
+
"use strict";
|
|
1175
|
+
execFileAsync = promisify(execFile);
|
|
1176
|
+
GhError = class extends Error {
|
|
1177
|
+
constructor(message, exitCode, stderr) {
|
|
1178
|
+
super(message);
|
|
1179
|
+
this.exitCode = exitCode;
|
|
1180
|
+
this.stderr = stderr;
|
|
1181
|
+
this.name = "GhError";
|
|
1182
|
+
}
|
|
1183
|
+
exitCode;
|
|
1184
|
+
stderr;
|
|
1185
|
+
};
|
|
1186
|
+
}
|
|
1187
|
+
});
|
|
1188
|
+
|
|
1189
|
+
// src/github/issue-planner.ts
|
|
1190
|
+
async function fetchIssue(issueNumber, options) {
|
|
1191
|
+
const args = [
|
|
1192
|
+
"issue",
|
|
1193
|
+
"view",
|
|
1194
|
+
String(issueNumber),
|
|
1195
|
+
"--json",
|
|
1196
|
+
ISSUE_JSON_FIELDS
|
|
1197
|
+
];
|
|
1198
|
+
if (options?.repo) {
|
|
1199
|
+
args.push("--repo", options.repo);
|
|
1200
|
+
}
|
|
1201
|
+
const raw = await ghJson(args, { cwd: options?.cwd });
|
|
1202
|
+
return GitHubIssueSchema.parse(raw);
|
|
1203
|
+
}
|
|
1204
|
+
function formatIssueAsRequirement(issue) {
|
|
1205
|
+
const parts = [`# ${issue.title}`];
|
|
1206
|
+
if (issue.body) {
|
|
1207
|
+
parts.push("", issue.body);
|
|
1208
|
+
}
|
|
1209
|
+
const extras = [];
|
|
1210
|
+
if (issue.labels.length > 0) {
|
|
1211
|
+
extras.push(`Labels: ${issue.labels.map((l) => l.name).join(", ")}`);
|
|
1212
|
+
}
|
|
1213
|
+
if (issue.assignees.length > 0) {
|
|
1214
|
+
extras.push(
|
|
1215
|
+
`Assignees: ${issue.assignees.map((a) => a.login).join(", ")}`
|
|
1216
|
+
);
|
|
1217
|
+
}
|
|
1218
|
+
if (extras.length > 0) {
|
|
1219
|
+
parts.push("", ...extras);
|
|
1220
|
+
}
|
|
1221
|
+
return parts.join("\n");
|
|
1222
|
+
}
|
|
1223
|
+
async function planFromIssue(issueNumber, client, options) {
|
|
1224
|
+
const issue = await fetchIssue(issueNumber, options);
|
|
1225
|
+
const requirement = formatIssueAsRequirement(issue);
|
|
1226
|
+
const dag = await decomposeRequirement(requirement, client);
|
|
1227
|
+
return { issue, dag };
|
|
1228
|
+
}
|
|
1229
|
+
var ISSUE_JSON_FIELDS;
|
|
1230
|
+
var init_issue_planner = __esm({
|
|
1231
|
+
"src/github/issue-planner.ts"() {
|
|
1232
|
+
"use strict";
|
|
1233
|
+
init_cli();
|
|
1234
|
+
init_types2();
|
|
1235
|
+
init_decompose();
|
|
1236
|
+
ISSUE_JSON_FIELDS = "number,title,body,state,url,labels,assignees,author,createdAt,updatedAt";
|
|
1237
|
+
}
|
|
1238
|
+
});
|
|
1239
|
+
|
|
1240
|
+
// src/github/pr-manager.ts
|
|
1241
|
+
import { execFile as execFile2 } from "child_process";
|
|
1242
|
+
import { promisify as promisify2 } from "util";
|
|
1243
|
+
async function createPR(options) {
|
|
1244
|
+
const args = [
|
|
1245
|
+
"pr",
|
|
1246
|
+
"create",
|
|
1247
|
+
"--title",
|
|
1248
|
+
options.title,
|
|
1249
|
+
"--body",
|
|
1250
|
+
options.body,
|
|
1251
|
+
"--head",
|
|
1252
|
+
options.head
|
|
1253
|
+
];
|
|
1254
|
+
if (options.base) {
|
|
1255
|
+
args.push("--base", options.base);
|
|
1256
|
+
}
|
|
1257
|
+
if (options.draft) {
|
|
1258
|
+
args.push("--draft");
|
|
1259
|
+
}
|
|
1260
|
+
if (options.labels) {
|
|
1261
|
+
for (const label of options.labels) {
|
|
1262
|
+
args.push("--label", label);
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
if (options.repo) {
|
|
1266
|
+
args.push("--repo", options.repo);
|
|
1267
|
+
}
|
|
1268
|
+
const ghOpts = options.cwd ? { cwd: options.cwd } : void 0;
|
|
1269
|
+
const result = await gh(args, ghOpts);
|
|
1270
|
+
if (!result.success) {
|
|
1271
|
+
const { GhError: GhError2 } = await Promise.resolve().then(() => (init_cli(), cli_exports));
|
|
1272
|
+
throw new GhError2(
|
|
1273
|
+
`Failed to create PR: ${result.stderr}`,
|
|
1274
|
+
result.exitCode,
|
|
1275
|
+
result.stderr
|
|
1276
|
+
);
|
|
1277
|
+
}
|
|
1278
|
+
const url = result.stdout.trim();
|
|
1279
|
+
const prNumber = parseInt(url.split("/").pop(), 10);
|
|
1280
|
+
return getPR(prNumber, { repo: options.repo, cwd: options.cwd });
|
|
1281
|
+
}
|
|
1282
|
+
async function listPRs(options) {
|
|
1283
|
+
const args = ["pr", "list", "--json", PR_JSON_FIELDS];
|
|
1284
|
+
if (options?.state) {
|
|
1285
|
+
args.push("--state", options.state);
|
|
1286
|
+
}
|
|
1287
|
+
if (options?.head) {
|
|
1288
|
+
args.push("--head", options.head);
|
|
1289
|
+
}
|
|
1290
|
+
if (options?.limit != null) {
|
|
1291
|
+
args.push("--limit", String(options.limit));
|
|
1292
|
+
}
|
|
1293
|
+
if (options?.repo) {
|
|
1294
|
+
args.push("--repo", options.repo);
|
|
1295
|
+
}
|
|
1296
|
+
const ghOpts = options?.cwd ? { cwd: options.cwd } : void 0;
|
|
1297
|
+
const raw = await ghJson(args, ghOpts);
|
|
1298
|
+
return raw.map((item) => GitHubPRSchema.parse(item));
|
|
1299
|
+
}
|
|
1300
|
+
async function getPR(prNumber, options) {
|
|
1301
|
+
const args = [
|
|
1302
|
+
"pr",
|
|
1303
|
+
"view",
|
|
1304
|
+
String(prNumber),
|
|
1305
|
+
"--json",
|
|
1306
|
+
PR_JSON_FIELDS
|
|
1307
|
+
];
|
|
1308
|
+
if (options?.repo) {
|
|
1309
|
+
args.push("--repo", options.repo);
|
|
1310
|
+
}
|
|
1311
|
+
const ghOpts = options?.cwd ? { cwd: options.cwd } : void 0;
|
|
1312
|
+
const raw = await ghJson(args, ghOpts);
|
|
1313
|
+
return GitHubPRSchema.parse(raw);
|
|
1314
|
+
}
|
|
1315
|
+
async function commentOnPR(prNumber, body, options) {
|
|
1316
|
+
const args = ["pr", "comment", String(prNumber), "--body", body];
|
|
1317
|
+
if (options?.repo) {
|
|
1318
|
+
args.push("--repo", options.repo);
|
|
1319
|
+
}
|
|
1320
|
+
const ghOpts = options?.cwd ? { cwd: options.cwd } : void 0;
|
|
1321
|
+
const result = await gh(args, ghOpts);
|
|
1322
|
+
if (!result.success) {
|
|
1323
|
+
const { GhError: GhError2 } = await Promise.resolve().then(() => (init_cli(), cli_exports));
|
|
1324
|
+
throw new GhError2(
|
|
1325
|
+
`Failed to comment on PR #${prNumber}: ${result.stderr}`,
|
|
1326
|
+
result.exitCode,
|
|
1327
|
+
result.stderr
|
|
1328
|
+
);
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
async function createBranch(branchName, options) {
|
|
1332
|
+
const args = ["checkout", "-b", branchName];
|
|
1333
|
+
if (options?.baseBranch) {
|
|
1334
|
+
args.push(options.baseBranch);
|
|
1335
|
+
}
|
|
1336
|
+
const execOpts = {};
|
|
1337
|
+
if (options?.cwd) {
|
|
1338
|
+
execOpts.cwd = options.cwd;
|
|
1339
|
+
}
|
|
1340
|
+
await execFileAsync2("git", args, execOpts);
|
|
1341
|
+
}
|
|
1342
|
+
var execFileAsync2, PR_JSON_FIELDS;
|
|
1343
|
+
var init_pr_manager = __esm({
|
|
1344
|
+
"src/github/pr-manager.ts"() {
|
|
1345
|
+
"use strict";
|
|
1346
|
+
init_cli();
|
|
1347
|
+
init_types2();
|
|
1348
|
+
execFileAsync2 = promisify2(execFile2);
|
|
1349
|
+
PR_JSON_FIELDS = "number,title,body,state,url,headRefName,baseRefName,isDraft,mergeable,labels,author,createdAt,updatedAt";
|
|
1350
|
+
}
|
|
1351
|
+
});
|
|
1352
|
+
|
|
1353
|
+
// src/github/ci-gate.ts
|
|
1354
|
+
async function getLatestRun(branch, options) {
|
|
1355
|
+
const args = [
|
|
1356
|
+
"run",
|
|
1357
|
+
"list",
|
|
1358
|
+
"--branch",
|
|
1359
|
+
branch,
|
|
1360
|
+
"--limit",
|
|
1361
|
+
"1",
|
|
1362
|
+
"--json",
|
|
1363
|
+
RUN_JSON_FIELDS
|
|
1364
|
+
];
|
|
1365
|
+
if (options?.workflow) {
|
|
1366
|
+
args.push("--workflow", options.workflow);
|
|
1367
|
+
}
|
|
1368
|
+
if (options?.repo) {
|
|
1369
|
+
args.push("--repo", options.repo);
|
|
1370
|
+
}
|
|
1371
|
+
const runs = await ghJson(args, { cwd: options?.cwd });
|
|
1372
|
+
if (!runs.length) return null;
|
|
1373
|
+
return WorkflowRunSchema.parse(runs[0]);
|
|
1374
|
+
}
|
|
1375
|
+
async function getCheckStatus(ref, options) {
|
|
1376
|
+
const isPRNumber = /^\d+$/.test(ref);
|
|
1377
|
+
if (isPRNumber) {
|
|
1378
|
+
const args = ["pr", "checks", ref, "--json", "name,status,conclusion"];
|
|
1379
|
+
if (options?.repo) args.push("--repo", options.repo);
|
|
1380
|
+
const checks = await ghJson(args, { cwd: options?.cwd });
|
|
1381
|
+
const details = checks.map((c) => ({
|
|
1382
|
+
name: c.name,
|
|
1383
|
+
status: c.status,
|
|
1384
|
+
conclusion: c.conclusion
|
|
1385
|
+
}));
|
|
1386
|
+
const passed = details.every(
|
|
1387
|
+
(d) => d.status === "completed" && d.conclusion === "success"
|
|
1388
|
+
);
|
|
1389
|
+
const pending = details.some((d) => d.status !== "completed");
|
|
1390
|
+
const failing = details.some(
|
|
1391
|
+
(d) => d.status === "completed" && d.conclusion !== "success" && d.conclusion !== "skipped" && d.conclusion !== "neutral"
|
|
1392
|
+
);
|
|
1393
|
+
return CheckStatusSchema.parse({
|
|
1394
|
+
passed: passed && details.length > 0,
|
|
1395
|
+
pending,
|
|
1396
|
+
failing,
|
|
1397
|
+
total: details.length,
|
|
1398
|
+
details
|
|
1399
|
+
});
|
|
1400
|
+
}
|
|
1401
|
+
const run = await getLatestRun(ref, options);
|
|
1402
|
+
if (!run) {
|
|
1403
|
+
return CheckStatusSchema.parse({
|
|
1404
|
+
passed: false,
|
|
1405
|
+
pending: false,
|
|
1406
|
+
failing: false,
|
|
1407
|
+
total: 0,
|
|
1408
|
+
details: []
|
|
1409
|
+
});
|
|
1410
|
+
}
|
|
1411
|
+
return CheckStatusSchema.parse({
|
|
1412
|
+
passed: run.status === "completed" && run.conclusion === "success",
|
|
1413
|
+
pending: run.status !== "completed",
|
|
1414
|
+
failing: run.status === "completed" && run.conclusion !== "success" && run.conclusion !== "skipped" && run.conclusion !== "neutral",
|
|
1415
|
+
total: 1,
|
|
1416
|
+
details: [
|
|
1417
|
+
{ name: run.name, status: run.status, conclusion: run.conclusion }
|
|
1418
|
+
]
|
|
1419
|
+
});
|
|
1420
|
+
}
|
|
1421
|
+
async function waitForCI(branch, options) {
|
|
1422
|
+
const pollInterval = options?.pollIntervalMs ?? 1e4;
|
|
1423
|
+
const timeout = options?.timeoutMs ?? 6e5;
|
|
1424
|
+
const deadline = Date.now() + timeout;
|
|
1425
|
+
while (Date.now() < deadline) {
|
|
1426
|
+
const run = await getLatestRun(branch, options);
|
|
1427
|
+
if (run && run.status === "completed") {
|
|
1428
|
+
return { passed: run.conclusion === "success", run };
|
|
1429
|
+
}
|
|
1430
|
+
if (Date.now() + pollInterval >= deadline) break;
|
|
1431
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
1432
|
+
}
|
|
1433
|
+
return { passed: false, run: null };
|
|
1434
|
+
}
|
|
1435
|
+
async function isCIPassing(branch, options) {
|
|
1436
|
+
const run = await getLatestRun(branch, options);
|
|
1437
|
+
return run !== null && run.status === "completed" && run.conclusion === "success";
|
|
1438
|
+
}
|
|
1439
|
+
var RUN_JSON_FIELDS;
|
|
1440
|
+
var init_ci_gate = __esm({
|
|
1441
|
+
"src/github/ci-gate.ts"() {
|
|
1442
|
+
"use strict";
|
|
1443
|
+
init_cli();
|
|
1444
|
+
init_types2();
|
|
1445
|
+
RUN_JSON_FIELDS = "databaseId,name,workflowName,status,conclusion,url,headBranch,event,createdAt,updatedAt";
|
|
1446
|
+
}
|
|
1447
|
+
});
|
|
1448
|
+
|
|
1449
|
+
// src/github/index.ts
|
|
1450
|
+
var github_exports = {};
|
|
1451
|
+
__export(github_exports, {
|
|
1452
|
+
CheckStatusSchema: () => CheckStatusSchema,
|
|
1453
|
+
GhError: () => GhError,
|
|
1454
|
+
GhResultSchema: () => GhResultSchema,
|
|
1455
|
+
GitHubIssueSchema: () => GitHubIssueSchema,
|
|
1456
|
+
GitHubPRSchema: () => GitHubPRSchema,
|
|
1457
|
+
WorkflowRunSchema: () => WorkflowRunSchema,
|
|
1458
|
+
commentOnPR: () => commentOnPR,
|
|
1459
|
+
createBranch: () => createBranch,
|
|
1460
|
+
createPR: () => createPR,
|
|
1461
|
+
fetchIssue: () => fetchIssue,
|
|
1462
|
+
formatIssueAsRequirement: () => formatIssueAsRequirement,
|
|
1463
|
+
getCheckStatus: () => getCheckStatus,
|
|
1464
|
+
getLatestRun: () => getLatestRun,
|
|
1465
|
+
getPR: () => getPR,
|
|
1466
|
+
gh: () => gh,
|
|
1467
|
+
ghAvailable: () => ghAvailable,
|
|
1468
|
+
ghCurrentRepo: () => ghCurrentRepo,
|
|
1469
|
+
ghJson: () => ghJson,
|
|
1470
|
+
isCIPassing: () => isCIPassing,
|
|
1471
|
+
listPRs: () => listPRs,
|
|
1472
|
+
planFromIssue: () => planFromIssue,
|
|
1473
|
+
waitForCI: () => waitForCI
|
|
1474
|
+
});
|
|
1475
|
+
var init_github = __esm({
|
|
1476
|
+
"src/github/index.ts"() {
|
|
1477
|
+
"use strict";
|
|
1478
|
+
init_types2();
|
|
1479
|
+
init_cli();
|
|
1480
|
+
init_issue_planner();
|
|
1481
|
+
init_pr_manager();
|
|
1482
|
+
init_ci_gate();
|
|
1483
|
+
}
|
|
1484
|
+
});
|
|
1485
|
+
|
|
798
1486
|
// src/dev/context-builder.ts
|
|
799
|
-
import
|
|
800
|
-
import
|
|
801
|
-
import
|
|
1487
|
+
import fs26 from "fs";
|
|
1488
|
+
import path26 from "path";
|
|
1489
|
+
import os23 from "os";
|
|
802
1490
|
import { createDatabase as createDatabase2, recall as recall2 } from "@aman_asmuei/amem-core";
|
|
803
1491
|
import {
|
|
804
1492
|
getIdentity as acoreGetIdentity2
|
|
@@ -826,9 +1514,9 @@ async function buildContext2(stack, opts) {
|
|
|
826
1514
|
const rules = [];
|
|
827
1515
|
let memoriesUsed = 0;
|
|
828
1516
|
try {
|
|
829
|
-
const amemDir = process.env.AMEM_DIR ??
|
|
830
|
-
const dbPath = process.env.AMEM_DB ??
|
|
831
|
-
if (!process.env.AMEM_DB && !
|
|
1517
|
+
const amemDir = process.env.AMEM_DIR ?? path26.join(os23.homedir(), ".amem");
|
|
1518
|
+
const dbPath = process.env.AMEM_DB ?? path26.join(amemDir, "memory.db");
|
|
1519
|
+
if (!process.env.AMEM_DB && !fs26.existsSync(dbPath)) throw new Error("no db");
|
|
832
1520
|
const db2 = createDatabase2(dbPath);
|
|
833
1521
|
const queryParts = [stack.projectName, ...stack.languages, ...stack.frameworks];
|
|
834
1522
|
const query = queryParts.join(" ");
|
|
@@ -984,8 +1672,8 @@ __export(claude_md_writer_exports, {
|
|
|
984
1672
|
writeClaudeMd: () => writeClaudeMd,
|
|
985
1673
|
writeContextFile: () => writeContextFile
|
|
986
1674
|
});
|
|
987
|
-
import
|
|
988
|
-
import
|
|
1675
|
+
import fs27 from "fs";
|
|
1676
|
+
import path27 from "path";
|
|
989
1677
|
function formatStack(stack) {
|
|
990
1678
|
const parts = [];
|
|
991
1679
|
const goFrameworks = ["fiber", "gin", "chi", "echo"];
|
|
@@ -1069,11 +1757,11 @@ function parseMarker(content) {
|
|
|
1069
1757
|
}
|
|
1070
1758
|
function checkStaleness(projectPath, editor = "claude") {
|
|
1071
1759
|
const target = EDITOR_TARGETS[editor];
|
|
1072
|
-
const filePath =
|
|
1073
|
-
if (!
|
|
1760
|
+
const filePath = path27.join(projectPath, target.contextFile);
|
|
1761
|
+
if (!fs27.existsSync(filePath)) {
|
|
1074
1762
|
return { status: "missing" };
|
|
1075
1763
|
}
|
|
1076
|
-
const content =
|
|
1764
|
+
const content = fs27.readFileSync(filePath, "utf-8");
|
|
1077
1765
|
const marker = parseMarker(content);
|
|
1078
1766
|
if (!marker) {
|
|
1079
1767
|
return { status: "no-marker" };
|
|
@@ -1082,22 +1770,22 @@ function checkStaleness(projectPath, editor = "claude") {
|
|
|
1082
1770
|
}
|
|
1083
1771
|
function writeContextFile(ctx, projectPath, editor = "claude") {
|
|
1084
1772
|
const target = EDITOR_TARGETS[editor];
|
|
1085
|
-
const filePath =
|
|
1773
|
+
const filePath = path27.join(projectPath, target.contextFile);
|
|
1086
1774
|
let backedUp = false;
|
|
1087
|
-
const parentDir =
|
|
1088
|
-
if (!
|
|
1089
|
-
|
|
1775
|
+
const parentDir = path27.dirname(filePath);
|
|
1776
|
+
if (!fs27.existsSync(parentDir)) {
|
|
1777
|
+
fs27.mkdirSync(parentDir, { recursive: true });
|
|
1090
1778
|
}
|
|
1091
|
-
if (
|
|
1092
|
-
const content =
|
|
1779
|
+
if (fs27.existsSync(filePath)) {
|
|
1780
|
+
const content = fs27.readFileSync(filePath, "utf-8");
|
|
1093
1781
|
const marker = parseMarker(content);
|
|
1094
1782
|
if (!marker) {
|
|
1095
|
-
|
|
1783
|
+
fs27.copyFileSync(filePath, `${filePath}.bak`);
|
|
1096
1784
|
backedUp = true;
|
|
1097
1785
|
}
|
|
1098
1786
|
}
|
|
1099
1787
|
const md = renderToString(ctx);
|
|
1100
|
-
|
|
1788
|
+
fs27.writeFileSync(filePath, md, "utf-8");
|
|
1101
1789
|
return { written: true, backedUp, path: filePath };
|
|
1102
1790
|
}
|
|
1103
1791
|
var EDITOR_TARGETS, writeClaudeMd;
|
|
@@ -1140,23 +1828,23 @@ var dev_command_exports = {};
|
|
|
1140
1828
|
__export(dev_command_exports, {
|
|
1141
1829
|
runDev: () => runDev
|
|
1142
1830
|
});
|
|
1143
|
-
import
|
|
1144
|
-
import
|
|
1831
|
+
import fs28 from "fs";
|
|
1832
|
+
import path28 from "path";
|
|
1145
1833
|
function ensureGitignore(projectPath, editor) {
|
|
1146
|
-
const gitignorePath =
|
|
1147
|
-
if (!
|
|
1148
|
-
const content =
|
|
1834
|
+
const gitignorePath = path28.join(projectPath, ".gitignore");
|
|
1835
|
+
if (!fs28.existsSync(gitignorePath)) return;
|
|
1836
|
+
const content = fs28.readFileSync(gitignorePath, "utf-8");
|
|
1149
1837
|
const target = EDITOR_TARGETS[editor];
|
|
1150
1838
|
if (content.includes(target.gitignoreEntry)) return;
|
|
1151
|
-
|
|
1839
|
+
fs28.appendFileSync(gitignorePath, `
|
|
1152
1840
|
# Generated by aman-agent dev
|
|
1153
1841
|
${target.gitignoreEntry}
|
|
1154
1842
|
`);
|
|
1155
1843
|
}
|
|
1156
1844
|
async function runDev(projectPath, flags = {}, precomputedStack) {
|
|
1157
|
-
const resolved =
|
|
1845
|
+
const resolved = path28.resolve(projectPath);
|
|
1158
1846
|
const editor = flags.editor ?? "claude";
|
|
1159
|
-
if (!
|
|
1847
|
+
if (!fs28.existsSync(resolved)) {
|
|
1160
1848
|
return { success: false, generated: false, error: `Directory not found: ${resolved}` };
|
|
1161
1849
|
}
|
|
1162
1850
|
const stack = precomputedStack ?? scanStack(resolved);
|
|
@@ -1164,8 +1852,8 @@ async function runDev(projectPath, flags = {}, precomputedStack) {
|
|
|
1164
1852
|
const ctx2 = await buildContext2(stack, { smart: flags.smart });
|
|
1165
1853
|
const newContent = renderToString(ctx2);
|
|
1166
1854
|
const target = EDITOR_TARGETS[editor];
|
|
1167
|
-
const existingPath =
|
|
1168
|
-
const existing =
|
|
1855
|
+
const existingPath = path28.join(resolved, target.contextFile);
|
|
1856
|
+
const existing = fs28.existsSync(existingPath) ? fs28.readFileSync(existingPath, "utf-8") : "";
|
|
1169
1857
|
return {
|
|
1170
1858
|
success: true,
|
|
1171
1859
|
generated: false,
|
|
@@ -2577,18 +3265,18 @@ var McpManager = class {
|
|
|
2577
3265
|
|
|
2578
3266
|
// src/agent.ts
|
|
2579
3267
|
import * as readline from "readline";
|
|
2580
|
-
import
|
|
2581
|
-
import
|
|
2582
|
-
import
|
|
3268
|
+
import fs25 from "fs";
|
|
3269
|
+
import path25 from "path";
|
|
3270
|
+
import os22 from "os";
|
|
2583
3271
|
import pc7 from "picocolors";
|
|
2584
3272
|
import { marked } from "marked";
|
|
2585
3273
|
import { markedTerminal } from "marked-terminal";
|
|
2586
3274
|
import logUpdate from "log-update";
|
|
2587
3275
|
|
|
2588
3276
|
// src/commands.ts
|
|
2589
|
-
import
|
|
2590
|
-
import
|
|
2591
|
-
import
|
|
3277
|
+
import fs22 from "fs";
|
|
3278
|
+
import path22 from "path";
|
|
3279
|
+
import os19 from "os";
|
|
2592
3280
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
2593
3281
|
import pc6 from "picocolors";
|
|
2594
3282
|
|
|
@@ -2940,6 +3628,136 @@ async function memorySync(action, opts = {}) {
|
|
|
2940
3628
|
import fs8 from "fs";
|
|
2941
3629
|
import path8 from "path";
|
|
2942
3630
|
import os7 from "os";
|
|
3631
|
+
|
|
3632
|
+
// src/profiles/orchestrator-profiles.ts
|
|
3633
|
+
var architectProfile = {
|
|
3634
|
+
name: "architect",
|
|
3635
|
+
label: "System Architect",
|
|
3636
|
+
description: "Designs system architecture, decomposes features into modules, plans file structure and interfaces",
|
|
3637
|
+
core: `# System Architect
|
|
3638
|
+
|
|
3639
|
+
You are a system architect. Your job is to:
|
|
3640
|
+
- Analyze requirements and design the overall system structure
|
|
3641
|
+
- Define module boundaries, interfaces, and data flows
|
|
3642
|
+
- Plan file structure and naming conventions
|
|
3643
|
+
- Identify dependencies and integration points
|
|
3644
|
+
- Choose appropriate patterns and abstractions
|
|
3645
|
+
- Consider scalability, maintainability, and testability
|
|
3646
|
+
|
|
3647
|
+
## Output Format
|
|
3648
|
+
Produce a clear, structured design document with:
|
|
3649
|
+
1. **Architecture overview** \u2014 high-level components and their relationships
|
|
3650
|
+
2. **File structure** \u2014 exact paths for new/modified files
|
|
3651
|
+
3. **Interfaces** \u2014 key types, function signatures, and data contracts
|
|
3652
|
+
4. **Dependencies** \u2014 what depends on what, build order
|
|
3653
|
+
5. **Risks** \u2014 potential issues and mitigation strategies
|
|
3654
|
+
|
|
3655
|
+
Be precise with file paths and interface definitions. The implementation agents will follow your design exactly.`,
|
|
3656
|
+
rules: `- Never write implementation code \u2014 design only
|
|
3657
|
+
- Always specify exact file paths
|
|
3658
|
+
- Consider existing codebase patterns before proposing new ones
|
|
3659
|
+
- Flag breaking changes explicitly`
|
|
3660
|
+
};
|
|
3661
|
+
var securityProfile = {
|
|
3662
|
+
name: "security",
|
|
3663
|
+
label: "Security Analyst",
|
|
3664
|
+
description: "Reviews code for security vulnerabilities, runs SAST checks, audits dependencies",
|
|
3665
|
+
core: `# Security Analyst
|
|
3666
|
+
|
|
3667
|
+
You are a security analyst. Your job is to:
|
|
3668
|
+
- Review code for OWASP Top 10 vulnerabilities
|
|
3669
|
+
- Check for injection flaws (SQL, command, XSS)
|
|
3670
|
+
- Verify authentication and authorization patterns
|
|
3671
|
+
- Audit dependency versions for known CVEs
|
|
3672
|
+
- Check for secrets/credentials in code
|
|
3673
|
+
- Validate input sanitization and output encoding
|
|
3674
|
+
- Review error handling for information leakage
|
|
3675
|
+
|
|
3676
|
+
## Output Format
|
|
3677
|
+
Produce a security report with:
|
|
3678
|
+
1. **Critical** \u2014 must fix before merge (injection, auth bypass, secrets)
|
|
3679
|
+
2. **High** \u2014 should fix (missing validation, weak crypto)
|
|
3680
|
+
3. **Medium** \u2014 recommended (verbose errors, missing rate limiting)
|
|
3681
|
+
4. **Low** \u2014 informational (best practice suggestions)
|
|
3682
|
+
|
|
3683
|
+
For each finding: file path, line number, description, remediation.`,
|
|
3684
|
+
rules: `- Never approve code with Critical findings
|
|
3685
|
+
- Always check for hardcoded secrets
|
|
3686
|
+
- Flag any use of eval, exec, or shell string concatenation
|
|
3687
|
+
- Verify all user input is validated at system boundaries`
|
|
3688
|
+
};
|
|
3689
|
+
var testerProfile = {
|
|
3690
|
+
name: "tester",
|
|
3691
|
+
label: "Test Engineer",
|
|
3692
|
+
description: "Writes comprehensive tests, identifies edge cases, ensures coverage",
|
|
3693
|
+
core: `# Test Engineer
|
|
3694
|
+
|
|
3695
|
+
You are a test engineer. Your job is to:
|
|
3696
|
+
- Write comprehensive unit and integration tests
|
|
3697
|
+
- Identify edge cases and boundary conditions
|
|
3698
|
+
- Test error paths and failure modes
|
|
3699
|
+
- Verify behavior against specifications
|
|
3700
|
+
- Ensure tests are deterministic and fast
|
|
3701
|
+
- Follow existing test patterns in the codebase
|
|
3702
|
+
|
|
3703
|
+
## Testing Principles
|
|
3704
|
+
- Test behavior, not implementation details
|
|
3705
|
+
- Each test should verify one specific thing
|
|
3706
|
+
- Use descriptive test names that explain the expected behavior
|
|
3707
|
+
- Arrange-Act-Assert pattern
|
|
3708
|
+
- Mock external dependencies, test internal logic directly
|
|
3709
|
+
- Prefer integration tests for complex interactions
|
|
3710
|
+
|
|
3711
|
+
## Output Format
|
|
3712
|
+
Produce test files following the project's existing patterns (Vitest, Jest, pytest, etc.).
|
|
3713
|
+
Include: happy path, error cases, edge cases, boundary values.`,
|
|
3714
|
+
rules: `- Never skip error path testing
|
|
3715
|
+
- Always test boundary conditions
|
|
3716
|
+
- Tests must be deterministic (no timing dependencies, no random values)
|
|
3717
|
+
- Follow the project's existing test framework and patterns`
|
|
3718
|
+
};
|
|
3719
|
+
var reviewerProfile = {
|
|
3720
|
+
name: "reviewer",
|
|
3721
|
+
label: "Code Reviewer",
|
|
3722
|
+
description: "Reviews code for quality, correctness, and adherence to patterns",
|
|
3723
|
+
core: `# Code Reviewer
|
|
3724
|
+
|
|
3725
|
+
You are a code reviewer. Your job is to:
|
|
3726
|
+
- Check code correctness and logic errors
|
|
3727
|
+
- Verify adherence to project conventions and patterns
|
|
3728
|
+
- Identify potential performance issues
|
|
3729
|
+
- Assess readability and maintainability
|
|
3730
|
+
- Check error handling completeness
|
|
3731
|
+
- Verify tests adequately cover the changes
|
|
3732
|
+
|
|
3733
|
+
## Review Approach
|
|
3734
|
+
- Focus on correctness first, style second
|
|
3735
|
+
- Flag bugs and logic errors as Critical
|
|
3736
|
+
- Flag missing error handling as High
|
|
3737
|
+
- Flag style and convention issues as Medium
|
|
3738
|
+
- Acknowledge good patterns and clean code
|
|
3739
|
+
|
|
3740
|
+
## Output Format
|
|
3741
|
+
Produce a review with confidence-scored findings:
|
|
3742
|
+
- **CRITICAL** (confidence > 0.9) \u2014 definite bugs or security issues
|
|
3743
|
+
- **IMPORTANT** (confidence > 0.7) \u2014 likely problems or missing handling
|
|
3744
|
+
- **SUGGESTION** (confidence > 0.5) \u2014 improvements worth considering
|
|
3745
|
+
- **PRAISE** \u2014 highlight good patterns
|
|
3746
|
+
|
|
3747
|
+
Include file path, line range, and specific explanation for each finding.`,
|
|
3748
|
+
rules: `- Never rubber-stamp \u2014 always provide substantive review
|
|
3749
|
+
- Focus on what matters: correctness > performance > style
|
|
3750
|
+
- Be specific: cite exact lines and explain why something is wrong
|
|
3751
|
+
- Distinguish between "must fix" and "nice to have"`
|
|
3752
|
+
};
|
|
3753
|
+
var ORCHESTRATOR_PROFILES = [
|
|
3754
|
+
architectProfile,
|
|
3755
|
+
securityProfile,
|
|
3756
|
+
testerProfile,
|
|
3757
|
+
reviewerProfile
|
|
3758
|
+
];
|
|
3759
|
+
|
|
3760
|
+
// src/profile-templates.ts
|
|
2943
3761
|
var BUILT_IN_PROFILES = [
|
|
2944
3762
|
{
|
|
2945
3763
|
name: "coder",
|
|
@@ -3027,7 +3845,8 @@ var BUILT_IN_PROFILES = [
|
|
|
3027
3845
|
- Present speculation as fact
|
|
3028
3846
|
- Ignore contradicting evidence
|
|
3029
3847
|
- Oversimplify complex topics`
|
|
3030
|
-
}
|
|
3848
|
+
},
|
|
3849
|
+
...ORCHESTRATOR_PROFILES
|
|
3031
3850
|
];
|
|
3032
3851
|
function installProfileTemplate(templateName, userName) {
|
|
3033
3852
|
const template = BUILT_IN_PROFILES.find((t) => t.name === templateName);
|
|
@@ -5253,49 +6072,115 @@ async function delegatePipeline(steps, initialInput, client, mcpManager, options
|
|
|
5253
6072
|
return results;
|
|
5254
6073
|
}
|
|
5255
6074
|
|
|
6075
|
+
// src/orchestrator/index.ts
|
|
6076
|
+
init_types();
|
|
6077
|
+
init_dag();
|
|
6078
|
+
init_decompose();
|
|
6079
|
+
|
|
6080
|
+
// src/orchestrator/scheduler.ts
|
|
6081
|
+
init_dag();
|
|
6082
|
+
|
|
6083
|
+
// src/orchestrator/checkpoint.ts
|
|
6084
|
+
import { readFile as readFile2, writeFile, mkdir } from "fs/promises";
|
|
6085
|
+
import { join } from "path";
|
|
6086
|
+
|
|
6087
|
+
// src/orchestrator/smart-orchestrate.ts
|
|
6088
|
+
init_decompose();
|
|
6089
|
+
|
|
6090
|
+
// src/orchestrator/templates/index.ts
|
|
6091
|
+
init_dag();
|
|
6092
|
+
|
|
6093
|
+
// src/project/detector.ts
|
|
6094
|
+
var FRONTEND_FRAMEWORKS = /* @__PURE__ */ new Set(["react", "vue", "svelte"]);
|
|
6095
|
+
var FULLSTACK_FRAMEWORKS = /* @__PURE__ */ new Set(["next", "nuxt", "remix"]);
|
|
6096
|
+
var BACKEND_FRAMEWORKS = /* @__PURE__ */ new Set([
|
|
6097
|
+
"express",
|
|
6098
|
+
"fastify",
|
|
6099
|
+
"hono",
|
|
6100
|
+
"nestjs",
|
|
6101
|
+
"fiber",
|
|
6102
|
+
"gin",
|
|
6103
|
+
"chi",
|
|
6104
|
+
"echo",
|
|
6105
|
+
"fastapi",
|
|
6106
|
+
"django",
|
|
6107
|
+
"flask"
|
|
6108
|
+
]);
|
|
6109
|
+
var WEB_FRAMEWORKS = /* @__PURE__ */ new Set([
|
|
6110
|
+
...FRONTEND_FRAMEWORKS,
|
|
6111
|
+
...FULLSTACK_FRAMEWORKS,
|
|
6112
|
+
...BACKEND_FRAMEWORKS
|
|
6113
|
+
]);
|
|
6114
|
+
|
|
6115
|
+
// src/orchestrator/smart-orchestrate.ts
|
|
6116
|
+
init_stack_detector();
|
|
6117
|
+
|
|
6118
|
+
// src/profiles/auto-install.ts
|
|
6119
|
+
import fs18 from "fs";
|
|
6120
|
+
import path18 from "path";
|
|
6121
|
+
import os15 from "os";
|
|
6122
|
+
|
|
6123
|
+
// src/orchestrator/index.ts
|
|
6124
|
+
init_dag();
|
|
6125
|
+
function formatDAGForDisplay(dag) {
|
|
6126
|
+
const lines = [];
|
|
6127
|
+
lines.push(`## ${dag.name}`);
|
|
6128
|
+
lines.push(`**Goal:** ${dag.goal}`);
|
|
6129
|
+
lines.push(`**Tasks:** ${dag.nodes.length} | **Gates:** ${dag.gates.length}`);
|
|
6130
|
+
lines.push("");
|
|
6131
|
+
for (const node of dag.nodes) {
|
|
6132
|
+
const depLabel = node.dependencies.length === 0 ? "(root)" : `(after: ${node.dependencies.join(", ")})`;
|
|
6133
|
+
lines.push(`- **${node.name}** \u2192 ${node.profile} [${node.tier}] ${depLabel}`);
|
|
6134
|
+
}
|
|
6135
|
+
for (const gate of dag.gates) {
|
|
6136
|
+
lines.push(`- \u{1F512} **${gate.name}** [${gate.type}]`);
|
|
6137
|
+
}
|
|
6138
|
+
return lines.join("\n");
|
|
6139
|
+
}
|
|
6140
|
+
|
|
5256
6141
|
// src/commands.ts
|
|
5257
6142
|
init_registry();
|
|
5258
6143
|
import { StreamableHTTPClientTransport as StreamableHTTPClientTransport2 } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
5259
6144
|
import { Client as Client3 } from "@modelcontextprotocol/sdk/client/index.js";
|
|
5260
6145
|
|
|
5261
6146
|
// src/teams.ts
|
|
5262
|
-
import
|
|
5263
|
-
import
|
|
5264
|
-
import
|
|
6147
|
+
import fs19 from "fs";
|
|
6148
|
+
import path19 from "path";
|
|
6149
|
+
import os16 from "os";
|
|
5265
6150
|
import pc4 from "picocolors";
|
|
5266
6151
|
function getTeamsDir() {
|
|
5267
|
-
return
|
|
6152
|
+
return path19.join(os16.homedir(), ".acore", "teams");
|
|
5268
6153
|
}
|
|
5269
6154
|
function ensureTeamsDir() {
|
|
5270
6155
|
const dir = getTeamsDir();
|
|
5271
|
-
if (!
|
|
6156
|
+
if (!fs19.existsSync(dir)) fs19.mkdirSync(dir, { recursive: true });
|
|
5272
6157
|
return dir;
|
|
5273
6158
|
}
|
|
5274
6159
|
function teamPath(name) {
|
|
5275
6160
|
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
5276
|
-
return
|
|
6161
|
+
return path19.join(ensureTeamsDir(), `${slug}.json`);
|
|
5277
6162
|
}
|
|
5278
6163
|
function createTeam(team) {
|
|
5279
6164
|
const fp = teamPath(team.name);
|
|
5280
|
-
|
|
6165
|
+
fs19.writeFileSync(fp, JSON.stringify(team, null, 2), "utf-8");
|
|
5281
6166
|
}
|
|
5282
6167
|
function loadTeam(name) {
|
|
5283
6168
|
const fp = teamPath(name);
|
|
5284
|
-
if (!
|
|
6169
|
+
if (!fs19.existsSync(fp)) return null;
|
|
5285
6170
|
try {
|
|
5286
|
-
return JSON.parse(
|
|
6171
|
+
return JSON.parse(fs19.readFileSync(fp, "utf-8"));
|
|
5287
6172
|
} catch {
|
|
5288
6173
|
return null;
|
|
5289
6174
|
}
|
|
5290
6175
|
}
|
|
5291
6176
|
function listTeams() {
|
|
5292
6177
|
const dir = getTeamsDir();
|
|
5293
|
-
if (!
|
|
6178
|
+
if (!fs19.existsSync(dir)) return [];
|
|
5294
6179
|
const teams = [];
|
|
5295
|
-
for (const file of
|
|
6180
|
+
for (const file of fs19.readdirSync(dir)) {
|
|
5296
6181
|
if (!file.endsWith(".json")) continue;
|
|
5297
6182
|
try {
|
|
5298
|
-
const content =
|
|
6183
|
+
const content = fs19.readFileSync(path19.join(dir, file), "utf-8");
|
|
5299
6184
|
teams.push(JSON.parse(content));
|
|
5300
6185
|
} catch {
|
|
5301
6186
|
}
|
|
@@ -5304,8 +6189,8 @@ function listTeams() {
|
|
|
5304
6189
|
}
|
|
5305
6190
|
function deleteTeam(name) {
|
|
5306
6191
|
const fp = teamPath(name);
|
|
5307
|
-
if (!
|
|
5308
|
-
|
|
6192
|
+
if (!fs19.existsSync(fp)) return false;
|
|
6193
|
+
fs19.unlinkSync(fp);
|
|
5309
6194
|
return true;
|
|
5310
6195
|
}
|
|
5311
6196
|
async function runTeam(team, task, client, mcpManager, tools) {
|
|
@@ -5532,23 +6417,23 @@ var BUILT_IN_TEAMS = [
|
|
|
5532
6417
|
|
|
5533
6418
|
// src/plans.ts
|
|
5534
6419
|
init_logger();
|
|
5535
|
-
import
|
|
5536
|
-
import
|
|
5537
|
-
import
|
|
6420
|
+
import fs20 from "fs";
|
|
6421
|
+
import path20 from "path";
|
|
6422
|
+
import os17 from "os";
|
|
5538
6423
|
function getPlansDir() {
|
|
5539
|
-
const localDir =
|
|
5540
|
-
const localAcore =
|
|
5541
|
-
if (
|
|
5542
|
-
return
|
|
6424
|
+
const localDir = path20.join(process.cwd(), ".acore", "plans");
|
|
6425
|
+
const localAcore = path20.join(process.cwd(), ".acore");
|
|
6426
|
+
if (fs20.existsSync(localAcore)) return localDir;
|
|
6427
|
+
return path20.join(os17.homedir(), ".acore", "plans");
|
|
5543
6428
|
}
|
|
5544
6429
|
function ensurePlansDir() {
|
|
5545
6430
|
const dir = getPlansDir();
|
|
5546
|
-
if (!
|
|
6431
|
+
if (!fs20.existsSync(dir)) fs20.mkdirSync(dir, { recursive: true });
|
|
5547
6432
|
return dir;
|
|
5548
6433
|
}
|
|
5549
6434
|
function planPath(name) {
|
|
5550
6435
|
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
5551
|
-
return
|
|
6436
|
+
return path20.join(ensurePlansDir(), `${slug}.md`);
|
|
5552
6437
|
}
|
|
5553
6438
|
function serializePlan(plan) {
|
|
5554
6439
|
const lines = [];
|
|
@@ -5574,7 +6459,7 @@ function parsePlan(content, filePath) {
|
|
|
5574
6459
|
const createdMatch = content.match(/\*\*Created:\*\*\s*(.+)/);
|
|
5575
6460
|
const updatedMatch = content.match(/\*\*Updated:\*\*\s*(.+)/);
|
|
5576
6461
|
const activeMatch = content.match(/\*\*Active:\*\*\s*(.+)/);
|
|
5577
|
-
const name = nameMatch?.[1]?.trim() ||
|
|
6462
|
+
const name = nameMatch?.[1]?.trim() || path20.basename(filePath, ".md");
|
|
5578
6463
|
const goal = goalMatch?.[1]?.trim() || "";
|
|
5579
6464
|
const createdAt = createdMatch?.[1]?.trim() || "";
|
|
5580
6465
|
const updatedAt = updatedMatch?.[1]?.trim() || "";
|
|
@@ -5616,22 +6501,22 @@ function createPlan(name, goal, steps) {
|
|
|
5616
6501
|
}
|
|
5617
6502
|
function savePlan(plan) {
|
|
5618
6503
|
const fp = planPath(plan.name);
|
|
5619
|
-
|
|
6504
|
+
fs20.writeFileSync(fp, serializePlan(plan), "utf-8");
|
|
5620
6505
|
}
|
|
5621
6506
|
function loadPlan(name) {
|
|
5622
6507
|
const fp = planPath(name);
|
|
5623
|
-
if (!
|
|
5624
|
-
const content =
|
|
6508
|
+
if (!fs20.existsSync(fp)) return null;
|
|
6509
|
+
const content = fs20.readFileSync(fp, "utf-8");
|
|
5625
6510
|
return parsePlan(content, fp);
|
|
5626
6511
|
}
|
|
5627
6512
|
function listPlans() {
|
|
5628
6513
|
const dir = getPlansDir();
|
|
5629
|
-
if (!
|
|
6514
|
+
if (!fs20.existsSync(dir)) return [];
|
|
5630
6515
|
const plans = [];
|
|
5631
|
-
for (const file of
|
|
6516
|
+
for (const file of fs20.readdirSync(dir)) {
|
|
5632
6517
|
if (!file.endsWith(".md")) continue;
|
|
5633
|
-
const fp =
|
|
5634
|
-
const content =
|
|
6518
|
+
const fp = path20.join(dir, file);
|
|
6519
|
+
const content = fs20.readFileSync(fp, "utf-8");
|
|
5635
6520
|
const plan = parsePlan(content, fp);
|
|
5636
6521
|
if (plan) plans.push(plan);
|
|
5637
6522
|
}
|
|
@@ -5726,13 +6611,14 @@ function progressBar(pct) {
|
|
|
5726
6611
|
}
|
|
5727
6612
|
|
|
5728
6613
|
// src/commands.ts
|
|
6614
|
+
init_github();
|
|
5729
6615
|
init_user_model();
|
|
5730
6616
|
|
|
5731
6617
|
// src/background.ts
|
|
5732
6618
|
init_logger();
|
|
5733
|
-
import
|
|
5734
|
-
import
|
|
5735
|
-
import
|
|
6619
|
+
import fs21 from "fs";
|
|
6620
|
+
import path21 from "path";
|
|
6621
|
+
import os18 from "os";
|
|
5736
6622
|
import pc5 from "picocolors";
|
|
5737
6623
|
var BACKGROUND_ELIGIBLE = /* @__PURE__ */ new Set([
|
|
5738
6624
|
"run_tests",
|
|
@@ -5771,13 +6657,13 @@ var NEVER_BACKGROUND = /* @__PURE__ */ new Set([
|
|
|
5771
6657
|
"file_list",
|
|
5772
6658
|
"avatar_prompt"
|
|
5773
6659
|
]);
|
|
5774
|
-
var TASK_LOG_DIR =
|
|
5775
|
-
var TASK_LOG_FILE =
|
|
6660
|
+
var TASK_LOG_DIR = path21.join(os18.homedir(), ".aman-agent");
|
|
6661
|
+
var TASK_LOG_FILE = path21.join(TASK_LOG_DIR, "bg-tasks.json");
|
|
5776
6662
|
var MAX_LOG_ENTRIES = 50;
|
|
5777
6663
|
function loadTaskLog() {
|
|
5778
6664
|
try {
|
|
5779
|
-
if (!
|
|
5780
|
-
const raw =
|
|
6665
|
+
if (!fs21.existsSync(TASK_LOG_FILE)) return [];
|
|
6666
|
+
const raw = fs21.readFileSync(TASK_LOG_FILE, "utf-8");
|
|
5781
6667
|
return JSON.parse(raw);
|
|
5782
6668
|
} catch {
|
|
5783
6669
|
return [];
|
|
@@ -5785,9 +6671,9 @@ function loadTaskLog() {
|
|
|
5785
6671
|
}
|
|
5786
6672
|
function saveTaskLog(entries) {
|
|
5787
6673
|
try {
|
|
5788
|
-
if (!
|
|
6674
|
+
if (!fs21.existsSync(TASK_LOG_DIR)) fs21.mkdirSync(TASK_LOG_DIR, { recursive: true });
|
|
5789
6675
|
const trimmed = entries.slice(-MAX_LOG_ENTRIES);
|
|
5790
|
-
|
|
6676
|
+
fs21.writeFileSync(TASK_LOG_FILE, JSON.stringify(trimmed, null, 2));
|
|
5791
6677
|
} catch (err) {
|
|
5792
6678
|
log.debug("background", "Failed to save task log", err);
|
|
5793
6679
|
}
|
|
@@ -5936,10 +6822,10 @@ import {
|
|
|
5936
6822
|
} from "@aman_asmuei/arules-core";
|
|
5937
6823
|
var AGENT_SCOPE = process.env.AMAN_AGENT_SCOPE ?? "dev:agent";
|
|
5938
6824
|
function readEcosystemFile(filePath, label) {
|
|
5939
|
-
if (!
|
|
6825
|
+
if (!fs22.existsSync(filePath)) {
|
|
5940
6826
|
return pc6.dim(`No ${label} file found at ${filePath}`);
|
|
5941
6827
|
}
|
|
5942
|
-
return
|
|
6828
|
+
return fs22.readFileSync(filePath, "utf-8").trim();
|
|
5943
6829
|
}
|
|
5944
6830
|
function parseCommand(input) {
|
|
5945
6831
|
const trimmed = input.trim();
|
|
@@ -6024,8 +6910,8 @@ async function handleIdentityCommand(action, args, _ctx) {
|
|
|
6024
6910
|
}
|
|
6025
6911
|
if (args.includes("--reset")) {
|
|
6026
6912
|
const modelPath = defaultModelPath();
|
|
6027
|
-
if (
|
|
6028
|
-
|
|
6913
|
+
if (fs22.existsSync(modelPath)) {
|
|
6914
|
+
fs22.unlinkSync(modelPath);
|
|
6029
6915
|
return { handled: true, output: pc6.green("User model reset. Starting fresh.") };
|
|
6030
6916
|
}
|
|
6031
6917
|
return { handled: true, output: pc6.dim("No user model to reset.") };
|
|
@@ -6269,9 +7155,9 @@ ${result.violations.map((v) => ` - ${v}`).join("\n")}`)
|
|
|
6269
7155
|
};
|
|
6270
7156
|
}
|
|
6271
7157
|
async function handleWorkflowsCommand(action, args, ctx) {
|
|
6272
|
-
const home2 =
|
|
7158
|
+
const home2 = os19.homedir();
|
|
6273
7159
|
if (!action) {
|
|
6274
|
-
const content = readEcosystemFile(
|
|
7160
|
+
const content = readEcosystemFile(path22.join(home2, ".aflow", "flow.md"), "workflows (aflow)");
|
|
6275
7161
|
return { handled: true, output: content };
|
|
6276
7162
|
}
|
|
6277
7163
|
if (action === "add") {
|
|
@@ -6293,7 +7179,7 @@ async function handleWorkflowsCommand(action, args, ctx) {
|
|
|
6293
7179
|
return { handled: true, output: pc6.yellow("Usage: /workflows get <name>") };
|
|
6294
7180
|
}
|
|
6295
7181
|
const name = args.join(" ").toLowerCase();
|
|
6296
|
-
const raw = readEcosystemFile(
|
|
7182
|
+
const raw = readEcosystemFile(path22.join(home2, ".aflow", "flow.md"), "workflows (aflow)");
|
|
6297
7183
|
if (raw.startsWith("No ")) {
|
|
6298
7184
|
return { handled: true, output: raw };
|
|
6299
7185
|
}
|
|
@@ -6352,12 +7238,12 @@ async function handleToolsCommand(action, args, _ctx) {
|
|
|
6352
7238
|
return { handled: true, output: pc6.yellow("Usage: /tools search <query...>") };
|
|
6353
7239
|
}
|
|
6354
7240
|
const query = args.join(" ").toLowerCase();
|
|
6355
|
-
const home2 =
|
|
6356
|
-
const toolsFile =
|
|
6357
|
-
if (!
|
|
7241
|
+
const home2 = os19.homedir();
|
|
7242
|
+
const toolsFile = path22.join(home2, ".akit", "tools.md");
|
|
7243
|
+
if (!fs22.existsSync(toolsFile)) {
|
|
6358
7244
|
return { handled: true, output: pc6.dim(`No tools file found. Use 'npx @aman_asmuei/akit search ${args.join(" ")}' to search the registry.`) };
|
|
6359
7245
|
}
|
|
6360
|
-
const raw =
|
|
7246
|
+
const raw = fs22.readFileSync(toolsFile, "utf-8").trim();
|
|
6361
7247
|
const lines = raw.split("\n");
|
|
6362
7248
|
const matches = lines.filter((l) => l.toLowerCase().includes(query));
|
|
6363
7249
|
if (matches.length === 0) {
|
|
@@ -6368,9 +7254,9 @@ async function handleToolsCommand(action, args, _ctx) {
|
|
|
6368
7254
|
return handleAkitCommand(action, args);
|
|
6369
7255
|
}
|
|
6370
7256
|
async function handleSkillsCommand(action, args, ctx) {
|
|
6371
|
-
const home2 =
|
|
7257
|
+
const home2 = os19.homedir();
|
|
6372
7258
|
if (!action) {
|
|
6373
|
-
const content = readEcosystemFile(
|
|
7259
|
+
const content = readEcosystemFile(path22.join(home2, ".askill", "skills.md"), "skills (askill)");
|
|
6374
7260
|
return { handled: true, output: content };
|
|
6375
7261
|
}
|
|
6376
7262
|
if (action === "install") {
|
|
@@ -6392,8 +7278,8 @@ async function handleSkillsCommand(action, args, ctx) {
|
|
|
6392
7278
|
return { handled: true, output: pc6.yellow("Usage: /skills search <query...>") };
|
|
6393
7279
|
}
|
|
6394
7280
|
const query = args.join(" ").toLowerCase();
|
|
6395
|
-
const home3 =
|
|
6396
|
-
const raw = readEcosystemFile(
|
|
7281
|
+
const home3 = os19.homedir();
|
|
7282
|
+
const raw = readEcosystemFile(path22.join(home3, ".askill", "skills.md"), "skills (askill)");
|
|
6397
7283
|
if (raw.startsWith("No ")) {
|
|
6398
7284
|
return { handled: true, output: raw };
|
|
6399
7285
|
}
|
|
@@ -6407,23 +7293,23 @@ async function handleSkillsCommand(action, args, ctx) {
|
|
|
6407
7293
|
if (action === "list") {
|
|
6408
7294
|
const autoOnly = args.includes("--auto");
|
|
6409
7295
|
if (autoOnly) {
|
|
6410
|
-
const logPath =
|
|
7296
|
+
const logPath = path22.join(os19.homedir(), ".aman-agent", "crystallization-log.json");
|
|
6411
7297
|
try {
|
|
6412
|
-
const content2 =
|
|
7298
|
+
const content2 = fs22.readFileSync(logPath, "utf-8");
|
|
6413
7299
|
const entries = JSON.parse(content2);
|
|
6414
7300
|
if (entries.length === 0) {
|
|
6415
7301
|
return { handled: true, output: pc6.dim("No crystallized skills yet.") };
|
|
6416
7302
|
}
|
|
6417
|
-
const suggestionsPath =
|
|
7303
|
+
const suggestionsPath = path22.join(os19.homedir(), ".aman-agent", "crystallization-suggestions.json");
|
|
6418
7304
|
let sugCounts = {};
|
|
6419
7305
|
try {
|
|
6420
|
-
const sc =
|
|
7306
|
+
const sc = fs22.readFileSync(suggestionsPath, "utf-8");
|
|
6421
7307
|
sugCounts = JSON.parse(sc);
|
|
6422
7308
|
} catch {
|
|
6423
7309
|
}
|
|
6424
7310
|
let versionCounts = {};
|
|
6425
7311
|
try {
|
|
6426
|
-
const skillsContent =
|
|
7312
|
+
const skillsContent = fs22.readFileSync(path22.join(os19.homedir(), ".askill", "skills.md"), "utf-8");
|
|
6427
7313
|
const versionRe = /^# (.+)\.v(\d+)$/gm;
|
|
6428
7314
|
let vMatch;
|
|
6429
7315
|
while ((vMatch = versionRe.exec(skillsContent)) !== null) {
|
|
@@ -6448,13 +7334,13 @@ async function handleSkillsCommand(action, args, ctx) {
|
|
|
6448
7334
|
return { handled: true, output: pc6.dim("No crystallized skills yet.") };
|
|
6449
7335
|
}
|
|
6450
7336
|
}
|
|
6451
|
-
const content = readEcosystemFile(
|
|
7337
|
+
const content = readEcosystemFile(path22.join(home2, ".askill", "skills.md"), "skills (askill)");
|
|
6452
7338
|
return { handled: true, output: content };
|
|
6453
7339
|
}
|
|
6454
7340
|
if (action === "crystallize") {
|
|
6455
|
-
const pmDir =
|
|
7341
|
+
const pmDir = path22.join(os19.homedir(), ".acore", "postmortems");
|
|
6456
7342
|
try {
|
|
6457
|
-
const files =
|
|
7343
|
+
const files = fs22.readdirSync(pmDir);
|
|
6458
7344
|
const jsonFiles = files.filter((f) => f.endsWith(".json")).sort().reverse();
|
|
6459
7345
|
if (jsonFiles.length === 0) {
|
|
6460
7346
|
return {
|
|
@@ -6463,7 +7349,7 @@ async function handleSkillsCommand(action, args, ctx) {
|
|
|
6463
7349
|
};
|
|
6464
7350
|
}
|
|
6465
7351
|
const latest = jsonFiles[0];
|
|
6466
|
-
const content =
|
|
7352
|
+
const content = fs22.readFileSync(path22.join(pmDir, latest), "utf-8");
|
|
6467
7353
|
const report = JSON.parse(content);
|
|
6468
7354
|
if (!report.crystallizationCandidates || report.crystallizationCandidates.length === 0) {
|
|
6469
7355
|
return {
|
|
@@ -6471,8 +7357,8 @@ async function handleSkillsCommand(action, args, ctx) {
|
|
|
6471
7357
|
output: pc6.dim(`No crystallization candidates in the most recent post-mortem (${latest}). Run a longer session or wait for the next auto-postmortem.`)
|
|
6472
7358
|
};
|
|
6473
7359
|
}
|
|
6474
|
-
const skillsMdPath =
|
|
6475
|
-
const logPath =
|
|
7360
|
+
const skillsMdPath = path22.join(os19.homedir(), ".askill", "skills.md");
|
|
7361
|
+
const logPath = path22.join(os19.homedir(), ".aman-agent", "crystallization-log.json");
|
|
6476
7362
|
const postmortemFilename = latest.replace(/\.json$/, ".md");
|
|
6477
7363
|
const lines = [
|
|
6478
7364
|
pc6.bold(`Found ${report.crystallizationCandidates.length} candidate(s) in ${latest}:`)
|
|
@@ -6529,9 +7415,9 @@ async function handleSkillsCommand(action, args, ctx) {
|
|
|
6529
7415
|
return { handled: true, output: pc6.yellow(`Unknown action: /skills ${action}. Try /skills --help`) };
|
|
6530
7416
|
}
|
|
6531
7417
|
async function handleEvalCommand(action, args, ctx) {
|
|
6532
|
-
const home2 =
|
|
7418
|
+
const home2 = os19.homedir();
|
|
6533
7419
|
if (!action) {
|
|
6534
|
-
const content = readEcosystemFile(
|
|
7420
|
+
const content = readEcosystemFile(path22.join(home2, ".aeval", "eval.md"), "evaluation (aeval)");
|
|
6535
7421
|
return { handled: true, output: content };
|
|
6536
7422
|
}
|
|
6537
7423
|
if (action === "milestone") {
|
|
@@ -6543,10 +7429,10 @@ async function handleEvalCommand(action, args, ctx) {
|
|
|
6543
7429
|
return { handled: true, output };
|
|
6544
7430
|
}
|
|
6545
7431
|
if (action === "report") {
|
|
6546
|
-
const evalFile =
|
|
7432
|
+
const evalFile = path22.join(home2, ".aeval", "eval.md");
|
|
6547
7433
|
const lines = [pc6.bold("\u{1F4CA} Eval Report")];
|
|
6548
|
-
if (
|
|
6549
|
-
lines.push("",
|
|
7434
|
+
if (fs22.existsSync(evalFile)) {
|
|
7435
|
+
lines.push("", fs22.readFileSync(evalFile, "utf-8").trim());
|
|
6550
7436
|
} else {
|
|
6551
7437
|
lines.push("", pc6.dim("No eval log yet. Use /eval milestone <text> to start."));
|
|
6552
7438
|
}
|
|
@@ -7104,10 +7990,10 @@ function handleSave() {
|
|
|
7104
7990
|
}
|
|
7105
7991
|
function handleReset(action) {
|
|
7106
7992
|
const dirs = {
|
|
7107
|
-
config:
|
|
7108
|
-
memory:
|
|
7109
|
-
identity:
|
|
7110
|
-
rules:
|
|
7993
|
+
config: path22.join(os19.homedir(), ".aman-agent"),
|
|
7994
|
+
memory: path22.join(os19.homedir(), ".amem"),
|
|
7995
|
+
identity: path22.join(os19.homedir(), ".acore"),
|
|
7996
|
+
rules: path22.join(os19.homedir(), ".arules")
|
|
7111
7997
|
};
|
|
7112
7998
|
if (action === "help" || !action) {
|
|
7113
7999
|
return {
|
|
@@ -7132,15 +8018,15 @@ function handleReset(action) {
|
|
|
7132
8018
|
const removed = [];
|
|
7133
8019
|
for (const target of targets) {
|
|
7134
8020
|
const dir = dirs[target];
|
|
7135
|
-
if (
|
|
7136
|
-
|
|
8021
|
+
if (fs22.existsSync(dir)) {
|
|
8022
|
+
fs22.rmSync(dir, { recursive: true, force: true });
|
|
7137
8023
|
removed.push(target);
|
|
7138
8024
|
}
|
|
7139
8025
|
}
|
|
7140
8026
|
if (targets.includes("config")) {
|
|
7141
8027
|
const configDir2 = dirs.config;
|
|
7142
|
-
|
|
7143
|
-
|
|
8028
|
+
fs22.mkdirSync(configDir2, { recursive: true });
|
|
8029
|
+
fs22.writeFileSync(path22.join(configDir2, ".reconfig"), "", "utf-8");
|
|
7144
8030
|
}
|
|
7145
8031
|
if (removed.length === 0) {
|
|
7146
8032
|
return { handled: true, output: pc6.dim("Nothing to reset \u2014 directories don't exist.") };
|
|
@@ -7157,11 +8043,11 @@ function handleReset(action) {
|
|
|
7157
8043
|
function handleUpdate() {
|
|
7158
8044
|
try {
|
|
7159
8045
|
const current = execFileSync3("npm", ["view", "@aman_asmuei/aman-agent", "version"], { encoding: "utf-8" }).trim();
|
|
7160
|
-
const local = true ? "0.
|
|
8046
|
+
const local = true ? "0.40.0" : "unknown";
|
|
7161
8047
|
if (current === local) {
|
|
7162
8048
|
return { handled: true, output: `${pc6.green("Up to date")} \u2014 v${local}` };
|
|
7163
8049
|
}
|
|
7164
|
-
const isVendored = process.execPath.includes(
|
|
8050
|
+
const isVendored = process.execPath.includes(path22.join(".aman-agent", "node"));
|
|
7165
8051
|
const updateCmd = isVendored ? "aman-agent update" : "npm install -g @aman_asmuei/aman-agent@latest";
|
|
7166
8052
|
return {
|
|
7167
8053
|
handled: true,
|
|
@@ -7197,11 +8083,11 @@ function handleExportCommand() {
|
|
|
7197
8083
|
return { handled: true, exportConversation: true };
|
|
7198
8084
|
}
|
|
7199
8085
|
function handleDebugCommand() {
|
|
7200
|
-
const logPath =
|
|
7201
|
-
if (!
|
|
8086
|
+
const logPath = path22.join(os19.homedir(), ".aman-agent", "debug.log");
|
|
8087
|
+
if (!fs22.existsSync(logPath)) {
|
|
7202
8088
|
return { handled: true, output: pc6.dim("No debug log found.") };
|
|
7203
8089
|
}
|
|
7204
|
-
const content =
|
|
8090
|
+
const content = fs22.readFileSync(logPath, "utf-8");
|
|
7205
8091
|
const lines = content.trim().split("\n");
|
|
7206
8092
|
const last20 = lines.slice(-20).join("\n");
|
|
7207
8093
|
return { handled: true, output: pc6.bold("Debug Log (last 20 entries):\n") + pc6.dim(last20) };
|
|
@@ -7481,7 +8367,7 @@ ${text3}` };
|
|
|
7481
8367
|
};
|
|
7482
8368
|
}
|
|
7483
8369
|
function handleProfileCommand(action, args) {
|
|
7484
|
-
const profilesDir =
|
|
8370
|
+
const profilesDir = path22.join(os19.homedir(), ".acore", "profiles");
|
|
7485
8371
|
if (action === "me") {
|
|
7486
8372
|
const user = loadUserIdentity();
|
|
7487
8373
|
if (!user) {
|
|
@@ -7549,8 +8435,8 @@ ${pc6.dim("Edit with: /profile edit")}` };
|
|
|
7549
8435
|
};
|
|
7550
8436
|
}
|
|
7551
8437
|
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
7552
|
-
const profileDir =
|
|
7553
|
-
if (
|
|
8438
|
+
const profileDir = path22.join(profilesDir, slug);
|
|
8439
|
+
if (fs22.existsSync(profileDir)) {
|
|
7554
8440
|
return { handled: true, output: pc6.yellow(`Profile already exists: ${slug}`) };
|
|
7555
8441
|
}
|
|
7556
8442
|
const builtIn = BUILT_IN_PROFILES.find((t) => t.name === slug);
|
|
@@ -7566,16 +8452,16 @@ ${pc6.dim("Edit with: /profile edit")}` };
|
|
|
7566
8452
|
Use: aman-agent --profile ${slug}`
|
|
7567
8453
|
};
|
|
7568
8454
|
}
|
|
7569
|
-
|
|
7570
|
-
const globalCore =
|
|
7571
|
-
if (
|
|
7572
|
-
let content =
|
|
8455
|
+
fs22.mkdirSync(profileDir, { recursive: true });
|
|
8456
|
+
const globalCore = path22.join(os19.homedir(), ".acore", "core.md");
|
|
8457
|
+
if (fs22.existsSync(globalCore)) {
|
|
8458
|
+
let content = fs22.readFileSync(globalCore, "utf-8");
|
|
7573
8459
|
const aiName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
7574
8460
|
content = content.replace(/^# .+$/m, `# ${aiName}`);
|
|
7575
|
-
|
|
8461
|
+
fs22.writeFileSync(path22.join(profileDir, "core.md"), content, "utf-8");
|
|
7576
8462
|
} else {
|
|
7577
8463
|
const aiName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
7578
|
-
|
|
8464
|
+
fs22.writeFileSync(path22.join(profileDir, "core.md"), `# ${aiName}
|
|
7579
8465
|
|
|
7580
8466
|
## Identity
|
|
7581
8467
|
- Role: ${aiName} is your AI companion
|
|
@@ -7588,7 +8474,7 @@ ${pc6.dim("Edit with: /profile edit")}` };
|
|
|
7588
8474
|
return {
|
|
7589
8475
|
handled: true,
|
|
7590
8476
|
output: pc6.green(`Profile created: ${slug}`) + `
|
|
7591
|
-
Edit: ${
|
|
8477
|
+
Edit: ${path22.join(profileDir, "core.md")}
|
|
7592
8478
|
Use: aman-agent --profile ${slug}
|
|
7593
8479
|
|
|
7594
8480
|
${pc6.dim("Add rules.md or skills.md for profile-specific overrides.")}`
|
|
@@ -7597,9 +8483,9 @@ ${pc6.dim("Edit with: /profile edit")}` };
|
|
|
7597
8483
|
case "show": {
|
|
7598
8484
|
const name = args[0];
|
|
7599
8485
|
if (!name) return { handled: true, output: pc6.yellow("Usage: /profile show <name>") };
|
|
7600
|
-
const profileDir =
|
|
7601
|
-
if (!
|
|
7602
|
-
const files =
|
|
8486
|
+
const profileDir = path22.join(profilesDir, name);
|
|
8487
|
+
if (!fs22.existsSync(profileDir)) return { handled: true, output: pc6.red(`Profile not found: ${name}`) };
|
|
8488
|
+
const files = fs22.readdirSync(profileDir).filter((f) => f.endsWith(".md"));
|
|
7603
8489
|
const lines = files.map((f) => ` ${f}`);
|
|
7604
8490
|
return { handled: true, output: `Profile: ${pc6.bold(name)}
|
|
7605
8491
|
Files:
|
|
@@ -7608,9 +8494,9 @@ ${lines.join("\n")}` };
|
|
|
7608
8494
|
case "delete": {
|
|
7609
8495
|
const name = args[0];
|
|
7610
8496
|
if (!name) return { handled: true, output: pc6.yellow("Usage: /profile delete <name>") };
|
|
7611
|
-
const profileDir =
|
|
7612
|
-
if (!
|
|
7613
|
-
|
|
8497
|
+
const profileDir = path22.join(profilesDir, name);
|
|
8498
|
+
if (!fs22.existsSync(profileDir)) return { handled: true, output: pc6.red(`Profile not found: ${name}`) };
|
|
8499
|
+
fs22.rmSync(profileDir, { recursive: true });
|
|
7614
8500
|
return { handled: true, output: pc6.dim(`Profile deleted: ${name}`) };
|
|
7615
8501
|
}
|
|
7616
8502
|
case "help":
|
|
@@ -7828,10 +8714,10 @@ function handleShowcaseCommand(action, args) {
|
|
|
7828
8714
|
Or place it as a sibling directory to aman-agent.`
|
|
7829
8715
|
};
|
|
7830
8716
|
}
|
|
7831
|
-
const corePath =
|
|
8717
|
+
const corePath = path22.join(os19.homedir(), ".acore", "core.md");
|
|
7832
8718
|
let currentShowcase = null;
|
|
7833
|
-
if (
|
|
7834
|
-
const content =
|
|
8719
|
+
if (fs22.existsSync(corePath)) {
|
|
8720
|
+
const content = fs22.readFileSync(corePath, "utf-8");
|
|
7835
8721
|
const nameMatch = content.match(/^# (.+)/m);
|
|
7836
8722
|
if (nameMatch) {
|
|
7837
8723
|
const coreName = nameMatch[1].trim().toLowerCase();
|
|
@@ -7972,6 +8858,121 @@ async function handleFileCommand(action, args) {
|
|
|
7972
8858
|
}
|
|
7973
8859
|
return { handled: true, output: pc6.yellow(`Unknown /file subcommand: ${action}. Try /file for help.`) };
|
|
7974
8860
|
}
|
|
8861
|
+
async function handleOrchestrateCommand(action, args, ctx) {
|
|
8862
|
+
if (!action) {
|
|
8863
|
+
return {
|
|
8864
|
+
handled: true,
|
|
8865
|
+
output: `Usage: /orchestrate <requirement>
|
|
8866
|
+
|
|
8867
|
+
Decomposes a requirement into a task DAG and executes it with parallel agents.
|
|
8868
|
+
|
|
8869
|
+
Alias: /orch`
|
|
8870
|
+
};
|
|
8871
|
+
}
|
|
8872
|
+
const requirement = [action, ...args].join(" ");
|
|
8873
|
+
if (!ctx.llmClient) {
|
|
8874
|
+
return { handled: true, output: pc6.red("Orchestration requires an LLM client. Not available.") };
|
|
8875
|
+
}
|
|
8876
|
+
try {
|
|
8877
|
+
const dag = await decomposeRequirement(requirement, ctx.llmClient);
|
|
8878
|
+
const display = formatDAGForDisplay(dag);
|
|
8879
|
+
return { handled: true, output: display };
|
|
8880
|
+
} catch (err) {
|
|
8881
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
8882
|
+
return { handled: true, output: pc6.red(`Orchestration failed: ${msg}`) };
|
|
8883
|
+
}
|
|
8884
|
+
}
|
|
8885
|
+
async function handleGitHubCommand(action, args, ctx) {
|
|
8886
|
+
if (!action) {
|
|
8887
|
+
const available = await ghAvailable();
|
|
8888
|
+
if (!available) {
|
|
8889
|
+
return { handled: true, output: pc6.red("GitHub CLI (gh) is not available or not authenticated. Run: gh auth login") };
|
|
8890
|
+
}
|
|
8891
|
+
const repo = await ghCurrentRepo();
|
|
8892
|
+
if (!repo) {
|
|
8893
|
+
return { handled: true, output: pc6.yellow("Not inside a GitHub repository.") };
|
|
8894
|
+
}
|
|
8895
|
+
return { handled: true, output: `GitHub repo: ${pc6.bold(`${repo.owner}/${repo.name}`)}` };
|
|
8896
|
+
}
|
|
8897
|
+
switch (action) {
|
|
8898
|
+
case "issues": {
|
|
8899
|
+
const { gh: ghExec } = await Promise.resolve().then(() => (init_github(), github_exports));
|
|
8900
|
+
const repoArgs = args.length > 0 ? ["--repo", args[0]] : [];
|
|
8901
|
+
const result = await ghExec(["issue", "list", "--limit", "10", ...repoArgs]);
|
|
8902
|
+
if (!result.success) {
|
|
8903
|
+
return { handled: true, output: pc6.red(`Failed to list issues: ${result.stderr}`) };
|
|
8904
|
+
}
|
|
8905
|
+
return { handled: true, output: result.stdout.trim() || pc6.dim("No open issues.") };
|
|
8906
|
+
}
|
|
8907
|
+
case "prs": {
|
|
8908
|
+
const repoArgs = args.length > 0 ? { repo: args[0] } : {};
|
|
8909
|
+
try {
|
|
8910
|
+
const prs = await listPRs({ state: "open", limit: 10, ...repoArgs });
|
|
8911
|
+
if (prs.length === 0) {
|
|
8912
|
+
return { handled: true, output: pc6.dim("No open PRs.") };
|
|
8913
|
+
}
|
|
8914
|
+
const lines = prs.map(
|
|
8915
|
+
(pr) => `#${pr.number} ${pr.title} (${pr.headRefName} \u2192 ${pr.baseRefName})${pr.isDraft ? " [draft]" : ""}`
|
|
8916
|
+
);
|
|
8917
|
+
return { handled: true, output: lines.join("\n") };
|
|
8918
|
+
} catch (err) {
|
|
8919
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
8920
|
+
return { handled: true, output: pc6.red(`Failed to list PRs: ${msg}`) };
|
|
8921
|
+
}
|
|
8922
|
+
}
|
|
8923
|
+
case "plan": {
|
|
8924
|
+
const issueNum = parseInt(args[0], 10);
|
|
8925
|
+
if (!issueNum || isNaN(issueNum)) {
|
|
8926
|
+
return { handled: true, output: pc6.red("Usage: /github plan <issue-number>") };
|
|
8927
|
+
}
|
|
8928
|
+
if (!ctx.llmClient) {
|
|
8929
|
+
return { handled: true, output: pc6.red("Planning requires an LLM client. Not available.") };
|
|
8930
|
+
}
|
|
8931
|
+
try {
|
|
8932
|
+
const issue = await fetchIssue(issueNum);
|
|
8933
|
+
const requirement = formatIssueAsRequirement(issue);
|
|
8934
|
+
const dag = await decomposeRequirement(requirement, ctx.llmClient);
|
|
8935
|
+
const display = formatDAGForDisplay(dag);
|
|
8936
|
+
return { handled: true, output: `${pc6.bold(`Plan for #${issue.number}: ${issue.title}`)}
|
|
8937
|
+
|
|
8938
|
+
${display}` };
|
|
8939
|
+
} catch (err) {
|
|
8940
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
8941
|
+
return { handled: true, output: pc6.red(`Failed to plan issue #${issueNum}: ${msg}`) };
|
|
8942
|
+
}
|
|
8943
|
+
}
|
|
8944
|
+
case "ci": {
|
|
8945
|
+
const branch = args[0];
|
|
8946
|
+
if (!branch) {
|
|
8947
|
+
return { handled: true, output: pc6.red("Usage: /github ci <branch>") };
|
|
8948
|
+
}
|
|
8949
|
+
try {
|
|
8950
|
+
const passing = await isCIPassing(branch);
|
|
8951
|
+
return {
|
|
8952
|
+
handled: true,
|
|
8953
|
+
output: passing ? pc6.green(`CI is passing on ${branch}`) : pc6.yellow(`CI is NOT passing on ${branch}`)
|
|
8954
|
+
};
|
|
8955
|
+
} catch (err) {
|
|
8956
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
8957
|
+
return { handled: true, output: pc6.red(`Failed to check CI: ${msg}`) };
|
|
8958
|
+
}
|
|
8959
|
+
}
|
|
8960
|
+
default:
|
|
8961
|
+
return {
|
|
8962
|
+
handled: true,
|
|
8963
|
+
output: [
|
|
8964
|
+
`Usage: /github [subcommand]`,
|
|
8965
|
+
``,
|
|
8966
|
+
`Subcommands:`,
|
|
8967
|
+
` (none) Show current repo info`,
|
|
8968
|
+
` issues [repo] List open issues`,
|
|
8969
|
+
` prs [repo] List open PRs`,
|
|
8970
|
+
` plan <number> Plan from a GitHub issue`,
|
|
8971
|
+
` ci <branch> Check CI status for a branch`
|
|
8972
|
+
].join("\n")
|
|
8973
|
+
};
|
|
8974
|
+
}
|
|
8975
|
+
}
|
|
7975
8976
|
var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
|
|
7976
8977
|
"quit",
|
|
7977
8978
|
"exit",
|
|
@@ -8005,7 +9006,10 @@ var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
8005
9006
|
"showcase",
|
|
8006
9007
|
"file",
|
|
8007
9008
|
"observe",
|
|
8008
|
-
"postmortem"
|
|
9009
|
+
"postmortem",
|
|
9010
|
+
"orchestrate",
|
|
9011
|
+
"orch",
|
|
9012
|
+
"github"
|
|
8009
9013
|
]);
|
|
8010
9014
|
async function handleObserveCommand(action, ctx) {
|
|
8011
9015
|
if (!ctx.observationSession) {
|
|
@@ -8142,6 +9146,11 @@ async function handleCommand(input, ctx) {
|
|
|
8142
9146
|
return handleObserveCommand(action, ctx);
|
|
8143
9147
|
case "postmortem":
|
|
8144
9148
|
return handlePostmortemCommand(action, args, ctx);
|
|
9149
|
+
case "orchestrate":
|
|
9150
|
+
case "orch":
|
|
9151
|
+
return handleOrchestrateCommand(action, args, ctx);
|
|
9152
|
+
case "github":
|
|
9153
|
+
return handleGitHubCommand(action, args, ctx);
|
|
8145
9154
|
default:
|
|
8146
9155
|
return { handled: false };
|
|
8147
9156
|
}
|
|
@@ -8229,10 +9238,10 @@ init_logger();
|
|
|
8229
9238
|
|
|
8230
9239
|
// src/skill-engine.ts
|
|
8231
9240
|
init_logger();
|
|
8232
|
-
import
|
|
9241
|
+
import fs23 from "fs";
|
|
8233
9242
|
import fsp from "fs/promises";
|
|
8234
|
-
import
|
|
8235
|
-
import
|
|
9243
|
+
import path23 from "path";
|
|
9244
|
+
import os20 from "os";
|
|
8236
9245
|
var SKILL_TRIGGERS = {
|
|
8237
9246
|
testing: ["test", "spec", "coverage", "tdd", "jest", "vitest", "mocha", "assert", "mock", "stub", "fixture", "e2e", "integration test", "unit test"],
|
|
8238
9247
|
"api-design": ["api", "endpoint", "rest", "graphql", "route", "controller", "middleware", "http", "request", "response", "status code", "pagination"],
|
|
@@ -8261,20 +9270,20 @@ async function loadRuntimeTriggers(skillsMdPath) {
|
|
|
8261
9270
|
return /* @__PURE__ */ new Map();
|
|
8262
9271
|
}
|
|
8263
9272
|
}
|
|
8264
|
-
var LEVEL_FILE =
|
|
9273
|
+
var LEVEL_FILE = path23.join(os20.homedir(), ".aman-agent", "skill-levels.json");
|
|
8265
9274
|
function loadSkillLevels() {
|
|
8266
9275
|
try {
|
|
8267
|
-
if (
|
|
8268
|
-
return JSON.parse(
|
|
9276
|
+
if (fs23.existsSync(LEVEL_FILE)) {
|
|
9277
|
+
return JSON.parse(fs23.readFileSync(LEVEL_FILE, "utf-8"));
|
|
8269
9278
|
}
|
|
8270
9279
|
} catch {
|
|
8271
9280
|
}
|
|
8272
9281
|
return {};
|
|
8273
9282
|
}
|
|
8274
9283
|
function saveSkillLevels(levels) {
|
|
8275
|
-
const dir =
|
|
8276
|
-
if (!
|
|
8277
|
-
|
|
9284
|
+
const dir = path23.dirname(LEVEL_FILE);
|
|
9285
|
+
if (!fs23.existsSync(dir)) fs23.mkdirSync(dir, { recursive: true });
|
|
9286
|
+
fs23.writeFileSync(LEVEL_FILE, JSON.stringify(levels, null, 2), "utf-8");
|
|
8278
9287
|
}
|
|
8279
9288
|
function computeLevel(activations) {
|
|
8280
9289
|
if (activations >= 50) return { level: 5, label: "Expert" };
|
|
@@ -8501,7 +9510,7 @@ async function autoTriggerSkills(userInput, mcpManager) {
|
|
|
8501
9510
|
const result = await mcpManager.callTool("skill_list", {});
|
|
8502
9511
|
const skills = JSON.parse(result);
|
|
8503
9512
|
const installed = skills.filter((s) => s.installed).map((s) => s.name);
|
|
8504
|
-
const skillsMdPath =
|
|
9513
|
+
const skillsMdPath = path23.join(os20.homedir(), ".askill", "skills.md");
|
|
8505
9514
|
const runtimeTriggers = await loadRuntimeTriggers(skillsMdPath);
|
|
8506
9515
|
if (installed.length === 0 && runtimeTriggers.size === 0) return "";
|
|
8507
9516
|
const matched = matchSkillsSemantic(userInput, installed, runtimeTriggers);
|
|
@@ -8958,9 +9967,9 @@ function humanizeError(message) {
|
|
|
8958
9967
|
}
|
|
8959
9968
|
|
|
8960
9969
|
// src/hints.ts
|
|
8961
|
-
import
|
|
8962
|
-
import
|
|
8963
|
-
import
|
|
9970
|
+
import fs24 from "fs";
|
|
9971
|
+
import path24 from "path";
|
|
9972
|
+
import os21 from "os";
|
|
8964
9973
|
var HINTS = [
|
|
8965
9974
|
{
|
|
8966
9975
|
id: "eval",
|
|
@@ -8998,11 +10007,11 @@ function getHint(state, ctx) {
|
|
|
8998
10007
|
}
|
|
8999
10008
|
return null;
|
|
9000
10009
|
}
|
|
9001
|
-
var HINTS_FILE =
|
|
10010
|
+
var HINTS_FILE = path24.join(os21.homedir(), ".aman-agent", "hints-seen.json");
|
|
9002
10011
|
function loadShownHints() {
|
|
9003
10012
|
try {
|
|
9004
|
-
if (
|
|
9005
|
-
const data = JSON.parse(
|
|
10013
|
+
if (fs24.existsSync(HINTS_FILE)) {
|
|
10014
|
+
const data = JSON.parse(fs24.readFileSync(HINTS_FILE, "utf-8"));
|
|
9006
10015
|
return new Set(Array.isArray(data) ? data : []);
|
|
9007
10016
|
}
|
|
9008
10017
|
} catch {
|
|
@@ -9011,9 +10020,9 @@ function loadShownHints() {
|
|
|
9011
10020
|
}
|
|
9012
10021
|
function saveShownHints(shown) {
|
|
9013
10022
|
try {
|
|
9014
|
-
const dir =
|
|
9015
|
-
|
|
9016
|
-
|
|
10023
|
+
const dir = path24.dirname(HINTS_FILE);
|
|
10024
|
+
fs24.mkdirSync(dir, { recursive: true });
|
|
10025
|
+
fs24.writeFileSync(HINTS_FILE, JSON.stringify([...shown]), "utf-8");
|
|
9017
10026
|
} catch {
|
|
9018
10027
|
}
|
|
9019
10028
|
}
|
|
@@ -9280,9 +10289,9 @@ ${task.result}`
|
|
|
9280
10289
|
}
|
|
9281
10290
|
if (cmdResult.exportConversation) {
|
|
9282
10291
|
try {
|
|
9283
|
-
const exportDir =
|
|
9284
|
-
|
|
9285
|
-
const exportPath =
|
|
10292
|
+
const exportDir = path25.join(os22.homedir(), ".aman-agent", "exports");
|
|
10293
|
+
fs25.mkdirSync(exportDir, { recursive: true });
|
|
10294
|
+
const exportPath = path25.join(exportDir, `${sessionId}.md`);
|
|
9286
10295
|
const lines = [
|
|
9287
10296
|
`# Conversation \u2014 ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
|
|
9288
10297
|
`**Model:** ${model}`,
|
|
@@ -9296,7 +10305,7 @@ ${task.result}`
|
|
|
9296
10305
|
lines.push(`${label} ${msg.content}`, "");
|
|
9297
10306
|
}
|
|
9298
10307
|
}
|
|
9299
|
-
|
|
10308
|
+
fs25.writeFileSync(exportPath, lines.join("\n"), "utf-8");
|
|
9300
10309
|
console.log(pc7.green(`Exported to ${exportPath}`));
|
|
9301
10310
|
} catch {
|
|
9302
10311
|
console.log(pc7.red("Failed to export conversation."));
|
|
@@ -9422,25 +10431,25 @@ ${knowledgeItem.content}
|
|
|
9422
10431
|
for (const match of filePathMatches) {
|
|
9423
10432
|
let filePath = match[1];
|
|
9424
10433
|
if (filePath.startsWith("~/")) {
|
|
9425
|
-
filePath =
|
|
10434
|
+
filePath = path25.join(os22.homedir(), filePath.slice(2));
|
|
9426
10435
|
}
|
|
9427
|
-
if (!
|
|
9428
|
-
const ext =
|
|
10436
|
+
if (!fs25.existsSync(filePath) || !fs25.statSync(filePath).isFile()) continue;
|
|
10437
|
+
const ext = path25.extname(filePath).toLowerCase();
|
|
9429
10438
|
if (imageExts.has(ext)) {
|
|
9430
10439
|
try {
|
|
9431
|
-
const stat =
|
|
10440
|
+
const stat = fs25.statSync(filePath);
|
|
9432
10441
|
if (stat.size > maxImageBytes) {
|
|
9433
|
-
process.stdout.write(pc7.yellow(` [skipped: ${
|
|
10442
|
+
process.stdout.write(pc7.yellow(` [skipped: ${path25.basename(filePath)} \u2014 exceeds 20MB limit]
|
|
9434
10443
|
`));
|
|
9435
10444
|
continue;
|
|
9436
10445
|
}
|
|
9437
|
-
const data =
|
|
10446
|
+
const data = fs25.readFileSync(filePath).toString("base64");
|
|
9438
10447
|
const mediaType = mimeMap[ext] || "image/png";
|
|
9439
10448
|
imageBlocks.push({
|
|
9440
10449
|
type: "image",
|
|
9441
10450
|
source: { type: "base64", media_type: mediaType, data }
|
|
9442
10451
|
});
|
|
9443
|
-
process.stdout.write(pc7.dim(` [attached image: ${
|
|
10452
|
+
process.stdout.write(pc7.dim(` [attached image: ${path25.basename(filePath)} (${(stat.size / 1024).toFixed(1)}KB)]
|
|
9444
10453
|
`));
|
|
9445
10454
|
} catch {
|
|
9446
10455
|
process.stdout.write(pc7.dim(` [could not read image: ${filePath}]
|
|
@@ -9448,7 +10457,7 @@ ${knowledgeItem.content}
|
|
|
9448
10457
|
}
|
|
9449
10458
|
} else if (textExts.has(ext) || ext === "") {
|
|
9450
10459
|
try {
|
|
9451
|
-
const content =
|
|
10460
|
+
const content = fs25.readFileSync(filePath, "utf-8");
|
|
9452
10461
|
const maxChars = 5e4;
|
|
9453
10462
|
const trimmed = content.length > maxChars ? content.slice(0, maxChars) + `
|
|
9454
10463
|
|
|
@@ -9458,7 +10467,7 @@ ${knowledgeItem.content}
|
|
|
9458
10467
|
<file path="${filePath}" size="${content.length} chars">
|
|
9459
10468
|
${trimmed}
|
|
9460
10469
|
</file>`;
|
|
9461
|
-
process.stdout.write(pc7.dim(` [attached: ${
|
|
10470
|
+
process.stdout.write(pc7.dim(` [attached: ${path25.basename(filePath)} (${(content.length / 1024).toFixed(1)}KB)]
|
|
9462
10471
|
`));
|
|
9463
10472
|
} catch {
|
|
9464
10473
|
process.stdout.write(pc7.dim(` [could not read: ${filePath}]
|
|
@@ -9467,7 +10476,7 @@ ${trimmed}
|
|
|
9467
10476
|
} else if (docExts.has(ext)) {
|
|
9468
10477
|
if (mcpManager) {
|
|
9469
10478
|
try {
|
|
9470
|
-
process.stdout.write(pc7.dim(` [converting: ${
|
|
10479
|
+
process.stdout.write(pc7.dim(` [converting: ${path25.basename(filePath)}...]
|
|
9471
10480
|
`));
|
|
9472
10481
|
const converted = await mcpManager.callTool("doc_convert", { path: filePath });
|
|
9473
10482
|
if (converted && !converted.startsWith("Error") && !converted.includes("Could not convert")) {
|
|
@@ -9476,7 +10485,7 @@ ${trimmed}
|
|
|
9476
10485
|
<file path="${filePath}" format="${ext}">
|
|
9477
10486
|
${converted.slice(0, 5e4)}
|
|
9478
10487
|
</file>`;
|
|
9479
|
-
process.stdout.write(pc7.dim(` [attached: ${
|
|
10488
|
+
process.stdout.write(pc7.dim(` [attached: ${path25.basename(filePath)} (converted from ${ext})]
|
|
9480
10489
|
`));
|
|
9481
10490
|
} else {
|
|
9482
10491
|
textContent += `
|
|
@@ -9488,7 +10497,7 @@ ${converted}
|
|
|
9488
10497
|
`));
|
|
9489
10498
|
}
|
|
9490
10499
|
} catch {
|
|
9491
|
-
process.stdout.write(pc7.dim(` [could not convert: ${
|
|
10500
|
+
process.stdout.write(pc7.dim(` [could not convert: ${path25.basename(filePath)}]
|
|
9492
10501
|
`));
|
|
9493
10502
|
}
|
|
9494
10503
|
} else {
|
|
@@ -9880,7 +10889,7 @@ ${result2.response}` : `[${input2.profile}] failed: ${result2.error}`;
|
|
|
9880
10889
|
}
|
|
9881
10890
|
if (hooksConfig?.featureHints) {
|
|
9882
10891
|
hintState.turnCount++;
|
|
9883
|
-
const hasWorkflows =
|
|
10892
|
+
const hasWorkflows = fs25.existsSync(path25.join(os22.homedir(), ".aflow", "flow.md"));
|
|
9884
10893
|
const memoryCount = memoryTokens > 0 ? Math.floor(memoryTokens / 5) : 0;
|
|
9885
10894
|
const hint = getHint(hintState, { hasWorkflows, memoryCount });
|
|
9886
10895
|
if (hint) {
|
|
@@ -9926,8 +10935,8 @@ async function saveConversationToMemory(messages, sessionId) {
|
|
|
9926
10935
|
}
|
|
9927
10936
|
|
|
9928
10937
|
// src/index.ts
|
|
9929
|
-
import
|
|
9930
|
-
import
|
|
10938
|
+
import fs29 from "fs";
|
|
10939
|
+
import path29 from "path";
|
|
9931
10940
|
|
|
9932
10941
|
// src/presets.ts
|
|
9933
10942
|
var PRESETS = {
|
|
@@ -10040,7 +11049,7 @@ import * as p3 from "@clack/prompts";
|
|
|
10040
11049
|
|
|
10041
11050
|
// src/server/index.ts
|
|
10042
11051
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
10043
|
-
import { z } from "zod";
|
|
11052
|
+
import { z as z3 } from "zod";
|
|
10044
11053
|
|
|
10045
11054
|
// src/server/transport.ts
|
|
10046
11055
|
import http from "http";
|
|
@@ -10141,7 +11150,7 @@ var Inbox = class {
|
|
|
10141
11150
|
// package.json
|
|
10142
11151
|
var package_default = {
|
|
10143
11152
|
name: "@aman_asmuei/aman-agent",
|
|
10144
|
-
version: "0.
|
|
11153
|
+
version: "0.40.0",
|
|
10145
11154
|
description: "Your AI companion, running locally \u2014 powered by the aman ecosystem",
|
|
10146
11155
|
type: "module",
|
|
10147
11156
|
engines: {
|
|
@@ -10307,8 +11316,8 @@ async function startAgentServer(opts) {
|
|
|
10307
11316
|
{
|
|
10308
11317
|
description: "Delegate a task to this agent. Returns the agent's final response text.",
|
|
10309
11318
|
inputSchema: {
|
|
10310
|
-
task:
|
|
10311
|
-
context:
|
|
11319
|
+
task: z3.string().describe("The task to run against this agent's profile"),
|
|
11320
|
+
context: z3.string().optional().describe("Optional extra context")
|
|
10312
11321
|
}
|
|
10313
11322
|
},
|
|
10314
11323
|
async (input) => {
|
|
@@ -10321,9 +11330,9 @@ async function startAgentServer(opts) {
|
|
|
10321
11330
|
{
|
|
10322
11331
|
description: "Deliver a one-way message into this agent's inbox. Drained at next user turn.",
|
|
10323
11332
|
inputSchema: {
|
|
10324
|
-
from:
|
|
10325
|
-
topic:
|
|
10326
|
-
body:
|
|
11333
|
+
from: z3.string().optional(),
|
|
11334
|
+
topic: z3.string().optional(),
|
|
11335
|
+
body: z3.string()
|
|
10327
11336
|
}
|
|
10328
11337
|
},
|
|
10329
11338
|
async (input) => {
|
|
@@ -10434,9 +11443,9 @@ async function runServe(opts) {
|
|
|
10434
11443
|
|
|
10435
11444
|
// src/index.ts
|
|
10436
11445
|
async function autoDetectConfig() {
|
|
10437
|
-
const reconfigMarker =
|
|
10438
|
-
if (
|
|
10439
|
-
|
|
11446
|
+
const reconfigMarker = path29.join(homeDir(), ".reconfig");
|
|
11447
|
+
if (fs29.existsSync(reconfigMarker)) {
|
|
11448
|
+
fs29.unlinkSync(reconfigMarker);
|
|
10440
11449
|
return null;
|
|
10441
11450
|
}
|
|
10442
11451
|
const anthropicKey = process.env.ANTHROPIC_API_KEY;
|
|
@@ -10465,10 +11474,10 @@ async function autoDetectConfig() {
|
|
|
10465
11474
|
return null;
|
|
10466
11475
|
}
|
|
10467
11476
|
function bootstrapEcosystem() {
|
|
10468
|
-
const corePath =
|
|
10469
|
-
if (
|
|
10470
|
-
|
|
10471
|
-
|
|
11477
|
+
const corePath = path29.join(identityDir(), "core.md");
|
|
11478
|
+
if (fs29.existsSync(corePath)) return false;
|
|
11479
|
+
fs29.mkdirSync(identityDir(), { recursive: true });
|
|
11480
|
+
fs29.writeFileSync(corePath, [
|
|
10472
11481
|
"# Aman",
|
|
10473
11482
|
"",
|
|
10474
11483
|
"## Personality",
|
|
@@ -10480,10 +11489,10 @@ function bootstrapEcosystem() {
|
|
|
10480
11489
|
"## Session",
|
|
10481
11490
|
"_New companion \u2014 no prior sessions._"
|
|
10482
11491
|
].join("\n"), "utf-8");
|
|
10483
|
-
const rulesPath =
|
|
10484
|
-
if (!
|
|
10485
|
-
|
|
10486
|
-
|
|
11492
|
+
const rulesPath = path29.join(rulesDir(), "rules.md");
|
|
11493
|
+
if (!fs29.existsSync(rulesPath)) {
|
|
11494
|
+
fs29.mkdirSync(rulesDir(), { recursive: true });
|
|
11495
|
+
fs29.writeFileSync(rulesPath, [
|
|
10487
11496
|
"# Guardrails",
|
|
10488
11497
|
"",
|
|
10489
11498
|
"## safety",
|
|
@@ -10495,20 +11504,20 @@ function bootstrapEcosystem() {
|
|
|
10495
11504
|
"- Respect the user's preferences stored in memory"
|
|
10496
11505
|
].join("\n"), "utf-8");
|
|
10497
11506
|
}
|
|
10498
|
-
const flowPath =
|
|
10499
|
-
if (!
|
|
10500
|
-
|
|
10501
|
-
|
|
11507
|
+
const flowPath = path29.join(workflowsDir(), "flow.md");
|
|
11508
|
+
if (!fs29.existsSync(flowPath)) {
|
|
11509
|
+
fs29.mkdirSync(workflowsDir(), { recursive: true });
|
|
11510
|
+
fs29.writeFileSync(flowPath, "# Workflows\n\n_No workflows defined yet. Use /workflows add to create one._\n", "utf-8");
|
|
10502
11511
|
}
|
|
10503
|
-
const skillPath =
|
|
10504
|
-
if (!
|
|
10505
|
-
|
|
10506
|
-
|
|
11512
|
+
const skillPath = path29.join(skillsDir(), "skills.md");
|
|
11513
|
+
if (!fs29.existsSync(skillPath)) {
|
|
11514
|
+
fs29.mkdirSync(skillsDir(), { recursive: true });
|
|
11515
|
+
fs29.writeFileSync(skillPath, "# Skills\n\n_No skills installed yet. Use /skills install to add domain expertise._\n", "utf-8");
|
|
10507
11516
|
}
|
|
10508
11517
|
return true;
|
|
10509
11518
|
}
|
|
10510
11519
|
var program = new Command();
|
|
10511
|
-
program.name("aman-agent").description("Your AI companion, running locally").version("0.
|
|
11520
|
+
program.name("aman-agent").description("Your AI companion, running locally").version("0.40.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) => {
|
|
10512
11521
|
p4.intro(pc9.bold("aman agent") + pc9.dim(" \u2014 your AI companion"));
|
|
10513
11522
|
let config = loadConfig();
|
|
10514
11523
|
if (!config) {
|
|
@@ -10863,18 +11872,18 @@ program.command("init").description("Set up your AI companion with a guided wiza
|
|
|
10863
11872
|
});
|
|
10864
11873
|
if (p4.isCancel(preset)) process.exit(0);
|
|
10865
11874
|
const result = applyPreset(preset, name || "Aman");
|
|
10866
|
-
|
|
10867
|
-
|
|
11875
|
+
fs29.mkdirSync(identityDir(), { recursive: true });
|
|
11876
|
+
fs29.writeFileSync(path29.join(identityDir(), "core.md"), result.coreMd, "utf-8");
|
|
10868
11877
|
p4.log.success(`Identity created \u2014 ${PRESETS[preset].identity.personality.split(".")[0].toLowerCase()}`);
|
|
10869
11878
|
if (result.rulesMd) {
|
|
10870
|
-
|
|
10871
|
-
|
|
11879
|
+
fs29.mkdirSync(rulesDir(), { recursive: true });
|
|
11880
|
+
fs29.writeFileSync(path29.join(rulesDir(), "rules.md"), result.rulesMd, "utf-8");
|
|
10872
11881
|
const ruleCount = (result.rulesMd.match(/^- /gm) || []).length;
|
|
10873
11882
|
p4.log.success(`${ruleCount} rules set`);
|
|
10874
11883
|
}
|
|
10875
11884
|
if (result.flowMd) {
|
|
10876
|
-
|
|
10877
|
-
|
|
11885
|
+
fs29.mkdirSync(workflowsDir(), { recursive: true });
|
|
11886
|
+
fs29.writeFileSync(path29.join(workflowsDir(), "flow.md"), result.flowMd, "utf-8");
|
|
10878
11887
|
const wfCount = (result.flowMd.match(/^## /gm) || []).length;
|
|
10879
11888
|
p4.log.success(`${wfCount} workflow${wfCount > 1 ? "s" : ""} added`);
|
|
10880
11889
|
}
|
|
@@ -10976,16 +11985,16 @@ ${result.diff}`);
|
|
|
10976
11985
|
});
|
|
10977
11986
|
program.command("setup").description("Run the full configuration wizard (provider, identity, presets)").action(async () => {
|
|
10978
11987
|
p4.intro(pc9.bold("aman agent setup") + pc9.dim(" \u2014 full configuration wizard"));
|
|
10979
|
-
const reconfigPath =
|
|
10980
|
-
|
|
10981
|
-
|
|
11988
|
+
const reconfigPath = path29.join(homeDir(), ".reconfig");
|
|
11989
|
+
fs29.mkdirSync(homeDir(), { recursive: true });
|
|
11990
|
+
fs29.writeFileSync(reconfigPath, "", "utf-8");
|
|
10982
11991
|
p4.log.info("Configuration reset. Restart aman-agent to complete setup.");
|
|
10983
11992
|
});
|
|
10984
11993
|
program.command("update").description("Update aman-agent to the latest version").action(async () => {
|
|
10985
11994
|
const { execFileSync: execFileSync4 } = await import("child_process");
|
|
10986
|
-
const isVendored = process.execPath.includes(
|
|
11995
|
+
const isVendored = process.execPath.includes(path29.join(".aman-agent", "node"));
|
|
10987
11996
|
if (isVendored) {
|
|
10988
|
-
const npmPath =
|
|
11997
|
+
const npmPath = path29.join(homeDir(), "node", "bin", "npm");
|
|
10989
11998
|
console.log("Updating aman-agent...");
|
|
10990
11999
|
try {
|
|
10991
12000
|
execFileSync4(npmPath, ["install", "-g", "@aman_asmuei/aman-agent@latest"], {
|
|
@@ -11013,7 +12022,7 @@ program.command("update").description("Update aman-agent to the latest version")
|
|
|
11013
12022
|
program.command("uninstall").description("Remove aman-agent and all its data").action(async () => {
|
|
11014
12023
|
const home2 = homeDir();
|
|
11015
12024
|
if (!process.stdin.isTTY) {
|
|
11016
|
-
|
|
12025
|
+
fs29.rmSync(home2, { recursive: true, force: true });
|
|
11017
12026
|
console.log("\u2713 Removed " + home2);
|
|
11018
12027
|
return;
|
|
11019
12028
|
}
|
|
@@ -11024,7 +12033,7 @@ program.command("uninstall").description("Remove aman-agent and all its data").a
|
|
|
11024
12033
|
console.log("Cancelled.");
|
|
11025
12034
|
return;
|
|
11026
12035
|
}
|
|
11027
|
-
|
|
12036
|
+
fs29.rmSync(home2, { recursive: true, force: true });
|
|
11028
12037
|
console.log("\u2713 Removed " + home2);
|
|
11029
12038
|
console.log("");
|
|
11030
12039
|
console.log("To complete uninstall, remove the PATH line from your shell config:");
|