@harness-engineering/cli 1.13.1 → 1.15.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 +240 -39
- package/dist/agents/skills/claude-code/harness-autopilot/skill.yaml +6 -0
- package/dist/agents/skills/claude-code/harness-brainstorming/SKILL.md +39 -0
- package/dist/agents/skills/claude-code/harness-code-review/SKILL.md +44 -0
- package/dist/agents/skills/claude-code/harness-execution/SKILL.md +44 -0
- package/dist/agents/skills/claude-code/harness-planning/SKILL.md +39 -0
- package/dist/agents/skills/claude-code/harness-product-spec/SKILL.md +5 -5
- package/dist/agents/skills/claude-code/harness-release-readiness/SKILL.md +3 -3
- package/dist/agents/skills/claude-code/harness-verification/SKILL.md +35 -0
- package/dist/agents/skills/claude-code/initialize-harness-project/SKILL.md +11 -3
- package/dist/agents/skills/gemini-cli/harness-autopilot/SKILL.md +240 -39
- package/dist/agents/skills/gemini-cli/harness-autopilot/skill.yaml +6 -0
- package/dist/agents/skills/gemini-cli/harness-brainstorming/SKILL.md +39 -0
- package/dist/agents/skills/gemini-cli/harness-code-review/SKILL.md +44 -0
- package/dist/agents/skills/gemini-cli/harness-execution/SKILL.md +44 -0
- package/dist/agents/skills/gemini-cli/harness-planning/SKILL.md +39 -0
- package/dist/agents/skills/gemini-cli/harness-product-spec/SKILL.md +5 -5
- package/dist/agents/skills/gemini-cli/harness-release-readiness/SKILL.md +3 -3
- package/dist/agents/skills/gemini-cli/harness-verification/SKILL.md +35 -0
- package/dist/agents/skills/gemini-cli/initialize-harness-project/SKILL.md +11 -3
- package/dist/agents/skills/package.json +1 -0
- package/dist/agents/skills/vitest.config.mts +5 -0
- package/dist/agents-md-ZGNIDWAF.js +8 -0
- package/dist/{architecture-2R5Z4ZAF.js → architecture-ZLIH5533.js} +4 -4
- package/dist/bin/harness-mcp.js +14 -14
- package/dist/bin/harness.js +27 -25
- package/dist/{check-phase-gate-2OFZ7OWW.js → check-phase-gate-ZOXVBDCN.js} +4 -4
- package/dist/{chunk-ND6PNADU.js → chunk-2BKLWLY6.js} +9 -9
- package/dist/{chunk-65FRIL4D.js → chunk-3ZZKVN62.js} +1 -1
- package/dist/{chunk-C2ERUR3L.js → chunk-7MJAPE3Z.js} +165 -49
- package/dist/{chunk-Z77YQRQT.js → chunk-B2HKP423.js} +16 -5
- package/dist/{chunk-QPEH2QPG.js → chunk-DBSOCI3G.js} +53 -54
- package/dist/{chunk-TKJZKICB.js → chunk-EDXIVMAP.js} +7 -7
- package/dist/{chunk-MHBMTPW7.js → chunk-ERS5EVUZ.js} +9 -0
- package/dist/{chunk-JSTQ3AWB.js → chunk-FIAPHX37.js} +1 -1
- package/dist/{chunk-IMFVFNJE.js → chunk-FTMXDOR6.js} +1 -1
- package/dist/{chunk-72GHBOL2.js → chunk-GZKSBLQL.js} +1 -1
- package/dist/{chunk-K6XAPGML.js → chunk-H7Y5CKTM.js} +1 -1
- package/dist/{chunk-SSKDAOX5.js → chunk-J4RAX7YB.js} +1164 -516
- package/dist/{chunk-UAX4I5ZE.js → chunk-LGYBN7Y6.js} +2 -2
- package/dist/{chunk-QY4T6YAZ.js → chunk-N25INEIX.js} +4 -4
- package/dist/{chunk-4ZMOCPYO.js → chunk-ND2ENWDM.js} +1 -1
- package/dist/{chunk-NERR4TAO.js → chunk-NNHDDXYT.js} +1250 -765
- package/dist/{chunk-NKDM3FMH.js → chunk-OD3S2NHN.js} +1 -1
- package/dist/{chunk-NOPU4RZ4.js → chunk-OFXQSFOW.js} +3 -3
- package/dist/{chunk-TS3XWPW5.js → chunk-RCWZBSK5.js} +1 -1
- package/dist/{chunk-VUCPTQ6G.js → chunk-SD3SQOZ2.js} +1 -1
- package/dist/{chunk-DZS7CJKL.js → chunk-VEPAJXBW.js} +45 -47
- package/dist/{chunk-IM32EEDM.js → chunk-YLXFKVJE.js} +9 -9
- package/dist/{chunk-Q6AB7W5Z.js → chunk-YQ6KC6TE.js} +1 -1
- package/dist/{chunk-PQ5YK4AY.js → chunk-Z2OOPXJO.js} +2740 -1221
- package/dist/ci-workflow-765LSHRD.js +8 -0
- package/dist/{dist-2B363XUH.js → dist-ALQDD67R.js} +64 -2
- package/dist/{dist-HXHWB7SV.js → dist-B26DFXMP.js} +571 -478
- package/dist/{dist-L7LAAQAS.js → dist-DZ63LLUD.js} +1 -1
- package/dist/{dist-D4RYGUZE.js → dist-USY2C5JL.js} +3 -1
- package/dist/{docs-FZOPM4GK.js → docs-NRMQCOJ6.js} +4 -4
- package/dist/engine-3RB7MXPP.js +8 -0
- package/dist/{entropy-LVHJMFGH.js → entropy-6AGX2ZUN.js} +3 -3
- package/dist/{feedback-IHLVLMRD.js → feedback-MY4QZIFD.js} +1 -1
- package/dist/{generate-agent-definitions-64S3CLEZ.js → generate-agent-definitions-ZAE726AU.js} +4 -4
- package/dist/{graph-loader-GJZ4FN4Y.js → graph-loader-2M2HXDQI.js} +1 -1
- package/dist/index.d.ts +156 -17
- package/dist/index.js +24 -24
- package/dist/loader-UUTVMQCC.js +10 -0
- package/dist/{mcp-JQUI7BVZ.js → mcp-VU5FMO52.js} +14 -14
- package/dist/{performance-ZTVSUANN.js → performance-2D7G6NMJ.js} +3 -3
- package/dist/{review-pipeline-76JHKGSV.js → review-pipeline-RAQ55ISU.js} +1 -1
- package/dist/runtime-BCK5RRZQ.js +9 -0
- package/dist/{security-FWQZF2IZ.js → security-2RPQEN62.js} +1 -1
- package/dist/templates/axum/Cargo.toml.hbs +8 -0
- package/dist/templates/axum/src/main.rs +12 -0
- package/dist/templates/axum/template.json +16 -0
- package/dist/templates/django/manage.py.hbs +19 -0
- package/dist/templates/django/requirements.txt.hbs +1 -0
- package/dist/templates/django/src/settings.py.hbs +44 -0
- package/dist/templates/django/src/urls.py +6 -0
- package/dist/templates/django/src/wsgi.py.hbs +9 -0
- package/dist/templates/django/template.json +21 -0
- package/dist/templates/express/package.json.hbs +15 -0
- package/dist/templates/express/src/app.ts +12 -0
- package/dist/templates/express/src/lib/.gitkeep +0 -0
- package/dist/templates/express/template.json +16 -0
- package/dist/templates/fastapi/requirements.txt.hbs +2 -0
- package/dist/templates/fastapi/src/main.py +8 -0
- package/dist/templates/fastapi/template.json +20 -0
- package/dist/templates/gin/go.mod.hbs +5 -0
- package/dist/templates/gin/main.go +15 -0
- package/dist/templates/gin/template.json +19 -0
- package/dist/templates/go-base/.golangci.yml +16 -0
- package/dist/templates/go-base/AGENTS.md.hbs +35 -0
- package/dist/templates/go-base/go.mod.hbs +3 -0
- package/dist/templates/go-base/harness.config.json.hbs +17 -0
- package/dist/templates/go-base/main.go +7 -0
- package/dist/templates/go-base/template.json +14 -0
- package/dist/templates/java-base/AGENTS.md.hbs +35 -0
- package/dist/templates/java-base/checkstyle.xml +20 -0
- package/dist/templates/java-base/harness.config.json.hbs +16 -0
- package/dist/templates/java-base/pom.xml.hbs +39 -0
- package/dist/templates/java-base/src/main/java/App.java.hbs +5 -0
- package/dist/templates/java-base/template.json +13 -0
- package/dist/templates/nestjs/nest-cli.json +5 -0
- package/dist/templates/nestjs/package.json.hbs +18 -0
- package/dist/templates/nestjs/src/app.module.ts +8 -0
- package/dist/templates/nestjs/src/lib/.gitkeep +0 -0
- package/dist/templates/nestjs/src/main.ts +11 -0
- package/dist/templates/nestjs/template.json +16 -0
- package/dist/templates/nextjs/template.json +15 -1
- package/dist/templates/python-base/.python-version +1 -0
- package/dist/templates/python-base/AGENTS.md.hbs +32 -0
- package/dist/templates/python-base/harness.config.json.hbs +16 -0
- package/dist/templates/python-base/pyproject.toml.hbs +18 -0
- package/dist/templates/python-base/ruff.toml +5 -0
- package/dist/templates/python-base/src/__init__.py +0 -0
- package/dist/templates/python-base/template.json +13 -0
- package/dist/templates/react-vite/index.html +12 -0
- package/dist/templates/react-vite/package.json.hbs +18 -0
- package/dist/templates/react-vite/src/App.tsx +7 -0
- package/dist/templates/react-vite/src/lib/.gitkeep +0 -0
- package/dist/templates/react-vite/src/main.tsx +9 -0
- package/dist/templates/react-vite/template.json +19 -0
- package/dist/templates/react-vite/vite.config.ts +6 -0
- package/dist/templates/rust-base/AGENTS.md.hbs +35 -0
- package/dist/templates/rust-base/Cargo.toml.hbs +6 -0
- package/dist/templates/rust-base/clippy.toml +2 -0
- package/dist/templates/rust-base/harness.config.json.hbs +17 -0
- package/dist/templates/rust-base/src/main.rs +3 -0
- package/dist/templates/rust-base/template.json +14 -0
- package/dist/templates/spring-boot/pom.xml.hbs +50 -0
- package/dist/templates/spring-boot/src/main/java/Application.java.hbs +19 -0
- package/dist/templates/spring-boot/template.json +15 -0
- package/dist/templates/vue/index.html +12 -0
- package/dist/templates/vue/package.json.hbs +16 -0
- package/dist/templates/vue/src/App.vue +7 -0
- package/dist/templates/vue/src/lib/.gitkeep +0 -0
- package/dist/templates/vue/src/main.ts +4 -0
- package/dist/templates/vue/template.json +19 -0
- package/dist/templates/vue/vite.config.ts +6 -0
- package/dist/{validate-GCHZJIL7.js → validate-KBYQAEWE.js} +4 -4
- package/dist/validate-cross-check-OABMREW4.js +8 -0
- package/package.json +7 -5
- package/dist/agents-md-XU3BHE22.js +0 -8
- package/dist/ci-workflow-EHV65NQB.js +0 -8
- package/dist/engine-OL4T6NZS.js +0 -8
- package/dist/loader-DPYFB6R6.js +0 -10
- package/dist/runtime-X7U6SC7K.js +0 -9
- package/dist/validate-cross-check-STFHYMAZ.js +0 -8
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Err,
|
|
3
3
|
Ok
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ERS5EVUZ.js";
|
|
5
5
|
|
|
6
6
|
// src/templates/engine.ts
|
|
7
7
|
import * as fs from "fs";
|
|
@@ -10,6 +10,19 @@ import Handlebars from "handlebars";
|
|
|
10
10
|
|
|
11
11
|
// src/templates/schema.ts
|
|
12
12
|
import { z } from "zod";
|
|
13
|
+
var LanguageEnum = z.enum(["typescript", "python", "go", "rust", "java"]);
|
|
14
|
+
var ToolingSchema = z.object({
|
|
15
|
+
packageManager: z.string().optional(),
|
|
16
|
+
linter: z.string().optional(),
|
|
17
|
+
formatter: z.string().optional(),
|
|
18
|
+
buildTool: z.string().optional(),
|
|
19
|
+
testRunner: z.string().optional(),
|
|
20
|
+
lockFile: z.string().optional()
|
|
21
|
+
});
|
|
22
|
+
var DetectPatternSchema = z.object({
|
|
23
|
+
file: z.string(),
|
|
24
|
+
contains: z.string().optional()
|
|
25
|
+
});
|
|
13
26
|
var MergeStrategySchema = z.object({
|
|
14
27
|
json: z.enum(["deep-merge", "overlay-wins"]).default("deep-merge"),
|
|
15
28
|
files: z.literal("overlay-wins").default("overlay-wins")
|
|
@@ -21,7 +34,10 @@ var TemplateMetadataSchema = z.object({
|
|
|
21
34
|
framework: z.string().optional(),
|
|
22
35
|
extends: z.string().optional(),
|
|
23
36
|
mergeStrategy: MergeStrategySchema.default({}),
|
|
24
|
-
version: z.literal(1)
|
|
37
|
+
version: z.literal(1),
|
|
38
|
+
language: LanguageEnum.optional(),
|
|
39
|
+
tooling: ToolingSchema.optional(),
|
|
40
|
+
detect: z.array(DetectPatternSchema).optional()
|
|
25
41
|
});
|
|
26
42
|
|
|
27
43
|
// src/templates/merger.ts
|
|
@@ -64,6 +80,57 @@ function mergePackageJson(base, overlay) {
|
|
|
64
80
|
}
|
|
65
81
|
|
|
66
82
|
// src/templates/engine.ts
|
|
83
|
+
var NON_JSON_PACKAGE_CONFIGS = /* @__PURE__ */ new Set(["pyproject.toml", "go.mod", "Cargo.toml", "pom.xml"]);
|
|
84
|
+
function scoreDetectPatterns(targetDir, patterns) {
|
|
85
|
+
let score = 0;
|
|
86
|
+
for (const pattern of patterns) {
|
|
87
|
+
const filePath = path.join(targetDir, pattern.file);
|
|
88
|
+
if (!fs.existsSync(filePath)) continue;
|
|
89
|
+
if (!pattern.contains) {
|
|
90
|
+
score++;
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const fd = fs.openSync(filePath, "r");
|
|
94
|
+
try {
|
|
95
|
+
const buf = Buffer.alloc(65536);
|
|
96
|
+
const bytesRead = fs.readSync(fd, buf, 0, 65536, 0);
|
|
97
|
+
const content = buf.toString("utf-8", 0, bytesRead);
|
|
98
|
+
if (content.includes(pattern.contains)) score++;
|
|
99
|
+
} finally {
|
|
100
|
+
fs.closeSync(fd);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return score;
|
|
104
|
+
}
|
|
105
|
+
function applyLanguageDefaults(context) {
|
|
106
|
+
return {
|
|
107
|
+
...context,
|
|
108
|
+
...context.language === "python" && context.pythonMinVersion === void 0 && { pythonMinVersion: "3.10" },
|
|
109
|
+
...context.language === "go" && context.goModulePath === void 0 && {
|
|
110
|
+
goModulePath: `github.com/example/${context.projectName}`
|
|
111
|
+
},
|
|
112
|
+
...context.language === "java" && context.javaGroupId === void 0 && {
|
|
113
|
+
javaGroupId: `com.example.${context.projectName.replace(/[^a-zA-Z0-9]/g, "").toLowerCase()}`
|
|
114
|
+
},
|
|
115
|
+
...context.language === "rust" && context.rustEdition === void 0 && { rustEdition: "2021" }
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function mergeJsonBuffers(jsonBuffers) {
|
|
119
|
+
try {
|
|
120
|
+
const results = [];
|
|
121
|
+
for (const [outputPath, jsons] of jsonBuffers) {
|
|
122
|
+
let merged = {};
|
|
123
|
+
for (const json of jsons) {
|
|
124
|
+
merged = outputPath === "package.json" ? mergePackageJson(merged, json) : deepMergeJson(merged, json);
|
|
125
|
+
}
|
|
126
|
+
results.push({ relativePath: outputPath, content: JSON.stringify(merged, null, 2) });
|
|
127
|
+
}
|
|
128
|
+
return Ok(results);
|
|
129
|
+
} catch (error) {
|
|
130
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
131
|
+
return Err(new Error(`JSON merge failed: ${msg}`));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
67
134
|
var TemplateEngine = class {
|
|
68
135
|
constructor(templatesDir) {
|
|
69
136
|
this.templatesDir = templatesDir;
|
|
@@ -89,7 +156,13 @@ var TemplateEngine = class {
|
|
|
89
156
|
);
|
|
90
157
|
}
|
|
91
158
|
}
|
|
92
|
-
resolveTemplate(level, framework) {
|
|
159
|
+
resolveTemplate(level, framework, language) {
|
|
160
|
+
if (language && language !== "typescript") {
|
|
161
|
+
return this.resolveLanguageTemplate(language, framework);
|
|
162
|
+
}
|
|
163
|
+
if (!level) {
|
|
164
|
+
return Err(new Error("Level is required for TypeScript/JavaScript templates"));
|
|
165
|
+
}
|
|
93
166
|
const levelDir = this.findTemplateDir(level, "level");
|
|
94
167
|
if (!levelDir) return Err(new Error(`Template not found for level: ${level}`));
|
|
95
168
|
const metaPath = path.join(levelDir, "template.json");
|
|
@@ -122,69 +195,60 @@ var TemplateEngine = class {
|
|
|
122
195
|
return Ok(resolved);
|
|
123
196
|
}
|
|
124
197
|
render(template, context) {
|
|
198
|
+
const effectiveContext = applyLanguageDefaults(context);
|
|
125
199
|
const rendered = [];
|
|
126
200
|
const jsonBuffers = /* @__PURE__ */ new Map();
|
|
127
201
|
for (const file of template.files) {
|
|
128
|
-
const
|
|
129
|
-
if (
|
|
130
|
-
|
|
131
|
-
const raw = fs.readFileSync(file.absolutePath, "utf-8");
|
|
132
|
-
const compiled = Handlebars.compile(raw, { strict: true });
|
|
133
|
-
const content = compiled(context);
|
|
134
|
-
if (outputPath.endsWith(".json") && file.relativePath.endsWith(".json.hbs")) {
|
|
135
|
-
if (!jsonBuffers.has(outputPath)) jsonBuffers.set(outputPath, []);
|
|
136
|
-
jsonBuffers.get(outputPath).push(JSON.parse(content));
|
|
137
|
-
} else {
|
|
138
|
-
rendered.push({ relativePath: outputPath, content });
|
|
139
|
-
}
|
|
140
|
-
} catch (error) {
|
|
141
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
142
|
-
return Err(
|
|
143
|
-
new Error(
|
|
144
|
-
`Template render failed in ${file.sourceTemplate}/${file.relativePath}: ${msg}`
|
|
145
|
-
)
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
} else {
|
|
149
|
-
try {
|
|
150
|
-
const content = fs.readFileSync(file.absolutePath, "utf-8");
|
|
151
|
-
rendered.push({ relativePath: file.relativePath, content });
|
|
152
|
-
} catch (error) {
|
|
153
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
154
|
-
return Err(
|
|
155
|
-
new Error(
|
|
156
|
-
`Template render failed in ${file.sourceTemplate}/${file.relativePath}: ${msg}`
|
|
157
|
-
)
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
202
|
+
const result = this.renderFile(file, effectiveContext, jsonBuffers);
|
|
203
|
+
if (!result.ok) return result;
|
|
204
|
+
if (result.value) rendered.push(result.value);
|
|
161
205
|
}
|
|
206
|
+
const mergeResult = mergeJsonBuffers(jsonBuffers);
|
|
207
|
+
if (!mergeResult.ok) return mergeResult;
|
|
208
|
+
rendered.push(...mergeResult.value);
|
|
209
|
+
return Ok({ files: rendered });
|
|
210
|
+
}
|
|
211
|
+
renderFile(file, context, jsonBuffers) {
|
|
212
|
+
const outputPath = file.relativePath.replace(/\.hbs$/, "");
|
|
162
213
|
try {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
214
|
+
if (file.isHandlebars) {
|
|
215
|
+
const raw = fs.readFileSync(file.absolutePath, "utf-8");
|
|
216
|
+
const compiled = Handlebars.compile(raw, { strict: true });
|
|
217
|
+
const content2 = compiled(context);
|
|
218
|
+
if (outputPath.endsWith(".json") && file.relativePath.endsWith(".json.hbs")) {
|
|
219
|
+
if (!jsonBuffers.has(outputPath)) jsonBuffers.set(outputPath, []);
|
|
220
|
+
jsonBuffers.get(outputPath).push(JSON.parse(content2));
|
|
221
|
+
return Ok(null);
|
|
167
222
|
}
|
|
168
|
-
|
|
223
|
+
return Ok({ relativePath: outputPath, content: content2 });
|
|
169
224
|
}
|
|
225
|
+
const content = fs.readFileSync(file.absolutePath, "utf-8");
|
|
226
|
+
return Ok({ relativePath: file.relativePath, content });
|
|
170
227
|
} catch (error) {
|
|
171
228
|
const msg = error instanceof Error ? error.message : String(error);
|
|
172
|
-
return Err(
|
|
229
|
+
return Err(
|
|
230
|
+
new Error(`Template render failed in ${file.sourceTemplate}/${file.relativePath}: ${msg}`)
|
|
231
|
+
);
|
|
173
232
|
}
|
|
174
|
-
return Ok({ files: rendered });
|
|
175
233
|
}
|
|
176
234
|
write(files, targetDir, options) {
|
|
177
235
|
try {
|
|
178
236
|
const written = [];
|
|
237
|
+
const skippedConfigs = [];
|
|
238
|
+
const isNonJsLanguage = options.language && options.language !== "typescript";
|
|
179
239
|
for (const file of files.files) {
|
|
180
240
|
const targetPath = path.join(targetDir, file.relativePath);
|
|
181
241
|
const dir = path.dirname(targetPath);
|
|
242
|
+
if (!options.overwrite && isNonJsLanguage && NON_JSON_PACKAGE_CONFIGS.has(file.relativePath) && fs.existsSync(targetPath)) {
|
|
243
|
+
skippedConfigs.push(file.relativePath);
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
182
246
|
if (!options.overwrite && fs.existsSync(targetPath)) continue;
|
|
183
247
|
fs.mkdirSync(dir, { recursive: true });
|
|
184
248
|
fs.writeFileSync(targetPath, file.content);
|
|
185
249
|
written.push(file.relativePath);
|
|
186
250
|
}
|
|
187
|
-
return Ok(written);
|
|
251
|
+
return Ok({ written, skippedConfigs });
|
|
188
252
|
} catch (error) {
|
|
189
253
|
return Err(
|
|
190
254
|
new Error(
|
|
@@ -193,6 +257,61 @@ var TemplateEngine = class {
|
|
|
193
257
|
);
|
|
194
258
|
}
|
|
195
259
|
}
|
|
260
|
+
detectFramework(targetDir) {
|
|
261
|
+
try {
|
|
262
|
+
const templatesResult = this.listTemplates();
|
|
263
|
+
if (!templatesResult.ok) return Err(templatesResult.error);
|
|
264
|
+
const candidates = [];
|
|
265
|
+
for (const meta of templatesResult.value) {
|
|
266
|
+
if (!meta.detect || meta.detect.length === 0) continue;
|
|
267
|
+
if (!meta.framework || !meta.language) continue;
|
|
268
|
+
const score = scoreDetectPatterns(targetDir, meta.detect);
|
|
269
|
+
if (score > 0) {
|
|
270
|
+
candidates.push({
|
|
271
|
+
framework: meta.framework,
|
|
272
|
+
language: meta.language,
|
|
273
|
+
score,
|
|
274
|
+
templateName: meta.name
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
candidates.sort((a, b) => b.score - a.score);
|
|
279
|
+
return Ok(candidates);
|
|
280
|
+
} catch (error) {
|
|
281
|
+
return Err(
|
|
282
|
+
new Error(
|
|
283
|
+
`Framework detection failed: ${error instanceof Error ? error.message : String(error)}`
|
|
284
|
+
)
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
resolveLanguageTemplate(language, framework) {
|
|
289
|
+
const baseName = `${language}-base`;
|
|
290
|
+
const baseDir = this.findTemplateDir(baseName, "name");
|
|
291
|
+
if (!baseDir) return Err(new Error(`Language base template not found: ${baseName}`));
|
|
292
|
+
const metaPath = path.join(baseDir, "template.json");
|
|
293
|
+
const metaRaw = JSON.parse(fs.readFileSync(metaPath, "utf-8"));
|
|
294
|
+
const metaResult = TemplateMetadataSchema.safeParse(metaRaw);
|
|
295
|
+
if (!metaResult.success)
|
|
296
|
+
return Err(new Error(`Invalid template.json in ${baseName}: ${metaResult.error.message}`));
|
|
297
|
+
const metadata = metaResult.data;
|
|
298
|
+
let files = this.collectFiles(baseDir, baseName);
|
|
299
|
+
let overlayMetadata;
|
|
300
|
+
if (framework) {
|
|
301
|
+
const frameworkDir = this.findTemplateDir(framework, "framework");
|
|
302
|
+
if (!frameworkDir) return Err(new Error(`Framework template not found: ${framework}`));
|
|
303
|
+
const fMetaPath = path.join(frameworkDir, "template.json");
|
|
304
|
+
const fMetaRaw = JSON.parse(fs.readFileSync(fMetaPath, "utf-8"));
|
|
305
|
+
const fMetaResult = TemplateMetadataSchema.safeParse(fMetaRaw);
|
|
306
|
+
if (fMetaResult.success) overlayMetadata = fMetaResult.data;
|
|
307
|
+
const frameworkFiles = this.collectFiles(frameworkDir, framework);
|
|
308
|
+
files = this.mergeFileLists(files, frameworkFiles);
|
|
309
|
+
}
|
|
310
|
+
files = files.filter((f) => f.relativePath !== "template.json");
|
|
311
|
+
const resolved = { metadata, files };
|
|
312
|
+
if (overlayMetadata !== void 0) resolved.overlayMetadata = overlayMetadata;
|
|
313
|
+
return Ok(resolved);
|
|
314
|
+
}
|
|
196
315
|
findTemplateDir(name, type) {
|
|
197
316
|
const entries = fs.readdirSync(this.templatesDir, { withFileTypes: true });
|
|
198
317
|
for (const entry of entries) {
|
|
@@ -202,11 +321,8 @@ var TemplateEngine = class {
|
|
|
202
321
|
const raw = JSON.parse(fs.readFileSync(metaPath, "utf-8"));
|
|
203
322
|
const parsed = TemplateMetadataSchema.safeParse(raw);
|
|
204
323
|
if (!parsed.success) continue;
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
if (type === "framework" && parsed.data.framework === name)
|
|
208
|
-
return path.join(this.templatesDir, entry.name);
|
|
209
|
-
if (parsed.data.name === name) return path.join(this.templatesDir, entry.name);
|
|
324
|
+
const fieldValue = parsed.data[type];
|
|
325
|
+
if (fieldValue === name) return path.join(this.templatesDir, entry.name);
|
|
210
326
|
}
|
|
211
327
|
return null;
|
|
212
328
|
}
|
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
} from "./chunk-3WGJMBKH.js";
|
|
5
5
|
import {
|
|
6
6
|
ArchConfigSchema
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-Z2OOPXJO.js";
|
|
8
8
|
import {
|
|
9
9
|
Err,
|
|
10
10
|
Ok
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-ERS5EVUZ.js";
|
|
12
12
|
|
|
13
13
|
// src/config/loader.ts
|
|
14
14
|
import * as fs from "fs";
|
|
@@ -184,12 +184,23 @@ var HarnessConfigSchema = z.object({
|
|
|
184
184
|
performance: PerformanceConfigSchema.optional(),
|
|
185
185
|
/** Project template settings (used by 'harness init') */
|
|
186
186
|
template: z.object({
|
|
187
|
-
/** Complexity level of the template */
|
|
188
|
-
level: z.enum(["basic", "intermediate", "advanced"]),
|
|
187
|
+
/** Complexity level of the template (JS/TS only) */
|
|
188
|
+
level: z.enum(["basic", "intermediate", "advanced"]).optional(),
|
|
189
|
+
/** Target language */
|
|
190
|
+
language: z.enum(["typescript", "python", "go", "rust", "java"]).optional(),
|
|
189
191
|
/** Primary technology framework */
|
|
190
192
|
framework: z.string().optional(),
|
|
191
193
|
/** Template version */
|
|
192
|
-
version: z.number()
|
|
194
|
+
version: z.number(),
|
|
195
|
+
/** Language-specific tooling configuration */
|
|
196
|
+
tooling: z.object({
|
|
197
|
+
packageManager: z.string().optional(),
|
|
198
|
+
linter: z.string().optional(),
|
|
199
|
+
formatter: z.string().optional(),
|
|
200
|
+
buildTool: z.string().optional(),
|
|
201
|
+
testRunner: z.string().optional(),
|
|
202
|
+
lockFile: z.string().optional()
|
|
203
|
+
}).optional()
|
|
193
204
|
}).optional(),
|
|
194
205
|
/** Phase gate and readiness check configuration */
|
|
195
206
|
phaseGates: PhaseGatesConfigSchema.optional(),
|
|
@@ -264,6 +264,49 @@ async function validate(options) {
|
|
|
264
264
|
}
|
|
265
265
|
return { success: true, ruleCount: parseResult.data.rules.length };
|
|
266
266
|
}
|
|
267
|
+
function resolveOutputDir(options, configOutput) {
|
|
268
|
+
const configDir = path3.dirname(path3.resolve(options.configPath));
|
|
269
|
+
return options.outputDir ? path3.resolve(options.outputDir) : path3.resolve(configDir, configOutput);
|
|
270
|
+
}
|
|
271
|
+
async function prepareOutputDir(outputDir, clean) {
|
|
272
|
+
if (clean) {
|
|
273
|
+
try {
|
|
274
|
+
await fs3.rm(outputDir, { recursive: true, force: true });
|
|
275
|
+
} catch {
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
await fs3.mkdir(outputDir, { recursive: true });
|
|
279
|
+
}
|
|
280
|
+
async function processRule(rule, templates, configDir, outputDir, configPath, dryRun, errors) {
|
|
281
|
+
const templateResult = await loadTemplate(rule.type, templates, configDir);
|
|
282
|
+
if (!templateResult.success) {
|
|
283
|
+
errors.push({ type: "template", error: templateResult.error, ruleName: rule.name });
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
const ruleResult = generateRule(rule, templateResult.source, outputDir, configPath);
|
|
287
|
+
if (!ruleResult.success) {
|
|
288
|
+
errors.push({ type: "render", error: ruleResult.error, ruleName: ruleResult.ruleName });
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
if (!dryRun) {
|
|
292
|
+
try {
|
|
293
|
+
await fs3.writeFile(ruleResult.rule.outputPath, ruleResult.rule.content, "utf-8");
|
|
294
|
+
} catch (err) {
|
|
295
|
+
errors.push({ type: "write", error: err, path: ruleResult.rule.outputPath });
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return rule.name;
|
|
300
|
+
}
|
|
301
|
+
async function writeIndexFile(outputDir, generatedRules, errors) {
|
|
302
|
+
const indexContent = generateIndex(generatedRules);
|
|
303
|
+
const indexPath = path3.join(outputDir, "index.ts");
|
|
304
|
+
try {
|
|
305
|
+
await fs3.writeFile(indexPath, indexContent, "utf-8");
|
|
306
|
+
} catch (err) {
|
|
307
|
+
errors.push({ type: "write", error: err, path: indexPath });
|
|
308
|
+
}
|
|
309
|
+
}
|
|
267
310
|
async function generate(options) {
|
|
268
311
|
const errors = [];
|
|
269
312
|
const parseResult = await parseConfig(options.configPath);
|
|
@@ -271,69 +314,25 @@ async function generate(options) {
|
|
|
271
314
|
return { success: false, errors: [{ type: "parse", error: parseResult.error }] };
|
|
272
315
|
}
|
|
273
316
|
const config = parseResult.data;
|
|
317
|
+
const outputDir = resolveOutputDir(options, config.output);
|
|
318
|
+
const dryRun = options.dryRun ?? false;
|
|
274
319
|
const configDir = path3.dirname(path3.resolve(options.configPath));
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
try {
|
|
278
|
-
await fs3.rm(outputDir, { recursive: true, force: true });
|
|
279
|
-
} catch {
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
if (!options.dryRun) {
|
|
283
|
-
await fs3.mkdir(outputDir, { recursive: true });
|
|
320
|
+
if (!dryRun) {
|
|
321
|
+
await prepareOutputDir(outputDir, options.clean ?? false);
|
|
284
322
|
}
|
|
285
323
|
const generatedRules = [];
|
|
286
324
|
for (const rule of config.rules) {
|
|
287
|
-
const
|
|
288
|
-
if (
|
|
289
|
-
|
|
290
|
-
type: "template",
|
|
291
|
-
error: templateResult.error,
|
|
292
|
-
ruleName: rule.name
|
|
293
|
-
});
|
|
294
|
-
continue;
|
|
295
|
-
}
|
|
296
|
-
const ruleResult = generateRule(rule, templateResult.source, outputDir, options.configPath);
|
|
297
|
-
if (!ruleResult.success) {
|
|
298
|
-
errors.push({
|
|
299
|
-
type: "render",
|
|
300
|
-
error: ruleResult.error,
|
|
301
|
-
ruleName: ruleResult.ruleName
|
|
302
|
-
});
|
|
303
|
-
continue;
|
|
304
|
-
}
|
|
305
|
-
if (!options.dryRun) {
|
|
306
|
-
try {
|
|
307
|
-
await fs3.writeFile(ruleResult.rule.outputPath, ruleResult.rule.content, "utf-8");
|
|
308
|
-
} catch (err) {
|
|
309
|
-
errors.push({
|
|
310
|
-
type: "write",
|
|
311
|
-
error: err,
|
|
312
|
-
path: ruleResult.rule.outputPath
|
|
313
|
-
});
|
|
314
|
-
continue;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
generatedRules.push(rule.name);
|
|
325
|
+
const name = await processRule(rule, config.templates, configDir, outputDir, options.configPath, dryRun, errors);
|
|
326
|
+
if (name)
|
|
327
|
+
generatedRules.push(name);
|
|
318
328
|
}
|
|
319
|
-
if (generatedRules.length > 0 && !
|
|
320
|
-
|
|
321
|
-
const indexPath = path3.join(outputDir, "index.ts");
|
|
322
|
-
try {
|
|
323
|
-
await fs3.writeFile(indexPath, indexContent, "utf-8");
|
|
324
|
-
} catch (err) {
|
|
325
|
-
errors.push({ type: "write", error: err, path: indexPath });
|
|
326
|
-
}
|
|
329
|
+
if (generatedRules.length > 0 && !dryRun) {
|
|
330
|
+
await writeIndexFile(outputDir, generatedRules, errors);
|
|
327
331
|
}
|
|
328
332
|
if (errors.length > 0) {
|
|
329
333
|
return { success: false, errors };
|
|
330
334
|
}
|
|
331
|
-
return {
|
|
332
|
-
success: true,
|
|
333
|
-
rulesGenerated: generatedRules,
|
|
334
|
-
outputDir,
|
|
335
|
-
dryRun: options.dryRun ?? false
|
|
336
|
-
};
|
|
335
|
+
return { success: true, rulesGenerated: generatedRules, outputDir, dryRun };
|
|
337
336
|
}
|
|
338
337
|
|
|
339
338
|
export {
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
} from "./chunk-W6Y7ZW3Y.js";
|
|
7
7
|
import {
|
|
8
8
|
Ok
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-ERS5EVUZ.js";
|
|
10
10
|
|
|
11
11
|
// src/mcp/tools/performance.ts
|
|
12
12
|
var checkPerformanceDefinition = {
|
|
@@ -27,7 +27,7 @@ var checkPerformanceDefinition = {
|
|
|
27
27
|
};
|
|
28
28
|
async function handleCheckPerformance(input) {
|
|
29
29
|
try {
|
|
30
|
-
const { EntropyAnalyzer } = await import("./dist-
|
|
30
|
+
const { EntropyAnalyzer } = await import("./dist-ALQDD67R.js");
|
|
31
31
|
const typeFilter = input.type ?? "all";
|
|
32
32
|
const projectPath = sanitizePath(input.path);
|
|
33
33
|
const analyzer = new EntropyAnalyzer({
|
|
@@ -40,10 +40,10 @@ async function handleCheckPerformance(input) {
|
|
|
40
40
|
});
|
|
41
41
|
let graphOptions;
|
|
42
42
|
try {
|
|
43
|
-
const { loadGraphStore } = await import("./graph-loader-
|
|
43
|
+
const { loadGraphStore } = await import("./graph-loader-2M2HXDQI.js");
|
|
44
44
|
const store = await loadGraphStore(projectPath);
|
|
45
45
|
if (store) {
|
|
46
|
-
const { GraphComplexityAdapter, GraphCouplingAdapter } = await import("./dist-
|
|
46
|
+
const { GraphComplexityAdapter, GraphCouplingAdapter } = await import("./dist-B26DFXMP.js");
|
|
47
47
|
const complexityAdapter = new GraphComplexityAdapter(store);
|
|
48
48
|
const couplingAdapter = new GraphCouplingAdapter(store);
|
|
49
49
|
graphOptions = {
|
|
@@ -80,7 +80,7 @@ var getPerfBaselinesDefinition = {
|
|
|
80
80
|
};
|
|
81
81
|
async function handleGetPerfBaselines(input) {
|
|
82
82
|
try {
|
|
83
|
-
const { BaselineManager } = await import("./dist-
|
|
83
|
+
const { BaselineManager } = await import("./dist-ALQDD67R.js");
|
|
84
84
|
const manager = new BaselineManager(sanitizePath(input.path));
|
|
85
85
|
const baselines = manager.load();
|
|
86
86
|
return resultToMcpResponse(
|
|
@@ -128,7 +128,7 @@ var updatePerfBaselinesDefinition = {
|
|
|
128
128
|
};
|
|
129
129
|
async function handleUpdatePerfBaselines(input) {
|
|
130
130
|
try {
|
|
131
|
-
const { BaselineManager } = await import("./dist-
|
|
131
|
+
const { BaselineManager } = await import("./dist-ALQDD67R.js");
|
|
132
132
|
const manager = new BaselineManager(sanitizePath(input.path));
|
|
133
133
|
manager.save(input.results, input.commitHash);
|
|
134
134
|
const updated = manager.load();
|
|
@@ -158,7 +158,7 @@ var getCriticalPathsDefinition = {
|
|
|
158
158
|
};
|
|
159
159
|
async function handleGetCriticalPaths(input) {
|
|
160
160
|
try {
|
|
161
|
-
const { CriticalPathResolver } = await import("./dist-
|
|
161
|
+
const { CriticalPathResolver } = await import("./dist-ALQDD67R.js");
|
|
162
162
|
const resolver = new CriticalPathResolver(sanitizePath(input.path));
|
|
163
163
|
const result = await resolver.resolve();
|
|
164
164
|
return resultToMcpResponse(Ok(result));
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
// ../types/dist/index.mjs
|
|
2
|
+
var SESSION_SECTION_NAMES = [
|
|
3
|
+
"terminology",
|
|
4
|
+
"decisions",
|
|
5
|
+
"constraints",
|
|
6
|
+
"risks",
|
|
7
|
+
"openQuestions",
|
|
8
|
+
"evidence"
|
|
9
|
+
];
|
|
2
10
|
function Ok(value) {
|
|
3
11
|
return { ok: true, value };
|
|
4
12
|
}
|
|
@@ -21,6 +29,7 @@ var STANDARD_COGNITIVE_MODES = [
|
|
|
21
29
|
];
|
|
22
30
|
|
|
23
31
|
export {
|
|
32
|
+
SESSION_SECTION_NAMES,
|
|
24
33
|
Ok,
|
|
25
34
|
Err,
|
|
26
35
|
isOk,
|
|
@@ -15,7 +15,7 @@ function evictIfNeeded() {
|
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
async function doLoadGraphStore(projectRoot) {
|
|
18
|
-
const { GraphStore } = await import("./dist-
|
|
18
|
+
const { GraphStore } = await import("./dist-B26DFXMP.js");
|
|
19
19
|
const graphDir = path.join(projectRoot, ".harness", "graph");
|
|
20
20
|
const store = new GraphStore();
|
|
21
21
|
const loaded = await store.load(graphDir);
|