@harness-engineering/cli 1.9.0 → 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/dist/agents/skills/claude-code/enforce-architecture/SKILL.md +4 -0
- package/dist/agents/skills/claude-code/harness-autopilot/SKILL.md +7 -2
- package/dist/agents/skills/claude-code/harness-brainstorming/SKILL.md +10 -1
- package/dist/agents/skills/claude-code/harness-execution/SKILL.md +2 -2
- package/dist/agents/skills/claude-code/harness-parallel-agents/SKILL.md +105 -20
- package/dist/agents/skills/claude-code/harness-pre-commit-review/SKILL.md +37 -0
- package/dist/agents/skills/gemini-cli/enforce-architecture/SKILL.md +4 -0
- package/dist/agents/skills/gemini-cli/harness-autopilot/SKILL.md +7 -2
- package/dist/agents/skills/gemini-cli/harness-brainstorming/SKILL.md +10 -1
- package/dist/agents/skills/gemini-cli/harness-execution/SKILL.md +2 -2
- package/dist/agents/skills/gemini-cli/harness-parallel-agents/SKILL.md +105 -20
- package/dist/agents/skills/gemini-cli/harness-pre-commit-review/SKILL.md +37 -0
- package/dist/agents-md-ZFV6RR5J.js +8 -0
- package/dist/architecture-EXNUMH5R.js +13 -0
- package/dist/bin/harness-mcp.d.ts +1 -0
- package/dist/bin/harness-mcp.js +28 -0
- package/dist/bin/harness.js +42 -8
- package/dist/check-phase-gate-VZFOY2PO.js +12 -0
- package/dist/chunk-2NCIKJES.js +470 -0
- package/dist/chunk-2YPZKGAG.js +62 -0
- package/dist/{chunk-CGSHUJES.js → chunk-2YSQOUHO.js} +4484 -2688
- package/dist/chunk-3WGJMBKH.js +45 -0
- package/dist/{chunk-ULSRSP53.js → chunk-6N4R6FVX.js} +11 -112
- package/dist/{chunk-6JIT7CEM.js → chunk-72GHBOL2.js} +1 -1
- package/dist/chunk-BM3PWGXQ.js +14 -0
- package/dist/chunk-C2ERUR3L.js +255 -0
- package/dist/chunk-EBJQ6N4M.js +39 -0
- package/dist/chunk-GNGELAXY.js +293 -0
- package/dist/chunk-GSIVNYVJ.js +187 -0
- package/dist/chunk-HD4IBGLA.js +80 -0
- package/dist/chunk-I6JZYEGT.js +4361 -0
- package/dist/chunk-IDZNPTYD.js +16 -0
- package/dist/chunk-JSTQ3AWB.js +31 -0
- package/dist/chunk-K6XAPGML.js +27 -0
- package/dist/chunk-KET4QQZB.js +8 -0
- package/dist/chunk-L2KLU56K.js +125 -0
- package/dist/chunk-MHBMTPW7.js +29 -0
- package/dist/chunk-NC6PXVWT.js +116 -0
- package/dist/chunk-NKDM3FMH.js +52 -0
- package/dist/chunk-PA2XHK75.js +248 -0
- package/dist/chunk-Q6AB7W5Z.js +135 -0
- package/dist/chunk-QPEH2QPG.js +347 -0
- package/dist/chunk-TEFCFC4H.js +15 -0
- package/dist/chunk-TI4TGEX6.js +85 -0
- package/dist/chunk-TRAPF4IX.js +185 -0
- package/dist/chunk-VRFZWGMS.js +68 -0
- package/dist/chunk-VUCPTQ6G.js +67 -0
- package/dist/chunk-W6Y7ZW3Y.js +13 -0
- package/dist/chunk-WJZDO6OY.js +103 -0
- package/dist/chunk-WUJTCNOU.js +122 -0
- package/dist/chunk-X3MN5UQJ.js +89 -0
- package/dist/chunk-Z75JC6I2.js +189 -0
- package/dist/chunk-ZOAWBDWU.js +72 -0
- package/dist/{chunk-RTPHUDZS.js → chunk-ZWC3MN5E.js} +1944 -2779
- package/dist/ci-workflow-K5RCRNYR.js +8 -0
- package/dist/constants-5JGUXPEK.js +6 -0
- package/dist/create-skill-WPXHSLX2.js +11 -0
- package/dist/dist-D4RYGUZE.js +14 -0
- package/dist/{dist-C5PYIQPF.js → dist-JVZ2MKBC.js} +108 -6
- package/dist/dist-L7LAAQAS.js +18 -0
- package/dist/{dist-I7DB5VKB.js → dist-M6BQODWC.js} +1145 -0
- package/dist/docs-PWCUVYWU.js +12 -0
- package/dist/engine-6XUP6GAK.js +8 -0
- package/dist/entropy-4I6JEYAC.js +12 -0
- package/dist/feedback-TNIW534S.js +18 -0
- package/dist/generate-agent-definitions-MWKEA5NU.js +15 -0
- package/dist/glob-helper-5OHBUQAI.js +52 -0
- package/dist/graph-loader-KO4GJ5N2.js +8 -0
- package/dist/index.d.ts +328 -12
- package/dist/index.js +93 -34
- package/dist/loader-4FIPIFII.js +10 -0
- package/dist/mcp-MOKLYNZL.js +34 -0
- package/dist/performance-BTOJCPXU.js +24 -0
- package/dist/review-pipeline-3YTW3463.js +9 -0
- package/dist/runner-VMYLHWOC.js +6 -0
- package/dist/runtime-GO7K2PJE.js +9 -0
- package/dist/security-4P2GGFF6.js +9 -0
- package/dist/skill-executor-RG45LUO5.js +8 -0
- package/dist/templates/orchestrator/WORKFLOW.md +48 -0
- package/dist/templates/orchestrator/template.json +6 -0
- package/dist/validate-JN44D2Q7.js +12 -0
- package/dist/validate-cross-check-DB7RIFFF.js +8 -0
- package/dist/version-KFFPOQAX.js +6 -0
- package/package.json +13 -7
- package/dist/create-skill-UZOHMXRU.js +0 -8
- package/dist/validate-cross-check-VG573VZO.js +0 -7
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import {
|
|
2
|
+
listPersonas,
|
|
3
|
+
loadPersona
|
|
4
|
+
} from "./chunk-Q6AB7W5Z.js";
|
|
5
|
+
import {
|
|
6
|
+
toKebabCase
|
|
7
|
+
} from "./chunk-KET4QQZB.js";
|
|
8
|
+
import {
|
|
9
|
+
GENERATED_HEADER_AGENT,
|
|
10
|
+
VALID_PLATFORMS,
|
|
11
|
+
applySyncPlan,
|
|
12
|
+
computeSyncPlan
|
|
13
|
+
} from "./chunk-ZOAWBDWU.js";
|
|
14
|
+
import {
|
|
15
|
+
resolvePersonasDir,
|
|
16
|
+
resolveSkillsDir
|
|
17
|
+
} from "./chunk-HD4IBGLA.js";
|
|
18
|
+
import {
|
|
19
|
+
CLIError,
|
|
20
|
+
ExitCode,
|
|
21
|
+
handleError
|
|
22
|
+
} from "./chunk-3WGJMBKH.js";
|
|
23
|
+
|
|
24
|
+
// src/commands/generate-agent-definitions.ts
|
|
25
|
+
import { Command } from "commander";
|
|
26
|
+
import * as fs from "fs";
|
|
27
|
+
import * as path from "path";
|
|
28
|
+
import * as os from "os";
|
|
29
|
+
|
|
30
|
+
// src/agent-definitions/generator.ts
|
|
31
|
+
var AGENT_DESCRIPTIONS = {
|
|
32
|
+
"code-reviewer": "Perform code review and address review findings using harness methodology. Use when reviewing code, fixing review findings, responding to review feedback, or when a code review has produced issues that need to be addressed.",
|
|
33
|
+
"task-executor": "Execute implementation plans task-by-task with state tracking, TDD, and verification. Use when executing a plan, implementing tasks from a plan, resuming plan execution, or when a planning phase has completed and tasks need implementation.",
|
|
34
|
+
"parallel-coordinator": "Dispatch independent tasks across isolated agents for parallel execution. Use when multiple independent tasks need to run concurrently, splitting work across agents, or coordinating parallel implementation.",
|
|
35
|
+
"architecture-enforcer": "Validate architectural constraints and dependency rules. Use when checking layer boundaries, detecting circular dependencies, or verifying import direction compliance.",
|
|
36
|
+
"documentation-maintainer": "Keep documentation in sync with source code. Use when detecting documentation drift, validating doc coverage, or aligning docs with code changes.",
|
|
37
|
+
"entropy-cleaner": "Detect and fix codebase entropy including drift, dead code, and pattern violations. Use when running cleanup, detecting dead code, or fixing pattern violations.",
|
|
38
|
+
planner: "Create detailed implementation plans from specs with task breakdown, dependency ordering, and checkpoint placement. Use when planning a phase, breaking a spec into tasks, or creating an execution plan.",
|
|
39
|
+
verifier: "Verify implementation completeness against spec and plan at three tiers (EXISTS, SUBSTANTIVE, WIRED). Use when checking if built code matches what was planned, validating phase completion, or auditing implementation quality."
|
|
40
|
+
};
|
|
41
|
+
var DEFAULT_TOOLS = ["Bash", "Read", "Write", "Edit", "Glob", "Grep"];
|
|
42
|
+
var GEMINI_TOOL_MAP = {
|
|
43
|
+
Bash: "run_shell_command",
|
|
44
|
+
Read: "read_file",
|
|
45
|
+
Write: "write_file",
|
|
46
|
+
Edit: "replace",
|
|
47
|
+
Glob: "glob",
|
|
48
|
+
Grep: "search_file_content"
|
|
49
|
+
};
|
|
50
|
+
function generateAgentDefinition(persona, skillContents) {
|
|
51
|
+
const kebabName = toKebabCase(persona.name);
|
|
52
|
+
const name = `harness-${kebabName}`;
|
|
53
|
+
const description = AGENT_DESCRIPTIONS[kebabName] ?? persona.description;
|
|
54
|
+
const methodologyParts = [];
|
|
55
|
+
for (const skillName of persona.skills) {
|
|
56
|
+
const content = skillContents.get(skillName);
|
|
57
|
+
if (content) {
|
|
58
|
+
methodologyParts.push(content);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
name,
|
|
63
|
+
description,
|
|
64
|
+
tools: [...DEFAULT_TOOLS],
|
|
65
|
+
role: persona.role,
|
|
66
|
+
skills: persona.skills,
|
|
67
|
+
steps: persona.steps,
|
|
68
|
+
methodology: methodologyParts.join("\n\n---\n\n")
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// src/agent-definitions/render-claude-code.ts
|
|
73
|
+
function formatStep(step, index) {
|
|
74
|
+
if ("command" in step && step.command) {
|
|
75
|
+
const cmd = step.command;
|
|
76
|
+
const when = step.when ?? "always";
|
|
77
|
+
return `${index + 1}. Run \`harness ${cmd}\` (${when})`;
|
|
78
|
+
}
|
|
79
|
+
if ("skill" in step && step.skill) {
|
|
80
|
+
const skill = step.skill;
|
|
81
|
+
const when = step.when ?? "always";
|
|
82
|
+
return `${index + 1}. Execute ${skill} skill (${when})`;
|
|
83
|
+
}
|
|
84
|
+
return `${index + 1}. Unknown step`;
|
|
85
|
+
}
|
|
86
|
+
function renderClaudeCodeAgent(def) {
|
|
87
|
+
const lines = ["---"];
|
|
88
|
+
lines.push(`name: ${def.name}`);
|
|
89
|
+
lines.push(`description: >`);
|
|
90
|
+
lines.push(` ${def.description}`);
|
|
91
|
+
lines.push(`tools: ${def.tools.join(", ")}`);
|
|
92
|
+
lines.push("---");
|
|
93
|
+
lines.push("");
|
|
94
|
+
lines.push(GENERATED_HEADER_AGENT);
|
|
95
|
+
lines.push("");
|
|
96
|
+
lines.push("## Role");
|
|
97
|
+
lines.push("");
|
|
98
|
+
lines.push(def.role);
|
|
99
|
+
lines.push("");
|
|
100
|
+
lines.push("## Skills");
|
|
101
|
+
lines.push("");
|
|
102
|
+
for (const skill of def.skills) {
|
|
103
|
+
lines.push(`- ${skill}`);
|
|
104
|
+
}
|
|
105
|
+
lines.push("");
|
|
106
|
+
lines.push("## Steps");
|
|
107
|
+
lines.push("");
|
|
108
|
+
def.steps.forEach((step, i) => {
|
|
109
|
+
lines.push(formatStep(step, i));
|
|
110
|
+
});
|
|
111
|
+
lines.push("");
|
|
112
|
+
if (def.methodology) {
|
|
113
|
+
lines.push("## Methodology");
|
|
114
|
+
lines.push("");
|
|
115
|
+
lines.push(def.methodology);
|
|
116
|
+
lines.push("");
|
|
117
|
+
}
|
|
118
|
+
return lines.join("\n");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// src/agent-definitions/render-gemini-cli.ts
|
|
122
|
+
function toGeminiToolName(tool) {
|
|
123
|
+
return GEMINI_TOOL_MAP[tool] ?? tool;
|
|
124
|
+
}
|
|
125
|
+
function formatStep2(step, index) {
|
|
126
|
+
if ("command" in step && step.command) {
|
|
127
|
+
const cmd = step.command;
|
|
128
|
+
const when = step.when ?? "always";
|
|
129
|
+
return `${index + 1}. Run \`harness ${cmd}\` (${when})`;
|
|
130
|
+
}
|
|
131
|
+
if ("skill" in step && step.skill) {
|
|
132
|
+
const skill = step.skill;
|
|
133
|
+
const when = step.when ?? "always";
|
|
134
|
+
return `${index + 1}. Execute ${skill} skill (${when})`;
|
|
135
|
+
}
|
|
136
|
+
return `${index + 1}. Unknown step`;
|
|
137
|
+
}
|
|
138
|
+
function renderGeminiAgent(def) {
|
|
139
|
+
const lines = ["---"];
|
|
140
|
+
lines.push(`name: ${def.name}`);
|
|
141
|
+
lines.push(`description: >`);
|
|
142
|
+
lines.push(` ${def.description}`);
|
|
143
|
+
if (def.tools.length > 0) {
|
|
144
|
+
lines.push("tools:");
|
|
145
|
+
for (const tool of def.tools) {
|
|
146
|
+
lines.push(` - ${toGeminiToolName(tool)}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
lines.push("---");
|
|
150
|
+
lines.push("");
|
|
151
|
+
lines.push(GENERATED_HEADER_AGENT);
|
|
152
|
+
lines.push("");
|
|
153
|
+
lines.push("## Role");
|
|
154
|
+
lines.push("");
|
|
155
|
+
lines.push(def.role);
|
|
156
|
+
lines.push("");
|
|
157
|
+
lines.push("## Skills");
|
|
158
|
+
lines.push("");
|
|
159
|
+
for (const skill of def.skills) {
|
|
160
|
+
lines.push(`- ${skill}`);
|
|
161
|
+
}
|
|
162
|
+
lines.push("");
|
|
163
|
+
lines.push("## Steps");
|
|
164
|
+
lines.push("");
|
|
165
|
+
def.steps.forEach((step, i) => {
|
|
166
|
+
lines.push(formatStep2(step, i));
|
|
167
|
+
});
|
|
168
|
+
lines.push("");
|
|
169
|
+
if (def.methodology) {
|
|
170
|
+
lines.push("## Methodology");
|
|
171
|
+
lines.push("");
|
|
172
|
+
lines.push(def.methodology);
|
|
173
|
+
lines.push("");
|
|
174
|
+
}
|
|
175
|
+
return lines.join("\n");
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// src/commands/generate-agent-definitions.ts
|
|
179
|
+
function resolveOutputDir(platform, opts) {
|
|
180
|
+
if (opts.output) {
|
|
181
|
+
return platform === "claude-code" ? path.join(opts.output, "claude-code") : path.join(opts.output, "gemini-cli");
|
|
182
|
+
}
|
|
183
|
+
if (opts.global) {
|
|
184
|
+
const home = os.homedir();
|
|
185
|
+
return platform === "claude-code" ? path.join(home, ".claude", "agents") : path.join(home, ".gemini", "agents");
|
|
186
|
+
}
|
|
187
|
+
return platform === "claude-code" ? path.join("agents", "agents", "claude-code") : path.join("agents", "agents", "gemini-cli");
|
|
188
|
+
}
|
|
189
|
+
function loadSkillContent(skillName) {
|
|
190
|
+
const skillsDir = resolveSkillsDir();
|
|
191
|
+
const skillMdPath = path.join(skillsDir, skillName, "SKILL.md");
|
|
192
|
+
if (!fs.existsSync(skillMdPath)) return null;
|
|
193
|
+
return fs.readFileSync(skillMdPath, "utf-8");
|
|
194
|
+
}
|
|
195
|
+
function getRenderer(platform) {
|
|
196
|
+
return platform === "claude-code" ? renderClaudeCodeAgent : renderGeminiAgent;
|
|
197
|
+
}
|
|
198
|
+
function generateAgentDefinitions(opts) {
|
|
199
|
+
const personasDir = resolvePersonasDir();
|
|
200
|
+
const personaList = listPersonas(personasDir);
|
|
201
|
+
if (!personaList.ok) return [];
|
|
202
|
+
const personas = personaList.value.map((meta) => loadPersona(meta.filePath)).filter((r) => r.ok).map((r) => r.value);
|
|
203
|
+
const allSkillNames = new Set(personas.flatMap((p) => p.skills));
|
|
204
|
+
const skillContents = /* @__PURE__ */ new Map();
|
|
205
|
+
for (const skillName of allSkillNames) {
|
|
206
|
+
const content = loadSkillContent(skillName);
|
|
207
|
+
if (content) {
|
|
208
|
+
skillContents.set(skillName, content);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const definitions = personas.map((p) => generateAgentDefinition(p, skillContents));
|
|
212
|
+
const results = [];
|
|
213
|
+
for (const platform of opts.platforms) {
|
|
214
|
+
const outputDir = resolveOutputDir(platform, opts);
|
|
215
|
+
const renderer = getRenderer(platform);
|
|
216
|
+
const rendered = /* @__PURE__ */ new Map();
|
|
217
|
+
for (const def of definitions) {
|
|
218
|
+
const filename = `${def.name}.md`;
|
|
219
|
+
rendered.set(filename, renderer(def));
|
|
220
|
+
}
|
|
221
|
+
const plan = computeSyncPlan(outputDir, rendered);
|
|
222
|
+
if (!opts.dryRun) {
|
|
223
|
+
applySyncPlan(outputDir, rendered, plan, false);
|
|
224
|
+
}
|
|
225
|
+
results.push({
|
|
226
|
+
platform,
|
|
227
|
+
added: plan.added,
|
|
228
|
+
updated: plan.updated,
|
|
229
|
+
removed: plan.removed,
|
|
230
|
+
unchanged: plan.unchanged,
|
|
231
|
+
outputDir
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
return results;
|
|
235
|
+
}
|
|
236
|
+
function createGenerateAgentDefinitionsCommand() {
|
|
237
|
+
return new Command("generate-agent-definitions").description("Generate agent definition files from personas for Claude Code and Gemini CLI").option("--platforms <list>", "Target platforms (comma-separated)", "claude-code,gemini-cli").option("--global", "Write to global agent directories", false).option("--output <dir>", "Custom output directory").option("--dry-run", "Show what would change without writing", false).action(async (opts, cmd) => {
|
|
238
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
239
|
+
const platforms = opts.platforms.split(",").map((p) => p.trim());
|
|
240
|
+
for (const p of platforms) {
|
|
241
|
+
if (!VALID_PLATFORMS.includes(p)) {
|
|
242
|
+
throw new CLIError(
|
|
243
|
+
`Invalid platform "${p}". Valid platforms: ${VALID_PLATFORMS.join(", ")}`,
|
|
244
|
+
ExitCode.VALIDATION_FAILED
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
try {
|
|
249
|
+
const results = generateAgentDefinitions({
|
|
250
|
+
platforms,
|
|
251
|
+
global: opts.global,
|
|
252
|
+
output: opts.output,
|
|
253
|
+
dryRun: opts.dryRun
|
|
254
|
+
});
|
|
255
|
+
if (globalOpts.json) {
|
|
256
|
+
console.log(JSON.stringify(results, null, 2));
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
for (const result of results) {
|
|
260
|
+
console.log(`
|
|
261
|
+
${result.platform} \u2192 ${result.outputDir}`);
|
|
262
|
+
if (result.added.length > 0) {
|
|
263
|
+
console.log(` + ${result.added.length} new: ${result.added.join(", ")}`);
|
|
264
|
+
}
|
|
265
|
+
if (result.updated.length > 0) {
|
|
266
|
+
console.log(` ~ ${result.updated.length} updated: ${result.updated.join(", ")}`);
|
|
267
|
+
}
|
|
268
|
+
if (result.removed.length > 0) {
|
|
269
|
+
console.log(` - ${result.removed.length} removed: ${result.removed.join(", ")}`);
|
|
270
|
+
}
|
|
271
|
+
if (result.unchanged.length > 0) {
|
|
272
|
+
console.log(` = ${result.unchanged.length} unchanged`);
|
|
273
|
+
}
|
|
274
|
+
if (opts.dryRun) {
|
|
275
|
+
console.log(" (dry run \u2014 no files written)");
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
} catch (error) {
|
|
279
|
+
handleError(error);
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export {
|
|
285
|
+
AGENT_DESCRIPTIONS,
|
|
286
|
+
DEFAULT_TOOLS,
|
|
287
|
+
GEMINI_TOOL_MAP,
|
|
288
|
+
generateAgentDefinition,
|
|
289
|
+
renderClaudeCodeAgent,
|
|
290
|
+
renderGeminiAgent,
|
|
291
|
+
generateAgentDefinitions,
|
|
292
|
+
createGenerateAgentDefinitionsCommand
|
|
293
|
+
};
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resultToMcpResponse
|
|
3
|
+
} from "./chunk-IDZNPTYD.js";
|
|
4
|
+
import {
|
|
5
|
+
sanitizePath
|
|
6
|
+
} from "./chunk-W6Y7ZW3Y.js";
|
|
7
|
+
import {
|
|
8
|
+
Ok
|
|
9
|
+
} from "./chunk-MHBMTPW7.js";
|
|
10
|
+
|
|
11
|
+
// src/mcp/tools/performance.ts
|
|
12
|
+
var checkPerformanceDefinition = {
|
|
13
|
+
name: "check_performance",
|
|
14
|
+
description: "Run performance checks: structural complexity, coupling metrics, and size budgets",
|
|
15
|
+
inputSchema: {
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: {
|
|
18
|
+
path: { type: "string", description: "Path to project root" },
|
|
19
|
+
type: {
|
|
20
|
+
type: "string",
|
|
21
|
+
enum: ["structural", "coupling", "size", "all"],
|
|
22
|
+
description: "Type of performance check (default: all)"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
required: ["path"]
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
async function handleCheckPerformance(input) {
|
|
29
|
+
try {
|
|
30
|
+
const { EntropyAnalyzer } = await import("./dist-JVZ2MKBC.js");
|
|
31
|
+
const typeFilter = input.type ?? "all";
|
|
32
|
+
const projectPath = sanitizePath(input.path);
|
|
33
|
+
const analyzer = new EntropyAnalyzer({
|
|
34
|
+
rootDir: projectPath,
|
|
35
|
+
analyze: {
|
|
36
|
+
complexity: typeFilter === "all" || typeFilter === "structural",
|
|
37
|
+
coupling: typeFilter === "all" || typeFilter === "coupling",
|
|
38
|
+
sizeBudget: typeFilter === "all" || typeFilter === "size"
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
let graphOptions;
|
|
42
|
+
try {
|
|
43
|
+
const { loadGraphStore } = await import("./graph-loader-KO4GJ5N2.js");
|
|
44
|
+
const store = await loadGraphStore(projectPath);
|
|
45
|
+
if (store) {
|
|
46
|
+
const { GraphComplexityAdapter, GraphCouplingAdapter } = await import("./dist-M6BQODWC.js");
|
|
47
|
+
const complexityAdapter = new GraphComplexityAdapter(store);
|
|
48
|
+
const couplingAdapter = new GraphCouplingAdapter(store);
|
|
49
|
+
graphOptions = {
|
|
50
|
+
graphComplexityData: complexityAdapter.computeComplexityHotspots(),
|
|
51
|
+
graphCouplingData: couplingAdapter.computeCouplingData()
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
} catch {
|
|
55
|
+
}
|
|
56
|
+
const result = await analyzer.analyze(graphOptions);
|
|
57
|
+
return resultToMcpResponse(result);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
return {
|
|
60
|
+
content: [
|
|
61
|
+
{
|
|
62
|
+
type: "text",
|
|
63
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
isError: true
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
var getPerfBaselinesDefinition = {
|
|
71
|
+
name: "get_perf_baselines",
|
|
72
|
+
description: "Read current performance baselines from .harness/perf/baselines.json",
|
|
73
|
+
inputSchema: {
|
|
74
|
+
type: "object",
|
|
75
|
+
properties: {
|
|
76
|
+
path: { type: "string", description: "Path to project root" }
|
|
77
|
+
},
|
|
78
|
+
required: ["path"]
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
async function handleGetPerfBaselines(input) {
|
|
82
|
+
try {
|
|
83
|
+
const { BaselineManager } = await import("./dist-JVZ2MKBC.js");
|
|
84
|
+
const manager = new BaselineManager(sanitizePath(input.path));
|
|
85
|
+
const baselines = manager.load();
|
|
86
|
+
return resultToMcpResponse(
|
|
87
|
+
Ok(baselines ?? { version: 1, updatedAt: "", updatedFrom: "", benchmarks: {} })
|
|
88
|
+
);
|
|
89
|
+
} catch (error) {
|
|
90
|
+
return {
|
|
91
|
+
content: [
|
|
92
|
+
{
|
|
93
|
+
type: "text",
|
|
94
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
95
|
+
}
|
|
96
|
+
],
|
|
97
|
+
isError: true
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
var updatePerfBaselinesDefinition = {
|
|
102
|
+
name: "update_perf_baselines",
|
|
103
|
+
description: "Update performance baselines from benchmark results. Run benchmarks first via CLI.",
|
|
104
|
+
inputSchema: {
|
|
105
|
+
type: "object",
|
|
106
|
+
properties: {
|
|
107
|
+
path: { type: "string", description: "Path to project root" },
|
|
108
|
+
commitHash: { type: "string", description: "Current commit hash for baseline tracking" },
|
|
109
|
+
results: {
|
|
110
|
+
type: "array",
|
|
111
|
+
description: "Array of benchmark results to save as baselines",
|
|
112
|
+
items: {
|
|
113
|
+
type: "object",
|
|
114
|
+
properties: {
|
|
115
|
+
name: { type: "string" },
|
|
116
|
+
file: { type: "string" },
|
|
117
|
+
opsPerSec: { type: "number" },
|
|
118
|
+
meanMs: { type: "number" },
|
|
119
|
+
p99Ms: { type: "number" },
|
|
120
|
+
marginOfError: { type: "number" }
|
|
121
|
+
},
|
|
122
|
+
required: ["name", "file", "opsPerSec", "meanMs", "p99Ms", "marginOfError"]
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
required: ["path", "commitHash", "results"]
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
async function handleUpdatePerfBaselines(input) {
|
|
130
|
+
try {
|
|
131
|
+
const { BaselineManager } = await import("./dist-JVZ2MKBC.js");
|
|
132
|
+
const manager = new BaselineManager(sanitizePath(input.path));
|
|
133
|
+
manager.save(input.results, input.commitHash);
|
|
134
|
+
const updated = manager.load();
|
|
135
|
+
return resultToMcpResponse(Ok(updated));
|
|
136
|
+
} catch (error) {
|
|
137
|
+
return {
|
|
138
|
+
content: [
|
|
139
|
+
{
|
|
140
|
+
type: "text",
|
|
141
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
142
|
+
}
|
|
143
|
+
],
|
|
144
|
+
isError: true
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
var getCriticalPathsDefinition = {
|
|
149
|
+
name: "get_critical_paths",
|
|
150
|
+
description: "List performance-critical functions from @perf-critical annotations and graph inference",
|
|
151
|
+
inputSchema: {
|
|
152
|
+
type: "object",
|
|
153
|
+
properties: {
|
|
154
|
+
path: { type: "string", description: "Path to project root" }
|
|
155
|
+
},
|
|
156
|
+
required: ["path"]
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
async function handleGetCriticalPaths(input) {
|
|
160
|
+
try {
|
|
161
|
+
const { CriticalPathResolver } = await import("./dist-JVZ2MKBC.js");
|
|
162
|
+
const resolver = new CriticalPathResolver(sanitizePath(input.path));
|
|
163
|
+
const result = await resolver.resolve();
|
|
164
|
+
return resultToMcpResponse(Ok(result));
|
|
165
|
+
} catch (error) {
|
|
166
|
+
return {
|
|
167
|
+
content: [
|
|
168
|
+
{
|
|
169
|
+
type: "text",
|
|
170
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
171
|
+
}
|
|
172
|
+
],
|
|
173
|
+
isError: true
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export {
|
|
179
|
+
checkPerformanceDefinition,
|
|
180
|
+
handleCheckPerformance,
|
|
181
|
+
getPerfBaselinesDefinition,
|
|
182
|
+
handleGetPerfBaselines,
|
|
183
|
+
updatePerfBaselinesDefinition,
|
|
184
|
+
handleUpdatePerfBaselines,
|
|
185
|
+
getCriticalPathsDefinition,
|
|
186
|
+
handleGetCriticalPaths
|
|
187
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// src/utils/paths.ts
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
var __dirname = path.dirname(__filename);
|
|
7
|
+
function findUpFrom(startDir, targetName, marker, maxLevels) {
|
|
8
|
+
let dir = startDir;
|
|
9
|
+
for (let i = 0; i < maxLevels; i++) {
|
|
10
|
+
const candidate = path.join(dir, targetName);
|
|
11
|
+
if (fs.existsSync(candidate) && fs.statSync(candidate).isDirectory()) {
|
|
12
|
+
if (fs.existsSync(path.join(candidate, marker))) {
|
|
13
|
+
return candidate;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
dir = path.dirname(dir);
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
function findUpDir(targetName, marker, maxLevels = 8) {
|
|
21
|
+
const fromModule = findUpFrom(__dirname, targetName, marker, maxLevels);
|
|
22
|
+
if (fromModule) return fromModule;
|
|
23
|
+
return findUpFrom(process.cwd(), targetName, marker, maxLevels);
|
|
24
|
+
}
|
|
25
|
+
function resolveTemplatesDir() {
|
|
26
|
+
return findUpDir("templates", "base") ?? path.join(__dirname, "templates");
|
|
27
|
+
}
|
|
28
|
+
function resolvePersonasDir() {
|
|
29
|
+
const agentsDir = findUpDir("agents", "personas");
|
|
30
|
+
if (agentsDir) {
|
|
31
|
+
return path.join(agentsDir, "personas");
|
|
32
|
+
}
|
|
33
|
+
return path.join(__dirname, "agents", "personas");
|
|
34
|
+
}
|
|
35
|
+
function resolveSkillsDir() {
|
|
36
|
+
const agentsDir = findUpDir("agents", "skills");
|
|
37
|
+
if (agentsDir) {
|
|
38
|
+
return path.join(agentsDir, "skills", "claude-code");
|
|
39
|
+
}
|
|
40
|
+
return path.join(__dirname, "agents", "skills", "claude-code");
|
|
41
|
+
}
|
|
42
|
+
function resolveProjectSkillsDir(cwd) {
|
|
43
|
+
let dir = cwd ?? process.cwd();
|
|
44
|
+
for (let i = 0; i < 8; i++) {
|
|
45
|
+
const candidate = path.join(dir, "agents", "skills", "claude-code");
|
|
46
|
+
if (fs.existsSync(candidate) && fs.statSync(candidate).isDirectory()) {
|
|
47
|
+
const agentsDir = path.join(dir, "agents");
|
|
48
|
+
if (fs.existsSync(path.join(agentsDir, "skills"))) {
|
|
49
|
+
return candidate;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const parent = path.dirname(dir);
|
|
53
|
+
if (parent === dir) break;
|
|
54
|
+
dir = parent;
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
function resolveGlobalSkillsDir() {
|
|
59
|
+
const agentsDir = findUpDir("agents", "skills");
|
|
60
|
+
if (agentsDir) {
|
|
61
|
+
return path.join(agentsDir, "skills", "claude-code");
|
|
62
|
+
}
|
|
63
|
+
return path.join(__dirname, "agents", "skills", "claude-code");
|
|
64
|
+
}
|
|
65
|
+
function resolveCommunitySkillsDir(platform = "claude-code") {
|
|
66
|
+
const agentsDir = findUpDir("agents", "skills");
|
|
67
|
+
if (agentsDir) {
|
|
68
|
+
return path.join(agentsDir, "skills", "community", platform);
|
|
69
|
+
}
|
|
70
|
+
return path.join(__dirname, "agents", "skills", "community", platform);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export {
|
|
74
|
+
resolveTemplatesDir,
|
|
75
|
+
resolvePersonasDir,
|
|
76
|
+
resolveSkillsDir,
|
|
77
|
+
resolveProjectSkillsDir,
|
|
78
|
+
resolveGlobalSkillsDir,
|
|
79
|
+
resolveCommunitySkillsDir
|
|
80
|
+
};
|