agent-enderun 1.10.4 ā 1.11.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 +34 -45
- package/dist/framework-mcp/tests/tools/quality/check_lint.test.js +1 -1
- package/dist/framework-mcp/tests/tools/quality/check_lint.test.js.map +1 -1
- package/dist/src/cli/adapters/core.d.ts +1 -1
- package/dist/src/cli/adapters/core.js +0 -1
- package/dist/src/cli/adapters/core.js.map +1 -1
- package/dist/src/cli/adapters/index.d.ts +1 -0
- package/dist/src/cli/adapters/index.js +1 -0
- package/dist/src/cli/adapters/index.js.map +1 -1
- package/dist/src/cli/adapters/scaffold.d.ts +1 -1
- package/dist/src/cli/adapters/scaffold.js +8 -6
- package/dist/src/cli/adapters/scaffold.js.map +1 -1
- package/dist/src/cli/commands/init/scaffold-core.d.ts +5 -2
- package/dist/src/cli/commands/init/scaffold-core.js +28 -6
- package/dist/src/cli/commands/init/scaffold-core.js.map +1 -1
- package/dist/src/cli/commands/init.js +31 -4
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/orchestrate.d.ts +6 -6
- package/dist/src/cli/commands/plan.d.ts +3 -1
- package/dist/src/cli/commands/plan.js +79 -22
- package/dist/src/cli/commands/plan.js.map +1 -1
- package/dist/src/cli/index.js +11 -15
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/cli/utils/compliance.js +0 -1
- package/dist/src/cli/utils/compliance.js.map +1 -1
- package/dist/src/cli/utils/config-schema.d.ts +7 -7
- package/dist/src/cli/utils/pkg.d.ts +19 -0
- package/dist/src/cli/utils/pkg.js +29 -5
- package/dist/src/cli/utils/pkg.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/backend.js +5 -4
- package/dist/src/modules/agents/registry/backend.js.map +1 -1
- package/dist/src/modules/agents/registry/database.js +2 -1
- package/dist/src/modules/agents/registry/database.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 +3 -2
- package/dist/src/modules/agents/registry/manager.js.map +1 -1
- package/dist/src/modules/agents/registry/native.js +1 -1
- package/dist/src/modules/agents/registry/native.js.map +1 -1
- package/dist/src/modules/agents/registry/security.js +1 -0
- package/dist/src/modules/agents/registry/security.js.map +1 -1
- package/dist/tests/approve.test.js +4 -9
- package/dist/tests/approve.test.js.map +1 -1
- package/framework-mcp/dist/constants.js +64 -0
- package/framework-mcp/dist/index.js +109 -0
- package/framework-mcp/dist/tools/control_plane/locking.js +64 -0
- package/framework-mcp/dist/tools/control_plane/registry.js +34 -0
- package/framework-mcp/dist/tools/dashboard/start_dashboard.js +29 -0
- package/framework-mcp/dist/tools/definitions.js +300 -0
- package/framework-mcp/dist/tools/file_system/batch_surgical_edit.js +59 -0
- package/framework-mcp/dist/tools/file_system/patch_file.js +25 -0
- package/framework-mcp/dist/tools/file_system/read_file.js +51 -0
- package/framework-mcp/dist/tools/file_system/replace_text.js +43 -0
- package/framework-mcp/dist/tools/file_system/write_file.js +38 -0
- package/framework-mcp/dist/tools/framework/audit_deps.js +41 -0
- package/framework-mcp/dist/tools/framework/get_status.js +5 -0
- package/framework-mcp/dist/tools/framework/orchestrate.js +5 -0
- package/framework-mcp/dist/tools/framework/run_tests.js +25 -0
- package/framework-mcp/dist/tools/framework/update_contract_hash.js +5 -0
- package/framework-mcp/dist/tools/framework/update_memory.js +8 -0
- package/framework-mcp/dist/tools/index.js +62 -0
- package/framework-mcp/dist/tools/memory/get_insights.js +34 -0
- package/framework-mcp/dist/tools/memory/read_memory.js +28 -0
- package/framework-mcp/dist/tools/messaging/log_action.js +22 -0
- package/framework-mcp/dist/tools/messaging/send_message.js +87 -0
- package/framework-mcp/dist/tools/observability/check_ports.js +26 -0
- package/framework-mcp/dist/tools/observability/get_health.js +19 -0
- package/framework-mcp/dist/tools/quality/check_lint.js +28 -0
- package/framework-mcp/dist/tools/search/get_gaps.js +48 -0
- package/framework-mcp/dist/tools/search/get_map.js +43 -0
- package/framework-mcp/dist/tools/search/grep_search.js +76 -0
- package/framework-mcp/dist/tools/search/list_dir.js +28 -0
- package/framework-mcp/dist/tools/shell/run_command.js +46 -0
- package/framework-mcp/dist/tools/types.js +1 -0
- package/framework-mcp/dist/utils/cli.js +20 -0
- package/framework-mcp/dist/utils/compliance.js +29 -0
- package/framework-mcp/dist/utils/fs.js +44 -0
- package/framework-mcp/dist/utils/metrics.js +56 -0
- package/framework-mcp/dist/utils/security.js +60 -0
- package/framework-mcp/package.json +19 -0
- package/framework-mcp/src/constants.ts +78 -0
- package/framework-mcp/src/declarations.d.ts +17 -0
- package/framework-mcp/src/index.ts +132 -0
- package/framework-mcp/src/tools/control_plane/locking.ts +71 -0
- package/framework-mcp/src/tools/control_plane/registry.ts +38 -0
- package/framework-mcp/src/tools/dashboard/start_dashboard.ts +33 -0
- package/framework-mcp/src/tools/definitions.ts +302 -0
- package/framework-mcp/src/tools/file_system/batch_surgical_edit.ts +79 -0
- package/framework-mcp/src/tools/file_system/patch_file.ts +33 -0
- package/framework-mcp/src/tools/file_system/read_file.ts +58 -0
- package/framework-mcp/src/tools/file_system/replace_text.ts +52 -0
- package/framework-mcp/src/tools/file_system/write_file.ts +45 -0
- package/framework-mcp/src/tools/framework/audit_deps.ts +49 -0
- package/framework-mcp/src/tools/framework/get_status.ts +7 -0
- package/framework-mcp/src/tools/framework/orchestrate.ts +7 -0
- package/framework-mcp/src/tools/framework/run_tests.ts +28 -0
- package/framework-mcp/src/tools/framework/update_contract_hash.ts +7 -0
- package/framework-mcp/src/tools/framework/update_memory.ts +10 -0
- package/framework-mcp/src/tools/index.ts +66 -0
- package/framework-mcp/src/tools/memory/get_insights.ts +41 -0
- package/framework-mcp/src/tools/memory/read_memory.ts +31 -0
- package/framework-mcp/src/tools/messaging/log_action.ts +28 -0
- package/framework-mcp/src/tools/messaging/send_message.ts +89 -0
- package/framework-mcp/src/tools/observability/check_ports.ts +30 -0
- package/framework-mcp/src/tools/observability/get_health.ts +24 -0
- package/framework-mcp/src/tools/quality/check_lint.ts +33 -0
- package/framework-mcp/src/tools/search/get_gaps.ts +54 -0
- package/framework-mcp/src/tools/search/get_map.ts +48 -0
- package/framework-mcp/src/tools/search/grep_search.ts +76 -0
- package/framework-mcp/src/tools/search/list_dir.ts +34 -0
- package/framework-mcp/src/tools/shell/run_command.ts +56 -0
- package/framework-mcp/src/tools/types.ts +89 -0
- package/framework-mcp/src/utils/cli.ts +20 -0
- package/framework-mcp/src/utils/compliance.ts +37 -0
- package/framework-mcp/src/utils/fs.ts +45 -0
- package/framework-mcp/src/utils/metrics.ts +73 -0
- package/framework-mcp/src/utils/security.ts +66 -0
- package/framework-mcp/tests/tools/file_system/file_system_tools.test.ts +212 -0
- package/framework-mcp/tests/tools/messaging/send_message.test.ts +136 -0
- package/framework-mcp/tests/tools/quality/check_lint.test.ts +46 -0
- package/framework-mcp/tests/tools/shell/run_command.test.ts +55 -0
- package/framework-mcp/tsconfig.json +14 -0
- package/package.json +5 -3
- package/src/cli/adapters/core.ts +2 -3
- package/src/cli/adapters/index.ts +1 -0
- package/src/cli/adapters/scaffold.ts +15 -6
- package/src/cli/commands/init/scaffold-core.ts +45 -6
- package/src/cli/commands/init.ts +31 -2
- package/src/cli/commands/plan.ts +89 -23
- package/src/cli/index.ts +14 -19
- package/src/cli/utils/compliance.ts +8 -9
- package/src/cli/utils/pkg.ts +42 -13
- package/src/modules/agents/registry/analyst.ts +1 -1
- package/src/modules/agents/registry/backend.ts +5 -4
- package/src/modules/agents/registry/database.ts +2 -1
- package/src/modules/agents/registry/git.ts +1 -1
- package/src/modules/agents/registry/manager.ts +3 -2
- package/src/modules/agents/registry/native.ts +1 -1
- package/src/modules/agents/registry/security.ts +1 -0
- package/templates/prompts/bug-fix-recipe.md +20 -0
- package/templates/prompts/contract-design-recipe.md +21 -0
- package/templates/prompts/db-management-recipe.md +25 -0
- package/templates/prompts/deployment-recipe.md +23 -0
- package/templates/prompts/new-feature-recipe.md +19 -0
- package/templates/prompts/performance-optimization-recipe.md +23 -0
- package/templates/prompts/pull-request-template.md +21 -0
- package/templates/prompts/refactoring-recipe.md +21 -0
- package/templates/prompts/security-audit-recipe.md +20 -0
- package/templates/standards/architecture-standards.md +23 -0
- package/templates/standards/auth-standards.md +125 -0
- package/templates/standards/crud-governance.md +21 -0
- package/templates/standards/deployment-standards.md +21 -0
- package/templates/standards/frontend-standards.md +37 -0
- package/templates/standards/github-actions-standards.md +43 -0
- package/templates/standards/i18n-standards.md +17 -0
- package/templates/standards/kysely-standards.md +47 -0
- package/templates/standards/llm-governance.md +15 -0
- package/templates/standards/logging-and-secrets.md +34 -0
- package/templates/standards/mobile-standards.md +23 -0
- package/templates/standards/observability-standards.md +15 -0
- package/templates/standards/performance-standards.md +15 -0
- package/templates/standards/pino-standards.md +46 -0
- package/templates/standards/playwright-standards.md +54 -0
- package/templates/standards/quality-standards.md +31 -0
- package/templates/standards/react-query-standards.md +72 -0
- package/templates/standards/react-router-standards.md +62 -0
- package/templates/standards/security-audit-standards.md +16 -0
- package/templates/standards/security-standards.md +21 -0
- package/templates/standards/swagger-standards.md +50 -0
- package/templates/standards/tailwind-standards.md +20 -0
- package/templates/standards/testing-standards.md +31 -0
- package/templates/standards/typeorm-standards.md +49 -0
- package/templates/standards/vitest-standards.md +110 -0
- package/src/cli/commands/app.ts +0 -56
- package/src/cli/utils/app-backend.ts +0 -257
- package/src/cli/utils/app-docs.ts +0 -83
- package/src/cli/utils/app-frontend.ts +0 -263
- package/src/cli/utils/app-inferrer.ts +0 -63
- package/src/cli/utils/app-mobile.ts +0 -113
- package/src/cli/utils/app-types.ts +0 -248
- package/src/cli/utils/app.ts +0 -6
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { describe, it, expect, vi, afterEach } from "vitest";
|
|
2
|
+
import { handleCheckLint } from "../../../src/tools/quality/check_lint.js";
|
|
3
|
+
import { exec } from "child_process";
|
|
4
|
+
|
|
5
|
+
vi.mock("child_process");
|
|
6
|
+
|
|
7
|
+
describe("handleCheckLint", () => {
|
|
8
|
+
const projectRoot = "/fake/project";
|
|
9
|
+
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
vi.clearAllMocks();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("should execute the lint command and return output on success", async () => {
|
|
15
|
+
const args = {};
|
|
16
|
+
|
|
17
|
+
vi.mocked(exec).mockImplementation((_cmd, _opts, callback) => {
|
|
18
|
+
// @ts-expect-error: Mock implementation callback type is complex
|
|
19
|
+
callback(null, "All good!", "");
|
|
20
|
+
return {} as any;
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const result = await handleCheckLint(projectRoot, args);
|
|
24
|
+
|
|
25
|
+
expect(exec).toHaveBeenCalledWith("npm run lint", { cwd: projectRoot, timeout: 60000 }, expect.any(Function));
|
|
26
|
+
expect(result.isError).toBeUndefined();
|
|
27
|
+
expect(result.content[0].text).toContain("All good!");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("should execute the lint command and return output on failure (lint issues found)", async () => {
|
|
31
|
+
const args = {};
|
|
32
|
+
const lintErrorOutput = "Error: 2 problems (2 errors, 0 warnings)";
|
|
33
|
+
|
|
34
|
+
vi.mocked(exec).mockImplementation((_cmd, _opts, callback) => {
|
|
35
|
+
// @ts-expect-error: Mock implementation callback type is complex
|
|
36
|
+
callback({ code: 1, message: "Lint errors found" }, lintErrorOutput, "");
|
|
37
|
+
return {} as any;
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const result = await handleCheckLint(projectRoot, args);
|
|
41
|
+
|
|
42
|
+
expect(exec).toHaveBeenCalledWith("npm run lint", { cwd: projectRoot, timeout: 60000 }, expect.any(Function));
|
|
43
|
+
expect(result.isError).toBe(true); // Implementation returns isError: true on failure
|
|
44
|
+
expect(result.content[0].text).toContain(lintErrorOutput);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { describe, it, expect, vi, afterEach } from "vitest";
|
|
2
|
+
import { handleRunCommand } from "../../../src/tools/shell/run_command.js";
|
|
3
|
+
import { exec } from "child_process";
|
|
4
|
+
|
|
5
|
+
vi.mock("child_process");
|
|
6
|
+
|
|
7
|
+
describe("handleRunCommand", () => {
|
|
8
|
+
const projectRoot = "/fake/project";
|
|
9
|
+
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
vi.clearAllMocks();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("should execute an allowed command", async () => {
|
|
15
|
+
const args = { command: "git status" };
|
|
16
|
+
|
|
17
|
+
vi.mocked(exec).mockImplementation((_cmd, _opts, callback) => {
|
|
18
|
+
// @ts-expect-error: Mock implementation callback type is complex
|
|
19
|
+
callback(null, "On branch main", "");
|
|
20
|
+
return {} as any;
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const result = await handleRunCommand(projectRoot, args);
|
|
24
|
+
|
|
25
|
+
expect(exec).toHaveBeenCalledWith("git status", { cwd: projectRoot, timeout: 30000 }, expect.any(Function));
|
|
26
|
+
expect(result.isError).toBeUndefined();
|
|
27
|
+
expect(result.content[0].text).toContain("On branch main");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("should reject a disallowed command", async () => {
|
|
31
|
+
const args = { command: "rm -rf /" };
|
|
32
|
+
const result = await handleRunCommand(projectRoot, args);
|
|
33
|
+
|
|
34
|
+
expect(exec).not.toHaveBeenCalled();
|
|
35
|
+
expect(result.isError).toBe(true);
|
|
36
|
+
expect(result.content[0].text).toContain("Command not allowed");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("should handle command failure", async () => {
|
|
40
|
+
const args = { command: "npm run build" };
|
|
41
|
+
|
|
42
|
+
vi.mocked(exec).mockImplementation((_cmd, _opts, callback) => {
|
|
43
|
+
// @ts-expect-error: Mock implementation callback type is complex
|
|
44
|
+
callback({ code: 1, message: "Build failed" }, "", "Error details");
|
|
45
|
+
return {} as any;
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const result = await handleRunCommand(projectRoot, args);
|
|
49
|
+
|
|
50
|
+
expect(exec).toHaveBeenCalledWith("npm run build", { cwd: projectRoot, timeout: 30000 }, expect.any(Function));
|
|
51
|
+
expect(result.isError).toBe(true);
|
|
52
|
+
expect(result.content[0].text).toContain("Command failed with exit code 1");
|
|
53
|
+
expect(result.content[0].text).toContain("Error details");
|
|
54
|
+
});
|
|
55
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"rootDir": "src",
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"types": ["node"]
|
|
12
|
+
},
|
|
13
|
+
"include": ["src/**/*.ts"]
|
|
14
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-enderun",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
4
4
|
"description": "The Supreme AI Governance & Autonomous Orchestration Framework for Enterprise Development. Acts as a Corporate AI Management Assistant.",
|
|
5
5
|
"author": "Yusuf BEKAR",
|
|
6
6
|
"license": "MIT",
|
|
@@ -33,6 +33,8 @@
|
|
|
33
33
|
"bin",
|
|
34
34
|
"dist",
|
|
35
35
|
"src",
|
|
36
|
+
"templates",
|
|
37
|
+
"framework-mcp",
|
|
36
38
|
"README.md",
|
|
37
39
|
"LICENSE"
|
|
38
40
|
],
|
|
@@ -58,7 +60,7 @@
|
|
|
58
60
|
},
|
|
59
61
|
"devDependencies": {
|
|
60
62
|
"@eslint/js": "^10.0.1",
|
|
61
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
63
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
62
64
|
"@pandacss/dev": "^1.11.1",
|
|
63
65
|
"@types/node": "^25.9.1",
|
|
64
66
|
"eslint": "^10.4.0",
|
|
@@ -69,7 +71,7 @@
|
|
|
69
71
|
"vitest": "^3.0.0"
|
|
70
72
|
},
|
|
71
73
|
"enderun": {
|
|
72
|
-
"version": "1.
|
|
74
|
+
"version": "1.11.0",
|
|
73
75
|
"initializedAt": "2026-06-04T18:51:28.970Z",
|
|
74
76
|
"frameworkDir": ".enderun"
|
|
75
77
|
},
|
package/src/cli/adapters/core.ts
CHANGED
|
@@ -3,8 +3,8 @@ import path from "path";
|
|
|
3
3
|
import { writeJsonFile } from "../utils/fs.js";
|
|
4
4
|
import { getPackageRoot } from "../utils/pkg.js";
|
|
5
5
|
|
|
6
|
-
import type { AdapterConfig, AdapterId } from "../../modules/adapters/types.js";
|
|
7
6
|
import { ADAPTER_CONFIGS, POST_INIT_HANDLERS } from "../../modules/adapters/definitions.js";
|
|
7
|
+
import type { AdapterConfig, AdapterId } from "../../modules/adapters/types.js";
|
|
8
8
|
|
|
9
9
|
export const ADAPTERS: Record<AdapterId, AdapterConfig> = ADAPTER_CONFIGS;
|
|
10
10
|
|
|
@@ -16,7 +16,6 @@ export const FRAMEWORK_DIR_CANDIDATES = [
|
|
|
16
16
|
".claude",
|
|
17
17
|
".github",
|
|
18
18
|
".grok",
|
|
19
|
-
".windsurf",
|
|
20
19
|
".antigravity",
|
|
21
20
|
".agent",
|
|
22
21
|
".gemini/antigravity-cli",
|
|
@@ -28,7 +27,7 @@ export const FRAMEWORK_DIR_CANDIDATES = [
|
|
|
28
27
|
export function buildMcpServerEntry(projectRoot: string) {
|
|
29
28
|
const packageRoot = getPackageRoot();
|
|
30
29
|
const mcpServerPath = path.join(packageRoot, "framework-mcp/dist/index.js");
|
|
31
|
-
|
|
30
|
+
|
|
32
31
|
if (!fs.existsSync(mcpServerPath)) {
|
|
33
32
|
console.warn(`ā ļø MCP Server not found at ${mcpServerPath}. Did you run 'npm run build'?`);
|
|
34
33
|
}
|
|
@@ -2,3 +2,4 @@ export { ADAPTER_IDS, type AdapterConfig, type AdapterId, type AdapterRole } fro
|
|
|
2
2
|
export { ADAPTERS, FRAMEWORK_DIR_CANDIDATES, runAdapterPostInit, buildMcpServerEntry } from "./core.js";
|
|
3
3
|
export { resolveAdapter, isAdapterShimFile, remapFrameworkContent } from "./utils.js";
|
|
4
4
|
export { scaffoldAgents } from "./scaffold.js";
|
|
5
|
+
export { resolveAgentsDir, mirrorUnifiedAgentsToNative } from "./paths.js";
|
|
@@ -14,12 +14,22 @@ import {
|
|
|
14
14
|
import type { AdapterId } from "../../modules/adapters/types.js";
|
|
15
15
|
import { ADAPTERS } from "./core.js";
|
|
16
16
|
|
|
17
|
-
export function scaffoldAgents(
|
|
17
|
+
export function scaffoldAgents(
|
|
18
|
+
projectRoot: string,
|
|
19
|
+
adapterId: AdapterId,
|
|
20
|
+
dryRun: boolean,
|
|
21
|
+
agentsToScaffold?: string[],
|
|
22
|
+
explicitDestDir?: string,
|
|
23
|
+
explicitExt?: string
|
|
24
|
+
): void {
|
|
18
25
|
const adapter = ADAPTERS[adapterId];
|
|
19
|
-
if (!adapter
|
|
26
|
+
if (!adapter) return;
|
|
20
27
|
|
|
21
28
|
const allowedAgents = agentsToScaffold ? new Set(agentsToScaffold) : undefined;
|
|
22
|
-
const destAgentsDir = path.join(projectRoot, adapter.agentsDir);
|
|
29
|
+
const destAgentsDir = explicitDestDir ? path.join(projectRoot, explicitDestDir) : (adapter.agentsDir ? path.join(projectRoot, adapter.agentsDir) : null);
|
|
30
|
+
const extension = explicitExt || adapter.agentsExt || ".md";
|
|
31
|
+
|
|
32
|
+
if (!destAgentsDir) return;
|
|
23
33
|
|
|
24
34
|
const baseKnowledgeDir = path.join(getPackageRoot(), "templates/standards");
|
|
25
35
|
|
|
@@ -30,7 +40,7 @@ export function scaffoldAgents(projectRoot: string, adapterId: AdapterId, dryRun
|
|
|
30
40
|
if (allowedAgents && !allowedAgents.has(agent.name)) continue;
|
|
31
41
|
|
|
32
42
|
let content = "";
|
|
33
|
-
let fileName = `${agent.name}${
|
|
43
|
+
let fileName = `${agent.name}${extension}`;
|
|
34
44
|
let secondaryContent: string | null = null;
|
|
35
45
|
let secondaryFileName: string | null = null;
|
|
36
46
|
|
|
@@ -72,8 +82,7 @@ export function scaffoldAgents(projectRoot: string, adapterId: AdapterId, dryRun
|
|
|
72
82
|
}
|
|
73
83
|
}
|
|
74
84
|
}
|
|
75
|
-
console.warn(`ā
Generated ${allowedAgents ? allowedAgents.size : ALL_AGENTS.length} Agent/Rule definitions under ${path.relative(projectRoot, destAgentsDir)}/`);
|
|
76
85
|
} catch (e) {
|
|
77
|
-
console.warn(`ā ļø Failed to scaffold agents: ${e}`);
|
|
86
|
+
console.warn(`ā ļø Failed to scaffold agents for ${adapterId}: ${e}`);
|
|
78
87
|
}
|
|
79
88
|
}
|
|
@@ -3,7 +3,8 @@ import path from "path";
|
|
|
3
3
|
import {
|
|
4
4
|
remapFrameworkContent,
|
|
5
5
|
type AdapterConfig,
|
|
6
|
-
type AdapterId
|
|
6
|
+
type AdapterId,
|
|
7
|
+
ADAPTERS
|
|
7
8
|
} from "../../adapters/index.js";
|
|
8
9
|
import { SHIM_TEMPLATES } from "../../shims.js";
|
|
9
10
|
import { writeJsonFile, writeTextFile } from "../../utils/fs.js";
|
|
@@ -38,7 +39,14 @@ export function scaffoldConstitution(targetDir: string, frameworkDir: string, ad
|
|
|
38
39
|
console.warn(`ā
Constitution file created inside: ${frameworkDir}/ENDERUN.md${readSuccess ? "" : " (default template)"}`);
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
export function scaffoldFrameworkConfigs(
|
|
42
|
+
export function scaffoldFrameworkConfigs(
|
|
43
|
+
targetDir: string,
|
|
44
|
+
fDir: string,
|
|
45
|
+
adapter: AdapterConfig,
|
|
46
|
+
dryRun: boolean,
|
|
47
|
+
selectedPalette: string,
|
|
48
|
+
options?: { unified?: boolean; adapters?: string[] }
|
|
49
|
+
) {
|
|
42
50
|
if (dryRun) return;
|
|
43
51
|
const frameworkDir = path.join(targetDir, fDir);
|
|
44
52
|
const palette = COLOR_PALETTES[selectedPalette as keyof typeof COLOR_PALETTES] || COLOR_PALETTES["Modern Blue"];
|
|
@@ -46,12 +54,28 @@ export function scaffoldFrameworkConfigs(targetDir: string, fDir: string, adapte
|
|
|
46
54
|
const config = {
|
|
47
55
|
name: FRAMEWORK_NAME,
|
|
48
56
|
version: getPackageVersion(),
|
|
57
|
+
unified: options?.unified || false,
|
|
58
|
+
adapters: options?.adapters || [adapter.id],
|
|
49
59
|
theme: {
|
|
50
60
|
palette: selectedPalette,
|
|
51
61
|
colors: palette
|
|
52
62
|
}
|
|
53
63
|
};
|
|
54
64
|
writeJsonFile(path.join(frameworkDir, "config.json"), config, dryRun);
|
|
65
|
+
|
|
66
|
+
// Scaffold shared-facts.json in memory-graph
|
|
67
|
+
const graphDir = path.join(frameworkDir, "memory-graph");
|
|
68
|
+
if (!fs.existsSync(graphDir)) fs.mkdirSync(graphDir, { recursive: true });
|
|
69
|
+
const sharedFactsPath = path.join(graphDir, "shared-facts.json");
|
|
70
|
+
if (!fs.existsSync(sharedFactsPath)) {
|
|
71
|
+
writeJsonFile(sharedFactsPath, {
|
|
72
|
+
project: FRAMEWORK_NAME,
|
|
73
|
+
initializedAt: new Date().toISOString(),
|
|
74
|
+
stack: [],
|
|
75
|
+
policies: []
|
|
76
|
+
}, dryRun);
|
|
77
|
+
}
|
|
78
|
+
|
|
55
79
|
let statusContent = "# šļø Status\n\n| Agent | State | Active Task | Last Updated | Notes | Extra | Backup |\n|---|---|---|---|---|---|---|\n";
|
|
56
80
|
for (const ag of ALL_AGENTS) {
|
|
57
81
|
statusContent += "| @" + ag.name + " | READY | Idle | - | - | - | - |\n";
|
|
@@ -59,13 +83,28 @@ export function scaffoldFrameworkConfigs(targetDir: string, fDir: string, adapte
|
|
|
59
83
|
writeTextFile(path.join(frameworkDir, "STATUS.md"), statusContent);
|
|
60
84
|
}
|
|
61
85
|
|
|
62
|
-
export function scaffoldShims(
|
|
86
|
+
export function scaffoldShims(
|
|
87
|
+
projectRoot: string,
|
|
88
|
+
coreDir: string,
|
|
89
|
+
adapterId: AdapterId,
|
|
90
|
+
adapter: AdapterConfig,
|
|
91
|
+
dryRun: boolean,
|
|
92
|
+
unified: boolean = false
|
|
93
|
+
) {
|
|
63
94
|
for (const [name, content] of Object.entries(SHIM_TEMPLATES)) {
|
|
64
|
-
|
|
95
|
+
const isSelectedAdapter = name.toLowerCase() === adapterId.split("-")[0] || name === adapterId;
|
|
96
|
+
|
|
97
|
+
if (unified || isSelectedAdapter) {
|
|
65
98
|
const shimContent = remapFrameworkContent(content, coreDir, adapterId);
|
|
66
|
-
const
|
|
99
|
+
const shimAdapter = ADAPTERS[name as AdapterId] || adapter;
|
|
100
|
+
const shimFileName = (unified && !isSelectedAdapter) ? (shimAdapter.shimFile || `${name.toUpperCase()}.md`) : (adapter.shimFile || `${name.toUpperCase()}.md`);
|
|
101
|
+
|
|
67
102
|
if (!dryRun) writeTextFile(path.join(projectRoot, shimFileName), shimContent);
|
|
68
|
-
|
|
103
|
+
if (isSelectedAdapter) {
|
|
104
|
+
console.warn(`ā
Platform shim created: ${shimFileName}`);
|
|
105
|
+
} else if (unified) {
|
|
106
|
+
console.warn(`ā
Unified platform shim added: ${shimFileName}`);
|
|
107
|
+
}
|
|
69
108
|
}
|
|
70
109
|
}
|
|
71
110
|
}
|
package/src/cli/commands/init.ts
CHANGED
|
@@ -5,6 +5,9 @@ import {
|
|
|
5
5
|
resolveAdapter,
|
|
6
6
|
runAdapterPostInit,
|
|
7
7
|
scaffoldAgents,
|
|
8
|
+
resolveAgentsDir,
|
|
9
|
+
mirrorUnifiedAgentsToNative,
|
|
10
|
+
ADAPTER_IDS,
|
|
8
11
|
type AdapterId,
|
|
9
12
|
} from "../adapters/index.js";
|
|
10
13
|
import { ensureDir } from "../utils/fs.js";
|
|
@@ -112,15 +115,41 @@ export async function initCommand(adapterName: string, options: { unified?: bool
|
|
|
112
115
|
}
|
|
113
116
|
|
|
114
117
|
scaffoldConstitution(projectRoot, coreDir, adapterId, dryRun);
|
|
118
|
+
scaffoldFrameworkConfigs(projectRoot, coreDir, adapter, dryRun, selectedPalette, {
|
|
119
|
+
unified: isUnified,
|
|
120
|
+
adapters: isUnified ? [...ADAPTER_IDS] : [adapterId]
|
|
121
|
+
});
|
|
115
122
|
|
|
116
123
|
scaffoldStandards(path.join(projectRoot, coreDir), dryRun);
|
|
117
|
-
|
|
124
|
+
|
|
125
|
+
if (isUnified) {
|
|
126
|
+
// Scaffold ALL agents for ALL adapters under unified hub
|
|
127
|
+
for (const id of ADAPTER_IDS) {
|
|
128
|
+
const dest = resolveAgentsDir(id, true, aiToolDir);
|
|
129
|
+
scaffoldAgents(projectRoot, id, dryRun, selectedAgents, dest.agentsDir, dest.agentsExt);
|
|
130
|
+
if (!dryRun) mirrorUnifiedAgentsToNative(projectRoot, id);
|
|
131
|
+
}
|
|
132
|
+
UI.success(`ā
Scaffolding complete for all adapters under ${aiToolDir}/ with native mirrors.`);
|
|
133
|
+
} else {
|
|
134
|
+
// Standard single-adapter scaffold
|
|
135
|
+
const dest = resolveAgentsDir(adapterId, false);
|
|
136
|
+
scaffoldAgents(projectRoot, adapterId, dryRun, selectedAgents, dest.agentsDir, dest.agentsExt);
|
|
137
|
+
UI.success(`ā
Generated agent definitions under ${dest.agentsDir}/`);
|
|
138
|
+
}
|
|
118
139
|
|
|
119
140
|
const skillsBaseDir = path.join(projectRoot, aiToolDir, "skills");
|
|
120
141
|
scaffoldSkills(skillsBaseDir, dryRun);
|
|
121
142
|
scaffoldOps(path.join(projectRoot, coreDir), dryRun);
|
|
122
|
-
scaffoldShims(projectRoot, coreDir, adapterId, adapter, dryRun);
|
|
143
|
+
scaffoldShims(projectRoot, coreDir, adapterId, adapter, dryRun, isUnified);
|
|
144
|
+
|
|
145
|
+
// Initialize runtime directories
|
|
146
|
+
if (!dryRun) {
|
|
147
|
+
ensureDir(path.join(projectRoot, coreDir, "messages"));
|
|
148
|
+
ensureDir(path.join(projectRoot, coreDir, "logs"));
|
|
149
|
+
ensureDir(path.join(projectRoot, coreDir, "memory-graph"));
|
|
150
|
+
}
|
|
123
151
|
|
|
152
|
+
initializeMemory(path.join(projectRoot, coreDir), dryRun);
|
|
124
153
|
runAdapterPostInit(adapter, projectRoot);
|
|
125
154
|
|
|
126
155
|
UI.success(`\nš ${FRAMEWORK_NAME} (v${getPackageVersion()}) initialized successfully!`);
|
package/src/cli/commands/plan.ts
CHANGED
|
@@ -1,47 +1,113 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
|
-
import { updateDocumentStore } from "../utils/memory.js";
|
|
4
3
|
import { generateULID } from "../utils/time.js";
|
|
5
4
|
import { UI } from "../utils/ui.js";
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
|
-
*
|
|
7
|
+
* Reads ALL markdown files from the docs/ directory and creates
|
|
8
|
+
* planning tasks from them. Agents will use this to understand
|
|
9
|
+
* project requirements and generate code accordingly.
|
|
9
10
|
*/
|
|
10
11
|
export async function planCommand() {
|
|
11
12
|
const projectRoot = process.cwd();
|
|
12
|
-
const
|
|
13
|
+
const docsDir = path.join(projectRoot, "docs");
|
|
13
14
|
|
|
14
|
-
if (!fs.existsSync(
|
|
15
|
-
UI.error("
|
|
15
|
+
if (!fs.existsSync(docsDir)) {
|
|
16
|
+
UI.error("Docs directory not found at docs/");
|
|
17
|
+
console.warn("š” Create a docs/ folder with your project requirements in .md files.");
|
|
16
18
|
return;
|
|
17
19
|
}
|
|
18
20
|
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
let match;
|
|
22
|
-
let count = 0;
|
|
21
|
+
const entries = fs.readdirSync(docsDir, { withFileTypes: true });
|
|
22
|
+
const mdFiles = entries.filter(e => e.isFile() && e.name.endsWith(".md"));
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
if (mdFiles.length === 0) {
|
|
25
|
+
UI.warning("No markdown files found in docs/ directory.");
|
|
26
|
+
console.warn("š” Add .md files to docs/ with your project requirements.");
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
UI.intent("Planning Engine", `Reading ${mdFiles.length} document(s) from docs/...`);
|
|
31
|
+
|
|
32
|
+
// Discover available template standards
|
|
33
|
+
const templatesDir = path.join(projectRoot, "templates");
|
|
34
|
+
const standards: string[] = [];
|
|
35
|
+
if (fs.existsSync(templatesDir)) {
|
|
36
|
+
const templateFiles = fs.readdirSync(templatesDir);
|
|
37
|
+
standards.push(...templateFiles.filter(f => f.endsWith("-standards.md")).map(f => `templates/${f}`));
|
|
38
|
+
if (standards.length > 0) {
|
|
39
|
+
UI.success(`Found ${standards.length} standard templates available for code generation.`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let totalTasks = 0;
|
|
44
|
+
|
|
45
|
+
for (const file of mdFiles) {
|
|
46
|
+
const filePath = path.join(docsDir, file.name);
|
|
47
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
48
|
+
const lines = content.split("\n");
|
|
30
49
|
const traceId = generateULID();
|
|
31
|
-
|
|
50
|
+
|
|
51
|
+
UI.success(`š docs/${file.name} (${lines.length} lines) ā Trace: ${traceId}`);
|
|
52
|
+
|
|
53
|
+
console.warn(` Content preview: ${content.substring(0, 200).replace(/\n/g, " ")}...`);
|
|
54
|
+
|
|
55
|
+
// Extract headings as task descriptions
|
|
56
|
+
const headingRegex = /^#{2,4}\s+(.+)$/gm;
|
|
57
|
+
let headingMatch;
|
|
58
|
+
let headingCount = 0;
|
|
59
|
+
while ((headingMatch = headingRegex.exec(content)) !== null) {
|
|
60
|
+
headingCount++;
|
|
61
|
+
totalTasks++;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Extract checklist items
|
|
65
|
+
const taskRegex = /- \[ \]\s+(.+)/g;
|
|
66
|
+
let taskMatch;
|
|
67
|
+
let taskCount = 0;
|
|
68
|
+
while ((taskMatch = taskRegex.exec(content)) !== null) {
|
|
69
|
+
if (taskMatch[1].trim().length >= 3) {
|
|
70
|
+
taskCount++;
|
|
71
|
+
totalTasks++;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
console.warn(` š ${headingCount} sections, ${taskCount} actionable tasks detected`);
|
|
76
|
+
|
|
77
|
+
// Store in project memory-compatible format
|
|
78
|
+
const memoryDir = path.join(projectRoot, ".enderun", "memory", "tasks");
|
|
79
|
+
if (!fs.existsSync(memoryDir)) {
|
|
80
|
+
fs.mkdirSync(memoryDir, { recursive: true });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const taskFile = path.join(memoryDir, `${traceId}.json`);
|
|
32
84
|
const taskData = {
|
|
33
85
|
traceId,
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
agent: agent.trim().replace("@", ""),
|
|
86
|
+
source: `docs/${file.name}`,
|
|
87
|
+
description: `Process requirements from docs/${file.name}`,
|
|
37
88
|
status: "PENDING",
|
|
38
|
-
createdAt: new Date().toISOString()
|
|
89
|
+
createdAt: new Date().toISOString(),
|
|
90
|
+
standards,
|
|
91
|
+
headings: headingCount,
|
|
92
|
+
tasks: taskCount,
|
|
93
|
+
preview: content.substring(0, 500),
|
|
39
94
|
};
|
|
95
|
+
fs.writeFileSync(taskFile, JSON.stringify(taskData, null, 2));
|
|
96
|
+
}
|
|
40
97
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
98
|
+
// Log available standards
|
|
99
|
+
if (standards.length > 0) {
|
|
100
|
+
console.warn("");
|
|
101
|
+
UI.divider();
|
|
102
|
+
console.warn("š Available Enterprise Standards:");
|
|
103
|
+
standards.forEach(s => console.warn(` - ${s}`));
|
|
104
|
+
UI.divider();
|
|
44
105
|
}
|
|
45
106
|
|
|
46
|
-
UI.success(
|
|
107
|
+
UI.success(`\nā
Planning complete: ${totalTasks} tasks identified from ${mdFiles.length} document(s).`);
|
|
108
|
+
console.warn("\nš Next steps:");
|
|
109
|
+
console.warn(" 1. Run 'agent-enderun status' to see project state");
|
|
110
|
+
console.warn(" 2. AI agents (Claude, Gemini, Grok, etc.) will read docs/ and templates/");
|
|
111
|
+
console.warn(" 3. Agents generate enterprise-standard code based on requirements");
|
|
112
|
+
console.warn(" 4. Use @agent delegation for specific tasks: agent-enderun @backend \"...\"");
|
|
47
113
|
}
|
package/src/cli/index.ts
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import fs from "fs";
|
|
3
|
-
import {
|
|
4
|
-
import { getMemoryPath, readActiveTraceId } from "./utils/memory.js";
|
|
5
|
-
import { planCommand } from "./commands/plan.js";
|
|
6
|
-
import { initCommand } from "./commands/init.js";
|
|
3
|
+
import { approveCommand } from "./commands/approve.js";
|
|
7
4
|
import { checkCommand } from "./commands/check.js";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
5
|
+
import { updateApiContractCommand, verifyApiContractCommand } from "./commands/contract.js";
|
|
6
|
+
import { initCommand } from "./commands/init.js";
|
|
10
7
|
import { updateProjectMemoryCommand } from "./commands/memory.js";
|
|
11
|
-
import { createAppCommand } from "./commands/app.js";
|
|
12
|
-
import { verifyApiContractCommand, updateApiContractCommand } from "./commands/contract.js";
|
|
13
8
|
import { orchestrateCommand, sendMessage } from "./commands/orchestrate.js";
|
|
14
|
-
import {
|
|
9
|
+
import { planCommand } from "./commands/plan.js";
|
|
10
|
+
import { statusCommand } from "./commands/status.js";
|
|
11
|
+
import { traceNewCommand } from "./commands/trace.js";
|
|
12
|
+
import { getMemoryPath, readActiveTraceId } from "./utils/memory.js";
|
|
13
|
+
import { getPackageVersion, getValidatorPath } from "./utils/pkg.js";
|
|
15
14
|
|
|
16
15
|
/**
|
|
17
16
|
* Main CLI entry point.
|
|
@@ -21,8 +20,8 @@ async function main() {
|
|
|
21
20
|
const command = args[0];
|
|
22
21
|
|
|
23
22
|
const KNOWN_COMMANDS = [
|
|
24
|
-
"init", "check", "status", "trace:new", "update_project_memory",
|
|
25
|
-
"
|
|
23
|
+
"init", "check", "status", "trace:new", "update_project_memory",
|
|
24
|
+
"plan", "orchestrate", "loop", "verify-contract", "update-contract",
|
|
26
25
|
"validate", "validate-army", "check:al", "version", "-v", "--version", "help", "-h", "--help",
|
|
27
26
|
"git:commit", "git:sync", "check:compliance", "explorer:graph", "explorer:audit",
|
|
28
27
|
"knowledge:update", "knowledge:search", "log:action", "run-script", "security:audit", "check:lint", "approve"
|
|
@@ -77,6 +76,7 @@ async function main() {
|
|
|
77
76
|
case "plan":
|
|
78
77
|
await planCommand();
|
|
79
78
|
break;
|
|
79
|
+
|
|
80
80
|
case "status":
|
|
81
81
|
await statusCommand();
|
|
82
82
|
break;
|
|
@@ -100,10 +100,6 @@ async function main() {
|
|
|
100
100
|
break;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
case "create-app":
|
|
104
|
-
await createAppCommand(args.slice(1));
|
|
105
|
-
break;
|
|
106
|
-
|
|
107
103
|
case "dashboard": {
|
|
108
104
|
const { dashboardCommand } = await import("./commands/dashboard.js");
|
|
109
105
|
await dashboardCommand(args.slice(1));
|
|
@@ -128,7 +124,7 @@ async function main() {
|
|
|
128
124
|
case "verify-contract":
|
|
129
125
|
await verifyApiContractCommand();
|
|
130
126
|
break;
|
|
131
|
-
|
|
127
|
+
|
|
132
128
|
case "update-contract":
|
|
133
129
|
await updateApiContractCommand();
|
|
134
130
|
break;
|
|
@@ -287,7 +283,7 @@ Commands:
|
|
|
287
283
|
check Perform an enterprise-grade system health check
|
|
288
284
|
status Show active phase, trace ID, and agent statuses
|
|
289
285
|
trace:new <desc> Start a new task chain with a unique Trace ID
|
|
290
|
-
|
|
286
|
+
plan Read all docs/ files and create planning tasks
|
|
291
287
|
orchestrate Start the dynamic Hermes agent orchestration loop
|
|
292
288
|
verify-contract Validate type alignment between backend and frontend
|
|
293
289
|
update-contract Generate and synchronize a new contract hash
|
|
@@ -314,8 +310,8 @@ Example:
|
|
|
314
310
|
`);
|
|
315
311
|
}
|
|
316
312
|
|
|
317
|
-
import { logger } from "../shared/logger.js";
|
|
318
313
|
import { EnderunBaseError } from "../shared/errors.js";
|
|
314
|
+
import { logger } from "../shared/logger.js";
|
|
319
315
|
|
|
320
316
|
main().catch((err) => {
|
|
321
317
|
if (err instanceof EnderunBaseError) {
|
|
@@ -330,4 +326,3 @@ main().catch((err) => {
|
|
|
330
326
|
logger.fatal("Fatal exception during CLI execution", err);
|
|
331
327
|
process.exit(1);
|
|
332
328
|
});
|
|
333
|
-
|
|
@@ -14,12 +14,11 @@ export function scanProjectCompliance(): ComplianceIssue[] {
|
|
|
14
14
|
|
|
15
15
|
for (const file of files) {
|
|
16
16
|
// Absolute skip for the scanner itself to avoid recursion/self-flagging
|
|
17
|
-
if (file.includes("compliance") ||
|
|
17
|
+
if (file.includes("compliance") ||
|
|
18
18
|
file.includes("definitions") ||
|
|
19
19
|
file.includes("agents/registry") || // Skip agent definitions
|
|
20
|
-
file.includes("app-backend.ts") || // Template generator
|
|
21
20
|
file.includes("scaffold-ops.ts") || // Template generator
|
|
22
|
-
file.includes("logger") ||
|
|
21
|
+
file.includes("logger") ||
|
|
23
22
|
file.includes("errors") ||
|
|
24
23
|
file.includes("shared/fs")) continue;
|
|
25
24
|
|
|
@@ -31,8 +30,8 @@ export function scanProjectCompliance(): ComplianceIssue[] {
|
|
|
31
30
|
const trimmedLine = line.trim();
|
|
32
31
|
|
|
33
32
|
// Skip comments and common doc string patterns
|
|
34
|
-
if (trimmedLine.startsWith("//") ||
|
|
35
|
-
trimmedLine.startsWith("*") ||
|
|
33
|
+
if (trimmedLine.startsWith("//") ||
|
|
34
|
+
trimmedLine.startsWith("*") ||
|
|
36
35
|
trimmedLine.startsWith("-") ||
|
|
37
36
|
trimmedLine.includes("\": \"") || // Ignore JSON-like values
|
|
38
37
|
trimmedLine.includes("default: ") || // Ignore default template values
|
|
@@ -48,9 +47,9 @@ export function scanProjectCompliance(): ComplianceIssue[] {
|
|
|
48
47
|
}
|
|
49
48
|
|
|
50
49
|
// 2. Secret check (Regex for simple API keys/assignments) - skip UI messages and templates
|
|
51
|
-
if (/(API_KEY|SECRET|PASSWORD)\s*[:=]/i.test(line) &&
|
|
52
|
-
!file.includes(".env") &&
|
|
53
|
-
!isUIMessage &&
|
|
50
|
+
if (/(API_KEY|SECRET|PASSWORD)\s*[:=]/i.test(line) &&
|
|
51
|
+
!file.includes(".env") &&
|
|
52
|
+
!isUIMessage &&
|
|
54
53
|
!trimmedLine.includes(".env.example") && // Skip template lines
|
|
55
54
|
!trimmedLine.includes("your_secret_key_here") && // Skip common placeholders
|
|
56
55
|
!trimmedLine.includes("pattern:")) {
|
|
@@ -68,7 +67,7 @@ export function scanProjectCompliance(): ComplianceIssue[] {
|
|
|
68
67
|
}
|
|
69
68
|
|
|
70
69
|
// 5. Raw fs write check (Atomic safety enforcement)
|
|
71
|
-
if ((line.includes("fs.writeFileSync") || line.includes("fs.appendFileSync")) &&
|
|
70
|
+
if ((line.includes("fs.writeFileSync") || line.includes("fs.appendFileSync")) &&
|
|
72
71
|
!file.includes("src/shared/fs.ts") && // Ignore the utility itself
|
|
73
72
|
!line.includes(".lock") && // Allow lock files
|
|
74
73
|
!line.includes("lockPath") && // Allow lock path variables
|