agent-enderun 1.11.3 → 1.11.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 +5 -5
- package/bin/validate-agent-army.js +0 -1
- package/dist/framework-mcp/src/index.js +11 -1
- package/dist/framework-mcp/src/index.js.map +1 -1
- package/dist/framework-mcp/src/tools/definitions.js +0 -10
- package/dist/framework-mcp/src/tools/definitions.js.map +1 -1
- package/dist/framework-mcp/src/tools/index.js +0 -2
- package/dist/framework-mcp/src/tools/index.js.map +1 -1
- package/dist/framework-mcp/src/utils/compliance.d.ts +1 -1
- package/dist/framework-mcp/src/utils/compliance.js +68 -19
- package/dist/framework-mcp/src/utils/compliance.js.map +1 -1
- package/dist/src/cli/adapters/scaffold.d.ts +1 -1
- package/dist/src/cli/adapters/scaffold.js +8 -8
- package/dist/src/cli/adapters/scaffold.js.map +1 -1
- package/dist/src/cli/commands/check.js +25 -40
- package/dist/src/cli/commands/check.js.map +1 -1
- package/dist/src/cli/commands/contract.d.ts +3 -1
- package/dist/src/cli/commands/contract.js +8 -2
- package/dist/src/cli/commands/contract.js.map +1 -1
- package/dist/src/cli/commands/init/scaffold-ops.js +0 -2
- package/dist/src/cli/commands/init/scaffold-ops.js.map +1 -1
- package/dist/src/cli/commands/init.js +4 -3
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/orchestrate.js +10 -3
- package/dist/src/cli/commands/orchestrate.js.map +1 -1
- package/dist/src/cli/commands/status.js.map +1 -1
- package/dist/src/cli/index.js +14 -19
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/cli/utils/compliance.d.ts +5 -1
- package/dist/src/cli/utils/compliance.js +90 -42
- package/dist/src/cli/utils/compliance.js.map +1 -1
- package/dist/src/cli/utils/ui.js +11 -11
- package/dist/src/cli/utils/ui.js.map +1 -1
- package/dist/src/modules/adapters/definitions.js +114 -113
- package/dist/src/modules/adapters/definitions.js.map +1 -1
- package/dist/src/modules/adapters/registry.d.ts +12 -0
- package/dist/src/modules/adapters/registry.js +19 -0
- package/dist/src/modules/adapters/registry.js.map +1 -0
- package/dist/src/modules/adapters/shared.js +5 -4
- package/dist/src/modules/adapters/shared.js.map +1 -1
- package/dist/src/modules/agents/definitions.d.ts +6 -6
- package/dist/src/modules/agents/definitions.js +35 -18
- package/dist/src/modules/agents/definitions.js.map +1 -1
- package/dist/src/modules/agents/registry/analyst.js +1 -1
- package/dist/src/modules/agents/registry/analyst.js.map +1 -1
- package/dist/src/modules/agents/registry/architect.js +1 -1
- package/dist/src/modules/agents/registry/architect.js.map +1 -1
- package/dist/src/modules/agents/registry/backend.js +1 -1
- package/dist/src/modules/agents/registry/backend.js.map +1 -1
- package/dist/src/modules/agents/registry/database.js +1 -1
- 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/explorer.js +1 -1
- package/dist/src/modules/agents/registry/explorer.js.map +1 -1
- package/dist/src/modules/agents/registry/frontend.js +1 -1
- package/dist/src/modules/agents/registry/frontend.js.map +1 -1
- package/dist/src/modules/agents/registry/git.js +1 -1
- package/dist/src/modules/agents/registry/git.js.map +1 -1
- package/dist/src/modules/agents/registry/manager.js +1 -2
- package/dist/src/modules/agents/registry/manager.js.map +1 -1
- package/dist/src/modules/agents/registry/mobile.js +1 -1
- package/dist/src/modules/agents/registry/mobile.js.map +1 -1
- package/dist/src/modules/agents/registry/quality.js +1 -1
- package/dist/src/modules/agents/registry/quality.js.map +1 -1
- package/dist/src/modules/agents/registry/security.js +1 -1
- package/dist/src/modules/agents/registry/security.js.map +1 -1
- package/dist/src/shared/fs.js +4 -3
- package/dist/src/shared/fs.js.map +1 -1
- package/dist/tests/agents-definitions.test.js +2 -1
- package/dist/tests/agents-definitions.test.js.map +1 -1
- package/dist/tests/integration/hermes_locking.test.d.ts +1 -0
- package/dist/tests/integration/hermes_locking.test.js +62 -0
- package/dist/tests/integration/hermes_locking.test.js.map +1 -0
- package/dist/tests/orchestrate.test.js +9 -6
- package/dist/tests/orchestrate.test.js.map +1 -1
- package/framework-mcp/dist/index.js +11 -1
- package/framework-mcp/dist/tools/definitions.js +0 -10
- package/framework-mcp/dist/tools/index.js +0 -2
- package/framework-mcp/dist/utils/compliance.js +68 -19
- package/framework-mcp/node_modules/.package-lock.json +1179 -0
- package/framework-mcp/package-lock.json +1191 -0
- package/framework-mcp/package.json +2 -2
- package/framework-mcp/src/index.ts +13 -1
- package/framework-mcp/src/tools/definitions.ts +0 -10
- package/framework-mcp/src/tools/index.ts +0 -2
- package/framework-mcp/src/utils/compliance.ts +82 -24
- package/package.json +3 -4
- package/src/cli/adapters/scaffold.ts +9 -8
- package/src/cli/commands/check.ts +26 -48
- package/src/cli/commands/contract.ts +5 -2
- package/src/cli/commands/init/scaffold-ops.ts +0 -3
- package/src/cli/commands/init.ts +5 -3
- package/src/cli/commands/orchestrate.ts +12 -3
- package/src/cli/commands/status.ts +3 -2
- package/src/cli/index.ts +14 -20
- package/src/cli/utils/compliance.ts +101 -47
- package/src/cli/utils/ui.ts +11 -11
- package/src/modules/adapters/definitions.ts +82 -57
- package/src/modules/adapters/registry.ts +27 -0
- package/src/modules/adapters/shared.ts +5 -4
- package/src/modules/agents/definitions.ts +35 -17
- package/src/modules/agents/registry/analyst.ts +1 -1
- package/src/modules/agents/registry/architect.ts +1 -1
- package/src/modules/agents/registry/backend.ts +1 -1
- package/src/modules/agents/registry/database.ts +1 -1
- package/src/modules/agents/registry/devops.ts +1 -1
- package/src/modules/agents/registry/explorer.ts +1 -1
- package/src/modules/agents/registry/frontend.ts +1 -1
- package/src/modules/agents/registry/git.ts +1 -1
- package/src/modules/agents/registry/manager.ts +1 -2
- package/src/modules/agents/registry/mobile.ts +1 -1
- package/src/modules/agents/registry/quality.ts +1 -1
- package/src/modules/agents/registry/security.ts +1 -1
- package/src/shared/fs.ts +4 -3
- package/templates/standards/frontend-standards.md +7 -2
- package/templates/standards/governance-standards.md +27 -1
- package/templates/standards/quality-standards.md +2 -1
- package/bin/enderun-dashboard.js +0 -25
- package/framework-mcp/src/tools/dashboard/start_dashboard.ts +0 -33
- package/src/cli/commands/dashboard/data-service.ts +0 -167
- package/src/cli/commands/dashboard/html-template.ts +0 -696
- package/src/cli/commands/dashboard/server.ts +0 -43
- package/src/cli/commands/dashboard.ts +0 -11
|
@@ -82,7 +82,6 @@ const CLAUDE_TOOL_MAP: Record<string, string> = {
|
|
|
82
82
|
get_framework_status: "Bash",
|
|
83
83
|
get_system_health: "Bash",
|
|
84
84
|
check_active_ports: "Bash",
|
|
85
|
-
start_dashboard: "Bash",
|
|
86
85
|
update_contract_hash: "Write",
|
|
87
86
|
acquire_lock: "Write",
|
|
88
87
|
release_lock: "Write",
|
|
@@ -121,7 +120,6 @@ const GEMINI_TOOL_MAP: Record<string, string> = {
|
|
|
121
120
|
get_framework_status: "run_shell_command",
|
|
122
121
|
get_system_health: "run_shell_command",
|
|
123
122
|
check_active_ports: "run_shell_command",
|
|
124
|
-
start_dashboard: "run_shell_command",
|
|
125
123
|
update_contract_hash: "write_file",
|
|
126
124
|
acquire_lock: "write_file",
|
|
127
125
|
release_lock: "write_file",
|
|
@@ -174,6 +172,7 @@ function buildSystemPrompt(
|
|
|
174
172
|
ag: AgentDefinition,
|
|
175
173
|
baseKnowledgeDir: string = path.join(getPackageRoot(), "templates/standards"),
|
|
176
174
|
stripMetaComments = false,
|
|
175
|
+
paths: Record<string, string> = { backend: "apps/backend", frontend: "apps/web", mobile: "apps/mobile", docs: "docs" }
|
|
177
176
|
): string {
|
|
178
177
|
const metaHeader = stripMetaComments ? [] : [
|
|
179
178
|
`<!-- name: ${ag.name} -->`,
|
|
@@ -195,6 +194,13 @@ function buildSystemPrompt(
|
|
|
195
194
|
`**Primary Role:** ${ag.role}`,
|
|
196
195
|
`**Authority Tier:** ${ag.tier} (Capability: ${ag.capability}/10)`,
|
|
197
196
|
"",
|
|
197
|
+
"## Project Structure",
|
|
198
|
+
`This project uses the following directory structure:`,
|
|
199
|
+
`- **Backend:** \`${paths.backend}\``,
|
|
200
|
+
`- **Frontend:** \`${paths.frontend}\``,
|
|
201
|
+
`- **Mobile:** \`${paths.mobile}\``,
|
|
202
|
+
`- **Documentation:** \`${paths.docs}\``,
|
|
203
|
+
"",
|
|
198
204
|
"## Chain of Thought Protocol",
|
|
199
205
|
"> Follow these steps in strict order for every task:",
|
|
200
206
|
"",
|
|
@@ -213,6 +219,7 @@ function buildSystemPrompt(
|
|
|
213
219
|
"- Never perform irreversible operations (schema drops, bulk deletes) without @manager approval.",
|
|
214
220
|
"- Prefer surgical edits (`replace_text`, `patch_file`) over full file rewrites.",
|
|
215
221
|
"- Escalate ambiguity to @manager instead of guessing.",
|
|
222
|
+
`- Ensure all development happens exclusively inside \`${paths.backend}\`, \`${paths.frontend}\`, or \`${paths.mobile}\`.`,
|
|
216
223
|
];
|
|
217
224
|
|
|
218
225
|
if (ag.instructions.knowledgeFiles?.length) {
|
|
@@ -237,7 +244,7 @@ function buildSystemPrompt(
|
|
|
237
244
|
// Ref: https://docs.anthropic.com/en/docs/claude-code/sub-agents
|
|
238
245
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
239
246
|
|
|
240
|
-
export function toClaudeCodeMd(ag: AgentDefinition, baseKnowledgeDir?: string): string {
|
|
247
|
+
export function toClaudeCodeMd(ag: AgentDefinition, baseKnowledgeDir?: string, paths?: Record<string, string>): string {
|
|
241
248
|
const tools = [...new Set(ag.tools.map((t: string) => CLAUDE_TOOL_MAP[t] ?? t))];
|
|
242
249
|
const model = resolveModel(ag.capability, "claude-code");
|
|
243
250
|
const color = ag.tier === "supreme" ? "purple"
|
|
@@ -256,7 +263,7 @@ export function toClaudeCodeMd(ag: AgentDefinition, baseKnowledgeDir?: string):
|
|
|
256
263
|
"---",
|
|
257
264
|
].join("\n");
|
|
258
265
|
|
|
259
|
-
return `${frontmatter}\n\n${buildSystemPrompt(ag, baseKnowledgeDir)}`;
|
|
266
|
+
return `${frontmatter}\n\n${buildSystemPrompt(ag, baseKnowledgeDir, false, paths)}`;
|
|
260
267
|
}
|
|
261
268
|
|
|
262
269
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -265,7 +272,7 @@ export function toClaudeCodeMd(ag: AgentDefinition, baseKnowledgeDir?: string):
|
|
|
265
272
|
// Ref: https://ai.google.dev/gemini-api/docs/agents
|
|
266
273
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
267
274
|
|
|
268
|
-
export function toGeminiCliMd(ag: AgentDefinition, baseKnowledgeDir?: string): string {
|
|
275
|
+
export function toGeminiCliMd(ag: AgentDefinition, baseKnowledgeDir?: string, paths?: Record<string, string>): string {
|
|
269
276
|
const tools = [...new Set(ag.tools.map((t: string) => GEMINI_TOOL_MAP[t] ?? t))];
|
|
270
277
|
const model = resolveModel(ag.capability, "gemini-cli");
|
|
271
278
|
|
|
@@ -280,7 +287,7 @@ export function toGeminiCliMd(ag: AgentDefinition, baseKnowledgeDir?: string): s
|
|
|
280
287
|
"---",
|
|
281
288
|
].join("\n");
|
|
282
289
|
|
|
283
|
-
const body = buildSystemPrompt(ag, baseKnowledgeDir, true);
|
|
290
|
+
const body = buildSystemPrompt(ag, baseKnowledgeDir, true, paths);
|
|
284
291
|
|
|
285
292
|
const metaFooter = [
|
|
286
293
|
"",
|
|
@@ -297,7 +304,7 @@ export function toGeminiCliMd(ag: AgentDefinition, baseKnowledgeDir?: string): s
|
|
|
297
304
|
// Spec: Antigravity customAgentSpec JSON schema
|
|
298
305
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
299
306
|
|
|
300
|
-
export function toAntigravityJson(ag: AgentDefinition, baseKnowledgeDir?: string): string {
|
|
307
|
+
export function toAntigravityJson(ag: AgentDefinition, baseKnowledgeDir?: string, paths?: Record<string, string>): string {
|
|
301
308
|
const knowledgeBase = baseKnowledgeDir ?? path.join(getPackageRoot(), "templates/standards");
|
|
302
309
|
|
|
303
310
|
// Embed actual file contents so the agent can read governance docs
|
|
@@ -321,6 +328,16 @@ export function toAntigravityJson(ag: AgentDefinition, baseKnowledgeDir?: string
|
|
|
321
328
|
title: "Identity & Mission",
|
|
322
329
|
content: `${ag.instructions.identity}\n\n**Mission:** ${ag.instructions.mission}`,
|
|
323
330
|
},
|
|
331
|
+
{
|
|
332
|
+
title: "Project Structure",
|
|
333
|
+
content: [
|
|
334
|
+
"This project uses the following directory structure:",
|
|
335
|
+
`- Backend: ${paths?.backend || "apps/backend"}`,
|
|
336
|
+
`- Frontend: ${paths?.frontend || "apps/web"}`,
|
|
337
|
+
`- Mobile: ${paths?.mobile || "apps/mobile"}`,
|
|
338
|
+
`- Documentation: ${paths?.docs || "docs"}`,
|
|
339
|
+
].join("\n"),
|
|
340
|
+
},
|
|
324
341
|
{
|
|
325
342
|
title: "Chain of Thought Protocol",
|
|
326
343
|
content: ag.instructions.chainOfThought,
|
|
@@ -337,6 +354,7 @@ export function toAntigravityJson(ag: AgentDefinition, baseKnowledgeDir?: string
|
|
|
337
354
|
"- Read PROJECT_MEMORY.md at session start.",
|
|
338
355
|
"- Prefer surgical edits over full file rewrites.",
|
|
339
356
|
"- Escalate high-risk operations to @manager.",
|
|
357
|
+
`- Ensure development happens inside ${paths?.backend || "apps/backend"}, ${paths?.frontend || "apps/web"}, or ${paths?.mobile || "apps/mobile"}.`,
|
|
340
358
|
].join("\n"),
|
|
341
359
|
},
|
|
342
360
|
...knowledgeSections,
|
|
@@ -356,7 +374,7 @@ export const buildAgentJson = toAntigravityJson;
|
|
|
356
374
|
// Valid fields: agent-type, display-name, when-to-use, model, allowed-tools
|
|
357
375
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
358
376
|
|
|
359
|
-
export function toCodexMd(ag: AgentDefinition, baseKnowledgeDir?: string): string {
|
|
377
|
+
export function toCodexMd(ag: AgentDefinition, baseKnowledgeDir?: string, paths?: Record<string, string>): string {
|
|
360
378
|
const model = resolveModel(ag.capability, "codex-cli");
|
|
361
379
|
const tools = [...new Set(ag.tools.map((t: string) => {
|
|
362
380
|
if (["read_file","view_file","list_dir","grep_search","get_memory_insights","read_project_memory","get_project_map","get_project_gaps","get_framework_status"].includes(t)) return "read";
|
|
@@ -375,7 +393,7 @@ export function toCodexMd(ag: AgentDefinition, baseKnowledgeDir?: string): strin
|
|
|
375
393
|
"---",
|
|
376
394
|
].join("\n");
|
|
377
395
|
|
|
378
|
-
const body = buildSystemPrompt(ag, baseKnowledgeDir, true);
|
|
396
|
+
const body = buildSystemPrompt(ag, baseKnowledgeDir, true, paths);
|
|
379
397
|
|
|
380
398
|
const metaFooter = [
|
|
381
399
|
"",
|
|
@@ -393,7 +411,7 @@ export function toCodexMd(ag: AgentDefinition, baseKnowledgeDir?: string): strin
|
|
|
393
411
|
// Ref: https://docs.cursor.com/context/rules
|
|
394
412
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
395
413
|
|
|
396
|
-
export function toCursorMdc(ag: AgentDefinition, baseKnowledgeDir?: string): string {
|
|
414
|
+
export function toCursorMdc(ag: AgentDefinition, baseKnowledgeDir?: string, paths?: Record<string, string>): string {
|
|
397
415
|
const glob = CURSOR_AGENT_GLOBS[ag.name] || "**/*";
|
|
398
416
|
// Only officially supported Cursor MDC frontmatter fields
|
|
399
417
|
const frontmatter = [
|
|
@@ -404,7 +422,7 @@ export function toCursorMdc(ag: AgentDefinition, baseKnowledgeDir?: string): str
|
|
|
404
422
|
"---",
|
|
405
423
|
].join("\n");
|
|
406
424
|
|
|
407
|
-
return `${frontmatter}\n\n${buildSystemPrompt(ag, baseKnowledgeDir)}`;
|
|
425
|
+
return `${frontmatter}\n\n${buildSystemPrompt(ag, baseKnowledgeDir, false, paths)}`;
|
|
408
426
|
}
|
|
409
427
|
|
|
410
428
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -418,19 +436,19 @@ export interface ExportedFile {
|
|
|
418
436
|
content: string;
|
|
419
437
|
}
|
|
420
438
|
|
|
421
|
-
export function exportAllAgents(target: ExportTarget): ExportedFile[] {
|
|
439
|
+
export function exportAllAgents(target: ExportTarget, paths?: Record<string, string>): ExportedFile[] {
|
|
422
440
|
return ALL_AGENTS.map(ag => {
|
|
423
441
|
switch (target) {
|
|
424
442
|
case "claude-code":
|
|
425
|
-
return { path: `.claude/agents/${ag.name}.md`, content: toClaudeCodeMd(ag) };
|
|
443
|
+
return { path: `.claude/agents/${ag.name}.md`, content: toClaudeCodeMd(ag, undefined, paths) };
|
|
426
444
|
case "gemini-cli":
|
|
427
|
-
return { path: `.gemini/agents/${ag.name}.md`, content: toGeminiCliMd(ag) };
|
|
445
|
+
return { path: `.gemini/agents/${ag.name}.md`, content: toGeminiCliMd(ag, undefined, paths) };
|
|
428
446
|
case "antigravity":
|
|
429
|
-
return { path: `.agents/${ag.name}/agent.json`, content: toAntigravityJson(ag) };
|
|
447
|
+
return { path: `.agents/${ag.name}/agent.json`, content: toAntigravityJson(ag, undefined, paths) };
|
|
430
448
|
case "codex-cli":
|
|
431
|
-
return { path: `.agents/${ag.name}.md`, content: toCodexMd(ag) };
|
|
449
|
+
return { path: `.agents/${ag.name}.md`, content: toCodexMd(ag, undefined, paths) };
|
|
432
450
|
case "cursor":
|
|
433
|
-
return { path: `.cursor/rules/${ag.name}.mdc`, content: toCursorMdc(ag) };
|
|
451
|
+
return { path: `.cursor/rules/${ag.name}.mdc`, content: toCursorMdc(ag, undefined, paths) };
|
|
434
452
|
}
|
|
435
453
|
});
|
|
436
454
|
}
|
|
@@ -39,6 +39,6 @@ export const analyst: AgentDefinition = {
|
|
|
39
39
|
"VERSIONING INTEGRITY: Validate that all API versioning changes are correctly registered in 'contract.version.json'.",
|
|
40
40
|
"LIVE AUDIT: Continuously audit business rules against the live implementation for drift.",
|
|
41
41
|
],
|
|
42
|
-
knowledgeFiles: ["architecture-standards.md", "crud-governance.md"],
|
|
42
|
+
knowledgeFiles: ["architecture-standards.md", "crud-governance.md", "governance-standards.md", "quality-standards.md"],
|
|
43
43
|
},
|
|
44
44
|
};
|
|
@@ -42,6 +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
|
+
knowledgeFiles: ["architecture-standards.md", "governance-standards.md", "performance-standards.md"],
|
|
46
46
|
},
|
|
47
47
|
};
|
|
@@ -43,6 +43,6 @@ export const backend: AgentDefinition = {
|
|
|
43
43
|
"HIGH-RISK OPS: Refuse User/Role management, bulk deletes, schema alterations, and billing changes autonomously. " +
|
|
44
44
|
"Return a standard refusal, send a managerApproval request to @manager, and shift to WAITING status.",
|
|
45
45
|
],
|
|
46
|
-
knowledgeFiles: ["crud-governance.md", "kysely-standards.md", "typeorm-standards.md"],
|
|
46
|
+
knowledgeFiles: ["crud-governance.md", "kysely-standards.md", "typeorm-standards.md", "auth-standards.md", "swagger-standards.md", "pino-standards.md"],
|
|
47
47
|
},
|
|
48
48
|
};
|
|
@@ -38,6 +38,6 @@ export const database: AgentDefinition = {
|
|
|
38
38
|
"DETERMINISTIC MIGRATIONS: Every migration must be reversible and produce identical results across environments.",
|
|
39
39
|
"PERFORMANCE FIRST: Design indexes proactively — never retroactively after a performance incident.",
|
|
40
40
|
],
|
|
41
|
-
knowledgeFiles: ["kysely-standards.md", "typeorm-standards.md", "quality-standards.md"],
|
|
41
|
+
knowledgeFiles: ["kysely-standards.md", "typeorm-standards.md", "quality-standards.md", "performance-standards.md"],
|
|
42
42
|
},
|
|
43
43
|
};
|
|
@@ -39,6 +39,6 @@ export const devops: AgentDefinition = {
|
|
|
39
39
|
"ENVIRONMENT ISOLATION: All variables managed via '.env' — hardcoded secrets trigger immediate escalation.",
|
|
40
40
|
"NO UNTRACKED DEPLOYMENTS: Every deployment must be declared, versioned, and traceable.",
|
|
41
41
|
],
|
|
42
|
-
knowledgeFiles: ["deployment-standards.md"],
|
|
42
|
+
knowledgeFiles: ["deployment-standards.md", "github-actions-standards.md", "observability-standards.md", "logging-and-secrets.md"],
|
|
43
43
|
},
|
|
44
44
|
};
|
|
@@ -36,6 +36,6 @@ export const explorer: AgentDefinition = {
|
|
|
36
36
|
"DEPENDENCY MAP: Map all file dependencies and surface them to @manager in a structured report.",
|
|
37
37
|
"RECON FIRST: No specialist should act on an unexplored codebase — flag absence of ADP as a phase blocker.",
|
|
38
38
|
],
|
|
39
|
-
knowledgeFiles: ["architecture-standards.md"],
|
|
39
|
+
knowledgeFiles: ["architecture-standards.md", "observability-standards.md"],
|
|
40
40
|
},
|
|
41
41
|
};
|
|
@@ -43,6 +43,6 @@ export const frontend: AgentDefinition = {
|
|
|
43
43
|
"OVERFLOW GUARD: Prevent horizontal scroll via proper box-sizing, max-width bounds, and container margins.",
|
|
44
44
|
"ATOMIC UI: Create shared components exclusively in 'apps/web/src/components/ui/'.",
|
|
45
45
|
],
|
|
46
|
-
knowledgeFiles: ["frontend-standards.md", "i18n-standards.md"],
|
|
46
|
+
knowledgeFiles: ["frontend-standards.md", "i18n-standards.md", "react-query-standards.md", "react-router-standards.md", "tailwind-standards.md", "performance-standards.md"],
|
|
47
47
|
},
|
|
48
48
|
};
|
|
@@ -36,6 +36,6 @@ export const git: AgentDefinition = {
|
|
|
36
36
|
"NO FORCE PUSH: Force-pushing to any shared branch is unconditionally forbidden.",
|
|
37
37
|
"GIT FLOW: Strictly follow git-flow branching conventions — feature, hotfix, release naming enforced.",
|
|
38
38
|
],
|
|
39
|
-
knowledgeFiles: ["logging-and-secrets.md"],
|
|
39
|
+
knowledgeFiles: ["logging-and-secrets.md", "governance-standards.md"],
|
|
40
40
|
},
|
|
41
41
|
};
|
|
@@ -30,7 +30,6 @@ export const manager: AgentDefinition = {
|
|
|
30
30
|
"get_framework_status",
|
|
31
31
|
"get_system_health",
|
|
32
32
|
"check_active_ports",
|
|
33
|
-
"start_dashboard",
|
|
34
33
|
],
|
|
35
34
|
instructions: {
|
|
36
35
|
identity: "AL Management Assistant and Supreme Discipline Enforcer",
|
|
@@ -54,6 +53,6 @@ export const manager: AgentDefinition = {
|
|
|
54
53
|
"MEMORY INTEGRITY: Synchronize 'PROJECT_MEMORY.md' after every single turn. Memory drift is treason.",
|
|
55
54
|
"LOCKING PROTOCOL: Always acquire a lock via 'acquire_lock' on 'memory' resource before writing to PROJECT_MEMORY.md. Release immediately after write.",
|
|
56
55
|
],
|
|
57
|
-
knowledgeFiles: ["governance-standards.md"],
|
|
56
|
+
knowledgeFiles: ["governance-standards.md", "llm-governance.md", "crud-governance.md"],
|
|
58
57
|
},
|
|
59
58
|
};
|
|
@@ -39,6 +39,6 @@ export const mobile: AgentDefinition = {
|
|
|
39
39
|
"TOUCH TARGETS: All touchable components must have a minimum interactive area of 44dp × 44dp.",
|
|
40
40
|
"OFFLINE FIRST: Implement caching via React Query and local storage for all critical data paths.",
|
|
41
41
|
],
|
|
42
|
-
knowledgeFiles: ["mobile-standards.md"],
|
|
42
|
+
knowledgeFiles: ["mobile-standards.md", "performance-standards.md", "react-query-standards.md"],
|
|
43
43
|
},
|
|
44
44
|
};
|
|
@@ -41,6 +41,6 @@ export const quality: AgentDefinition = {
|
|
|
41
41
|
"ZERO TOLERANCE: Reject any code containing lint errors, 'any' type usage, or hardcoded 'console.log'.",
|
|
42
42
|
"TEST PATTERN: Enforce Given-When-Then pattern in all test suites without exception.",
|
|
43
43
|
],
|
|
44
|
-
knowledgeFiles: ["quality-standards.md", "testing-standards.md"],
|
|
44
|
+
knowledgeFiles: ["quality-standards.md", "testing-standards.md", "vitest-standards.md", "playwright-standards.md"],
|
|
45
45
|
},
|
|
46
46
|
};
|
|
@@ -37,6 +37,6 @@ export const security: AgentDefinition = {
|
|
|
37
37
|
"RAW SQL FORBIDDEN: Reject any query that bypasses Kysely — zero exceptions.",
|
|
38
38
|
"AUDIT LOGS: Monitor and log all high-risk administrative actions via 'log_agent_action'.",
|
|
39
39
|
],
|
|
40
|
-
knowledgeFiles: ["security-standards.md"],
|
|
40
|
+
knowledgeFiles: ["security-standards.md", "security-audit-standards.md", "auth-standards.md", "logging-and-secrets.md"],
|
|
41
41
|
},
|
|
42
42
|
};
|
package/src/shared/fs.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
|
+
import { logger } from "./logger.js";
|
|
3
4
|
|
|
4
5
|
export function ensureDir(dirPath: string, dryRun = false): void {
|
|
5
6
|
if (!fs.existsSync(dirPath)) {
|
|
6
7
|
if (dryRun) {
|
|
7
|
-
|
|
8
|
+
logger.info(`[DRY RUN] Would create directory: ${dirPath}`);
|
|
8
9
|
} else {
|
|
9
10
|
fs.mkdirSync(dirPath, { recursive: true });
|
|
10
11
|
}
|
|
@@ -17,7 +18,7 @@ export function ensureDir(dirPath: string, dryRun = false): void {
|
|
|
17
18
|
*/
|
|
18
19
|
export function writeTextFile(filePath: string, content: string, dryRun = false): void {
|
|
19
20
|
if (dryRun) {
|
|
20
|
-
|
|
21
|
+
logger.info(`[DRY RUN] Would write file: ${filePath}`);
|
|
21
22
|
return;
|
|
22
23
|
}
|
|
23
24
|
const dir = path.dirname(filePath);
|
|
@@ -37,7 +38,7 @@ export function writeTextFile(filePath: string, content: string, dryRun = false)
|
|
|
37
38
|
|
|
38
39
|
export function appendFile(filePath: string, content: string, dryRun = false): void {
|
|
39
40
|
if (dryRun) {
|
|
40
|
-
|
|
41
|
+
logger.info(`[DRY RUN] Would append to file: ${filePath}`);
|
|
41
42
|
return;
|
|
42
43
|
}
|
|
43
44
|
ensureDir(path.dirname(filePath));
|
|
@@ -2,8 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
This document defines the UI/UX standards for projects managed by Agent Enderun. All interfaces must comply with "Mobile-First", "Fluid Responsive", and "Cross-Device Adaptive" principles.
|
|
4
4
|
|
|
5
|
-
## 1.
|
|
6
|
-
- **
|
|
5
|
+
## 1. Zero UI Library Policy (Supreme Mandate)
|
|
6
|
+
- **NO Third-Party UI Frameworks:** Usage of `@chakra-ui`, `mui`, `@shadcn`, `antd`, or similar pre-built component libraries is **STRICTLY FORBIDDEN**.
|
|
7
|
+
- **Atomic Manual Construction:** Every UI component (Button, Modal, Input, etc.) must be built manually from scratch using atomic CSS principles.
|
|
8
|
+
- **Styling Engine:** All styles must be written with type-safe **Panda CSS** or structured **Tailwind CSS**.
|
|
9
|
+
- **Reasoning:** Pre-built libraries introduce massive bloat, difficult-to-override styles, and dependency lock-in. Agent Enderun enforces pure, lightweight, and 100% customizable UI code.
|
|
10
|
+
|
|
11
|
+
## 2. Design System: Panda CSS & Tailwind Integration
|
|
7
12
|
- **Token Usage:** Colors, spacing, and font sizes must be managed via the `token()` function or standard CSS variables.
|
|
8
13
|
- **Responsive Syntax:** Object-based responsive syntax is mandatory:
|
|
9
14
|
```typescript
|
|
@@ -28,7 +28,33 @@ A single TODO, lint error, or unverified contract blocks the phase transition.
|
|
|
28
28
|
|
|
29
29
|
---
|
|
30
30
|
|
|
31
|
-
## 3.
|
|
31
|
+
## 3. Hermes Self-Healing Protocol
|
|
32
|
+
- If an agent remains in `EXECUTING` state for >30 minutes, the orchestrator triggers **Self-Healing**.
|
|
33
|
+
- The agent is reset to `READY`, and the task is logged for human review or retry.
|
|
34
|
+
- Blocked agents should not be left abandoned; they must be recovered to keep the loop fluid.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 4. Proportional Governance Model (Autonomy Levels)
|
|
39
|
+
Governance controls are mapped to agent autonomy to ensure safety and EU AI Act compliance.
|
|
40
|
+
|
|
41
|
+
| Level | Mode | Authority | Governance Focus |
|
|
42
|
+
|---|---|---|---|
|
|
43
|
+
| **L1** | Observe | Read-only access | Scoped data access, usage logging |
|
|
44
|
+
| **L2** | Advise | Recommendations only | Accuracy checks, bias mitigation |
|
|
45
|
+
| **L3** | Guided | Action with human "OK" | Meaningful human review (No rubber-stamping) |
|
|
46
|
+
| **L4** | Autonomous| Independent execution | **Circuit breakers**, real-time monitoring |
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 5. Circuit Breaker & Kill Switch Protocol
|
|
51
|
+
- **L4 Emergency Stop:** Every autonomous agent **must** support an immediate "Kill Switch" signal.
|
|
52
|
+
- **Recursive Failure Guard:** If an agent chain (Agent A calling Agent B) fails twice at the same node, the entire Trace ID is **Frozen** until human intervention.
|
|
53
|
+
- **Audit Traceability:** Every autonomous action must be attributable to a unique **Agent ID** and **Trace ID** in an immutable log.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 6. Trace ID Discipline
|
|
32
58
|
|
|
33
59
|
- Every task chain begins with a unique Trace ID (e.g. `TRC-042`).
|
|
34
60
|
- All agent messages, logs, and commits **must** carry the active Trace ID.
|
|
@@ -7,7 +7,8 @@ This document defines the technical discipline rules that all code produced by t
|
|
|
7
7
|
- **No Explicit Any:** The use of `any` is strictly forbidden. `unknown` should be used for uncertain types and verified with type guards.
|
|
8
8
|
- **Exhaustive Checks:** All cases must be checked (exhaustive) in `switch-case` structures, or safety must be provided with the `never` type.
|
|
9
9
|
|
|
10
|
-
## 2. ESLint and Static Analysis
|
|
10
|
+
## 2. ESLint and Static Analysis (AST Enforced)
|
|
11
|
+
- **Real-Time AST Audits:** Every file mutation by an agent is scanned via **Abstract Syntax Tree (AST)** analysis. Prohibited patterns (`any`, `console.log`) are blocked at the protocol level.
|
|
11
12
|
- **Zero Warnings:** No ESLint warnings or errors can exist in the codebase.
|
|
12
13
|
- **Naming Conventions:**
|
|
13
14
|
- Variables and functions: `camelCase`
|
package/bin/enderun-dashboard.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { spawn } from "node:child_process";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
|
-
import { dirname, join } from "node:path";
|
|
5
|
-
import fs from "node:fs";
|
|
6
|
-
|
|
7
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
-
const __dirname = dirname(__filename);
|
|
9
|
-
|
|
10
|
-
const cliPath = join(__dirname, "../dist/src/cli/index.js");
|
|
11
|
-
|
|
12
|
-
if (!fs.existsSync(cliPath)) {
|
|
13
|
-
process.stderr.write("\n❌ Error: Compiled CLI not found at 'dist/src/cli/index.js'\n");
|
|
14
|
-
process.stderr.write("💡 Solution Tip: Run 'npm run build' to compile the project first.\n\n");
|
|
15
|
-
process.exit(1);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const child = spawn("node", [cliPath, "dashboard", ...process.argv.slice(2)], {
|
|
19
|
-
stdio: "inherit",
|
|
20
|
-
shell: false
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
child.on("exit", (code) => {
|
|
24
|
-
process.exit(code ?? 0);
|
|
25
|
-
});
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import { exec } from "child_process";
|
|
4
|
-
import { StartDashboardArgs, ToolResult } from "../types.js";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Starts the Enderun Web Dashboard server.
|
|
8
|
-
*/
|
|
9
|
-
export function handleStartDashboard(projectRoot: string, args: StartDashboardArgs): ToolResult {
|
|
10
|
-
const port = args.port || 5858;
|
|
11
|
-
const dashboardScript = path.join(projectRoot, "bin/enderun-dashboard.js");
|
|
12
|
-
|
|
13
|
-
if (!fs.existsSync(dashboardScript)) {
|
|
14
|
-
throw new Error("Dashboard server script not found in bin/enderun-dashboard.js");
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
try {
|
|
18
|
-
// Start the dashboard as a background process
|
|
19
|
-
exec(`node "${dashboardScript}"`, {
|
|
20
|
-
cwd: projectRoot,
|
|
21
|
-
env: { ...process.env, PORT: String(port) }
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
return {
|
|
25
|
-
content: [{
|
|
26
|
-
type: "text",
|
|
27
|
-
text: `🖥️ **Enderun Web Dashboard started!**\n\nAccess it at: http://localhost:${port}\n\nThis interface will show real-time agent status, system health, and orchestration logs.`
|
|
28
|
-
}]
|
|
29
|
-
};
|
|
30
|
-
} catch (e) {
|
|
31
|
-
return { isError: true, content: [{ type: "text", text: `Failed to start dashboard: ${String(e)}` }] };
|
|
32
|
-
}
|
|
33
|
-
}
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import { getFrameworkDir } from "../../utils/memory.js";
|
|
4
|
-
|
|
5
|
-
export function parseProjectMemory() {
|
|
6
|
-
const frameworkDir = getFrameworkDir();
|
|
7
|
-
if (!frameworkDir) return { error: "No framework directory found. Run init." };
|
|
8
|
-
|
|
9
|
-
const memPath = path.join(frameworkDir, "memory/PROJECT_MEMORY.md");
|
|
10
|
-
if (!fs.existsSync(memPath)) return { error: "PROJECT_MEMORY.md not found" };
|
|
11
|
-
|
|
12
|
-
try {
|
|
13
|
-
const content = fs.readFileSync(memPath, "utf8");
|
|
14
|
-
|
|
15
|
-
// Parse Phase & Trace ID
|
|
16
|
-
const phaseMatch = content.match(/Phase:\s*([^\n\r]+)/i);
|
|
17
|
-
const traceMatch = content.match(/Trace ID:\s*([^\n\r]+)/i);
|
|
18
|
-
const managerMatch = content.match(/@manager state:\s*([^\n\r]+)/i);
|
|
19
|
-
|
|
20
|
-
// Parse Active Tasks Table
|
|
21
|
-
const tasks = [];
|
|
22
|
-
const lines = content.split("\n");
|
|
23
|
-
let inTaskTable = false;
|
|
24
|
-
|
|
25
|
-
for (const line of lines) {
|
|
26
|
-
if (line.includes("| Trace ID | Task |")) {
|
|
27
|
-
inTaskTable = true;
|
|
28
|
-
continue;
|
|
29
|
-
}
|
|
30
|
-
if (inTaskTable && line.trim() === "") {
|
|
31
|
-
inTaskTable = false;
|
|
32
|
-
continue;
|
|
33
|
-
}
|
|
34
|
-
if (inTaskTable && line.startsWith("|") && !line.includes(":---")) {
|
|
35
|
-
const cols = line.split("|").map(c => c.trim()).filter(Boolean);
|
|
36
|
-
if (cols.length >= 5) {
|
|
37
|
-
tasks.push({
|
|
38
|
-
traceId: cols[0],
|
|
39
|
-
task: cols[1],
|
|
40
|
-
agent: cols[2],
|
|
41
|
-
priority: cols[3],
|
|
42
|
-
status: cols[4]
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Parse History Section
|
|
49
|
-
const history = [];
|
|
50
|
-
const historyParts = content.split(/##\s+HISTORY/i);
|
|
51
|
-
if (historyParts[1]) {
|
|
52
|
-
const histLines = historyParts[1].split("\n");
|
|
53
|
-
let currentItem: { title: string, body: string[] } | null = null;
|
|
54
|
-
for (const line of histLines) {
|
|
55
|
-
if (line.startsWith("###")) {
|
|
56
|
-
if (currentItem) history.push(currentItem);
|
|
57
|
-
currentItem = { title: line.replace("###", "").trim(), body: [] };
|
|
58
|
-
} else if (currentItem && line.trim() !== "") {
|
|
59
|
-
currentItem.body.push(line.trim());
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
if (currentItem) history.push(currentItem);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return {
|
|
66
|
-
phase: phaseMatch ? phaseMatch[1].trim() : "PHASE_0",
|
|
67
|
-
traceId: traceMatch ? traceMatch[1].trim() : "N/A",
|
|
68
|
-
managerState: managerMatch ? managerMatch[1].trim() : "ACTIVE",
|
|
69
|
-
tasks,
|
|
70
|
-
history: history.slice(0, 15) // Return last 15 entries
|
|
71
|
-
};
|
|
72
|
-
} catch (e: unknown) {
|
|
73
|
-
return { error: e instanceof Error ? e.message : String(e) };
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
interface ProjectStructureEntry {
|
|
78
|
-
name: string;
|
|
79
|
-
path: string;
|
|
80
|
-
type: "directory" | "file";
|
|
81
|
-
children?: ProjectStructureEntry[];
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export function getProjectStructure(): ProjectStructureEntry[] {
|
|
85
|
-
const projectRoot = process.cwd();
|
|
86
|
-
|
|
87
|
-
function walk(dir: string, depth = 0): ProjectStructureEntry[] {
|
|
88
|
-
if (depth > 3) return []; // Limit depth for performance
|
|
89
|
-
|
|
90
|
-
const entries: ProjectStructureEntry[] = [];
|
|
91
|
-
let files: fs.Dirent[];
|
|
92
|
-
|
|
93
|
-
try {
|
|
94
|
-
files = fs.readdirSync(dir, { withFileTypes: true });
|
|
95
|
-
} catch (_e) {
|
|
96
|
-
// Silently ignore directories that cannot be read
|
|
97
|
-
return [];
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
for (const file of files) {
|
|
101
|
-
if (file.name.startsWith(".") || file.name === "node_modules" || file.name === "dist") continue;
|
|
102
|
-
|
|
103
|
-
const fullPath = path.join(dir, file.name);
|
|
104
|
-
const entry: ProjectStructureEntry = {
|
|
105
|
-
name: file.name,
|
|
106
|
-
path: path.relative(projectRoot, fullPath),
|
|
107
|
-
type: file.isDirectory() ? "directory" : "file"
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
if (file.isDirectory()) {
|
|
111
|
-
entry.children = walk(fullPath, depth + 1);
|
|
112
|
-
}
|
|
113
|
-
entries.push(entry);
|
|
114
|
-
}
|
|
115
|
-
return entries;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
try {
|
|
119
|
-
return walk(projectRoot);
|
|
120
|
-
} catch {
|
|
121
|
-
return [];
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export function readManagerLogs() {
|
|
126
|
-
const frameworkDir = getFrameworkDir();
|
|
127
|
-
if (!frameworkDir) return [];
|
|
128
|
-
|
|
129
|
-
const logsPath = path.join(frameworkDir, "logs/manager.json");
|
|
130
|
-
if (!fs.existsSync(logsPath)) return [];
|
|
131
|
-
|
|
132
|
-
try {
|
|
133
|
-
const raw = fs.readFileSync(logsPath, "utf8");
|
|
134
|
-
// Handle both json array format and jsonl format
|
|
135
|
-
if (raw.trim().startsWith("[")) {
|
|
136
|
-
return JSON.parse(raw);
|
|
137
|
-
} else {
|
|
138
|
-
return raw.split("\n").filter(Boolean).map(line => JSON.parse(line));
|
|
139
|
-
}
|
|
140
|
-
} catch {
|
|
141
|
-
return [];
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export function listAgents() {
|
|
146
|
-
const frameworkDir = getFrameworkDir();
|
|
147
|
-
if (!frameworkDir) return [];
|
|
148
|
-
const agentsPath = path.join(frameworkDir, "agents");
|
|
149
|
-
if (!fs.existsSync(agentsPath)) return [];
|
|
150
|
-
|
|
151
|
-
try {
|
|
152
|
-
const files = fs.readdirSync(agentsPath).filter(f => f.endsWith(".json") && f !== "agent_army_schema.json");
|
|
153
|
-
return files.map(file => {
|
|
154
|
-
const content = JSON.parse(fs.readFileSync(path.join(agentsPath, file), "utf8"));
|
|
155
|
-
return {
|
|
156
|
-
name: content.name,
|
|
157
|
-
displayName: content.displayName || content.name,
|
|
158
|
-
description: content.description,
|
|
159
|
-
role: content.role,
|
|
160
|
-
capability: content.capability,
|
|
161
|
-
tags: content.tags || []
|
|
162
|
-
};
|
|
163
|
-
});
|
|
164
|
-
} catch {
|
|
165
|
-
return [];
|
|
166
|
-
}
|
|
167
|
-
}
|