@elyracode/doctor 0.4.4 → 0.4.5
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 +15 -0
- package/extensions/index.ts +89 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ elyra install npm:@elyracode/doctor
|
|
|
11
11
|
## Commands
|
|
12
12
|
|
|
13
13
|
- `/doctor` -- Run all health checks and send the report to the agent for analysis
|
|
14
|
+
- `/doctor --heal` -- Run checks and auto-fix issues (the agent works through each finding step by step)
|
|
14
15
|
|
|
15
16
|
## Tools
|
|
16
17
|
|
|
@@ -41,6 +42,20 @@ elyra install npm:@elyracode/doctor
|
|
|
41
42
|
|
|
42
43
|
The agent runs the checks automatically and suggests fixes based on findings.
|
|
43
44
|
|
|
45
|
+
### Auto-Heal Mode
|
|
46
|
+
```
|
|
47
|
+
/doctor --heal
|
|
48
|
+
```
|
|
49
|
+
The agent works through each error and warning step by step:
|
|
50
|
+
- **Security**: runs `npm audit fix` / `composer update`
|
|
51
|
+
- **Dependencies**: updates outdated packages one by one
|
|
52
|
+
- **Configuration**: fills in missing .env keys
|
|
53
|
+
- **Code debt**: implements TODOs, resolves FIXMEs, cleans up HACKs
|
|
54
|
+
- **Code quality**: refactors large files into smaller modules
|
|
55
|
+
- **Project**: creates missing essential files
|
|
56
|
+
|
|
57
|
+
After each fix, the agent verifies the change didn't break anything.
|
|
58
|
+
|
|
44
59
|
## Report Format
|
|
45
60
|
|
|
46
61
|
```
|
package/extensions/index.ts
CHANGED
|
@@ -5,17 +5,37 @@ import { type Finding, runAllChecks } from "./checks.js";
|
|
|
5
5
|
export default function (elyra: ExtensionAPI): void {
|
|
6
6
|
// ── Command: /doctor ──
|
|
7
7
|
elyra.registerCommand("doctor", {
|
|
8
|
-
description: "Run project health analysis",
|
|
9
|
-
handler: async (
|
|
8
|
+
description: "Run project health analysis. Use --heal to auto-fix issues.",
|
|
9
|
+
handler: async (args: string, ctx) => {
|
|
10
|
+
const healMode = args.trim() === "--heal" || args.trim() === "heal";
|
|
11
|
+
|
|
10
12
|
ctx.ui.notify("Running health checks...");
|
|
11
13
|
|
|
12
14
|
const cwd = process.cwd();
|
|
13
15
|
const findings = runAllChecks(cwd);
|
|
14
16
|
const report = formatReport(findings);
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
if (healMode) {
|
|
19
|
+
const actionable = findings.filter((f) => f.severity === "error" || f.severity === "warning");
|
|
20
|
+
if (actionable.length === 0) {
|
|
21
|
+
elyra.sendUserMessage(
|
|
22
|
+
`Health check complete. No issues to fix.\n\n${report}`,
|
|
23
|
+
);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const healInstructions = formatHealInstructions(actionable);
|
|
28
|
+
elyra.sendUserMessage(
|
|
29
|
+
`Health check found ${actionable.length} issue${actionable.length > 1 ? "s" : ""} to fix. ` +
|
|
30
|
+
`Work through each one systematically. For each issue: analyze it, fix it if possible, and report what you did.\n\n` +
|
|
31
|
+
`${report}\n\n` +
|
|
32
|
+
`## Auto-Heal Instructions\n\n${healInstructions}`,
|
|
33
|
+
);
|
|
34
|
+
} else {
|
|
35
|
+
elyra.sendUserMessage(
|
|
36
|
+
`Here is the project health report. Analyze the findings and suggest the most important fixes:\n\n${report}`,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
19
39
|
},
|
|
20
40
|
});
|
|
21
41
|
|
|
@@ -109,3 +129,67 @@ function formatReport(findings: Finding[]): string {
|
|
|
109
129
|
|
|
110
130
|
return lines.join("\n");
|
|
111
131
|
}
|
|
132
|
+
|
|
133
|
+
function formatHealInstructions(findings: Finding[]): string {
|
|
134
|
+
const instructions: string[] = [];
|
|
135
|
+
let step = 1;
|
|
136
|
+
|
|
137
|
+
for (const f of findings) {
|
|
138
|
+
const action = getHealAction(f);
|
|
139
|
+
if (action) {
|
|
140
|
+
instructions.push(`### Step ${step}: ${f.category} -- ${f.message}`);
|
|
141
|
+
instructions.push(action);
|
|
142
|
+
instructions.push("");
|
|
143
|
+
step++;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (instructions.length === 0) {
|
|
148
|
+
return "No auto-healable issues found.";
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
instructions.push(`### Step ${step}: Verify`);
|
|
152
|
+
instructions.push("Run the health check again to verify all issues are resolved.");
|
|
153
|
+
|
|
154
|
+
return instructions.join("\n");
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function getHealAction(finding: Finding): string | undefined {
|
|
158
|
+
const msg = finding.message.toLowerCase();
|
|
159
|
+
const cat = finding.category.toLowerCase();
|
|
160
|
+
|
|
161
|
+
if (cat === "security" && msg.includes("npm")) {
|
|
162
|
+
return "Run `npm audit fix` to fix vulnerabilities automatically. If that doesn't resolve all issues, run `npm audit` to see which packages need manual updates, then update them with `npm install <package>@latest`.";
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (cat === "security" && msg.includes("composer")) {
|
|
166
|
+
return "Run `composer audit` to see affected packages, then `composer update <package>` for each one. Check that tests still pass after updating.";
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (cat === "dependencies" && msg.includes("outdated")) {
|
|
170
|
+
return "Run `npm outdated` to see the full list. Update packages one by one with `npm install <package>@latest`, running tests after each update to catch breaking changes.";
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (cat === "configuration" && msg.includes(".env file is missing")) {
|
|
174
|
+
return "Copy `.env.example` to `.env` with `cp .env.example .env`. Then read the example file and fill in the values that need customization (database credentials, API keys, etc.).";
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (cat === "configuration" && msg.includes("keys in .env.example missing")) {
|
|
178
|
+
return "Read `.env.example` to find the missing keys. For each one: check the codebase to understand what it controls, determine a sensible default value, and add it to `.env`.";
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (cat === "code debt") {
|
|
182
|
+
return "Read each TODO/FIXME/HACK comment. For each one: if the task is small, implement it now and remove the comment. If it's large, create a GitHub issue and update the comment with the issue number. Remove stale comments that no longer apply.";
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (cat === "code quality" && msg.includes("files over")) {
|
|
186
|
+
return "For each large file: read it and identify responsibilities that can be extracted into separate classes/functions/files. Refactor one file at a time, running tests after each change.";
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (cat === "project" && msg.includes("missing")) {
|
|
190
|
+
const file = finding.message.replace("Missing ", "");
|
|
191
|
+
return `Create the missing ${file}. Read similar files in the project for conventions, or use standard templates.`;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|