@alecsibilia/luca 13.0.0-alpha.1
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/LICENSE +201 -0
- package/README.md +47 -0
- package/bin/luca.js +3 -0
- package/dist/chunks/branch.mjs +47 -0
- package/dist/chunks/bun-runtime.mjs +46 -0
- package/dist/chunks/checks.mjs +53 -0
- package/dist/chunks/claim-verify.mjs +465 -0
- package/dist/chunks/classify.mjs +105 -0
- package/dist/chunks/confidence.mjs +199 -0
- package/dist/chunks/doctor.mjs +158 -0
- package/dist/chunks/hook.mjs +696 -0
- package/dist/chunks/init.mjs +715 -0
- package/dist/chunks/muninndb-health.mjs +66 -0
- package/dist/chunks/phase.mjs +38 -0
- package/dist/chunks/pr-review.mjs +122 -0
- package/dist/chunks/preferences.mjs +61 -0
- package/dist/chunks/repair.mjs +111 -0
- package/dist/chunks/repo.mjs +58 -0
- package/dist/chunks/retro.mjs +86 -0
- package/dist/chunks/roadmap.mjs +58 -0
- package/dist/chunks/rules.mjs +527 -0
- package/dist/chunks/stale-mcp-server.mjs +90 -0
- package/dist/chunks/state.mjs +57 -0
- package/dist/chunks/stray-local-install.mjs +200 -0
- package/dist/chunks/telemetry.mjs +165 -0
- package/dist/chunks/todo.mjs +151 -0
- package/dist/chunks/vault-init.mjs +300 -0
- package/dist/chunks/verification.mjs +95 -0
- package/dist/chunks/version.mjs +70 -0
- package/dist/chunks/workflow.mjs +47 -0
- package/dist/claude/.claude/agents/architect.md +410 -0
- package/dist/claude/.claude/agents/build.md +111 -0
- package/dist/claude/.claude/agents/discuss.md +93 -0
- package/dist/claude/.claude/agents/discussion.md +149 -0
- package/dist/claude/.claude/agents/execute.md +416 -0
- package/dist/claude/.claude/agents/executor.md +161 -0
- package/dist/claude/.claude/agents/fast.md +84 -0
- package/dist/claude/.claude/agents/finalize.md +484 -0
- package/dist/claude/.claude/agents/learner.md +160 -0
- package/dist/claude/.claude/agents/plan-reviewer.md +129 -0
- package/dist/claude/.claude/agents/plan.md +96 -0
- package/dist/claude/.claude/agents/research.md +327 -0
- package/dist/claude/.claude/agents/researcher.md +78 -0
- package/dist/claude/.claude/agents/review.md +283 -0
- package/dist/claude/.claude/agents/reviewer.md +163 -0
- package/dist/claude/.claude/agents/shadow-scanner.md +257 -0
- package/dist/claude/.claude/agents/triage.md +230 -0
- package/dist/claude/.claude/agents/verifier.md +131 -0
- package/dist/claude/.claude/commands/bug-diagnose.md +12 -0
- package/dist/claude/.claude/commands/gh-issue-triage.md +14 -0
- package/dist/claude/.claude/commands/gh-pr-address.md +235 -0
- package/dist/claude/.claude/commands/gh-prepare.md +12 -0
- package/dist/claude/.claude/commands/grill-me.md +12 -0
- package/dist/claude/.claude/commands/lu-review.md +51 -0
- package/dist/claude/.claude/commands/lu.md +75 -0
- package/dist/claude/.claude/commands/luca-init.md +14 -0
- package/dist/claude/.claude/commands/luca-telemetry-report.md +12 -0
- package/dist/claude/.claude/commands/memory-audit.md +12 -0
- package/dist/claude/.claude/commands/milestone-new.md +122 -0
- package/dist/claude/.claude/commands/phase-discuss.md +45 -0
- package/dist/claude/.claude/commands/phase-execute.md +39 -0
- package/dist/claude/.claude/commands/phase-plan.md +53 -0
- package/dist/claude/.claude/commands/repo-cleanup.md +80 -0
- package/dist/claude/.claude/commands/todo-add.md +28 -0
- package/dist/claude/.claude/commands/todo-check.md +36 -0
- package/dist/claude/.claude/hooks/context-refresher.ts +285 -0
- package/dist/claude/.claude/hooks/continuation-messages.ts +215 -0
- package/dist/claude/.claude/hooks/pipeline-guard.ts +182 -0
- package/dist/claude/.claude/settings.json +41 -0
- package/dist/claude/skills/arch-audit/SKILL.md +161 -0
- package/dist/claude/skills/autopilot/SKILL.md +1299 -0
- package/dist/claude/skills/bug-diagnose/SKILL.md +102 -0
- package/dist/claude/skills/choose/SKILL.md +124 -0
- package/dist/claude/skills/gh-issue-triage/SKILL.md +97 -0
- package/dist/claude/skills/gh-pr-address/SKILL.md +235 -0
- package/dist/claude/skills/gh-prepare/SKILL.md +209 -0
- package/dist/claude/skills/grill-me/SKILL.md +46 -0
- package/dist/claude/skills/lu/SKILL.md +112 -0
- package/dist/claude/skills/lu-review/SKILL.md +51 -0
- package/dist/claude/skills/luca-init/SKILL.md +91 -0
- package/dist/claude/skills/luca-telemetry-report/SKILL.md +145 -0
- package/dist/claude/skills/luca-write-surface/SKILL.md +213 -0
- package/dist/claude/skills/memory-audit/SKILL.md +217 -0
- package/dist/claude/skills/milestone-audit/SKILL.md +545 -0
- package/dist/claude/skills/milestone-complete/SKILL.md +168 -0
- package/dist/claude/skills/milestone-gaps/SKILL.md +60 -0
- package/dist/claude/skills/milestone-new/SKILL.md +125 -0
- package/dist/claude/skills/note/SKILL.md +162 -0
- package/dist/claude/skills/phase-add/SKILL.md +91 -0
- package/dist/claude/skills/phase-assumptions/SKILL.md +92 -0
- package/dist/claude/skills/phase-discuss/SKILL.md +165 -0
- package/dist/claude/skills/phase-execute/SKILL.md +1786 -0
- package/dist/claude/skills/phase-insert/SKILL.md +100 -0
- package/dist/claude/skills/phase-plan/SKILL.md +461 -0
- package/dist/claude/skills/phase-remove/SKILL.md +113 -0
- package/dist/claude/skills/phase-research/SKILL.md +80 -0
- package/dist/claude/skills/post-init-tour/SKILL.md +58 -0
- package/dist/claude/skills/progress/SKILL.md +271 -0
- package/dist/claude/skills/project-new/SKILL.md +609 -0
- package/dist/claude/skills/quick/SKILL.md +256 -0
- package/dist/claude/skills/rename-audit/SKILL.md +52 -0
- package/dist/claude/skills/repo-audit/SKILL.md +88 -0
- package/dist/claude/skills/repo-cleanup/SKILL.md +80 -0
- package/dist/claude/skills/seed-memory/SKILL.md +235 -0
- package/dist/claude/skills/session-pause/SKILL.md +126 -0
- package/dist/claude/skills/session-plan/SKILL.md +112 -0
- package/dist/claude/skills/session-resume/SKILL.md +75 -0
- package/dist/claude/skills/todo-add/SKILL.md +85 -0
- package/dist/claude/skills/todo-check/SKILL.md +77 -0
- package/dist/claude/skills/workflow-save/SKILL.md +277 -0
- package/dist/index.d.mts +33 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.mjs +69 -0
- package/dist/shared/luca.B3Mimc0P.mjs +52 -0
- package/dist/shared/luca.B3saVjJm.mjs +163 -0
- package/dist/shared/luca.BYdjkfnz.mjs +217 -0
- package/dist/shared/luca.BmhNkYe2.mjs +56 -0
- package/dist/shared/luca.C4gMUoBd.mjs +358 -0
- package/dist/shared/luca.CQ3g1xrD.mjs +19 -0
- package/dist/shared/luca.CRmaAfXR.mjs +713 -0
- package/dist/shared/luca.CrXzXueR.mjs +57 -0
- package/dist/shared/luca.DTomPq7I.mjs +91 -0
- package/dist/shared/luca.DjDTeDCi.mjs +1904 -0
- package/dist/shared/luca.HZxBTBgD.mjs +201 -0
- package/dist/shared/luca.TSMg1t7I.mjs +10 -0
- package/dist/shared/luca.dM-MKlNE.mjs +25 -0
- package/dist/shared/luca.naWEcQ4B.mjs +7 -0
- package/package.json +76 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { defineCommand } from 'citty';
|
|
2
|
+
import '../shared/luca.CRmaAfXR.mjs';
|
|
3
|
+
import { l as loadCurrentState, r as resolveActiveSlug } from '../shared/luca.CrXzXueR.mjs';
|
|
4
|
+
import 'node:fs';
|
|
5
|
+
import 'node:fs/promises';
|
|
6
|
+
import 'node:path';
|
|
7
|
+
import 'node:crypto';
|
|
8
|
+
import 'node:module';
|
|
9
|
+
import 'node:url';
|
|
10
|
+
import 'node:child_process';
|
|
11
|
+
import { b as renderConfidenceJournalMarkdown, r as readConfidenceJournal, g as getConfidenceSummary } from '../shared/luca.HZxBTBgD.mjs';
|
|
12
|
+
import { l as logger } from '../shared/luca.dM-MKlNE.mjs';
|
|
13
|
+
import 'zod';
|
|
14
|
+
import { c as readJsonPayload, r as runWriteHandler, t as lucaConfidenceLogTool } from '../shared/luca.DjDTeDCi.mjs';
|
|
15
|
+
import 'node:os';
|
|
16
|
+
import '../shared/luca.TSMg1t7I.mjs';
|
|
17
|
+
import 'consola';
|
|
18
|
+
import '../shared/luca.CQ3g1xrD.mjs';
|
|
19
|
+
import '../shared/luca.B3Mimc0P.mjs';
|
|
20
|
+
|
|
21
|
+
async function resolveSlug(opts) {
|
|
22
|
+
if (opts.explicit) return opts.explicit;
|
|
23
|
+
const state = await loadCurrentState({ cwd: opts.cwd });
|
|
24
|
+
const r = resolveActiveSlug(state);
|
|
25
|
+
if (!r.ok) {
|
|
26
|
+
logger.error(`luca confidence: ${r.error}`);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
return r.slug;
|
|
30
|
+
}
|
|
31
|
+
function splitCsv(input) {
|
|
32
|
+
if (!input) return [];
|
|
33
|
+
return input.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
34
|
+
}
|
|
35
|
+
const logCommand = defineCommand({
|
|
36
|
+
meta: {
|
|
37
|
+
name: "log",
|
|
38
|
+
description: "Append a confidence entry to the active phase's confidence.jsonl (one JSONL line per call). Payload uses the canonical ConfidenceEntrySchema shape (phase, wave, task, confidence, category, decision, alternatives, reasoning, risk, files, reviewHint?). Phase-agnostic, but an active phase must exist."
|
|
39
|
+
},
|
|
40
|
+
args: {
|
|
41
|
+
// File-driven input (preferred for structured callers)
|
|
42
|
+
file: {
|
|
43
|
+
type: "string",
|
|
44
|
+
description: "Path to a JSON payload matching the canonical ConfidenceEntrySchema shape (minus `timestamp`, which is server-stamped). When set, all other flags below are ignored."
|
|
45
|
+
},
|
|
46
|
+
// Flag-driven input (every field is also a CLI flag)
|
|
47
|
+
phase: {
|
|
48
|
+
type: "string",
|
|
49
|
+
description: "Phase name from the plan / roadmap."
|
|
50
|
+
},
|
|
51
|
+
wave: {
|
|
52
|
+
type: "string",
|
|
53
|
+
description: "Wave number within the phase (parsed as a number)."
|
|
54
|
+
},
|
|
55
|
+
task: {
|
|
56
|
+
type: "string",
|
|
57
|
+
description: "Task ID or description from the plan."
|
|
58
|
+
},
|
|
59
|
+
confidence: {
|
|
60
|
+
type: "string",
|
|
61
|
+
description: "high | medium | low."
|
|
62
|
+
},
|
|
63
|
+
category: {
|
|
64
|
+
type: "string",
|
|
65
|
+
description: "One of: plan-gap, design-choice, convention-unclear, requirement-ambiguous, dependency-unknown, scope-creep."
|
|
66
|
+
},
|
|
67
|
+
decision: {
|
|
68
|
+
type: "string",
|
|
69
|
+
description: "What the executor actually decided to do."
|
|
70
|
+
},
|
|
71
|
+
alternatives: {
|
|
72
|
+
type: "string",
|
|
73
|
+
description: 'Comma-separated list of other options considered (e.g. `--alternatives="a,b,c"`).'
|
|
74
|
+
},
|
|
75
|
+
reasoning: {
|
|
76
|
+
type: "string",
|
|
77
|
+
description: "Why this choice was made over the alternatives."
|
|
78
|
+
},
|
|
79
|
+
risk: {
|
|
80
|
+
type: "string",
|
|
81
|
+
description: "What could go wrong if this was the wrong call."
|
|
82
|
+
},
|
|
83
|
+
files: {
|
|
84
|
+
type: "string",
|
|
85
|
+
description: 'Comma-separated list of files affected by this decision (e.g. `--files="src/a.ts,src/b.ts"`).'
|
|
86
|
+
},
|
|
87
|
+
"review-hint": {
|
|
88
|
+
type: "string",
|
|
89
|
+
description: "Optional. Suggested focus area for a human reviewer."
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
async run({ args }) {
|
|
93
|
+
let payload;
|
|
94
|
+
if (args.file) {
|
|
95
|
+
const fromFile = await readJsonPayload("confidence log", args.file);
|
|
96
|
+
if (typeof fromFile !== "object" || fromFile === null || Array.isArray(fromFile)) {
|
|
97
|
+
logger.error(
|
|
98
|
+
`luca confidence log: --file payload must be a JSON object.`
|
|
99
|
+
);
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
payload = fromFile;
|
|
103
|
+
} else {
|
|
104
|
+
payload = {
|
|
105
|
+
phase: args.phase,
|
|
106
|
+
wave: args.wave !== void 0 ? Number(args.wave) : void 0,
|
|
107
|
+
task: args.task,
|
|
108
|
+
confidence: args.confidence,
|
|
109
|
+
category: args.category,
|
|
110
|
+
decision: args.decision,
|
|
111
|
+
alternatives: splitCsv(args.alternatives),
|
|
112
|
+
reasoning: args.reasoning,
|
|
113
|
+
risk: args.risk,
|
|
114
|
+
files: splitCsv(args.files),
|
|
115
|
+
...args["review-hint"] !== void 0 ? { reviewHint: args["review-hint"] } : {}
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
await runWriteHandler(
|
|
119
|
+
"confidence log",
|
|
120
|
+
lucaConfidenceLogTool,
|
|
121
|
+
payload
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
const readCommand = defineCommand({
|
|
126
|
+
meta: {
|
|
127
|
+
name: "read",
|
|
128
|
+
description: "Read every entry in a phase's confidence.jsonl as a JSON array."
|
|
129
|
+
},
|
|
130
|
+
args: {
|
|
131
|
+
slug: {
|
|
132
|
+
type: "string",
|
|
133
|
+
description: "Phase slug to read (default: the active phase)."
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
async run({ args }) {
|
|
137
|
+
const cwd = process.cwd();
|
|
138
|
+
const slug = await resolveSlug({ explicit: args.slug, cwd });
|
|
139
|
+
const entries = readConfidenceJournal({ cwd, slug });
|
|
140
|
+
process.stdout.write(`${JSON.stringify(entries, null, 2)}
|
|
141
|
+
`);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
const summaryCommand = defineCommand({
|
|
145
|
+
meta: {
|
|
146
|
+
name: "summary",
|
|
147
|
+
description: "Print aggregate counts (total / high / medium / low / categories) for a phase's confidence journal."
|
|
148
|
+
},
|
|
149
|
+
args: {
|
|
150
|
+
slug: {
|
|
151
|
+
type: "string",
|
|
152
|
+
description: "Phase slug to summarize (default: the active phase)."
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
async run({ args }) {
|
|
156
|
+
const cwd = process.cwd();
|
|
157
|
+
const slug = await resolveSlug({ explicit: args.slug, cwd });
|
|
158
|
+
const summary = getConfidenceSummary(
|
|
159
|
+
readConfidenceJournal({ cwd, slug })
|
|
160
|
+
);
|
|
161
|
+
process.stdout.write(`${JSON.stringify(summary, null, 2)}
|
|
162
|
+
`);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
const renderCommand = defineCommand({
|
|
166
|
+
meta: {
|
|
167
|
+
name: "render",
|
|
168
|
+
description: "Render a phase's confidence journal as Markdown (stdout)."
|
|
169
|
+
},
|
|
170
|
+
args: {
|
|
171
|
+
slug: {
|
|
172
|
+
type: "string",
|
|
173
|
+
description: "Phase slug to render (default: the active phase)."
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
async run({ args }) {
|
|
177
|
+
const cwd = process.cwd();
|
|
178
|
+
const slug = await resolveSlug({ explicit: args.slug, cwd });
|
|
179
|
+
const md = renderConfidenceJournalMarkdown(
|
|
180
|
+
readConfidenceJournal({ cwd, slug })
|
|
181
|
+
);
|
|
182
|
+
process.stdout.write(`${md}
|
|
183
|
+
`);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
const confidenceCommand = defineCommand({
|
|
187
|
+
meta: {
|
|
188
|
+
name: "confidence",
|
|
189
|
+
description: "Read and write the active phase's Luca confidence journal"
|
|
190
|
+
},
|
|
191
|
+
subCommands: {
|
|
192
|
+
log: logCommand,
|
|
193
|
+
read: readCommand,
|
|
194
|
+
summary: summaryCommand,
|
|
195
|
+
render: renderCommand
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
export { confidenceCommand };
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { defineCommand } from 'citty';
|
|
2
|
+
import { l as logger } from '../shared/luca.dM-MKlNE.mjs';
|
|
3
|
+
import 'consola';
|
|
4
|
+
|
|
5
|
+
async function executeDoctor(options = {}) {
|
|
6
|
+
const { verbose = false, scope, fix = false } = options;
|
|
7
|
+
logger.info("Running environment diagnostics...\n");
|
|
8
|
+
const { bunRuntimeCheck } = await import('./bun-runtime.mjs');
|
|
9
|
+
const { muninndbHealthCheck } = await import('./muninndb-health.mjs');
|
|
10
|
+
const { staleMcpServerCheck } = await import('./stale-mcp-server.mjs');
|
|
11
|
+
const { strayLocalInstallCheck } = await import('./stray-local-install.mjs');
|
|
12
|
+
const allChecks = [
|
|
13
|
+
// Prerequisites
|
|
14
|
+
bunRuntimeCheck,
|
|
15
|
+
staleMcpServerCheck,
|
|
16
|
+
// Global
|
|
17
|
+
muninndbHealthCheck,
|
|
18
|
+
// Project (cwd-dependent)
|
|
19
|
+
strayLocalInstallCheck
|
|
20
|
+
];
|
|
21
|
+
const checks = scope ? allChecks.filter((check) => check.scope === scope) : allChecks;
|
|
22
|
+
if (checks.length === 0) {
|
|
23
|
+
logger.warn(`No checks found for scope: ${scope}`);
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
const scopeLabel = scope ? ` (scope: ${scope})` : "";
|
|
27
|
+
const results = await Promise.all(checks.map((check) => check.run()));
|
|
28
|
+
const passCount = results.filter((r) => r.status === "pass").length;
|
|
29
|
+
const failCount = results.filter((r) => r.status === "fail").length;
|
|
30
|
+
const warningCount = results.filter((r) => r.status === "warning").length;
|
|
31
|
+
logger.info(`Environment Diagnostics${scopeLabel}`);
|
|
32
|
+
logger.info("=".repeat(50));
|
|
33
|
+
for (const result of results) {
|
|
34
|
+
const icon = result.status === "pass" ? "+" : result.status === "fail" ? "x" : "!";
|
|
35
|
+
const logLine = `${icon} ${result.name}: ${result.message}`;
|
|
36
|
+
if (result.status === "pass") {
|
|
37
|
+
logger.success(logLine);
|
|
38
|
+
} else if (result.status === "fail") {
|
|
39
|
+
logger.error(logLine);
|
|
40
|
+
} else {
|
|
41
|
+
logger.warn(logLine);
|
|
42
|
+
}
|
|
43
|
+
if (result.details && (verbose || result.status !== "pass")) {
|
|
44
|
+
logger.info(` ${result.details}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
logger.info("");
|
|
48
|
+
logger.info("=".repeat(50));
|
|
49
|
+
logger.info(
|
|
50
|
+
`Results: ${passCount} passing, ${failCount} failing, ${warningCount} warning(s)`
|
|
51
|
+
);
|
|
52
|
+
if (fix) {
|
|
53
|
+
await applyFixes(checks, results);
|
|
54
|
+
} else {
|
|
55
|
+
const fixableChecks = results.filter(
|
|
56
|
+
(r) => (r.status === "fail" || r.status === "warning") && r.fixCommand
|
|
57
|
+
);
|
|
58
|
+
if (fixableChecks.length > 0) {
|
|
59
|
+
logger.info("");
|
|
60
|
+
logger.info("Suggested fixes:");
|
|
61
|
+
logger.info("-".repeat(50));
|
|
62
|
+
for (const check of fixableChecks) {
|
|
63
|
+
if (check.fixCommand) {
|
|
64
|
+
logger.info(` ${check.name}:`);
|
|
65
|
+
logger.info(` ${check.fixCommand}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
logger.info("");
|
|
71
|
+
if (failCount > 0) {
|
|
72
|
+
if (!verbose) {
|
|
73
|
+
logger.error(
|
|
74
|
+
"Some checks failed. Run with --verbose for more details."
|
|
75
|
+
);
|
|
76
|
+
} else {
|
|
77
|
+
logger.error("Some checks failed.");
|
|
78
|
+
}
|
|
79
|
+
return 1;
|
|
80
|
+
}
|
|
81
|
+
if (warningCount > 0) {
|
|
82
|
+
logger.warn("All checks passed with warnings.");
|
|
83
|
+
return 0;
|
|
84
|
+
}
|
|
85
|
+
logger.success("All checks passed! Your environment is ready.");
|
|
86
|
+
return 0;
|
|
87
|
+
}
|
|
88
|
+
async function applyFixes(checks, results) {
|
|
89
|
+
const fixable = checks.map((check, index) => ({ check, result: results[index] })).filter(
|
|
90
|
+
(pair) => pair.result !== void 0 && pair.result.status !== "pass" && typeof pair.check.fix === "function"
|
|
91
|
+
);
|
|
92
|
+
if (fixable.length === 0) {
|
|
93
|
+
const hasIssues = results.some((result) => result.status !== "pass");
|
|
94
|
+
if (hasIssues) {
|
|
95
|
+
logger.info("");
|
|
96
|
+
logger.info("No automatic fixes available for the issues above.");
|
|
97
|
+
}
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
logger.info("");
|
|
101
|
+
logger.info("Applying fixes (--fix)");
|
|
102
|
+
logger.info("-".repeat(50));
|
|
103
|
+
for (const { check } of fixable) {
|
|
104
|
+
const fixResult = await check.fix();
|
|
105
|
+
for (const action of fixResult.applied) {
|
|
106
|
+
logger.success(`+ ${check.name}: ${action}`);
|
|
107
|
+
}
|
|
108
|
+
for (const error of fixResult.errors) {
|
|
109
|
+
logger.error(`x ${check.name}: ${error}`);
|
|
110
|
+
}
|
|
111
|
+
if (fixResult.applied.length === 0 && fixResult.errors.length === 0) {
|
|
112
|
+
logger.info(` ${check.name}: nothing to fix`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const VALID_SCOPES = ["prerequisites", "global", "project"];
|
|
118
|
+
const doctor = defineCommand({
|
|
119
|
+
meta: {
|
|
120
|
+
name: "doctor",
|
|
121
|
+
description: "Run environment diagnostics and health checks"
|
|
122
|
+
},
|
|
123
|
+
args: {
|
|
124
|
+
verbose: {
|
|
125
|
+
type: "boolean",
|
|
126
|
+
description: "Show detailed check information",
|
|
127
|
+
alias: "v",
|
|
128
|
+
default: false
|
|
129
|
+
},
|
|
130
|
+
scope: {
|
|
131
|
+
type: "string",
|
|
132
|
+
description: "Filter checks by scope: prerequisites, global, or project",
|
|
133
|
+
alias: "s"
|
|
134
|
+
},
|
|
135
|
+
fix: {
|
|
136
|
+
type: "boolean",
|
|
137
|
+
description: "Apply automatic fixes for issues that support remediation (e.g. stray local installs)",
|
|
138
|
+
default: false
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
async run({ args }) {
|
|
142
|
+
const scope = args.scope;
|
|
143
|
+
if (scope && !VALID_SCOPES.includes(scope)) {
|
|
144
|
+
console.error(
|
|
145
|
+
`Invalid --scope value: "${scope}". Valid options: ${VALID_SCOPES.join(", ")}`
|
|
146
|
+
);
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
const exitCode = await executeDoctor({
|
|
150
|
+
verbose: args.verbose,
|
|
151
|
+
scope,
|
|
152
|
+
fix: args.fix
|
|
153
|
+
});
|
|
154
|
+
process.exit(exitCode);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
export { doctor as default };
|