agent-enderun 1.1.5 β 1.1.7
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/ENDERUN.md +13 -10
- package/README.md +14 -31
- package/bin/run-multi-test.js +77 -0
- package/dist/framework-mcp/src/tools/dashboard/start_dashboard.d.ts +5 -0
- package/dist/framework-mcp/src/tools/dashboard/start_dashboard.js +30 -0
- package/dist/framework-mcp/src/tools/dashboard/start_dashboard.js.map +1 -0
- package/dist/framework-mcp/src/tools/definitions.js +118 -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 +5 -0
- package/dist/framework-mcp/src/tools/file_system/batch_surgical_edit.js +51 -0
- package/dist/framework-mcp/src/tools/file_system/batch_surgical_edit.js.map +1 -0
- package/dist/framework-mcp/src/tools/file_system/replace_text.js +8 -4
- package/dist/framework-mcp/src/tools/file_system/replace_text.js.map +1 -1
- package/dist/framework-mcp/src/tools/file_system/write_file.js +3 -0
- package/dist/framework-mcp/src/tools/file_system/write_file.js.map +1 -1
- package/dist/framework-mcp/src/tools/framework/audit_deps.d.ts +6 -0
- package/dist/framework-mcp/src/tools/framework/audit_deps.js +42 -0
- package/dist/framework-mcp/src/tools/framework/audit_deps.js.map +1 -0
- package/dist/framework-mcp/src/tools/framework/run_tests.d.ts +5 -0
- package/dist/framework-mcp/src/tools/framework/run_tests.js +26 -0
- package/dist/framework-mcp/src/tools/framework/run_tests.js.map +1 -0
- package/dist/framework-mcp/src/tools/index.js +24 -0
- package/dist/framework-mcp/src/tools/index.js.map +1 -1
- package/dist/framework-mcp/src/tools/memory/get_insights.d.ts +6 -0
- package/dist/framework-mcp/src/tools/memory/get_insights.js +35 -0
- package/dist/framework-mcp/src/tools/memory/get_insights.js.map +1 -0
- package/dist/framework-mcp/src/tools/memory/read_memory.d.ts +6 -0
- package/dist/framework-mcp/src/tools/memory/read_memory.js +29 -0
- package/dist/framework-mcp/src/tools/memory/read_memory.js.map +1 -0
- package/dist/framework-mcp/src/tools/messaging/send_message.js +1 -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 +5 -0
- package/dist/framework-mcp/src/tools/observability/check_ports.js +27 -0
- package/dist/framework-mcp/src/tools/observability/check_ports.js.map +1 -0
- package/dist/framework-mcp/src/tools/observability/get_health.d.ts +5 -0
- package/dist/framework-mcp/src/tools/observability/get_health.js +21 -0
- package/dist/framework-mcp/src/tools/observability/get_health.js.map +1 -0
- package/dist/framework-mcp/src/tools/search/get_gaps.d.ts +6 -0
- package/dist/framework-mcp/src/tools/search/get_gaps.js +49 -0
- package/dist/framework-mcp/src/tools/search/get_gaps.js.map +1 -0
- package/dist/framework-mcp/src/tools/search/get_map.d.ts +6 -0
- package/dist/framework-mcp/src/tools/search/get_map.js +45 -0
- package/dist/framework-mcp/src/tools/search/get_map.js.map +1 -0
- package/dist/framework-mcp/src/tools/search/grep_search.d.ts +5 -0
- package/dist/framework-mcp/src/tools/search/grep_search.js +60 -0
- package/dist/framework-mcp/src/tools/search/grep_search.js.map +1 -0
- package/dist/framework-mcp/src/tools/search/list_dir.d.ts +5 -0
- package/dist/framework-mcp/src/tools/search/list_dir.js +29 -0
- package/dist/framework-mcp/src/tools/search/list_dir.js.map +1 -0
- package/dist/framework-mcp/src/tools/types.d.ts +10 -5
- package/dist/framework-mcp/src/utils/compliance.d.ts +5 -0
- package/dist/framework-mcp/src/utils/compliance.js +30 -0
- package/dist/framework-mcp/src/utils/compliance.js.map +1 -0
- package/dist/framework-mcp/tests/tools/messaging/send_message.test.js +5 -5
- package/dist/framework-mcp/tests/tools/messaging/send_message.test.js.map +1 -1
- package/dist/src/cli/adapters/types.d.ts +2 -2
- package/dist/src/cli/adapters.d.ts +1 -1
- package/dist/src/cli/adapters.js +45 -77
- package/dist/src/cli/adapters.js.map +1 -1
- package/dist/src/cli/commands/check.js +52 -6
- package/dist/src/cli/commands/check.js.map +1 -1
- package/dist/src/cli/commands/init.d.ts +5 -1
- package/dist/src/cli/commands/init.js +184 -106
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/orchestrate.d.ts +3 -3
- package/dist/src/cli/commands/orchestrate.js +14 -8
- package/dist/src/cli/commands/orchestrate.js.map +1 -1
- package/dist/src/cli/commands/status.js +3 -2
- package/dist/src/cli/commands/status.js.map +1 -1
- package/dist/src/cli/index.js +4 -3
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/cli/shims.js +6 -6
- package/dist/src/cli/utils/app-backend.d.ts +2 -0
- package/dist/src/cli/utils/app-backend.js +236 -0
- package/dist/src/cli/utils/app-backend.js.map +1 -0
- package/dist/src/cli/utils/app-docs.d.ts +3 -0
- package/dist/src/cli/utils/app-docs.js +59 -0
- package/dist/src/cli/utils/app-docs.js.map +1 -0
- package/dist/src/cli/utils/app-frontend.d.ts +2 -0
- package/dist/src/cli/utils/app-frontend.js +248 -0
- package/dist/src/cli/utils/app-frontend.js.map +1 -0
- package/dist/src/cli/utils/app-inferrer.d.ts +14 -0
- package/dist/src/cli/utils/app-inferrer.js +39 -0
- package/dist/src/cli/utils/app-inferrer.js.map +1 -0
- package/dist/src/cli/utils/app-types.d.ts +3 -0
- package/dist/src/cli/utils/app-types.js +233 -0
- package/dist/src/cli/utils/app-types.js.map +1 -0
- package/dist/src/cli/utils/app.d.ts +5 -32
- package/dist/src/cli/utils/app.js +5 -794
- package/dist/src/cli/utils/app.js.map +1 -1
- package/dist/src/cli/utils/memory.js +8 -4
- package/dist/src/cli/utils/memory.js.map +1 -1
- package/dist/src/modules/adapters/antigravity-cli.js +3 -3
- package/dist/src/modules/adapters/antigravity-cli.js.map +1 -1
- package/dist/src/modules/adapters/claude.js +1 -1
- package/dist/src/modules/adapters/claude.js.map +1 -1
- package/dist/src/modules/adapters/codex.js +2 -2
- package/dist/src/modules/adapters/codex.js.map +1 -1
- package/dist/src/modules/adapters/cursor.js +1 -1
- package/dist/src/modules/adapters/cursor.js.map +1 -1
- package/dist/src/modules/adapters/definitions.d.ts +9 -0
- package/dist/src/modules/adapters/definitions.js +124 -0
- package/dist/src/modules/adapters/definitions.js.map +1 -0
- package/dist/src/modules/adapters/gemini.js +2 -2
- package/dist/src/modules/adapters/gemini.js.map +1 -1
- package/dist/src/modules/adapters/grok.js +1 -1
- package/dist/src/modules/adapters/grok.js.map +1 -1
- package/dist/src/modules/agents/definitions.js +26 -27
- package/dist/src/modules/agents/definitions.js.map +1 -1
- package/dist/src/shared/config.d.ts +3 -3
- package/dist/src/shared/logger.js +8 -5
- package/dist/src/shared/logger.js.map +1 -1
- package/dist/tests/adapter.test.d.ts +1 -0
- package/dist/tests/adapter.test.js +129 -0
- package/dist/tests/adapter.test.js.map +1 -0
- package/dist/tests/agents-definitions.test.d.ts +1 -0
- package/dist/tests/agents-definitions.test.js +54 -0
- package/dist/tests/agents-definitions.test.js.map +1 -0
- package/dist/tests/approve.test.d.ts +1 -0
- package/dist/tests/approve.test.js +88 -0
- package/dist/tests/approve.test.js.map +1 -0
- package/dist/tests/config.test.d.ts +1 -0
- package/dist/tests/config.test.js +58 -0
- package/dist/tests/config.test.js.map +1 -0
- package/dist/tests/container.runner.d.ts +1 -0
- package/dist/tests/container.runner.js +68 -0
- package/dist/tests/container.runner.js.map +1 -0
- package/dist/tests/container.test.d.ts +1 -0
- package/dist/tests/container.test.js +73 -0
- package/dist/tests/container.test.js.map +1 -0
- package/dist/tests/errors.test.d.ts +1 -0
- package/dist/tests/errors.test.js +64 -0
- package/dist/tests/errors.test.js.map +1 -0
- package/dist/tests/fs-utils.test.d.ts +1 -0
- package/dist/tests/fs-utils.test.js +101 -0
- package/dist/tests/fs-utils.test.js.map +1 -0
- package/dist/tests/logger.test.d.ts +1 -0
- package/dist/tests/logger.test.js +81 -0
- package/dist/tests/logger.test.js.map +1 -0
- package/dist/tests/memory-utils.test.d.ts +1 -0
- package/dist/tests/memory-utils.test.js +173 -0
- package/dist/tests/memory-utils.test.js.map +1 -0
- package/dist/tests/orchestrate.test.d.ts +1 -0
- package/dist/tests/orchestrate.test.js +131 -0
- package/dist/tests/orchestrate.test.js.map +1 -0
- package/dist/tests/skills-definitions.test.d.ts +1 -0
- package/dist/tests/skills-definitions.test.js +34 -0
- package/dist/tests/skills-definitions.test.js.map +1 -0
- package/dist/tests/status.test.d.ts +1 -0
- package/dist/tests/status.test.js +105 -0
- package/dist/tests/status.test.js.map +1 -0
- package/dist/tests/string.test.d.ts +1 -0
- package/dist/tests/string.test.js +89 -0
- package/dist/tests/string.test.js.map +1 -0
- package/dist/tests/time.test.d.ts +1 -0
- package/dist/tests/time.test.js +48 -0
- package/dist/tests/time.test.js.map +1 -0
- package/dist/tests/trace.test.d.ts +1 -0
- package/dist/tests/trace.test.js +61 -0
- package/dist/tests/trace.test.js.map +1 -0
- package/dist/vitest.config.js +1 -0
- package/dist/vitest.config.js.map +1 -1
- package/docs/getting-started.md +4 -0
- package/docs/user/corporate-governance.md +25 -0
- package/framework-mcp/dist/tools/dashboard/start_dashboard.js +29 -0
- package/framework-mcp/dist/tools/definitions.js +118 -0
- package/framework-mcp/dist/tools/file_system/batch_surgical_edit.js +50 -0
- package/framework-mcp/dist/tools/file_system/replace_text.js +8 -4
- package/framework-mcp/dist/tools/file_system/write_file.js +3 -0
- package/framework-mcp/dist/tools/framework/audit_deps.js +41 -0
- package/framework-mcp/dist/tools/framework/run_tests.js +25 -0
- package/framework-mcp/dist/tools/index.js +24 -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/send_message.js +1 -1
- package/framework-mcp/dist/tools/observability/check_ports.js +26 -0
- package/framework-mcp/dist/tools/observability/get_health.js +20 -0
- package/framework-mcp/dist/tools/search/get_gaps.js +48 -0
- package/framework-mcp/dist/tools/search/get_map.js +44 -0
- package/framework-mcp/dist/tools/search/grep_search.js +59 -0
- package/framework-mcp/dist/tools/search/list_dir.js +28 -0
- package/framework-mcp/dist/utils/compliance.js +29 -0
- package/framework-mcp/package.json +1 -1
- package/framework-mcp/src/tools/dashboard/start_dashboard.ts +33 -0
- package/framework-mcp/src/tools/definitions.ts +118 -0
- package/framework-mcp/src/tools/file_system/batch_surgical_edit.ts +70 -0
- package/framework-mcp/src/tools/file_system/replace_text.ts +10 -4
- package/framework-mcp/src/tools/file_system/write_file.ts +5 -0
- package/framework-mcp/src/tools/framework/audit_deps.ts +49 -0
- package/framework-mcp/src/tools/framework/run_tests.ts +28 -0
- package/framework-mcp/src/tools/index.ts +24 -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/send_message.ts +1 -1
- package/framework-mcp/src/tools/observability/check_ports.ts +30 -0
- package/framework-mcp/src/tools/observability/get_health.ts +25 -0
- package/framework-mcp/src/tools/search/get_gaps.ts +54 -0
- package/framework-mcp/src/tools/search/get_map.ts +50 -0
- package/framework-mcp/src/tools/search/grep_search.ts +66 -0
- package/framework-mcp/src/tools/search/list_dir.ts +34 -0
- package/framework-mcp/src/tools/types.ts +11 -1
- package/framework-mcp/src/utils/compliance.ts +37 -0
- package/framework-mcp/tests/tools/messaging/send_message.test.ts +5 -5
- package/package.json +3 -3
- package/src/cli/adapters/types.ts +2 -2
- package/src/cli/adapters.ts +45 -80
- package/src/cli/commands/check.ts +52 -6
- package/src/cli/commands/init.ts +193 -114
- package/src/cli/commands/orchestrate.ts +14 -8
- package/src/cli/commands/status.ts +3 -2
- package/src/cli/index.ts +4 -3
- package/src/cli/shims.ts +6 -6
- package/src/cli/utils/app-backend.ts +249 -0
- package/src/cli/utils/app-docs.ts +65 -0
- package/src/cli/utils/app-frontend.ts +257 -0
- package/src/cli/utils/app-inferrer.ts +53 -0
- package/src/cli/utils/app-types.ts +243 -0
- package/src/cli/utils/app.ts +5 -849
- package/src/cli/utils/memory.ts +8 -4
- package/src/modules/adapters/definitions.ts +125 -0
- package/src/modules/agents/definitions.ts +26 -27
- package/src/shared/logger.ts +8 -5
- package/templates/prompts/bug-fix-recipe.md +20 -0
- package/templates/prompts/new-feature-recipe.md +19 -0
- package/templates/prompts/refactoring-recipe.md +21 -0
- package/templates/standards/architecture-standards.md +23 -0
- package/templates/standards/crud-governance.md +21 -0
- package/templates/standards/frontend-standards.md +38 -0
- package/templates/standards/i18n-standards.md +17 -0
- package/templates/standards/logging-and-secrets.md +29 -0
- package/templates/standards/mobile-standards.md +24 -0
- package/templates/standards/quality-standards.md +31 -0
- package/templates/standards/security-standards.md +21 -0
- package/templates/standards/tailwind-standards.md +20 -0
- package/templates/standards/testing-standards.md +31 -0
- package/src/modules/adapters/antigravity-cli.ts +0 -25
- package/src/modules/adapters/claude.ts +0 -36
- package/src/modules/adapters/codex.ts +0 -22
- package/src/modules/adapters/cursor.ts +0 -22
- package/src/modules/adapters/gemini.ts +0 -27
- package/src/modules/adapters/grok.ts +0 -20
- package/templates/architecture/agents-manifest.md +0 -79
- package/templates/architecture/approval-flows.md +0 -61
- package/templates/architecture/enterprise-architecture.md +0 -69
- package/templates/architecture/standards/crud-governance.md +0 -46
- package/templates/architecture/standards/data-fetching-patterns.md +0 -13
- package/templates/architecture/standards/design-system.md +0 -31
- package/templates/architecture/standards/documentation-ownership.md +0 -21
- package/templates/architecture/standards/logging.md +0 -7
- package/templates/architecture/standards/mobile-standards.md +0 -48
- package/templates/architecture/standards/tech-stack.md +0 -9
- package/templates/backend/error-handling.md +0 -74
- package/templates/frontend/component-patterns.md +0 -91
|
@@ -14,6 +14,29 @@ export const TOOLS: ToolDefinition[] = [
|
|
|
14
14
|
required: ["path"],
|
|
15
15
|
},
|
|
16
16
|
},
|
|
17
|
+
{
|
|
18
|
+
name: "list_dir",
|
|
19
|
+
description: "List the contents of a directory. Essential for codebase exploration.",
|
|
20
|
+
inputSchema: {
|
|
21
|
+
type: "object",
|
|
22
|
+
properties: {
|
|
23
|
+
path: { type: "string", description: "Path to the directory relative to project root (default: '.')" },
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: "grep_search",
|
|
29
|
+
description: "Perform a recursive regex search across the codebase to find functions, variables, or patterns.",
|
|
30
|
+
inputSchema: {
|
|
31
|
+
type: "object",
|
|
32
|
+
properties: {
|
|
33
|
+
pattern: { type: "string", description: "The regex pattern to search for" },
|
|
34
|
+
includePattern: { type: "string", description: "Optional: Filter files by extension (e.g., '.ts')" },
|
|
35
|
+
excludePattern: { type: "string", description: "Optional: Directory pattern to exclude (default: 'node_modules')" },
|
|
36
|
+
},
|
|
37
|
+
required: ["pattern"],
|
|
38
|
+
},
|
|
39
|
+
},
|
|
17
40
|
{
|
|
18
41
|
name: "write_file",
|
|
19
42
|
description: "Write content to a file. Creates directories if missing.",
|
|
@@ -35,10 +58,34 @@ export const TOOLS: ToolDefinition[] = [
|
|
|
35
58
|
path: { type: "string", description: "Path to the file" },
|
|
36
59
|
oldText: { type: "string", description: "The exact text to find" },
|
|
37
60
|
newText: { type: "string", description: "The text to replace it with" },
|
|
61
|
+
allowMultiple: { type: "boolean", description: "Allow multiple replacements if oldText is not unique." }
|
|
38
62
|
},
|
|
39
63
|
required: ["path", "oldText", "newText"],
|
|
40
64
|
},
|
|
41
65
|
},
|
|
66
|
+
{
|
|
67
|
+
name: "batch_surgical_edit",
|
|
68
|
+
description: "Perform multiple surgical text replacements across multiple files in a single batch request. More efficient for cross-cutting changes.",
|
|
69
|
+
inputSchema: {
|
|
70
|
+
type: "object",
|
|
71
|
+
properties: {
|
|
72
|
+
edits: {
|
|
73
|
+
type: "array",
|
|
74
|
+
items: {
|
|
75
|
+
type: "object",
|
|
76
|
+
properties: {
|
|
77
|
+
path: { type: "string", description: "Path to the file" },
|
|
78
|
+
oldText: { type: "string", description: "The exact text to find" },
|
|
79
|
+
newText: { type: "string", description: "The text to replace it with" },
|
|
80
|
+
allowMultiple: { type: "boolean", description: "Allow multiple replacements in this file." }
|
|
81
|
+
},
|
|
82
|
+
required: ["path", "oldText", "newText"]
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
required: ["edits"],
|
|
87
|
+
},
|
|
88
|
+
},
|
|
42
89
|
{
|
|
43
90
|
name: "patch_file",
|
|
44
91
|
description: "Safely update a file by replacing a specific line range with new content.",
|
|
@@ -53,11 +100,82 @@ export const TOOLS: ToolDefinition[] = [
|
|
|
53
100
|
required: ["path", "startLine", "endLine", "newContent"],
|
|
54
101
|
},
|
|
55
102
|
},
|
|
103
|
+
{
|
|
104
|
+
name: "get_project_map",
|
|
105
|
+
description: "Generate a tree-view map of the project structure to visualize the layout. Useful for onboarding and architectural analysis.",
|
|
106
|
+
inputSchema: {
|
|
107
|
+
type: "object",
|
|
108
|
+
properties: {
|
|
109
|
+
maxDepth: { type: "number", description: "Maximum directory depth to scan (default: 3)" },
|
|
110
|
+
includeFiles: { type: "boolean", description: "Whether to include files in the map (default: true)" }
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: "get_project_gaps",
|
|
116
|
+
description: "Scans the codebase for TODOs, FIXMEs, and empty function bodies. Helps identify what is left and where the agent might have skipped logic.",
|
|
117
|
+
inputSchema: {
|
|
118
|
+
type: "object",
|
|
119
|
+
properties: {
|
|
120
|
+
path: { type: "string", description: "Path to the source directory (default: 'src')" },
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: "audit_dependencies",
|
|
126
|
+
description: "Audits package.json for unused, redundant, or duplicate-like packages to ensure a clean dependency tree.",
|
|
127
|
+
inputSchema: { type: "object", properties: {} },
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
name: "run_tests",
|
|
131
|
+
description: "Execute project test suites (Vitest, Playwright, etc.) and capture detailed pass/fail reports for analysis.",
|
|
132
|
+
inputSchema: {
|
|
133
|
+
type: "object",
|
|
134
|
+
properties: {
|
|
135
|
+
command: { type: "string", description: "The test command to run (default: 'npm test')" }
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
name: "get_system_health",
|
|
141
|
+
description: "Retrieve real-time system metrics like CPU load, RAM usage, and uptime.",
|
|
142
|
+
inputSchema: { type: "object", properties: {} }
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
name: "check_active_ports",
|
|
146
|
+
description: "Identify which network ports are currently active and listening. Helps verify if the dev server or API is running.",
|
|
147
|
+
inputSchema: {
|
|
148
|
+
type: "object",
|
|
149
|
+
properties: {
|
|
150
|
+
filter: { type: "string", description: "Optional: Filter results by port number or service name (e.g., ':3000')" }
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
name: "start_dashboard",
|
|
156
|
+
description: "Start the Enderun Web Dashboard (Command Center) to visualize real-time agent status, logs, and system metrics in the browser.",
|
|
157
|
+
inputSchema: {
|
|
158
|
+
type: "object",
|
|
159
|
+
properties: {
|
|
160
|
+
port: { type: "number", description: "Optional: Port to run the dashboard on (default: 5858)" }
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
},
|
|
56
164
|
{
|
|
57
165
|
name: "get_framework_status",
|
|
58
166
|
description: "Get the current project phase, active traces, and agent states.",
|
|
59
167
|
inputSchema: { type: "object", properties: {} },
|
|
60
168
|
},
|
|
169
|
+
{
|
|
170
|
+
name: "read_project_memory",
|
|
171
|
+
description: "Read the full project central memory (PROJECT_MEMORY.md). Use this at the start of a session to gain context.",
|
|
172
|
+
inputSchema: { type: "object", properties: {} },
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
name: "get_memory_insights",
|
|
176
|
+
description: "Retrieve a summarized version of the project memory (active phase, trace, and last 5 actions) to save tokens.",
|
|
177
|
+
inputSchema: { type: "object", properties: {} },
|
|
178
|
+
},
|
|
61
179
|
{
|
|
62
180
|
name: "update_project_memory",
|
|
63
181
|
description: "Update a specific section in PROJECT_MEMORY.md.",
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import { safePath } from "../../utils/security.js";
|
|
3
|
+
import { ToolArgs, ToolResult } from "../types.js";
|
|
4
|
+
import { Metrics } from "../../utils/metrics.js";
|
|
5
|
+
import { verifyCorporateCompliance } from "../../utils/compliance.js";
|
|
6
|
+
|
|
7
|
+
interface SurgicalEdit {
|
|
8
|
+
path: string;
|
|
9
|
+
oldText: string;
|
|
10
|
+
newText: string;
|
|
11
|
+
allowMultiple?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Performs multiple surgical text replacements across multiple files in a single batch.
|
|
16
|
+
*/
|
|
17
|
+
export function handleBatchSurgicalEdit(projectRoot: string, args: ToolArgs): ToolResult {
|
|
18
|
+
const edits = args.edits as SurgicalEdit[];
|
|
19
|
+
if (!Array.isArray(edits) || edits.length === 0) {
|
|
20
|
+
throw new Error("No edits provided in the batch request.");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const results: string[] = [];
|
|
24
|
+
let totalTokens = 0;
|
|
25
|
+
|
|
26
|
+
for (const edit of edits) {
|
|
27
|
+
const filePath = safePath(projectRoot, edit.path);
|
|
28
|
+
if (!fs.existsSync(filePath)) {
|
|
29
|
+
throw new Error(`File not found: ${edit.path}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
33
|
+
const { oldText, newText, allowMultiple = false } = edit;
|
|
34
|
+
|
|
35
|
+
if (!content.includes(oldText)) {
|
|
36
|
+
throw new Error(`Text not found in file ${edit.path}: "${oldText.slice(0, 50)}..."`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Surgical precision guard
|
|
40
|
+
if (!allowMultiple) {
|
|
41
|
+
const firstIndex = content.indexOf(oldText);
|
|
42
|
+
const lastIndex = content.lastIndexOf(oldText);
|
|
43
|
+
if (firstIndex !== lastIndex) {
|
|
44
|
+
throw new Error(`Ambiguous replacement in ${edit.path}: "${oldText.slice(0, 50)}..." found multiple times.`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const newContent = allowMultiple
|
|
49
|
+
? content.replace(new RegExp(oldText.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"), newText)
|
|
50
|
+
: content.replace(oldText, newText);
|
|
51
|
+
|
|
52
|
+
// ENFORCE CORPORATE COMPLIANCE
|
|
53
|
+
verifyCorporateCompliance(newContent, edit.path);
|
|
54
|
+
|
|
55
|
+
fs.writeFileSync(filePath, newContent);
|
|
56
|
+
|
|
57
|
+
const tokens = Metrics.estimateTokens(newText);
|
|
58
|
+
totalTokens += tokens;
|
|
59
|
+
results.push(`β
Edited ${edit.path}`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
Metrics.logUsage(projectRoot, "@mcp", `batch_surgical_edit: ${edits.length} files`, totalTokens);
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
content: [{
|
|
66
|
+
type: "text",
|
|
67
|
+
text: `Successfully performed ${edits.length} edits:\n${results.join("\n")}`
|
|
68
|
+
}]
|
|
69
|
+
};
|
|
70
|
+
}
|
|
@@ -3,9 +3,11 @@ import { safePath } from "../../utils/security.js";
|
|
|
3
3
|
import { ToolArgs, ToolResult } from "../types.js";
|
|
4
4
|
import { Metrics } from "../../utils/metrics.js";
|
|
5
5
|
|
|
6
|
+
import { verifyCorporateCompliance } from "../../utils/compliance.js";
|
|
7
|
+
|
|
6
8
|
export function handleReplaceText(projectRoot: string, args: ToolArgs): ToolResult {
|
|
7
9
|
const filePath = safePath(projectRoot, args.path as string);
|
|
8
|
-
|
|
10
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
9
11
|
const oldText = args.oldText as string;
|
|
10
12
|
const newText = args.newText as string;
|
|
11
13
|
const allowMultiple = args.allowMultiple || false; // Default to false
|
|
@@ -28,13 +30,17 @@ export function handleReplaceText(projectRoot: string, args: ToolArgs): ToolResu
|
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
// Perform replacement(s)
|
|
33
|
+
let newContent: string;
|
|
31
34
|
if (allowMultiple) {
|
|
32
|
-
|
|
35
|
+
newContent = content.replace(new RegExp(oldText.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"), newText);
|
|
33
36
|
} else {
|
|
34
|
-
|
|
37
|
+
newContent = content.replace(oldText, newText);
|
|
35
38
|
}
|
|
39
|
+
|
|
40
|
+
// ENFORCE CORPORATE COMPLIANCE
|
|
41
|
+
verifyCorporateCompliance(newContent, args.path as string);
|
|
36
42
|
|
|
37
|
-
fs.writeFileSync(filePath,
|
|
43
|
+
fs.writeFileSync(filePath, newContent);
|
|
38
44
|
|
|
39
45
|
const tokens = Metrics.estimateTokens(newText);
|
|
40
46
|
Metrics.logUsage(projectRoot, "@mcp", `replace_text: ${args.path}`, tokens);
|
|
@@ -4,10 +4,15 @@ import { safePath, resolveFrameworkDir } from "../../utils/security.js";
|
|
|
4
4
|
import { Metrics } from "../../utils/metrics.js";
|
|
5
5
|
import { ToolArgs, ToolResult } from "../types.js";
|
|
6
6
|
|
|
7
|
+
import { verifyCorporateCompliance } from "../../utils/compliance.js";
|
|
8
|
+
|
|
7
9
|
export function handleWriteFile(projectRoot: string, args: ToolArgs): ToolResult {
|
|
8
10
|
const filePath = safePath(projectRoot, args.path as string);
|
|
9
11
|
const content = args.content as string;
|
|
10
12
|
|
|
13
|
+
// ENFORCE CORPORATE COMPLIANCE
|
|
14
|
+
verifyCorporateCompliance(content, args.path as string);
|
|
15
|
+
|
|
11
16
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
12
17
|
fs.writeFileSync(filePath, content);
|
|
13
18
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { ToolArgs, ToolResult } from "../types.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Audits package.json for unused or duplicate-like packages.
|
|
7
|
+
* Focuses on project health and cleanup.
|
|
8
|
+
*/
|
|
9
|
+
export function handleAuditDependencies(projectRoot: string, _args: ToolArgs): ToolResult {
|
|
10
|
+
const pkgPath = path.join(projectRoot, "package.json");
|
|
11
|
+
if (!fs.existsSync(pkgPath)) {
|
|
12
|
+
throw new Error("package.json not found.");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
16
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
17
|
+
const depNames = Object.keys(deps);
|
|
18
|
+
|
|
19
|
+
const results: string[] = [];
|
|
20
|
+
|
|
21
|
+
// 1. Look for similar packages (potential duplicates)
|
|
22
|
+
const similarityGroups: Record<string, string[]> = {
|
|
23
|
+
"CSS/Styling": ["tailwind", "panda", "styled-components", "emotion", "sass"],
|
|
24
|
+
"Testing": ["vitest", "jest", "mocha", "jasmine"],
|
|
25
|
+
"Fetching": ["axios", "ky", "fetch"]
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
for (const [group, patterns] of Object.entries(similarityGroups)) {
|
|
29
|
+
const found = depNames.filter(d => patterns.some(p => d.includes(p)));
|
|
30
|
+
if (found.length > 1) {
|
|
31
|
+
results.push(`β οΈ Potential redundancy in [${group}]: Found ${found.join(", ")}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 2. Scan for "any" usage in package names (bad practice markers)
|
|
36
|
+
const legacyDeps = depNames.filter(d => d.includes("legacy") || d.includes("compat"));
|
|
37
|
+
if (legacyDeps.length > 0) {
|
|
38
|
+
results.push(`βΉοΈ Legacy compatibility packages detected: ${legacyDeps.join(", ")}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
content: [{
|
|
43
|
+
type: "text",
|
|
44
|
+
text: results.length > 0
|
|
45
|
+
? `Dependency Audit Results:\n\n${results.join("\n")}`
|
|
46
|
+
: "β
Dependencies look clean and consolidated."
|
|
47
|
+
}]
|
|
48
|
+
};
|
|
49
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import { ToolArgs, ToolResult } from "../types.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Executes project tests and returns results for agent analysis.
|
|
6
|
+
*/
|
|
7
|
+
export function handleRunTests(projectRoot: string, args: ToolArgs): ToolResult {
|
|
8
|
+
const testCommand = args.command as string || "npm test";
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
const output = execSync(testCommand, { cwd: projectRoot, encoding: "utf8", stdio: "pipe" });
|
|
12
|
+
return {
|
|
13
|
+
content: [{ type: "text", text: `β
Tests passed successfully!\n\n${output}` }]
|
|
14
|
+
};
|
|
15
|
+
} catch (error: unknown) {
|
|
16
|
+
const err = error as { stderr?: Buffer; stdout?: Buffer };
|
|
17
|
+
const stderr = err.stderr?.toString() || "";
|
|
18
|
+
const stdout = err.stdout?.toString() || "";
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
isError: true,
|
|
22
|
+
content: [{
|
|
23
|
+
type: "text",
|
|
24
|
+
text: `β Tests FAILED!\n\n--- STDOUT ---\n${stdout}\n\n--- STDERR ---\n${stderr}`
|
|
25
|
+
}]
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -2,11 +2,23 @@ import { TOOLS } from "./definitions.js";
|
|
|
2
2
|
import { handleReadFile } from "./file_system/read_file.js";
|
|
3
3
|
import { handleWriteFile } from "./file_system/write_file.js";
|
|
4
4
|
import { handleReplaceText } from "./file_system/replace_text.js";
|
|
5
|
+
import { handleBatchSurgicalEdit } from "./file_system/batch_surgical_edit.js";
|
|
5
6
|
import { handlePatchFile } from "./file_system/patch_file.js";
|
|
7
|
+
import { handleGrepSearch } from "./search/grep_search.js";
|
|
8
|
+
import { handleListDir } from "./search/list_dir.js";
|
|
9
|
+
import { handleGetProjectGaps } from "./search/get_gaps.js";
|
|
10
|
+
import { handleGetProjectMap } from "./search/get_map.js";
|
|
6
11
|
import { handleGetFrameworkStatus } from "./framework/get_status.js";
|
|
7
12
|
import { handleUpdateProjectMemory } from "./framework/update_memory.js";
|
|
13
|
+
import { handleAuditDependencies } from "./framework/audit_deps.js";
|
|
14
|
+
import { handleRunTests } from "./framework/run_tests.js";
|
|
15
|
+
import { handleGetSystemHealth } from "./observability/get_health.js";
|
|
16
|
+
import { handleCheckPorts } from "./observability/check_ports.js";
|
|
17
|
+
import { handleStartDashboard } from "./dashboard/start_dashboard.js";
|
|
8
18
|
import { handleOrchestrateLoop } from "./framework/orchestrate.js";
|
|
9
19
|
import { handleUpdateContractHash } from "./framework/update_contract_hash.js";
|
|
20
|
+
import { handleReadProjectMemory } from "./memory/read_memory.js";
|
|
21
|
+
import { handleGetMemoryInsights } from "./memory/get_insights.js";
|
|
10
22
|
import { handleSendAgentMessage } from "./messaging/send_message.js";
|
|
11
23
|
import { handleLogAgentAction } from "./messaging/log_action.js";
|
|
12
24
|
import { handleAcquireLock, handleReleaseLock } from "./control_plane/locking.js";
|
|
@@ -19,11 +31,23 @@ export type ToolHandler = (projectRoot: string, args: ToolArgs) => ToolResult |
|
|
|
19
31
|
// Map of tool names to their handler functions
|
|
20
32
|
export const toolHandlers: Record<string, ToolHandler> = {
|
|
21
33
|
read_file: handleReadFile,
|
|
34
|
+
list_dir: handleListDir,
|
|
35
|
+
grep_search: handleGrepSearch,
|
|
36
|
+
get_project_map: handleGetProjectMap,
|
|
37
|
+
get_project_gaps: handleGetProjectGaps,
|
|
22
38
|
write_file: handleWriteFile,
|
|
23
39
|
replace_text: handleReplaceText,
|
|
40
|
+
batch_surgical_edit: handleBatchSurgicalEdit,
|
|
24
41
|
patch_file: handlePatchFile,
|
|
25
42
|
get_framework_status: handleGetFrameworkStatus,
|
|
43
|
+
read_project_memory: handleReadProjectMemory,
|
|
44
|
+
get_memory_insights: handleGetMemoryInsights,
|
|
26
45
|
update_project_memory: handleUpdateProjectMemory,
|
|
46
|
+
audit_dependencies: handleAuditDependencies,
|
|
47
|
+
run_tests: handleRunTests,
|
|
48
|
+
get_system_health: handleGetSystemHealth,
|
|
49
|
+
check_active_ports: handleCheckPorts,
|
|
50
|
+
start_dashboard: handleStartDashboard,
|
|
27
51
|
orchestrate_loop: handleOrchestrateLoop,
|
|
28
52
|
send_agent_message: handleSendAgentMessage,
|
|
29
53
|
log_agent_action: handleLogAgentAction,
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { resolveFrameworkDir } from "../../utils/security.js";
|
|
4
|
+
import { ToolArgs, ToolResult } from "../types.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Extracts key insights from the project memory to minimize token usage.
|
|
8
|
+
* Returns only the active phase, trace, and the last 5 decisions/tasks.
|
|
9
|
+
*/
|
|
10
|
+
export function handleGetMemoryInsights(projectRoot: string, _args: ToolArgs): ToolResult {
|
|
11
|
+
try {
|
|
12
|
+
const frameworkDir = resolveFrameworkDir(projectRoot);
|
|
13
|
+
const memoryPath = path.join(projectRoot, frameworkDir, "memory/PROJECT_MEMORY.md");
|
|
14
|
+
|
|
15
|
+
if (!fs.existsSync(memoryPath)) {
|
|
16
|
+
return { content: [{ type: "text", text: "New project: No history available." }] };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const content = fs.readFileSync(memoryPath, "utf8");
|
|
20
|
+
const lines = content.split("\n");
|
|
21
|
+
|
|
22
|
+
const activePhase = lines.find(l => l.includes("Active Phase:"))?.split(":")[1]?.trim() || "Unknown";
|
|
23
|
+
const activeTrace = lines.find(l => l.includes("Active Trace:"))?.split(":")[1]?.trim() || "None";
|
|
24
|
+
|
|
25
|
+
// Find the last 5 history items (heuristic)
|
|
26
|
+
const historyStartIndex = lines.findIndex(l => l.includes("## History"));
|
|
27
|
+
let recentHistory = "No history found.";
|
|
28
|
+
if (historyStartIndex !== -1) {
|
|
29
|
+
recentHistory = lines.slice(historyStartIndex + 1, historyStartIndex + 15)
|
|
30
|
+
.filter(l => l.trim().startsWith("-"))
|
|
31
|
+
.slice(-5)
|
|
32
|
+
.join("\n");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const insights = `π§ **Memory Insights**\n- **Phase:** ${activePhase}\n- **Trace:** ${activeTrace}\n\n**Recent Actions:**\n${recentHistory}`;
|
|
36
|
+
|
|
37
|
+
return { content: [{ type: "text", text: insights }] };
|
|
38
|
+
} catch (e) {
|
|
39
|
+
return { isError: true, content: [{ type: "text", text: `Failed to extract insights: ${String(e)}` }] };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { resolveFrameworkDir } from "../../utils/security.js";
|
|
4
|
+
import { ToolArgs, ToolResult } from "../types.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Reads the project's central memory (PROJECT_MEMORY.md).
|
|
8
|
+
* This is the "brain" of the project.
|
|
9
|
+
*/
|
|
10
|
+
export function handleReadProjectMemory(projectRoot: string, _args: ToolArgs): ToolResult {
|
|
11
|
+
try {
|
|
12
|
+
const frameworkDir = resolveFrameworkDir(projectRoot);
|
|
13
|
+
const memoryPath = path.join(projectRoot, frameworkDir, "memory/PROJECT_MEMORY.md");
|
|
14
|
+
|
|
15
|
+
if (!fs.existsSync(memoryPath)) {
|
|
16
|
+
return {
|
|
17
|
+
content: [{ type: "text", text: "βΉοΈ Project memory file not found. It might be a new project." }]
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const content = fs.readFileSync(memoryPath, "utf8");
|
|
22
|
+
return {
|
|
23
|
+
content: [{ type: "text", text: content }]
|
|
24
|
+
};
|
|
25
|
+
} catch (e) {
|
|
26
|
+
return {
|
|
27
|
+
isError: true,
|
|
28
|
+
content: [{ type: "text", text: `Failed to read project memory: ${String(e)}` }]
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -11,7 +11,7 @@ export async function handleSendAgentMessage(projectRoot: string, args: ToolArgs
|
|
|
11
11
|
const messagesDir = path.join(projectRoot, frameworkDir, "messages");
|
|
12
12
|
const agentName = to.replace("@", "");
|
|
13
13
|
const messagePath = path.join(messagesDir, `${agentName}.json`);
|
|
14
|
-
const lockPath = path.join(messagesDir,
|
|
14
|
+
const lockPath = path.join(messagesDir, `${agentName}.lock`);
|
|
15
15
|
|
|
16
16
|
// Hermes Lock Protocol: Retry 3 times with 500ms delay
|
|
17
17
|
let retries = 3;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import { ToolArgs, ToolResult } from "../types.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Checks for active network ports and their status.
|
|
6
|
+
*/
|
|
7
|
+
export function handleCheckPorts(projectRoot: string, args: ToolArgs): ToolResult {
|
|
8
|
+
const filter = args.filter as string || ""; // Optional filter (e.g., ":3000")
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
// Using 'lsof -i -P -n' to list open files and network connections
|
|
12
|
+
// Note: may require permissions or behave differently on non-Unix systems
|
|
13
|
+
const command = process.platform === "win32"
|
|
14
|
+
? `netstat -ano | findstr LISTENING ${filter ? `| findstr ${filter}` : ""}`
|
|
15
|
+
: `lsof -i -P -n | grep LISTEN ${filter ? `| grep ${filter}` : ""}`;
|
|
16
|
+
|
|
17
|
+
const output = execSync(command, { encoding: "utf8" });
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
content: [{
|
|
21
|
+
type: "text",
|
|
22
|
+
text: `π‘ **Active Listening Ports:**\n\n${output || "No active listening ports found matching filter."}`
|
|
23
|
+
}]
|
|
24
|
+
};
|
|
25
|
+
} catch (e) {
|
|
26
|
+
return {
|
|
27
|
+
content: [{ type: "text", text: "βΉοΈ No active ports found or command failed (this is normal if nothing is listening)." }]
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import os from "os";
|
|
2
|
+
import { ToolArgs, ToolResult } from "../types.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Retrieves system health metrics including CPU load and memory usage.
|
|
6
|
+
*/
|
|
7
|
+
export function handleGetSystemHealth(projectRoot: string, args: ToolArgs): ToolResult {
|
|
8
|
+
const totalMem = os.totalmem();
|
|
9
|
+
const freeMem = os.freemem();
|
|
10
|
+
const usedMem = totalMem - freeMem;
|
|
11
|
+
const memUsagePercent = ((usedMem / totalMem) * 100).toFixed(2);
|
|
12
|
+
|
|
13
|
+
const cpus = os.cpus();
|
|
14
|
+
const loadAvg = os.loadavg(); // [1, 5, 15] minute averages
|
|
15
|
+
|
|
16
|
+
const healthReport = `π₯οΈ **System Health Report**
|
|
17
|
+
- **Memory:** ${memUsagePercent}% used (${(usedMem / 1024 / 1024 / 1024).toFixed(2)} GB / ${(totalMem / 1024 / 1024 / 1024).toFixed(2)} GB)
|
|
18
|
+
- **CPU Load (1m, 5m, 15m):** ${loadAvg.map(l => l.toFixed(2)).join(", ")}
|
|
19
|
+
- **Platform:** ${os.platform()} (${os.release()})
|
|
20
|
+
- **Uptime:** ${(os.uptime() / 3600).toFixed(2)} hours`;
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
content: [{ type: "text", text: healthReport }]
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { safePath } from "../../utils/security.js";
|
|
4
|
+
import { ToolArgs, ToolResult } from "../types.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Scans the codebase for TODOs, FIXMEs, and empty function bodies.
|
|
8
|
+
* Helps identify what's left and where the agent might have skipped logic.
|
|
9
|
+
*/
|
|
10
|
+
export function handleGetProjectGaps(projectRoot: string, args: ToolArgs): ToolResult {
|
|
11
|
+
const srcDir = safePath(projectRoot, args.path as string || "src");
|
|
12
|
+
const results: string[] = [];
|
|
13
|
+
|
|
14
|
+
const walk = (dir: string) => {
|
|
15
|
+
if (!fs.existsSync(dir)) return;
|
|
16
|
+
const files = fs.readdirSync(dir);
|
|
17
|
+
for (const file of files) {
|
|
18
|
+
const fullPath = path.join(dir, file);
|
|
19
|
+
const relativePath = path.relative(projectRoot, fullPath);
|
|
20
|
+
|
|
21
|
+
if (fs.statSync(fullPath).isDirectory()) {
|
|
22
|
+
if (file !== "node_modules" && file !== "dist" && !file.startsWith(".")) {
|
|
23
|
+
walk(fullPath);
|
|
24
|
+
}
|
|
25
|
+
} else if (file.endsWith(".ts") || file.endsWith(".tsx")) {
|
|
26
|
+
const content = fs.readFileSync(fullPath, "utf8");
|
|
27
|
+
const lines = content.split("\n");
|
|
28
|
+
|
|
29
|
+
lines.forEach((line, index) => {
|
|
30
|
+
// 1. Scan for markers
|
|
31
|
+
if (line.includes("TODO") || line.includes("FIXME") || line.includes("!!!")) {
|
|
32
|
+
results.push(`[${relativePath}:${index + 1}] Marker found: ${line.trim()}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 2. Scan for empty function placeholders (heuristic)
|
|
36
|
+
if (line.includes("throw new Error(\"Not implemented") || line.includes("// ... rest of code")) {
|
|
37
|
+
results.push(`[${relativePath}:${index + 1}] Gap found: ${line.trim()}`);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
walk(srcDir);
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
content: [{
|
|
48
|
+
type: "text",
|
|
49
|
+
text: results.length > 0
|
|
50
|
+
? `Found ${results.length} gaps/todos:\n\n${results.join("\n")}`
|
|
51
|
+
: "β
No major gaps or TODOs found in the scanned directory."
|
|
52
|
+
}]
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { safePath } from "../../utils/security.js";
|
|
4
|
+
import { ToolArgs, ToolResult } from "../types.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Generates a tree-view map of the project structure.
|
|
8
|
+
* Helps agents visualize the entire project layout quickly.
|
|
9
|
+
*/
|
|
10
|
+
export function handleGetProjectMap(projectRoot: string, args: ToolArgs): ToolResult {
|
|
11
|
+
const maxDepth = Number(args.maxDepth) || 3;
|
|
12
|
+
const includeFiles = args.includeFiles !== false;
|
|
13
|
+
|
|
14
|
+
const buildTree = (dir: string, depth: number): string[] => {
|
|
15
|
+
if (depth > maxDepth) return [];
|
|
16
|
+
|
|
17
|
+
const results: string[] = [];
|
|
18
|
+
const files = fs.readdirSync(dir);
|
|
19
|
+
|
|
20
|
+
files.forEach(file => {
|
|
21
|
+
if (file === "node_modules" || file === ".git" || file === "dist" || file.startsWith(".")) return;
|
|
22
|
+
|
|
23
|
+
const fullPath = path.join(dir, file);
|
|
24
|
+
const relativePath = path.relative(projectRoot, fullPath);
|
|
25
|
+
const stat = fs.statSync(fullPath);
|
|
26
|
+
const indent = " ".repeat(depth);
|
|
27
|
+
|
|
28
|
+
if (stat.isDirectory()) {
|
|
29
|
+
results.push(`${indent}π ${file}/`);
|
|
30
|
+
results.push(...buildTree(fullPath, depth + 1));
|
|
31
|
+
} else if (includeFiles) {
|
|
32
|
+
results.push(`${indent}π ${file}`);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
return results;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
const tree = buildTree(projectRoot, 0);
|
|
41
|
+
return {
|
|
42
|
+
content: [{
|
|
43
|
+
type: "text",
|
|
44
|
+
text: `πΊοΈ **Project Map (Depth: ${maxDepth})**\n\n${tree.join("\n")}`
|
|
45
|
+
}]
|
|
46
|
+
};
|
|
47
|
+
} catch (e) {
|
|
48
|
+
return { isError: true, content: [{ type: "text", text: `Failed to map project: ${String(e)}` }] };
|
|
49
|
+
}
|
|
50
|
+
}
|