agent-enderun 1.10.2 → 1.10.4
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 +2 -1
- package/dist/framework-mcp/src/constants.d.ts +47 -0
- package/dist/framework-mcp/src/constants.js +65 -0
- package/dist/framework-mcp/src/constants.js.map +1 -0
- package/dist/framework-mcp/src/index.js +26 -5
- package/dist/framework-mcp/src/index.js.map +1 -1
- package/dist/framework-mcp/src/tools/control_plane/locking.d.ts +3 -9
- package/dist/framework-mcp/src/tools/control_plane/locking.js.map +1 -1
- package/dist/framework-mcp/src/tools/control_plane/registry.d.ts +2 -8
- package/dist/framework-mcp/src/tools/control_plane/registry.js.map +1 -1
- package/dist/framework-mcp/src/tools/dashboard/start_dashboard.d.ts +2 -2
- package/dist/framework-mcp/src/tools/dashboard/start_dashboard.js.map +1 -1
- package/dist/framework-mcp/src/tools/definitions.js +30 -0
- package/dist/framework-mcp/src/tools/definitions.js.map +1 -1
- package/dist/framework-mcp/src/tools/file_system/batch_surgical_edit.d.ts +2 -2
- package/dist/framework-mcp/src/tools/file_system/batch_surgical_edit.js +12 -4
- package/dist/framework-mcp/src/tools/file_system/batch_surgical_edit.js.map +1 -1
- package/dist/framework-mcp/src/tools/file_system/patch_file.d.ts +2 -2
- package/dist/framework-mcp/src/tools/file_system/patch_file.js +6 -2
- package/dist/framework-mcp/src/tools/file_system/patch_file.js.map +1 -1
- package/dist/framework-mcp/src/tools/file_system/read_file.d.ts +2 -2
- package/dist/framework-mcp/src/tools/file_system/read_file.js +43 -26
- package/dist/framework-mcp/src/tools/file_system/read_file.js.map +1 -1
- package/dist/framework-mcp/src/tools/file_system/replace_text.d.ts +2 -2
- package/dist/framework-mcp/src/tools/file_system/replace_text.js +7 -3
- package/dist/framework-mcp/src/tools/file_system/replace_text.js.map +1 -1
- package/dist/framework-mcp/src/tools/file_system/write_file.d.ts +2 -2
- package/dist/framework-mcp/src/tools/file_system/write_file.js +27 -15
- package/dist/framework-mcp/src/tools/file_system/write_file.js.map +1 -1
- package/dist/framework-mcp/src/tools/framework/get_status.d.ts +2 -2
- package/dist/framework-mcp/src/tools/framework/get_status.js.map +1 -1
- package/dist/framework-mcp/src/tools/framework/orchestrate.d.ts +2 -2
- package/dist/framework-mcp/src/tools/framework/orchestrate.js.map +1 -1
- package/dist/framework-mcp/src/tools/framework/run_tests.d.ts +2 -2
- package/dist/framework-mcp/src/tools/framework/run_tests.js.map +1 -1
- package/dist/framework-mcp/src/tools/framework/update_contract_hash.d.ts +2 -2
- package/dist/framework-mcp/src/tools/framework/update_contract_hash.js.map +1 -1
- package/dist/framework-mcp/src/tools/framework/update_memory.d.ts +2 -2
- package/dist/framework-mcp/src/tools/framework/update_memory.js +1 -1
- package/dist/framework-mcp/src/tools/framework/update_memory.js.map +1 -1
- package/dist/framework-mcp/src/tools/index.d.ts +1 -2
- package/dist/framework-mcp/src/tools/index.js +33 -25
- package/dist/framework-mcp/src/tools/index.js.map +1 -1
- package/dist/framework-mcp/src/tools/messaging/log_action.d.ts +2 -2
- package/dist/framework-mcp/src/tools/messaging/log_action.js.map +1 -1
- package/dist/framework-mcp/src/tools/messaging/send_message.d.ts +2 -2
- package/dist/framework-mcp/src/tools/messaging/send_message.js +14 -1
- package/dist/framework-mcp/src/tools/messaging/send_message.js.map +1 -1
- package/dist/framework-mcp/src/tools/observability/check_ports.d.ts +2 -2
- package/dist/framework-mcp/src/tools/observability/check_ports.js.map +1 -1
- package/dist/framework-mcp/src/tools/quality/check_lint.d.ts +5 -0
- package/dist/framework-mcp/src/tools/quality/check_lint.js +29 -0
- package/dist/framework-mcp/src/tools/quality/check_lint.js.map +1 -0
- package/dist/framework-mcp/src/tools/search/get_gaps.d.ts +2 -2
- package/dist/framework-mcp/src/tools/search/get_gaps.js.map +1 -1
- package/dist/framework-mcp/src/tools/search/get_map.d.ts +2 -2
- package/dist/framework-mcp/src/tools/search/get_map.js +1 -1
- package/dist/framework-mcp/src/tools/search/get_map.js.map +1 -1
- package/dist/framework-mcp/src/tools/search/grep_search.d.ts +2 -2
- package/dist/framework-mcp/src/tools/search/grep_search.js +45 -28
- package/dist/framework-mcp/src/tools/search/grep_search.js.map +1 -1
- package/dist/framework-mcp/src/tools/search/list_dir.d.ts +2 -2
- package/dist/framework-mcp/src/tools/search/list_dir.js.map +1 -1
- package/dist/framework-mcp/src/tools/shell/run_command.d.ts +2 -0
- package/dist/framework-mcp/src/tools/shell/run_command.js +47 -0
- package/dist/framework-mcp/src/tools/shell/run_command.js.map +1 -0
- package/dist/framework-mcp/src/tools/types.d.ts +95 -28
- package/dist/framework-mcp/src/utils/metrics.d.ts +20 -0
- package/dist/framework-mcp/src/utils/metrics.js +24 -6
- package/dist/framework-mcp/src/utils/metrics.js.map +1 -1
- package/dist/framework-mcp/src/utils/security.d.ts +1 -3
- package/dist/framework-mcp/src/utils/security.js +21 -18
- package/dist/framework-mcp/src/utils/security.js.map +1 -1
- package/dist/framework-mcp/tests/tools/file_system/file_system_tools.test.js +19 -14
- package/dist/framework-mcp/tests/tools/file_system/file_system_tools.test.js.map +1 -1
- package/dist/framework-mcp/tests/tools/messaging/send_message.test.js +1 -1
- package/dist/framework-mcp/tests/tools/messaging/send_message.test.js.map +1 -1
- package/dist/framework-mcp/tests/tools/quality/check_lint.test.d.ts +1 -0
- package/dist/framework-mcp/tests/tools/quality/check_lint.test.js +36 -0
- package/dist/framework-mcp/tests/tools/quality/check_lint.test.js.map +1 -0
- package/dist/framework-mcp/tests/tools/shell/run_command.test.d.ts +1 -0
- package/dist/framework-mcp/tests/tools/shell/run_command.test.js +43 -0
- package/dist/framework-mcp/tests/tools/shell/run_command.test.js.map +1 -0
- package/dist/src/cli/adapters/core.d.ts +1 -1
- package/dist/src/cli/adapters/core.js +5 -0
- package/dist/src/cli/adapters/core.js.map +1 -1
- package/dist/src/cli/adapters/paths.d.ts +15 -0
- package/dist/src/cli/adapters/paths.js +101 -0
- package/dist/src/cli/adapters/paths.js.map +1 -0
- package/dist/src/cli/adapters/scaffold.js +2 -1
- package/dist/src/cli/adapters/scaffold.js.map +1 -1
- package/dist/src/cli/commands/check.js +15 -36
- package/dist/src/cli/commands/check.js.map +1 -1
- package/dist/src/cli/commands/dashboard/data-service.d.ts +8 -0
- package/dist/src/cli/commands/dashboard/data-service.js +37 -0
- package/dist/src/cli/commands/dashboard/data-service.js.map +1 -1
- package/dist/src/cli/commands/init/scaffold-standards.js +6 -1
- package/dist/src/cli/commands/init/scaffold-standards.js.map +1 -1
- package/dist/src/cli/commands/init.js +2 -5
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/orchestrate.d.ts +5 -0
- package/dist/src/cli/commands/orchestrate.js +148 -128
- package/dist/src/cli/commands/orchestrate.js.map +1 -1
- package/dist/src/cli/utils/fs.js +1 -1
- package/dist/src/cli/utils/fs.js.map +1 -1
- package/dist/src/cli/utils/memory.d.ts +1 -1
- package/dist/src/cli/utils/memory.js +28 -8
- package/dist/src/cli/utils/memory.js.map +1 -1
- package/dist/src/modules/adapters/definitions.js +3 -3
- package/dist/src/modules/adapters/definitions.js.map +1 -1
- package/dist/src/modules/agents/definitions.js +2 -1
- package/dist/src/modules/agents/definitions.js.map +1 -1
- package/dist/src/modules/agents/registry/architect.js +1 -0
- package/dist/src/modules/agents/registry/architect.js.map +1 -1
- package/dist/src/modules/agents/registry/backend.js +3 -3
- package/dist/src/modules/agents/registry/backend.js.map +1 -1
- package/dist/src/modules/agents/registry/database.js +3 -3
- package/dist/src/modules/agents/registry/database.js.map +1 -1
- package/dist/src/modules/agents/registry/devops.js +1 -1
- package/dist/src/modules/agents/registry/devops.js.map +1 -1
- package/dist/src/modules/agents/registry/quality.js +1 -0
- package/dist/src/modules/agents/registry/quality.js.map +1 -1
- package/dist/src/shared/constants.d.ts +113 -0
- package/dist/src/shared/constants.js +178 -0
- package/dist/src/shared/constants.js.map +1 -0
- package/dist/tests/adapters/paths.test.d.ts +1 -0
- package/dist/tests/adapters/paths.test.js +63 -0
- package/dist/tests/adapters/paths.test.js.map +1 -0
- package/dist/tests/approve.test.js +2 -1
- package/dist/tests/approve.test.js.map +1 -1
- package/dist/tests/cli/init/unified_init.test.d.ts +1 -0
- package/dist/tests/cli/init/unified_init.test.js +47 -0
- package/dist/tests/cli/init/unified_init.test.js.map +1 -0
- package/dist/tests/fs-utils.test.js +1 -1
- package/dist/tests/fs-utils.test.js.map +1 -1
- package/dist/tests/memory-utils.test.js +1 -1
- package/dist/tests/memory-utils.test.js.map +1 -1
- package/dist/tests/shared/constants.test.d.ts +1 -0
- package/dist/tests/shared/constants.test.js +17 -0
- package/dist/tests/shared/constants.test.js.map +1 -0
- package/dist/tests/trace.test.js +2 -2
- package/dist/tests/trace.test.js.map +1 -1
- package/package.json +6 -6
- package/src/cli/adapters/core.ts +7 -0
- package/src/cli/adapters/paths.ts +134 -0
- package/src/cli/adapters/scaffold.ts +2 -1
- package/src/cli/commands/check.ts +16 -38
- package/src/cli/commands/dashboard/data-service.ts +48 -0
- package/src/cli/commands/init/scaffold-standards.ts +6 -1
- package/src/cli/commands/init.ts +1 -4
- package/src/cli/commands/orchestrate.ts +151 -127
- package/src/cli/utils/fs.ts +1 -1
- package/src/cli/utils/memory.ts +32 -7
- package/src/modules/adapters/definitions.ts +4 -3
- package/src/modules/agents/definitions.ts +2 -1
- package/src/modules/agents/registry/architect.ts +1 -0
- package/src/modules/agents/registry/backend.ts +3 -3
- package/src/modules/agents/registry/database.ts +3 -3
- package/src/modules/agents/registry/devops.ts +1 -1
- package/src/modules/agents/registry/quality.ts +1 -0
- package/src/shared/constants.ts +212 -0
- package/bin/validate-agent-army.js +0 -148
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
|
-
import chalk from "chalk";
|
|
4
3
|
import { getFrameworkDir, updateDocumentStore, readStatus } from "../utils/memory.js";
|
|
5
4
|
import { UI } from "../utils/ui.js";
|
|
6
5
|
import { writeTextFile, appendFile } from "../utils/fs.js";
|
|
@@ -19,7 +18,8 @@ export const HermesMessageSchema = z.object({
|
|
|
19
18
|
parentId: z.string().optional(),
|
|
20
19
|
status: z.enum(["PENDING", "PROCESSED", "WAITING", "APPROVED"]),
|
|
21
20
|
priority: z.enum(["HIGH", "NORMAL", "LOW"]).optional(),
|
|
22
|
-
action: z.string().optional()
|
|
21
|
+
action: z.string().optional(),
|
|
22
|
+
requiresApproval: z.boolean().optional(),
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
export type HermesMessage = z.infer<typeof HermesMessageSchema>;
|
|
@@ -49,162 +49,182 @@ export async function orchestrateCommand() {
|
|
|
49
49
|
isLooping = true;
|
|
50
50
|
|
|
51
51
|
while (isLooping) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
try {
|
|
53
|
+
// Initial load from disk to sync the cache
|
|
54
|
+
if (Object.keys(agentStatusCache).length === 0) {
|
|
55
|
+
const diskStatus = readStatus();
|
|
56
|
+
agentStatusCache = diskStatus || {};
|
|
57
|
+
}
|
|
57
58
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
59
|
+
// Check for agent timeouts (e.g. 30 minutes in EXECUTING state)
|
|
60
|
+
const agentStatuses = readStatus();
|
|
61
|
+
let updatedStatus = false;
|
|
62
|
+
for (const [agentName, info] of Object.entries(agentStatuses)) {
|
|
63
|
+
const { state, lastUpdated } = info as { state: string; task: string; lastUpdated?: string };
|
|
64
|
+
if (state === "EXECUTING" && lastUpdated) {
|
|
65
|
+
const lastUpdatedTime = Date.parse(lastUpdated);
|
|
66
|
+
if (!isNaN(lastUpdatedTime) && Date.now() - lastUpdatedTime > 30 * 60 * 1000) {
|
|
67
|
+
UI.error(`⚠️ Agent ${agentName} has TIMED OUT (in EXECUTING state for >30m). Transitioning to BLOCKED.`);
|
|
68
|
+
agentStatuses[agentName] = { state: "BLOCKED", task: "Timeout occurred", lastUpdated: new Date().toISOString() };
|
|
69
|
+
updatedStatus = true;
|
|
70
|
+
}
|
|
69
71
|
}
|
|
70
72
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
73
|
+
if (updatedStatus) {
|
|
74
|
+
updateDocumentStore("status", agentStatuses);
|
|
75
|
+
agentStatusCache = { ...agentStatuses }; // Sync cache
|
|
76
|
+
}
|
|
76
77
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
if (fs.existsSync(messagesDir)) {
|
|
79
|
+
const messageFiles = fs.readdirSync(messagesDir).filter((f) => f.endsWith(".json"));
|
|
80
|
+
const pendingMessages: HermesMessage[] = [];
|
|
81
|
+
const fileMessagesMap: Record<string, HermesMessage[]> = {};
|
|
81
82
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
83
|
+
for (const file of messageFiles) {
|
|
84
|
+
const filePath = path.join(messagesDir, file);
|
|
85
|
+
try {
|
|
86
|
+
const content = fs.readFileSync(filePath, "utf8").trim();
|
|
87
|
+
if (!content) continue;
|
|
88
|
+
const lines = content.split("\n");
|
|
89
|
+
const allMsgs: HermesMessage[] = [];
|
|
90
|
+
lines.forEach((line) => {
|
|
91
|
+
if (!line.trim()) return;
|
|
92
|
+
try {
|
|
93
|
+
const parsed = JSON.parse(line);
|
|
94
|
+
const msg = HermesMessageSchema.parse(parsed);
|
|
95
|
+
|
|
96
|
+
// Contract Validation
|
|
97
|
+
if (msg.category === "ACTION" || msg.category === "DELEGATION") {
|
|
98
|
+
try {
|
|
99
|
+
const payload = JSON.parse(msg.content);
|
|
100
|
+
TaskRequestSchema.parse(payload);
|
|
101
|
+
} catch (e) {
|
|
102
|
+
UI.error(`Invalid task contract payload: ${(e as Error).message}`);
|
|
103
|
+
return; // Skip invalid message
|
|
104
|
+
}
|
|
103
105
|
}
|
|
104
|
-
}
|
|
105
106
|
|
|
106
|
-
|
|
107
|
-
|
|
107
|
+
// A message is actionable if it's pending, or if it's been approved.
|
|
108
|
+
if (msg.status === "PENDING" || msg.status === "APPROVED") {
|
|
109
|
+
pendingMessages.push(msg);
|
|
110
|
+
}
|
|
111
|
+
allMsgs.push(msg);
|
|
112
|
+
} catch (e) {
|
|
113
|
+
UI.error(`Skipping invalid Hermes message format: ${(e as Error).message}`);
|
|
108
114
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
} catch (err) {
|
|
116
|
-
UI.error(`Error occurred while reading ${file}.`);
|
|
117
|
-
logger.debug(`Failed to read message file ${file}`, err);
|
|
115
|
+
});
|
|
116
|
+
fileMessagesMap[file] = allMsgs;
|
|
117
|
+
} catch (err) {
|
|
118
|
+
UI.error(`Error occurred while reading ${file}.`);
|
|
119
|
+
logger.debug(`Failed to read message file ${file}`, err);
|
|
120
|
+
}
|
|
118
121
|
}
|
|
119
|
-
}
|
|
120
122
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
123
|
+
if (pendingMessages.length > 0) {
|
|
124
|
+
// Sort by priority: HIGH -> NORMAL -> LOW
|
|
125
|
+
const priorityOrder = { HIGH: 1, NORMAL: 2, LOW: 3 };
|
|
126
|
+
pendingMessages.sort((a, b) => {
|
|
127
|
+
const pA = priorityOrder[a.priority || "NORMAL"] || 2;
|
|
128
|
+
const pB = priorityOrder[b.priority || "NORMAL"] || 2;
|
|
129
|
+
if (pA !== pB) return pA - pB;
|
|
130
|
+
return Date.parse(a.timestamp) - Date.parse(b.timestamp);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
UI.intent("Multi-Agent Orchestration", `${pendingMessages.length} pending tasks and collaboration messages found.`);
|
|
130
134
|
|
|
131
|
-
|
|
135
|
+
const statusChanges: Record<string, { state: string; task: string }> = {};
|
|
132
136
|
|
|
133
|
-
|
|
137
|
+
for (const msg of pendingMessages) {
|
|
138
|
+
const { from, to, content, traceId, category, status, requiresApproval } = msg;
|
|
134
139
|
|
|
135
|
-
|
|
136
|
-
|
|
140
|
+
// Approval Gate for high-risk actions.
|
|
141
|
+
// If it requires approval but isn't approved yet, skip it for now.
|
|
142
|
+
if ((category === "ACTION" || category === "ALERT") && requiresApproval && status !== "APPROVED") {
|
|
143
|
+
logger.debug(`Action for @${to} (Trace: ${traceId}) is pending manager approval.`);
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Gate for regular messages.
|
|
148
|
+
// If it's a non-approval-required message, it should only be processed when PENDING.
|
|
149
|
+
// This prevents re-processing of SUBTASK/REPLY messages that might get set to APPROVED.
|
|
150
|
+
if (!(category === "ACTION" || category === "ALERT") && status !== "PENDING") {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
137
153
|
|
|
138
|
-
const isSubtask = category === "SUBTASK" || !!parentId;
|
|
139
|
-
const agentLabel = isSubtask ? `${to} (Sub-Agent)` : to;
|
|
140
154
|
|
|
141
|
-
|
|
155
|
+
const isSubtask = category === "SUBTASK" || !!msg.parentId;
|
|
156
|
+
const agentLabel = isSubtask ? `${to} (Sub-Agent)` : to;
|
|
142
157
|
|
|
143
|
-
|
|
144
|
-
if (category === "DELEGATION" || category === "SUBTASK") targetState = "BRIEFED";
|
|
158
|
+
UI.agentBox(agentLabel, content, `Trace: ${traceId} | From: ${from} | Category: ${category}`);
|
|
145
159
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
160
|
+
let targetState = "EXECUTING";
|
|
161
|
+
if (category === "DELEGATION" || category === "SUBTASK") targetState = "BRIEFED";
|
|
162
|
+
|
|
163
|
+
let taskDescription = content;
|
|
164
|
+
if (category === "DELEGATION" || category === "ACTION") {
|
|
165
|
+
try {
|
|
166
|
+
const payload = JSON.parse(content);
|
|
167
|
+
taskDescription = payload.task || content;
|
|
168
|
+
} catch {
|
|
169
|
+
// Ignore
|
|
170
|
+
}
|
|
153
171
|
}
|
|
154
|
-
}
|
|
155
172
|
|
|
156
|
-
|
|
173
|
+
statusChanges[to] = { state: targetState, task: taskDescription };
|
|
157
174
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
175
|
+
if (targetState === "BRIEFED") {
|
|
176
|
+
UI.success(`${to} informed and took over the task.`);
|
|
177
|
+
statusChanges[to] = { state: "EXECUTING", task: taskDescription };
|
|
178
|
+
}
|
|
162
179
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
180
|
+
if (isSubtask) {
|
|
181
|
+
UI.success(`Sub-task connection established (Parent: ${msg.parentId || "Unknown"}).`);
|
|
182
|
+
}
|
|
166
183
|
|
|
167
|
-
|
|
168
|
-
console.warn(chalk.gray(` 👉 Instructions: ${frameworkDir}/agents/${to.replace("@", "")}.md`));
|
|
184
|
+
UI.success(`Collaboration initiated: ${from} -> ${to}`);
|
|
169
185
|
|
|
170
|
-
|
|
171
|
-
|
|
186
|
+
msg.status = "PROCESSED";
|
|
187
|
+
}
|
|
172
188
|
|
|
173
|
-
|
|
189
|
+
applyBatchStatusUpdates(statusChanges);
|
|
174
190
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
for (const file of Object.keys(fileMessagesMap)) {
|
|
178
|
-
const filePath = path.join(messagesDir, file);
|
|
179
|
-
const msgs = fileMessagesMap[file];
|
|
180
|
-
|
|
181
|
-
const activeMsgs = msgs.filter(m => m.status !== "PROCESSED");
|
|
182
|
-
const processedMsgs = msgs.filter(m => m.status === "PROCESSED");
|
|
191
|
+
const archiveDir = path.join(messagesDir, "archive");
|
|
183
192
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
193
|
+
for (const file of Object.keys(fileMessagesMap)) {
|
|
194
|
+
const filePath = path.join(messagesDir, file);
|
|
195
|
+
const msgs = fileMessagesMap[file];
|
|
196
|
+
|
|
197
|
+
const activeMsgs = msgs.filter(m => m.status !== "PROCESSED");
|
|
198
|
+
const processedMsgs = msgs.filter(m => m.status === "PROCESSED");
|
|
199
|
+
|
|
200
|
+
try {
|
|
201
|
+
if (activeMsgs.length > 0) {
|
|
202
|
+
const updatedContent = activeMsgs.map(m => JSON.stringify(m)).join("\n") + "\n";
|
|
203
|
+
writeTextFile(filePath, updatedContent);
|
|
204
|
+
} else if (fs.existsSync(filePath)) {
|
|
205
|
+
writeTextFile(filePath, "");
|
|
206
|
+
}
|
|
191
207
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
208
|
+
if (processedMsgs.length > 0) {
|
|
209
|
+
if (!fs.existsSync(archiveDir)) {
|
|
210
|
+
fs.mkdirSync(archiveDir, { recursive: true });
|
|
211
|
+
}
|
|
212
|
+
const agentName = file.replace(".json", "");
|
|
213
|
+
const archivePath = path.join(archiveDir, `${agentName}_archive.json`);
|
|
214
|
+
const archiveContent = processedMsgs.map(m => JSON.stringify(m)).join("\n") + "\n";
|
|
215
|
+
appendFile(archivePath, archiveContent);
|
|
216
|
+
UI.success(`Archived ${processedMsgs.length} messages for @${agentName}`);
|
|
195
217
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
appendFile(archivePath, archiveContent);
|
|
200
|
-
UI.success(`Archived ${processedMsgs.length} messages for @${agentName}`);
|
|
218
|
+
} catch (err) {
|
|
219
|
+
UI.error(`Error occurred while updating and archiving the message file ${file}.`);
|
|
220
|
+
logger.debug(`Failed to update and archive message file ${file}`, err);
|
|
201
221
|
}
|
|
202
|
-
} catch (err) {
|
|
203
|
-
UI.error(`Error occurred while updating and archiving the message file ${file}.`);
|
|
204
|
-
logger.debug(`Failed to update and archive message file ${file}`, err);
|
|
205
222
|
}
|
|
206
223
|
}
|
|
207
224
|
}
|
|
225
|
+
} catch (globalLoopErr) {
|
|
226
|
+
UI.error(`⚠️ Critical error in Hermes orchestration loop: ${(globalLoopErr as Error).message}`);
|
|
227
|
+
logger.debug("Hermes global loop failure", globalLoopErr);
|
|
208
228
|
}
|
|
209
229
|
|
|
210
230
|
// Prevent 100% CPU and provide breathing room for I/O
|
|
@@ -223,6 +243,7 @@ export async function sendMessage(args: {
|
|
|
223
243
|
traceId: string;
|
|
224
244
|
parentId?: string;
|
|
225
245
|
priority?: "HIGH" | "NORMAL" | "LOW";
|
|
246
|
+
requiresApproval?: boolean;
|
|
226
247
|
}) {
|
|
227
248
|
const frameworkDir = getFrameworkDir();
|
|
228
249
|
const messagesDir = path.join(frameworkDir, "messages");
|
|
@@ -274,11 +295,14 @@ export async function sendMessage(args: {
|
|
|
274
295
|
|
|
275
296
|
try {
|
|
276
297
|
const defaultPriority = (args.category === "ALERT" || args.category === "ACTION") ? "HIGH" : "NORMAL";
|
|
298
|
+
const requiresApproval = args.requiresApproval !== undefined ? args.requiresApproval : (args.category === "ALERT" || args.category === "ACTION");
|
|
299
|
+
|
|
277
300
|
const message: HermesMessage = {
|
|
278
301
|
timestamp: new Date().toISOString(),
|
|
279
302
|
priority: args.priority || defaultPriority,
|
|
280
303
|
...args,
|
|
281
|
-
status: "PENDING"
|
|
304
|
+
status: "PENDING",
|
|
305
|
+
requiresApproval: requiresApproval,
|
|
282
306
|
};
|
|
283
307
|
|
|
284
308
|
appendFile(messagePath, JSON.stringify(message) + "\n");
|
package/src/cli/utils/fs.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { ensureDir, writeTextFile, writeJsonFile, appendFile } from "../../share
|
|
|
8
8
|
|
|
9
9
|
export { ensureDir, writeTextFile, writeJsonFile, appendFile };
|
|
10
10
|
|
|
11
|
-
export function updateGitIgnore(targetPath: string, frameworkDir = ".
|
|
11
|
+
export function updateGitIgnore(targetPath: string, frameworkDir = ".enderun", dryRun = false): void {
|
|
12
12
|
const IGNORE_LINES = [
|
|
13
13
|
"# Agent Enderun",
|
|
14
14
|
`${frameworkDir}/logs/*.json`,
|
package/src/cli/utils/memory.ts
CHANGED
|
@@ -5,9 +5,13 @@ import { logger } from "../../shared/logger.js";
|
|
|
5
5
|
import { ensureDir, writeTextFile, writeJsonFile } from "../../shared/fs.js";
|
|
6
6
|
import { StateSchema, AgentStatusSchema, TaskSchema } from "./schemas.js";
|
|
7
7
|
import type { TraceID } from "../../shared/types.js";
|
|
8
|
+
import {
|
|
9
|
+
FRAMEWORK,
|
|
10
|
+
FRAMEWORK_DIR_CANDIDATES,
|
|
11
|
+
MCP,
|
|
12
|
+
} from "../../shared/constants.js";
|
|
8
13
|
|
|
9
14
|
export { generateULID } from "./time.js";
|
|
10
|
-
export { FRAMEWORK_DIR_CANDIDATES } from "../adapters/index.js";
|
|
11
15
|
|
|
12
16
|
const CWD = process.cwd();
|
|
13
17
|
const HOME = os.homedir();
|
|
@@ -28,9 +32,24 @@ function findFrameworkDir(basePath: string): string | null {
|
|
|
28
32
|
return null;
|
|
29
33
|
}
|
|
30
34
|
|
|
35
|
+
export function isFrameworkDevelopmentRepo(): boolean {
|
|
36
|
+
try {
|
|
37
|
+
const pkgPath = path.join(CWD, "package.json");
|
|
38
|
+
if (fs.existsSync(pkgPath)) {
|
|
39
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
40
|
+
if (pkg.name === "agent-enderun") {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
} catch (err) {
|
|
45
|
+
logger.debug("Failed to read package.json in isFrameworkDevelopmentRepo", err);
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
31
50
|
export function getLocalFrameworkDir(): string {
|
|
32
51
|
const localDir = findFrameworkDir(CWD);
|
|
33
|
-
return localDir || path.join(CWD,
|
|
52
|
+
return localDir || path.join(CWD, FRAMEWORK.CORE_DIR);
|
|
34
53
|
}
|
|
35
54
|
|
|
36
55
|
export function getConfigDir(): string {
|
|
@@ -38,17 +57,23 @@ export function getConfigDir(): string {
|
|
|
38
57
|
if (localDir) return localDir;
|
|
39
58
|
|
|
40
59
|
// Check for standard local directories if package.json doesn't specify
|
|
41
|
-
const localCandidates = [
|
|
60
|
+
const localCandidates = [...FRAMEWORK_DIR_CANDIDATES, ".agent"] as string[];
|
|
42
61
|
for (const cand of localCandidates) {
|
|
43
62
|
const p = path.join(CWD, cand);
|
|
44
63
|
if (fs.existsSync(p)) return p;
|
|
45
64
|
}
|
|
46
65
|
|
|
47
|
-
|
|
66
|
+
// In dev repo, don't fall back to global dir. Point to local default.
|
|
67
|
+
if (isFrameworkDevelopmentRepo()) {
|
|
68
|
+
return path.join(CWD, FRAMEWORK.CORE_DIR);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return path.join(HOME, FRAMEWORK.CORE_DIR);
|
|
48
72
|
}
|
|
49
73
|
|
|
50
74
|
export function getFrameworkDir(): string {
|
|
51
|
-
|
|
75
|
+
const testDir = process.env[MCP.TEST_DIR_ENV];
|
|
76
|
+
if (testDir) return testDir;
|
|
52
77
|
return getConfigDir();
|
|
53
78
|
}
|
|
54
79
|
|
|
@@ -105,7 +130,7 @@ export function readActiveTraceId(memoryContent: string): string | null {
|
|
|
105
130
|
try {
|
|
106
131
|
const state = JSON.parse(memoryContent);
|
|
107
132
|
return state.traceId || null;
|
|
108
|
-
} catch {
|
|
133
|
+
} catch (_e) { /* ignore */
|
|
109
134
|
return null;
|
|
110
135
|
}
|
|
111
136
|
}
|
|
@@ -254,7 +279,7 @@ export function acquireMemoryLock(lockPath: string): boolean {
|
|
|
254
279
|
fs.writeFileSync(lockPath, String(Date.now()), { flag: "wx" });
|
|
255
280
|
return true;
|
|
256
281
|
}
|
|
257
|
-
} catch {
|
|
282
|
+
} catch (_e) { /* ignore */
|
|
258
283
|
// Ignore
|
|
259
284
|
}
|
|
260
285
|
}
|
|
@@ -3,6 +3,7 @@ import type { AdapterConfig, AdapterId } from "./types.js";
|
|
|
3
3
|
import { addMcpServerToClaude, findClaudeConfigPath } from "../../cli/utils/claude.js";
|
|
4
4
|
import { writeJsonFile } from "../../shared/fs.js";
|
|
5
5
|
import { registerGlobalAntigravityPlugins } from "./shared.js";
|
|
6
|
+
import { unifiedAdapterPath, UNIFIED_ADAPTER_SLUG } from "../../shared/constants.js";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Mapped Adapter Configurations
|
|
@@ -16,7 +17,7 @@ export const ADAPTER_CONFIGS: Record<AdapterId, AdapterConfig> = {
|
|
|
16
17
|
role: "commander",
|
|
17
18
|
templateDir: ".enderun",
|
|
18
19
|
nestedDirs: ["agents", "rules"],
|
|
19
|
-
agentsDir: ".gemini/agents",
|
|
20
|
+
agentsDir: ".gemini/agents", // Use unified path
|
|
20
21
|
agentsExt: ".md"
|
|
21
22
|
},
|
|
22
23
|
claude: {
|
|
@@ -38,7 +39,7 @@ export const ADAPTER_CONFIGS: Record<AdapterId, AdapterConfig> = {
|
|
|
38
39
|
role: "researcher",
|
|
39
40
|
templateDir: ".enderun",
|
|
40
41
|
nestedDirs: ["rules"],
|
|
41
|
-
agentsDir: ".grok",
|
|
42
|
+
agentsDir: ".grok/agents",
|
|
42
43
|
agentsExt: ".md"
|
|
43
44
|
},
|
|
44
45
|
cursor: {
|
|
@@ -60,7 +61,7 @@ export const ADAPTER_CONFIGS: Record<AdapterId, AdapterConfig> = {
|
|
|
60
61
|
role: "implementer",
|
|
61
62
|
templateDir: ".enderun",
|
|
62
63
|
nestedDirs: ["skills", "rules", "instructions"],
|
|
63
|
-
agentsDir: ".agents/
|
|
64
|
+
agentsDir: ".agents/instructions",
|
|
64
65
|
agentsExt: ".md"
|
|
65
66
|
},
|
|
66
67
|
"antigravity-cli": {
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import fs from "fs";
|
|
7
7
|
import path from "path";
|
|
8
8
|
import { AgentDefinition } from "./types.js";
|
|
9
|
+
import { getPackageRoot } from "../../cli/utils/pkg.js";
|
|
9
10
|
|
|
10
11
|
// Import individual agent definitions
|
|
11
12
|
import { manager } from "./registry/manager.js";
|
|
@@ -124,7 +125,7 @@ function resolveModel(
|
|
|
124
125
|
}
|
|
125
126
|
|
|
126
127
|
/** Build a flat system prompt string from structured instructions */
|
|
127
|
-
function buildSystemPrompt(ag: AgentDefinition, baseKnowledgeDir: string = path.join(
|
|
128
|
+
function buildSystemPrompt(ag: AgentDefinition, baseKnowledgeDir: string = path.join(getPackageRoot(), "templates/standards")): string {
|
|
128
129
|
const lines: string[] = [
|
|
129
130
|
"# Identity",
|
|
130
131
|
ag.instructions.identity,
|
|
@@ -42,5 +42,6 @@ export const architect: AgentDefinition = {
|
|
|
42
42
|
"CONTRACT STABILITY: Validate 'contract.version.json' consistency before and after every schema change.",
|
|
43
43
|
"GOVERNANCE READ: Always read architecture governance docs before making design decisions.",
|
|
44
44
|
],
|
|
45
|
+
knowledgeFiles: ["architecture-standards.md"],
|
|
45
46
|
},
|
|
46
47
|
};
|
|
@@ -7,8 +7,8 @@ export const backend: AgentDefinition = {
|
|
|
7
7
|
displayName: "Backend Specialist",
|
|
8
8
|
role: "Backend Development",
|
|
9
9
|
description:
|
|
10
|
-
"Server logic
|
|
11
|
-
"Owns the
|
|
10
|
+
"Server logic and API implementation specialist. " +
|
|
11
|
+
"Owns the API contracts and business logic implementation.",
|
|
12
12
|
capability: 9,
|
|
13
13
|
tier: "core",
|
|
14
14
|
tags: ["core", "logic"],
|
|
@@ -42,6 +42,6 @@ export const backend: AgentDefinition = {
|
|
|
42
42
|
"HIGH-RISK OPS: Refuse User/Role management, bulk deletes, schema alterations, and billing changes autonomously. " +
|
|
43
43
|
"Return a standard refusal, send a managerApproval request to @manager, and shift to WAITING status.",
|
|
44
44
|
],
|
|
45
|
-
knowledgeFiles: ["
|
|
45
|
+
knowledgeFiles: ["crud-governance.md"],
|
|
46
46
|
},
|
|
47
47
|
};
|
|
@@ -7,8 +7,8 @@ export const database: AgentDefinition = {
|
|
|
7
7
|
displayName: "Database Specialist",
|
|
8
8
|
role: "Data Management",
|
|
9
9
|
description:
|
|
10
|
-
"SQL Schema design and
|
|
11
|
-
"
|
|
10
|
+
"SQL Schema design, migration, and query optimization specialist. " +
|
|
11
|
+
"Owns the database schema, migrations, and data integrity.",
|
|
12
12
|
capability: 9,
|
|
13
13
|
tier: "core",
|
|
14
14
|
tags: ["core", "data"],
|
|
@@ -37,6 +37,6 @@ export const database: AgentDefinition = {
|
|
|
37
37
|
"DETERMINISTIC MIGRATIONS: Every migration must be reversible and produce identical results across environments.",
|
|
38
38
|
"PERFORMANCE FIRST: Design indexes proactively — never retroactively after a performance incident.",
|
|
39
39
|
],
|
|
40
|
-
knowledgeFiles: ["
|
|
40
|
+
knowledgeFiles: ["performance-standards.md", "quality-standards.md"],
|
|
41
41
|
},
|
|
42
42
|
};
|
|
@@ -37,6 +37,6 @@ export const devops: AgentDefinition = {
|
|
|
37
37
|
"ENVIRONMENT ISOLATION: All variables managed via '.env' — hardcoded secrets trigger immediate escalation.",
|
|
38
38
|
"NO UNTRACKED DEPLOYMENTS: Every deployment must be declared, versioned, and traceable.",
|
|
39
39
|
],
|
|
40
|
-
knowledgeFiles: ["
|
|
40
|
+
knowledgeFiles: ["deployment-standards.md"],
|
|
41
41
|
},
|
|
42
42
|
};
|