@harness-engineering/cli 1.9.0 → 1.10.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/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/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-md-EMRFLNBC.js +8 -0
- package/dist/architecture-5JNN5L3M.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-WOKIYGAM.js +12 -0
- package/dist/chunk-46YA6FI3.js +293 -0
- package/dist/chunk-4PFMY3H7.js +248 -0
- package/dist/{chunk-6JIT7CEM.js → chunk-72GHBOL2.js} +1 -1
- package/dist/chunk-7X7ZAYMY.js +373 -0
- package/dist/chunk-B7HFEHWP.js +35 -0
- package/dist/chunk-BM3PWGXQ.js +14 -0
- package/dist/chunk-C2ERUR3L.js +255 -0
- package/dist/chunk-CWZ4Y2PO.js +189 -0
- package/dist/{chunk-ULSRSP53.js → chunk-ECUJQS3B.js} +11 -112
- package/dist/chunk-EOLRW32Q.js +72 -0
- package/dist/chunk-F3YDAJFQ.js +125 -0
- package/dist/chunk-F4PTVZWA.js +116 -0
- package/dist/chunk-FPIPT36X.js +187 -0
- package/dist/chunk-FX7SQHGD.js +103 -0
- package/dist/chunk-HIOXKZYF.js +15 -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-LXU5M77O.js +4028 -0
- package/dist/chunk-MDUK2J2O.js +67 -0
- package/dist/chunk-MHBMTPW7.js +29 -0
- package/dist/chunk-MO4YQOMB.js +85 -0
- package/dist/chunk-NKDM3FMH.js +52 -0
- package/dist/{chunk-CGSHUJES.js → chunk-NX6DSZSM.js} +7 -26
- package/dist/chunk-OPXH4CQN.js +62 -0
- package/dist/{chunk-RTPHUDZS.js → chunk-PAHHT2IK.js} +466 -2714
- package/dist/chunk-PMTFPOCT.js +122 -0
- package/dist/chunk-PSXF277V.js +89 -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-TRAPF4IX.js +185 -0
- package/dist/chunk-VUCPTQ6G.js +67 -0
- package/dist/chunk-W6Y7ZW3Y.js +13 -0
- package/dist/chunk-ZOAWBDWU.js +72 -0
- package/dist/ci-workflow-ZBBUNTHQ.js +8 -0
- package/dist/constants-5JGUXPEK.js +6 -0
- package/dist/create-skill-LUWO46WF.js +11 -0
- package/dist/dist-D4RYGUZE.js +14 -0
- package/dist/dist-L7LAAQAS.js +18 -0
- package/dist/{dist-C5PYIQPF.js → dist-PBTNVK6K.js} +8 -6
- package/dist/docs-PTJGD6XI.js +12 -0
- package/dist/engine-SCMZ3G3E.js +8 -0
- package/dist/entropy-YIUBGKY7.js +12 -0
- package/dist/feedback-WEVQSLAA.js +18 -0
- package/dist/generate-agent-definitions-BU5LOJTI.js +15 -0
- package/dist/glob-helper-5OHBUQAI.js +52 -0
- package/dist/graph-loader-RLO3KRIX.js +8 -0
- package/dist/index.d.ts +11 -1
- package/dist/index.js +84 -33
- package/dist/loader-6S6PVGSF.js +10 -0
- package/dist/mcp-BNLBTCXZ.js +34 -0
- package/dist/performance-5TVW6SA6.js +24 -0
- package/dist/review-pipeline-4JTQAWKW.js +9 -0
- package/dist/runner-VMYLHWOC.js +6 -0
- package/dist/runtime-PXIM7UV6.js +9 -0
- package/dist/security-URYTKLGK.js +9 -0
- package/dist/skill-executor-KVS47DAU.js +8 -0
- package/dist/validate-KSDUUK2M.js +12 -0
- package/dist/validate-cross-check-WZAX357V.js +8 -0
- package/dist/version-KFFPOQAX.js +6 -0
- package/package.json +6 -4
- package/dist/create-skill-UZOHMXRU.js +0 -8
- package/dist/validate-cross-check-VG573VZO.js +0 -7
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveSkillsDir
|
|
3
|
+
} from "./chunk-EOLRW32Q.js";
|
|
4
|
+
import {
|
|
5
|
+
SkillMetadataSchema
|
|
6
|
+
} from "./chunk-MDUK2J2O.js";
|
|
7
|
+
|
|
8
|
+
// src/persona/skill-executor.ts
|
|
9
|
+
import * as fs from "fs";
|
|
10
|
+
import * as path from "path";
|
|
11
|
+
import { parse } from "yaml";
|
|
12
|
+
function resolveOutputMode(mode, trigger) {
|
|
13
|
+
if (mode !== "auto") return mode;
|
|
14
|
+
return trigger === "manual" ? "inline" : "artifact";
|
|
15
|
+
}
|
|
16
|
+
function buildArtifactPath(projectPath, headSha) {
|
|
17
|
+
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
18
|
+
const sha = headSha?.slice(0, 7) ?? "unknown";
|
|
19
|
+
return path.join(projectPath, ".harness", "reviews", `${date}-${sha}.md`);
|
|
20
|
+
}
|
|
21
|
+
function buildArtifactContent(skillName, trigger, headSha) {
|
|
22
|
+
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
23
|
+
return [
|
|
24
|
+
"---",
|
|
25
|
+
`skill: ${skillName}`,
|
|
26
|
+
`trigger: ${trigger}`,
|
|
27
|
+
`sha: ${headSha?.slice(0, 7) ?? "unknown"}`,
|
|
28
|
+
`date: ${date}`,
|
|
29
|
+
`assessment: pending`,
|
|
30
|
+
"---",
|
|
31
|
+
"",
|
|
32
|
+
`# Review by ${skillName}`,
|
|
33
|
+
"",
|
|
34
|
+
"## Strengths",
|
|
35
|
+
"",
|
|
36
|
+
"- (review pending)",
|
|
37
|
+
"",
|
|
38
|
+
"## Issues",
|
|
39
|
+
"",
|
|
40
|
+
"### Critical",
|
|
41
|
+
"",
|
|
42
|
+
"- None identified",
|
|
43
|
+
"",
|
|
44
|
+
"### Important",
|
|
45
|
+
"",
|
|
46
|
+
"- None identified",
|
|
47
|
+
"",
|
|
48
|
+
"### Suggestions",
|
|
49
|
+
"",
|
|
50
|
+
"- None identified",
|
|
51
|
+
"",
|
|
52
|
+
"## Assessment",
|
|
53
|
+
"",
|
|
54
|
+
"Pending \u2014 skill execution scaffolded.",
|
|
55
|
+
"",
|
|
56
|
+
"## Harness Checks",
|
|
57
|
+
"",
|
|
58
|
+
"- (run harness validate, check-deps, check-docs to populate)",
|
|
59
|
+
""
|
|
60
|
+
].join("\n");
|
|
61
|
+
}
|
|
62
|
+
async function executeSkill(skillName, context) {
|
|
63
|
+
const startTime = Date.now();
|
|
64
|
+
const skillsDir = resolveSkillsDir();
|
|
65
|
+
const skillDir = path.join(skillsDir, skillName);
|
|
66
|
+
if (!fs.existsSync(skillDir)) {
|
|
67
|
+
return {
|
|
68
|
+
status: "fail",
|
|
69
|
+
output: `Skill not found: ${skillName}`,
|
|
70
|
+
durationMs: Date.now() - startTime
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
const yamlPath = path.join(skillDir, "skill.yaml");
|
|
74
|
+
if (!fs.existsSync(yamlPath)) {
|
|
75
|
+
return {
|
|
76
|
+
status: "fail",
|
|
77
|
+
output: `skill.yaml not found for ${skillName}`,
|
|
78
|
+
durationMs: Date.now() - startTime
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const raw = fs.readFileSync(yamlPath, "utf-8");
|
|
82
|
+
const parsed = parse(raw);
|
|
83
|
+
const metadataResult = SkillMetadataSchema.safeParse(parsed);
|
|
84
|
+
if (!metadataResult.success) {
|
|
85
|
+
return {
|
|
86
|
+
status: "fail",
|
|
87
|
+
output: `Invalid skill metadata: ${metadataResult.error.message}`,
|
|
88
|
+
durationMs: Date.now() - startTime
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
const skillMdPath = path.join(skillDir, "SKILL.md");
|
|
92
|
+
if (!fs.existsSync(skillMdPath)) {
|
|
93
|
+
return {
|
|
94
|
+
status: "fail",
|
|
95
|
+
output: `SKILL.md not found for ${skillName}`,
|
|
96
|
+
durationMs: Date.now() - startTime
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
const skillContent = fs.readFileSync(skillMdPath, "utf-8");
|
|
100
|
+
const metadata = metadataResult.data;
|
|
101
|
+
const resolvedMode = resolveOutputMode(context.outputMode, context.trigger);
|
|
102
|
+
const output = `Skill ${metadata.name} (${metadata.type}) loaded.
|
|
103
|
+
Cognitive mode: ${metadata.cognitive_mode ?? "default"}
|
|
104
|
+
Content length: ${skillContent.length} chars
|
|
105
|
+
Trigger: ${context.trigger}
|
|
106
|
+
`;
|
|
107
|
+
let artifactPath;
|
|
108
|
+
if (resolvedMode === "artifact") {
|
|
109
|
+
artifactPath = buildArtifactPath(context.projectPath, context.headSha);
|
|
110
|
+
const artifactContent = buildArtifactContent(skillName, context.trigger, context.headSha);
|
|
111
|
+
const dir = path.dirname(artifactPath);
|
|
112
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
113
|
+
fs.writeFileSync(artifactPath, artifactContent, "utf-8");
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
status: "pass",
|
|
117
|
+
output,
|
|
118
|
+
...artifactPath ? { artifactPath } : {},
|
|
119
|
+
durationMs: Date.now() - startTime
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export {
|
|
124
|
+
executeSkill
|
|
125
|
+
};
|
|
@@ -0,0 +1,116 @@
|
|
|
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/docs.ts
|
|
12
|
+
import * as path from "path";
|
|
13
|
+
var checkDocsDefinition = {
|
|
14
|
+
name: "check_docs",
|
|
15
|
+
description: "Analyze documentation coverage and/or validate knowledge map integrity",
|
|
16
|
+
inputSchema: {
|
|
17
|
+
type: "object",
|
|
18
|
+
properties: {
|
|
19
|
+
path: { type: "string", description: "Path to project root" },
|
|
20
|
+
domain: { type: "string", description: "Domain/module to check" },
|
|
21
|
+
scope: {
|
|
22
|
+
type: "string",
|
|
23
|
+
enum: ["coverage", "integrity", "all"],
|
|
24
|
+
description: "Scope of check: 'coverage' (doc coverage), 'integrity' (knowledge map validation), 'all' (both). Default: 'coverage'"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
required: ["path"]
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
async function handleCheckDocs(input) {
|
|
31
|
+
try {
|
|
32
|
+
const projectPath = sanitizePath(input.path);
|
|
33
|
+
const scope = input.scope ?? "coverage";
|
|
34
|
+
if (scope === "integrity") {
|
|
35
|
+
const { validateKnowledgeMap } = await import("./dist-PBTNVK6K.js");
|
|
36
|
+
const result2 = await validateKnowledgeMap(projectPath);
|
|
37
|
+
return resultToMcpResponse(result2);
|
|
38
|
+
}
|
|
39
|
+
if (scope === "all") {
|
|
40
|
+
const { checkDocCoverage: checkDocCoverage2, validateKnowledgeMap } = await import("./dist-PBTNVK6K.js");
|
|
41
|
+
const domain2 = input.domain ?? "src";
|
|
42
|
+
const { loadGraphStore: loadGraphStore2 } = await import("./graph-loader-RLO3KRIX.js");
|
|
43
|
+
const store2 = await loadGraphStore2(projectPath);
|
|
44
|
+
let graphCoverage2;
|
|
45
|
+
if (store2) {
|
|
46
|
+
const { Assembler } = await import("./dist-I7DB5VKB.js");
|
|
47
|
+
const assembler = new Assembler(store2);
|
|
48
|
+
const report = assembler.checkCoverage();
|
|
49
|
+
graphCoverage2 = {
|
|
50
|
+
documented: [...report.documented],
|
|
51
|
+
undocumented: [...report.undocumented],
|
|
52
|
+
coveragePercentage: report.coveragePercentage
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const [coverageResult, integrityResult] = await Promise.allSettled([
|
|
56
|
+
checkDocCoverage2(domain2, {
|
|
57
|
+
sourceDir: path.resolve(projectPath, "src"),
|
|
58
|
+
docsDir: path.resolve(projectPath, "docs"),
|
|
59
|
+
...graphCoverage2 !== void 0 && { graphCoverage: graphCoverage2 }
|
|
60
|
+
}),
|
|
61
|
+
validateKnowledgeMap(projectPath)
|
|
62
|
+
]);
|
|
63
|
+
let coverage;
|
|
64
|
+
if (coverageResult.status === "fulfilled") {
|
|
65
|
+
const r = coverageResult.value;
|
|
66
|
+
coverage = r.ok ? r.value : { error: r.error };
|
|
67
|
+
} else {
|
|
68
|
+
coverage = { error: String(coverageResult.reason) };
|
|
69
|
+
}
|
|
70
|
+
let integrity;
|
|
71
|
+
if (integrityResult.status === "fulfilled") {
|
|
72
|
+
const r = integrityResult.value;
|
|
73
|
+
integrity = r.ok ? r.value : { error: r.error };
|
|
74
|
+
} else {
|
|
75
|
+
integrity = { error: String(integrityResult.reason) };
|
|
76
|
+
}
|
|
77
|
+
return resultToMcpResponse(Ok({ coverage, integrity }));
|
|
78
|
+
}
|
|
79
|
+
const { checkDocCoverage } = await import("./dist-PBTNVK6K.js");
|
|
80
|
+
const domain = input.domain ?? "src";
|
|
81
|
+
const { loadGraphStore } = await import("./graph-loader-RLO3KRIX.js");
|
|
82
|
+
const store = await loadGraphStore(projectPath);
|
|
83
|
+
let graphCoverage;
|
|
84
|
+
if (store) {
|
|
85
|
+
const { Assembler } = await import("./dist-I7DB5VKB.js");
|
|
86
|
+
const assembler = new Assembler(store);
|
|
87
|
+
const report = assembler.checkCoverage();
|
|
88
|
+
graphCoverage = {
|
|
89
|
+
documented: [...report.documented],
|
|
90
|
+
undocumented: [...report.undocumented],
|
|
91
|
+
coveragePercentage: report.coveragePercentage
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
const result = await checkDocCoverage(domain, {
|
|
95
|
+
sourceDir: path.resolve(projectPath, "src"),
|
|
96
|
+
docsDir: path.resolve(projectPath, "docs"),
|
|
97
|
+
...graphCoverage !== void 0 && { graphCoverage }
|
|
98
|
+
});
|
|
99
|
+
return resultToMcpResponse(result);
|
|
100
|
+
} catch (error) {
|
|
101
|
+
return {
|
|
102
|
+
content: [
|
|
103
|
+
{
|
|
104
|
+
type: "text",
|
|
105
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
106
|
+
}
|
|
107
|
+
],
|
|
108
|
+
isError: true
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export {
|
|
114
|
+
checkDocsDefinition,
|
|
115
|
+
handleCheckDocs
|
|
116
|
+
};
|
|
@@ -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-PBTNVK6K.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-RLO3KRIX.js");
|
|
44
|
+
const store = await loadGraphStore(projectPath);
|
|
45
|
+
if (store) {
|
|
46
|
+
const { GraphComplexityAdapter, GraphCouplingAdapter } = await import("./dist-I7DB5VKB.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-PBTNVK6K.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-PBTNVK6K.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-PBTNVK6K.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,103 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveProjectConfig
|
|
3
|
+
} from "./chunk-K6XAPGML.js";
|
|
4
|
+
import {
|
|
5
|
+
sanitizePath
|
|
6
|
+
} from "./chunk-W6Y7ZW3Y.js";
|
|
7
|
+
|
|
8
|
+
// src/mcp/tools/validate.ts
|
|
9
|
+
import * as path from "path";
|
|
10
|
+
var validateToolDefinition = {
|
|
11
|
+
name: "validate_project",
|
|
12
|
+
description: "Run all validation checks on a harness engineering project",
|
|
13
|
+
inputSchema: {
|
|
14
|
+
type: "object",
|
|
15
|
+
properties: {
|
|
16
|
+
path: { type: "string", description: "Path to project root directory" }
|
|
17
|
+
},
|
|
18
|
+
required: ["path"]
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
async function handleValidateProject(input) {
|
|
22
|
+
let projectPath;
|
|
23
|
+
try {
|
|
24
|
+
projectPath = sanitizePath(input.path);
|
|
25
|
+
} catch (error) {
|
|
26
|
+
return {
|
|
27
|
+
content: [
|
|
28
|
+
{
|
|
29
|
+
type: "text",
|
|
30
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
isError: true
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const errors = [];
|
|
37
|
+
const checks = {
|
|
38
|
+
config: "fail",
|
|
39
|
+
structure: "skipped",
|
|
40
|
+
agentsMap: "skipped"
|
|
41
|
+
};
|
|
42
|
+
const configResult = resolveProjectConfig(projectPath);
|
|
43
|
+
if (!configResult.ok) {
|
|
44
|
+
errors.push(`Config: ${configResult.error.message}`);
|
|
45
|
+
return {
|
|
46
|
+
content: [{ type: "text", text: JSON.stringify({ valid: false, checks, errors }) }]
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
checks.config = "pass";
|
|
50
|
+
const config = configResult.value;
|
|
51
|
+
try {
|
|
52
|
+
const core = await import("./dist-PBTNVK6K.js");
|
|
53
|
+
if (typeof core.validateFileStructure === "function" && Array.isArray(config.conventions)) {
|
|
54
|
+
const conventions = config.conventions;
|
|
55
|
+
const structureResult = await core.validateFileStructure(projectPath, conventions);
|
|
56
|
+
if (structureResult.ok) {
|
|
57
|
+
checks.structure = structureResult.value.valid ? "pass" : "fail";
|
|
58
|
+
if (!structureResult.value.valid) {
|
|
59
|
+
for (const missing of structureResult.value.missing) {
|
|
60
|
+
errors.push(`Missing required file: ${missing}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
} else {
|
|
64
|
+
checks.structure = "fail";
|
|
65
|
+
errors.push(`Structure validation error: ${structureResult.error.message}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
} catch {
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
const core = await import("./dist-PBTNVK6K.js");
|
|
72
|
+
if (typeof core.validateAgentsMap === "function") {
|
|
73
|
+
const agentsMapPath = path.join(projectPath, "AGENTS.md");
|
|
74
|
+
const agentsResult = await core.validateAgentsMap(agentsMapPath);
|
|
75
|
+
if (agentsResult.ok) {
|
|
76
|
+
checks.agentsMap = agentsResult.value.valid ? "pass" : "fail";
|
|
77
|
+
if (!agentsResult.value.valid) {
|
|
78
|
+
if (agentsResult.value.missingSections.length > 0) {
|
|
79
|
+
errors.push(
|
|
80
|
+
`AGENTS.md missing sections: ${agentsResult.value.missingSections.join(", ")}`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
if (agentsResult.value.brokenLinks.length > 0) {
|
|
84
|
+
errors.push(`AGENTS.md has ${agentsResult.value.brokenLinks.length} broken link(s)`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
checks.agentsMap = "fail";
|
|
89
|
+
errors.push(`AGENTS.md validation error: ${agentsResult.error.message}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
} catch {
|
|
93
|
+
}
|
|
94
|
+
const valid = errors.length === 0;
|
|
95
|
+
return {
|
|
96
|
+
content: [{ type: "text", text: JSON.stringify({ valid, checks, errors }) }]
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export {
|
|
101
|
+
validateToolDefinition,
|
|
102
|
+
handleValidateProject
|
|
103
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// src/output/logger.ts
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
var logger = {
|
|
4
|
+
info: (message) => console.log(chalk.blue("i"), message),
|
|
5
|
+
success: (message) => console.log(chalk.green("v"), message),
|
|
6
|
+
warn: (message) => console.log(chalk.yellow("!"), message),
|
|
7
|
+
error: (message) => console.error(chalk.red("x"), message),
|
|
8
|
+
dim: (message) => console.log(chalk.dim(message)),
|
|
9
|
+
// For JSON output mode
|
|
10
|
+
raw: (data) => console.log(JSON.stringify(data, null, 2))
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
logger
|
|
15
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// src/mcp/utils/result-adapter.ts
|
|
2
|
+
function resultToMcpResponse(result) {
|
|
3
|
+
if (result.ok) {
|
|
4
|
+
return {
|
|
5
|
+
content: [{ type: "text", text: JSON.stringify(result.value) }]
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
return {
|
|
9
|
+
content: [{ type: "text", text: result.error.message }],
|
|
10
|
+
isError: true
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export {
|
|
15
|
+
resultToMcpResponse
|
|
16
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
toKebabCase
|
|
3
|
+
} from "./chunk-KET4QQZB.js";
|
|
4
|
+
import {
|
|
5
|
+
Err,
|
|
6
|
+
Ok
|
|
7
|
+
} from "./chunk-MHBMTPW7.js";
|
|
8
|
+
|
|
9
|
+
// src/persona/generators/runtime.ts
|
|
10
|
+
function generateRuntime(persona) {
|
|
11
|
+
try {
|
|
12
|
+
const config = {
|
|
13
|
+
name: toKebabCase(persona.name),
|
|
14
|
+
skills: persona.skills,
|
|
15
|
+
steps: persona.steps,
|
|
16
|
+
timeout: persona.config.timeout,
|
|
17
|
+
severity: persona.config.severity
|
|
18
|
+
};
|
|
19
|
+
return Ok(JSON.stringify(config, null, 2));
|
|
20
|
+
} catch (error) {
|
|
21
|
+
return Err(
|
|
22
|
+
new Error(
|
|
23
|
+
`Failed to generate runtime config: ${error instanceof Error ? error.message : String(error)}`
|
|
24
|
+
)
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export {
|
|
30
|
+
generateRuntime
|
|
31
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Err,
|
|
3
|
+
Ok
|
|
4
|
+
} from "./chunk-MHBMTPW7.js";
|
|
5
|
+
|
|
6
|
+
// src/mcp/utils/config-resolver.ts
|
|
7
|
+
import * as fs from "fs";
|
|
8
|
+
import * as path from "path";
|
|
9
|
+
function resolveProjectConfig(projectPath) {
|
|
10
|
+
const configPath = path.join(projectPath, "harness.config.json");
|
|
11
|
+
if (!fs.existsSync(configPath)) {
|
|
12
|
+
return Err(new Error(`No harness.config.json found in ${projectPath}`));
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const raw = fs.readFileSync(configPath, "utf-8");
|
|
16
|
+
const config = JSON.parse(raw);
|
|
17
|
+
return Ok(config);
|
|
18
|
+
} catch (error) {
|
|
19
|
+
return Err(
|
|
20
|
+
new Error(`Failed to parse config: ${error instanceof Error ? error.message : String(error)}`)
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export {
|
|
26
|
+
resolveProjectConfig
|
|
27
|
+
};
|