@harness-engineering/cli 1.13.1 → 1.14.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-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-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-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-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-md-YTYQDA3P.js +8 -0
- package/dist/{architecture-2R5Z4ZAF.js → architecture-JQZYM4US.js} +4 -4
- package/dist/bin/harness-mcp.js +14 -14
- package/dist/bin/harness.js +24 -24
- package/dist/{check-phase-gate-2OFZ7OWW.js → check-phase-gate-L3RADYWO.js} +4 -4
- package/dist/{chunk-QY4T6YAZ.js → chunk-3C2MLBPJ.js} +4 -4
- package/dist/{chunk-UAX4I5ZE.js → chunk-6KTUUFRN.js} +2 -2
- package/dist/{chunk-ND6PNADU.js → chunk-7IP4JIFL.js} +9 -9
- package/dist/{chunk-C2ERUR3L.js → chunk-7MJAPE3Z.js} +165 -49
- package/dist/{chunk-PQ5YK4AY.js → chunk-ABQHQ6I5.js} +1583 -1169
- package/dist/{chunk-QPEH2QPG.js → chunk-DBSOCI3G.js} +53 -54
- 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-4ZMOCPYO.js → chunk-NLVUVUGD.js} +1 -1
- package/dist/{chunk-Z77YQRQT.js → chunk-O5OJVPL6.js} +16 -5
- package/dist/{chunk-NKDM3FMH.js → chunk-OD3S2NHN.js} +1 -1
- package/dist/{chunk-65FRIL4D.js → chunk-OSXBPAMK.js} +1 -1
- package/dist/{chunk-DZS7CJKL.js → chunk-OXLLOSSR.js} +45 -47
- package/dist/{chunk-TS3XWPW5.js → chunk-RCWZBSK5.js} +1 -1
- package/dist/{chunk-NOPU4RZ4.js → chunk-S2FXOWOR.js} +3 -3
- package/dist/{chunk-VUCPTQ6G.js → chunk-SD3SQOZ2.js} +1 -1
- package/dist/{chunk-IM32EEDM.js → chunk-TPOTOBR7.js} +9 -9
- package/dist/{chunk-SSKDAOX5.js → chunk-XKECDXJS.js} +436 -340
- package/dist/{chunk-TKJZKICB.js → chunk-YPYGXRDR.js} +7 -7
- package/dist/{chunk-Q6AB7W5Z.js → chunk-YQ6KC6TE.js} +1 -1
- package/dist/{chunk-NERR4TAO.js → chunk-YZD2MRNQ.js} +972 -747
- package/dist/ci-workflow-EQZFVX3P.js +8 -0
- package/dist/{dist-HXHWB7SV.js → dist-B26DFXMP.js} +571 -478
- package/dist/{dist-L7LAAQAS.js → dist-DZ63LLUD.js} +1 -1
- package/dist/{dist-2B363XUH.js → dist-HWXF2C3R.js} +18 -2
- package/dist/{dist-D4RYGUZE.js → dist-USY2C5JL.js} +3 -1
- package/dist/{docs-FZOPM4GK.js → docs-7ECGYMAV.js} +4 -4
- package/dist/engine-EG4EH4IX.js +8 -0
- package/dist/{entropy-LVHJMFGH.js → entropy-5USWKLVS.js} +3 -3
- package/dist/{feedback-IHLVLMRD.js → feedback-UTBXZZHF.js} +1 -1
- package/dist/{generate-agent-definitions-64S3CLEZ.js → generate-agent-definitions-3PM5EU7V.js} +4 -4
- package/dist/{graph-loader-GJZ4FN4Y.js → graph-loader-2M2HXDQI.js} +1 -1
- package/dist/index.d.ts +148 -9
- package/dist/index.js +24 -24
- package/dist/loader-ZPALXIVR.js +10 -0
- package/dist/{mcp-JQUI7BVZ.js → mcp-362EZHF4.js} +14 -14
- package/dist/{performance-ZTVSUANN.js → performance-OQAFMJUD.js} +3 -3
- package/dist/{review-pipeline-76JHKGSV.js → review-pipeline-C4GCFVGP.js} +1 -1
- package/dist/runtime-7YLVK453.js +9 -0
- package/dist/{security-FWQZF2IZ.js → security-PZOX7AQS.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-FD3Z6VJD.js} +4 -4
- package/dist/validate-cross-check-WNJM6H2D.js +8 -0
- package/package.json +5 -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,20 +1,20 @@
|
|
|
1
1
|
import {
|
|
2
2
|
generateCIWorkflow
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-SD3SQOZ2.js";
|
|
4
4
|
import {
|
|
5
5
|
OutputFormatter,
|
|
6
6
|
OutputMode,
|
|
7
7
|
createCheckPhaseGateCommand,
|
|
8
8
|
findFiles
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-6KTUUFRN.js";
|
|
10
10
|
import {
|
|
11
11
|
createGenerateAgentDefinitionsCommand,
|
|
12
12
|
generateAgentDefinitions
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-RCWZBSK5.js";
|
|
14
14
|
import {
|
|
15
15
|
listPersonas,
|
|
16
16
|
loadPersona
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-YQ6KC6TE.js";
|
|
18
18
|
import {
|
|
19
19
|
runPersona
|
|
20
20
|
} from "./chunk-TRAPF4IX.js";
|
|
@@ -33,29 +33,31 @@ import {
|
|
|
33
33
|
import {
|
|
34
34
|
generate,
|
|
35
35
|
validate
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-DBSOCI3G.js";
|
|
37
37
|
import {
|
|
38
38
|
generateRuntime
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-FIAPHX37.js";
|
|
40
40
|
import {
|
|
41
41
|
toKebabCase
|
|
42
42
|
} from "./chunk-KET4QQZB.js";
|
|
43
43
|
import {
|
|
44
44
|
generateAgentsMd
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-OD3S2NHN.js";
|
|
46
46
|
import {
|
|
47
|
+
appendFrameworkAgents,
|
|
47
48
|
createGenerateSlashCommandsCommand,
|
|
48
49
|
generateSlashCommands,
|
|
49
50
|
handleGetImpact,
|
|
50
|
-
handleOrphanDeletion
|
|
51
|
-
|
|
51
|
+
handleOrphanDeletion,
|
|
52
|
+
persistToolingConfig
|
|
53
|
+
} from "./chunk-YZD2MRNQ.js";
|
|
52
54
|
import {
|
|
53
55
|
VALID_PLATFORMS
|
|
54
56
|
} from "./chunk-ZOAWBDWU.js";
|
|
55
57
|
import {
|
|
56
58
|
findConfigFile,
|
|
57
59
|
resolveConfig
|
|
58
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-O5OJVPL6.js";
|
|
59
61
|
import {
|
|
60
62
|
resolveGlobalSkillsDir,
|
|
61
63
|
resolvePersonasDir,
|
|
@@ -76,7 +78,7 @@ import {
|
|
|
76
78
|
} from "./chunk-BM3PWGXQ.js";
|
|
77
79
|
import {
|
|
78
80
|
TemplateEngine
|
|
79
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-7MJAPE3Z.js";
|
|
80
82
|
import {
|
|
81
83
|
ArchBaselineManager,
|
|
82
84
|
ArchConfigSchema,
|
|
@@ -125,11 +127,11 @@ import {
|
|
|
125
127
|
validateKnowledgeMap,
|
|
126
128
|
writeConfig,
|
|
127
129
|
writeLockfile
|
|
128
|
-
} from "./chunk-
|
|
130
|
+
} from "./chunk-ABQHQ6I5.js";
|
|
129
131
|
import {
|
|
130
132
|
Err,
|
|
131
133
|
Ok
|
|
132
|
-
} from "./chunk-
|
|
134
|
+
} from "./chunk-ERS5EVUZ.js";
|
|
133
135
|
|
|
134
136
|
// src/index.ts
|
|
135
137
|
import { Command as Command55 } from "commander";
|
|
@@ -211,7 +213,7 @@ function createValidateCommand() {
|
|
|
211
213
|
process.exit(result.error.exitCode);
|
|
212
214
|
}
|
|
213
215
|
if (opts.crossCheck) {
|
|
214
|
-
const { runCrossCheck: runCrossCheck2 } = await import("./validate-cross-check-
|
|
216
|
+
const { runCrossCheck: runCrossCheck2 } = await import("./validate-cross-check-WNJM6H2D.js");
|
|
215
217
|
const cwd = process.cwd();
|
|
216
218
|
const specsDir = path.join(cwd, "docs", "specs");
|
|
217
219
|
const plansDir = path.join(cwd, "docs", "plans");
|
|
@@ -564,12 +566,11 @@ function createCheckSecurityCommand() {
|
|
|
564
566
|
// src/commands/perf.ts
|
|
565
567
|
import { Command as Command5 } from "commander";
|
|
566
568
|
import * as path5 from "path";
|
|
567
|
-
function
|
|
568
|
-
const perf = new Command5("perf").description("Performance benchmark and baseline management");
|
|
569
|
+
function registerBenchCommand(perf) {
|
|
569
570
|
perf.command("bench [glob]").description("Run benchmarks via vitest bench").action(async (glob, _opts, cmd) => {
|
|
570
571
|
const globalOpts = cmd.optsWithGlobals();
|
|
571
572
|
const cwd = process.cwd();
|
|
572
|
-
const { BenchmarkRunner } = await import("./dist-
|
|
573
|
+
const { BenchmarkRunner } = await import("./dist-HWXF2C3R.js");
|
|
573
574
|
const runner = new BenchmarkRunner();
|
|
574
575
|
const benchFiles = runner.discover(cwd, glob);
|
|
575
576
|
if (benchFiles.length === 0) {
|
|
@@ -580,48 +581,47 @@ function createPerfCommand() {
|
|
|
580
581
|
}
|
|
581
582
|
return;
|
|
582
583
|
}
|
|
583
|
-
|
|
584
|
-
logger.info(`Found ${benchFiles.length} benchmark file(s). Running...`);
|
|
585
|
-
} else {
|
|
586
|
-
logger.info(`Found ${benchFiles.length} benchmark file(s):`);
|
|
587
|
-
for (const f of benchFiles) {
|
|
588
|
-
logger.info(` ${f}`);
|
|
589
|
-
}
|
|
590
|
-
logger.info("Running benchmarks...");
|
|
591
|
-
}
|
|
584
|
+
logBenchDiscovery(globalOpts.json, benchFiles);
|
|
592
585
|
const result = await runner.run(glob ? { cwd, glob } : { cwd });
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
586
|
+
outputBenchResults(globalOpts.json, result);
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
function logBenchDiscovery(json, benchFiles) {
|
|
590
|
+
if (json) {
|
|
591
|
+
logger.info(`Found ${benchFiles.length} benchmark file(s). Running...`);
|
|
592
|
+
} else {
|
|
593
|
+
logger.info(`Found ${benchFiles.length} benchmark file(s):`);
|
|
594
|
+
for (const f of benchFiles) logger.info(` ${f}`);
|
|
595
|
+
logger.info("Running benchmarks...");
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
function outputBenchResults(json, result) {
|
|
599
|
+
if (json) {
|
|
600
|
+
console.log(JSON.stringify({ results: result.results, success: result.success }));
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
if (result.success && result.results.length > 0) {
|
|
604
|
+
logger.info(`
|
|
598
605
|
Results (${result.results.length} benchmarks):`);
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
` ${r.file}::${r.name}: ${r.opsPerSec} ops/s (mean: ${r.meanMs.toFixed(2)}ms)`
|
|
602
|
-
);
|
|
603
|
-
}
|
|
604
|
-
logger.info("\nTo save as baselines: harness perf baselines update");
|
|
605
|
-
} else {
|
|
606
|
-
logger.info("Benchmark run completed. Check output above for details.");
|
|
607
|
-
if (result.rawOutput) {
|
|
608
|
-
console.log(result.rawOutput);
|
|
609
|
-
}
|
|
610
|
-
}
|
|
606
|
+
for (const r of result.results) {
|
|
607
|
+
logger.info(` ${r.file}::${r.name}: ${r.opsPerSec} ops/s (mean: ${r.meanMs.toFixed(2)}ms)`);
|
|
611
608
|
}
|
|
612
|
-
|
|
609
|
+
logger.info("\nTo save as baselines: harness perf baselines update");
|
|
610
|
+
} else {
|
|
611
|
+
logger.info("Benchmark run completed. Check output above for details.");
|
|
612
|
+
if (result.rawOutput) console.log(result.rawOutput);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
function registerBaselinesCommands(perf) {
|
|
613
616
|
const baselines = perf.command("baselines").description("Manage performance baselines");
|
|
614
617
|
baselines.command("show").description("Display current baselines").action(async (_opts, cmd) => {
|
|
615
618
|
const globalOpts = cmd.optsWithGlobals();
|
|
616
|
-
const
|
|
617
|
-
const manager = new BaselineManager(cwd);
|
|
619
|
+
const manager = new BaselineManager(process.cwd());
|
|
618
620
|
const data = manager.load();
|
|
619
621
|
if (!data) {
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
logger.info("No baselines file found at .harness/perf/baselines.json");
|
|
624
|
-
}
|
|
622
|
+
console.log(
|
|
623
|
+
globalOpts.json ? JSON.stringify({ baselines: null, message: "No baselines file found" }) : "No baselines file found at .harness/perf/baselines.json"
|
|
624
|
+
);
|
|
625
625
|
return;
|
|
626
626
|
}
|
|
627
627
|
if (globalOpts.json) {
|
|
@@ -638,7 +638,7 @@ Results (${result.results.length} benchmarks):`);
|
|
|
638
638
|
baselines.command("update").description("Update baselines from latest benchmark run").action(async (_opts, cmd) => {
|
|
639
639
|
const globalOpts = cmd.optsWithGlobals();
|
|
640
640
|
const cwd = process.cwd();
|
|
641
|
-
const { BenchmarkRunner } = await import("./dist-
|
|
641
|
+
const { BenchmarkRunner } = await import("./dist-HWXF2C3R.js");
|
|
642
642
|
const runner = new BenchmarkRunner();
|
|
643
643
|
const manager = new BaselineManager(cwd);
|
|
644
644
|
logger.info("Running benchmarks to update baselines...");
|
|
@@ -649,12 +649,7 @@ Results (${result.results.length} benchmarks):`);
|
|
|
649
649
|
);
|
|
650
650
|
return;
|
|
651
651
|
}
|
|
652
|
-
|
|
653
|
-
try {
|
|
654
|
-
const { execSync: execSync5 } = await import("child_process");
|
|
655
|
-
commitHash = execSync5("git rev-parse --short HEAD", { cwd, encoding: "utf-8" }).trim();
|
|
656
|
-
} catch {
|
|
657
|
-
}
|
|
652
|
+
const commitHash = await getCommitHash(cwd);
|
|
658
653
|
manager.save(benchResult.results, commitHash);
|
|
659
654
|
if (globalOpts.json) {
|
|
660
655
|
console.log(JSON.stringify({ updated: benchResult.results.length, commitHash }));
|
|
@@ -663,10 +658,20 @@ Results (${result.results.length} benchmarks):`);
|
|
|
663
658
|
logger.info("Baselines saved to .harness/perf/baselines.json");
|
|
664
659
|
}
|
|
665
660
|
});
|
|
661
|
+
}
|
|
662
|
+
async function getCommitHash(cwd) {
|
|
663
|
+
try {
|
|
664
|
+
const { execSync: execSync5 } = await import("child_process");
|
|
665
|
+
return execSync5("git rev-parse --short HEAD", { cwd, encoding: "utf-8" }).trim();
|
|
666
|
+
} catch {
|
|
667
|
+
return "unknown";
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
function registerReportCommand(perf) {
|
|
666
671
|
perf.command("report").description("Full performance report with metrics, trends, and hotspots").action(async (_opts, cmd) => {
|
|
667
672
|
const globalOpts = cmd.optsWithGlobals();
|
|
668
673
|
const cwd = process.cwd();
|
|
669
|
-
const { EntropyAnalyzer: EntropyAnalyzer2 } = await import("./dist-
|
|
674
|
+
const { EntropyAnalyzer: EntropyAnalyzer2 } = await import("./dist-HWXF2C3R.js");
|
|
670
675
|
const analyzer = new EntropyAnalyzer2({
|
|
671
676
|
rootDir: path5.resolve(cwd),
|
|
672
677
|
analyze: { complexity: true, coupling: true }
|
|
@@ -703,10 +708,11 @@ Results (${result.results.length} benchmarks):`);
|
|
|
703
708
|
}
|
|
704
709
|
}
|
|
705
710
|
});
|
|
711
|
+
}
|
|
712
|
+
function registerCriticalPathsCommand(perf) {
|
|
706
713
|
perf.command("critical-paths").description("Show resolved critical path set (annotations + graph inference)").action(async (_opts, cmd) => {
|
|
707
714
|
const globalOpts = cmd.optsWithGlobals();
|
|
708
|
-
const
|
|
709
|
-
const resolver = new CriticalPathResolver(cwd);
|
|
715
|
+
const resolver = new CriticalPathResolver(process.cwd());
|
|
710
716
|
const result = await resolver.resolve();
|
|
711
717
|
if (globalOpts.json) {
|
|
712
718
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -721,12 +727,29 @@ Results (${result.results.length} benchmarks):`);
|
|
|
721
727
|
}
|
|
722
728
|
}
|
|
723
729
|
});
|
|
730
|
+
}
|
|
731
|
+
function createPerfCommand() {
|
|
732
|
+
const perf = new Command5("perf").description("Performance benchmark and baseline management");
|
|
733
|
+
registerBenchCommand(perf);
|
|
734
|
+
registerBaselinesCommands(perf);
|
|
735
|
+
registerReportCommand(perf);
|
|
736
|
+
registerCriticalPathsCommand(perf);
|
|
724
737
|
return perf;
|
|
725
738
|
}
|
|
726
739
|
|
|
727
740
|
// src/commands/check-docs.ts
|
|
728
741
|
import { Command as Command6 } from "commander";
|
|
729
742
|
import * as path6 from "path";
|
|
743
|
+
|
|
744
|
+
// src/utils/output.ts
|
|
745
|
+
function resolveOutputMode(globalOpts) {
|
|
746
|
+
if (globalOpts.json) return OutputMode.JSON;
|
|
747
|
+
if (globalOpts.quiet) return OutputMode.QUIET;
|
|
748
|
+
if (globalOpts.verbose) return OutputMode.VERBOSE;
|
|
749
|
+
return OutputMode.TEXT;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// src/commands/check-docs.ts
|
|
730
753
|
async function runCheckDocs(options) {
|
|
731
754
|
const cwd = options.cwd ?? process.cwd();
|
|
732
755
|
const minCoverage = options.minCoverage ?? 80;
|
|
@@ -777,7 +800,7 @@ async function runCheckDocs(options) {
|
|
|
777
800
|
function createCheckDocsCommand() {
|
|
778
801
|
const command = new Command6("check-docs").description("Check documentation coverage").option("--min-coverage <percent>", "Minimum coverage percentage", "80").action(async (opts, cmd) => {
|
|
779
802
|
const globalOpts = cmd.optsWithGlobals();
|
|
780
|
-
const mode = globalOpts
|
|
803
|
+
const mode = resolveOutputMode(globalOpts);
|
|
781
804
|
const formatter = new OutputFormatter(mode);
|
|
782
805
|
const result = await runCheckDocs({
|
|
783
806
|
configPath: globalOpts.config,
|
|
@@ -947,7 +970,6 @@ function createSetupMcpCommand() {
|
|
|
947
970
|
async function runInit(options) {
|
|
948
971
|
const cwd = options.cwd ?? process.cwd();
|
|
949
972
|
const name = options.name ?? path8.basename(cwd);
|
|
950
|
-
const level = options.level ?? "basic";
|
|
951
973
|
const force = options.force ?? false;
|
|
952
974
|
const configPath = path8.join(cwd, "harness.config.json");
|
|
953
975
|
if (!force && fs2.existsSync(configPath)) {
|
|
@@ -955,33 +977,82 @@ async function runInit(options) {
|
|
|
955
977
|
new CLIError("Project already initialized. Use --force to overwrite.", ExitCode.ERROR)
|
|
956
978
|
);
|
|
957
979
|
}
|
|
958
|
-
const
|
|
959
|
-
const
|
|
960
|
-
const
|
|
961
|
-
|
|
962
|
-
|
|
980
|
+
const engine = new TemplateEngine(resolveTemplatesDir());
|
|
981
|
+
const templates = engine.listTemplates();
|
|
982
|
+
const templateList = templates.ok ? templates.value : [];
|
|
983
|
+
const validationError = validateFrameworkLanguage(options, templateList);
|
|
984
|
+
if (validationError) return Err(validationError);
|
|
985
|
+
const detected = tryAutoDetect(engine, cwd, options);
|
|
986
|
+
if (detected) return Ok(detected);
|
|
987
|
+
const language = resolveLanguage(options, templateList);
|
|
988
|
+
return scaffoldProject(engine, { cwd, name, force, language, options });
|
|
989
|
+
}
|
|
990
|
+
function validateFrameworkLanguage(options, templateList) {
|
|
991
|
+
if (!options.framework || !options.language) return null;
|
|
992
|
+
const fwTemplate = templateList.find((t) => t.framework === options.framework);
|
|
993
|
+
if (fwTemplate?.language && fwTemplate.language !== options.language) {
|
|
994
|
+
return new CLIError(
|
|
995
|
+
`Framework "${options.framework}" is a ${fwTemplate.language} framework, but --language ${options.language} was specified. Remove --language or use --language ${fwTemplate.language}.`,
|
|
996
|
+
ExitCode.ERROR
|
|
997
|
+
);
|
|
998
|
+
}
|
|
999
|
+
return null;
|
|
1000
|
+
}
|
|
1001
|
+
function tryAutoDetect(engine, cwd, options) {
|
|
1002
|
+
if (options.framework || options.language) return null;
|
|
1003
|
+
const detectResult = engine.detectFramework(cwd);
|
|
1004
|
+
if (detectResult.ok && detectResult.value.length > 0) {
|
|
1005
|
+
return { filesCreated: [], skippedConfigs: [], detectedFrameworks: detectResult.value };
|
|
963
1006
|
}
|
|
1007
|
+
return null;
|
|
1008
|
+
}
|
|
1009
|
+
function resolveLanguage(options, templateList) {
|
|
1010
|
+
if (options.language) return options.language;
|
|
1011
|
+
if (options.framework) {
|
|
1012
|
+
const fwTemplate = templateList.find((t) => t.framework === options.framework);
|
|
1013
|
+
if (fwTemplate?.language) return fwTemplate.language;
|
|
1014
|
+
}
|
|
1015
|
+
return void 0;
|
|
1016
|
+
}
|
|
1017
|
+
function scaffoldProject(engine, ctx) {
|
|
1018
|
+
const { cwd, name, force, language, options } = ctx;
|
|
1019
|
+
const isNonJs = language && language !== "typescript";
|
|
1020
|
+
const level = isNonJs ? void 0 : options.level ?? "basic";
|
|
1021
|
+
const resolveResult = engine.resolveTemplate(level, options.framework, language);
|
|
1022
|
+
if (!resolveResult.ok) return Err(new CLIError(resolveResult.error.message, ExitCode.ERROR));
|
|
964
1023
|
const renderResult = engine.render(resolveResult.value, {
|
|
965
1024
|
projectName: name,
|
|
966
|
-
level,
|
|
967
|
-
...options.framework !== void 0 && { framework: options.framework }
|
|
1025
|
+
level: level ?? "",
|
|
1026
|
+
...options.framework !== void 0 && { framework: options.framework },
|
|
1027
|
+
...language !== void 0 && { language }
|
|
968
1028
|
});
|
|
969
|
-
if (!renderResult.ok)
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
1029
|
+
if (!renderResult.ok) return Err(new CLIError(renderResult.error.message, ExitCode.ERROR));
|
|
1030
|
+
const writeResult = engine.write(renderResult.value, cwd, {
|
|
1031
|
+
overwrite: force,
|
|
1032
|
+
...language !== void 0 && { language }
|
|
1033
|
+
});
|
|
1034
|
+
if (!writeResult.ok) return Err(new CLIError(writeResult.error.message, ExitCode.ERROR));
|
|
1035
|
+
if (writeResult.value.skippedConfigs.length > 0) {
|
|
1036
|
+
logger.warn("Skipped existing package config files:");
|
|
1037
|
+
for (const file of writeResult.value.skippedConfigs) {
|
|
1038
|
+
logger.info(` - ${file} (add harness dependencies manually)`);
|
|
1039
|
+
}
|
|
975
1040
|
}
|
|
976
|
-
|
|
1041
|
+
persistToolingConfig(cwd, resolveResult.value, options.framework);
|
|
1042
|
+
appendFrameworkAgents(cwd, options.framework, language);
|
|
1043
|
+
return Ok({
|
|
1044
|
+
filesCreated: writeResult.value.written,
|
|
1045
|
+
skippedConfigs: writeResult.value.skippedConfigs
|
|
1046
|
+
});
|
|
977
1047
|
}
|
|
978
1048
|
function createInitCommand() {
|
|
979
|
-
const command = new Command8("init").description("Initialize a new harness-engineering project").option("-n, --name <name>", "Project name").option("-l, --level <level>", "Adoption level (basic, intermediate, advanced)", "basic").option("--framework <framework>", "Framework overlay (nextjs)").option("-f, --force", "Overwrite existing files").option("-y, --yes", "Use defaults without prompting").action(async (opts, cmd) => {
|
|
1049
|
+
const command = new Command8("init").description("Initialize a new harness-engineering project").option("-n, --name <name>", "Project name").option("-l, --level <level>", "Adoption level (basic, intermediate, advanced)", "basic").option("--framework <framework>", "Framework overlay (nextjs)").option("--language <language>", "Target language (typescript, python, go, rust, java)").option("-f, --force", "Overwrite existing files").option("-y, --yes", "Use defaults without prompting").action(async (opts, cmd) => {
|
|
980
1050
|
const globalOpts = cmd.optsWithGlobals();
|
|
981
1051
|
const result = await runInit({
|
|
982
1052
|
name: opts.name,
|
|
983
1053
|
level: opts.level,
|
|
984
1054
|
framework: opts.framework,
|
|
1055
|
+
language: opts.language,
|
|
985
1056
|
force: opts.force
|
|
986
1057
|
});
|
|
987
1058
|
if (!result.ok) {
|
|
@@ -1077,10 +1148,39 @@ async function runCleanup(options) {
|
|
|
1077
1148
|
result.totalIssues = result.driftIssues.length + result.deadCode.length + result.patternViolations.length;
|
|
1078
1149
|
return Ok(result);
|
|
1079
1150
|
}
|
|
1151
|
+
function printCleanupResult(value, formatter) {
|
|
1152
|
+
console.log(
|
|
1153
|
+
formatter.formatSummary("Entropy issues", value.totalIssues.toString(), value.totalIssues === 0)
|
|
1154
|
+
);
|
|
1155
|
+
if (value.driftIssues.length > 0) {
|
|
1156
|
+
console.log("\nDocumentation drift:");
|
|
1157
|
+
for (const issue of value.driftIssues) {
|
|
1158
|
+
console.log(` - ${issue.file}: ${issue.issue}`);
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
if (value.deadCode.length > 0) {
|
|
1162
|
+
console.log("\nDead code:");
|
|
1163
|
+
for (const item of value.deadCode.slice(0, 10)) {
|
|
1164
|
+
console.log(` - ${item.file}${item.symbol ? `: ${item.symbol}` : ""}`);
|
|
1165
|
+
}
|
|
1166
|
+
if (value.deadCode.length > 10) {
|
|
1167
|
+
console.log(` ... and ${value.deadCode.length - 10} more`);
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
if (value.patternViolations.length > 0) {
|
|
1171
|
+
console.log("\nPattern violations:");
|
|
1172
|
+
for (const violation of value.patternViolations.slice(0, 10)) {
|
|
1173
|
+
console.log(` - ${violation.file} [${violation.pattern}]: ${violation.message}`);
|
|
1174
|
+
}
|
|
1175
|
+
if (value.patternViolations.length > 10) {
|
|
1176
|
+
console.log(` ... and ${value.patternViolations.length - 10} more`);
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1080
1180
|
function createCleanupCommand() {
|
|
1081
1181
|
const command = new Command9("cleanup").description("Detect entropy issues (doc drift, dead code, patterns)").option("-t, --type <type>", "Issue type: drift, dead-code, patterns, all", "all").action(async (opts, cmd) => {
|
|
1082
1182
|
const globalOpts = cmd.optsWithGlobals();
|
|
1083
|
-
const mode = globalOpts
|
|
1183
|
+
const mode = resolveOutputMode(globalOpts);
|
|
1084
1184
|
const formatter = new OutputFormatter(mode);
|
|
1085
1185
|
const result = await runCleanup({
|
|
1086
1186
|
configPath: globalOpts.config,
|
|
@@ -1100,37 +1200,7 @@ function createCleanupCommand() {
|
|
|
1100
1200
|
if (mode === OutputMode.JSON) {
|
|
1101
1201
|
console.log(JSON.stringify(result.value, null, 2));
|
|
1102
1202
|
} else if (mode !== OutputMode.QUIET || result.value.totalIssues > 0) {
|
|
1103
|
-
|
|
1104
|
-
formatter.formatSummary(
|
|
1105
|
-
"Entropy issues",
|
|
1106
|
-
result.value.totalIssues.toString(),
|
|
1107
|
-
result.value.totalIssues === 0
|
|
1108
|
-
)
|
|
1109
|
-
);
|
|
1110
|
-
if (result.value.driftIssues.length > 0) {
|
|
1111
|
-
console.log("\nDocumentation drift:");
|
|
1112
|
-
for (const issue of result.value.driftIssues) {
|
|
1113
|
-
console.log(` - ${issue.file}: ${issue.issue}`);
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1116
|
-
if (result.value.deadCode.length > 0) {
|
|
1117
|
-
console.log("\nDead code:");
|
|
1118
|
-
for (const item of result.value.deadCode.slice(0, 10)) {
|
|
1119
|
-
console.log(` - ${item.file}${item.symbol ? `: ${item.symbol}` : ""}`);
|
|
1120
|
-
}
|
|
1121
|
-
if (result.value.deadCode.length > 10) {
|
|
1122
|
-
console.log(` ... and ${result.value.deadCode.length - 10} more`);
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1125
|
-
if (result.value.patternViolations.length > 0) {
|
|
1126
|
-
console.log("\nPattern violations:");
|
|
1127
|
-
for (const violation of result.value.patternViolations.slice(0, 10)) {
|
|
1128
|
-
console.log(` - ${violation.file} [${violation.pattern}]: ${violation.message}`);
|
|
1129
|
-
}
|
|
1130
|
-
if (result.value.patternViolations.length > 10) {
|
|
1131
|
-
console.log(` ... and ${result.value.patternViolations.length - 10} more`);
|
|
1132
|
-
}
|
|
1133
|
-
}
|
|
1203
|
+
printCleanupResult(result.value, formatter);
|
|
1134
1204
|
}
|
|
1135
1205
|
process.exit(result.value.totalIssues === 0 ? ExitCode.SUCCESS : ExitCode.VALIDATION_FAILED);
|
|
1136
1206
|
});
|
|
@@ -1238,10 +1308,42 @@ async function runFixDrift(options) {
|
|
|
1238
1308
|
};
|
|
1239
1309
|
return Ok(result);
|
|
1240
1310
|
}
|
|
1311
|
+
function printFixDriftResult(value, mode, formatter) {
|
|
1312
|
+
const statusMessage = value.dryRun ? "(dry-run)" : "";
|
|
1313
|
+
console.log(
|
|
1314
|
+
formatter.formatSummary(
|
|
1315
|
+
`Fix drift ${statusMessage}`,
|
|
1316
|
+
`${value.fixes.length} fixes, ${value.suggestions.length} suggestions`,
|
|
1317
|
+
value.fixes.length === 0 && value.suggestions.length === 0
|
|
1318
|
+
)
|
|
1319
|
+
);
|
|
1320
|
+
if (value.fixes.length > 0) {
|
|
1321
|
+
console.log("\nFixes:");
|
|
1322
|
+
for (const fix of value.fixes.slice(0, 10)) {
|
|
1323
|
+
const status = fix.applied ? "[applied]" : "[pending]";
|
|
1324
|
+
console.log(` ${status} ${fix.action}: ${fix.file}`);
|
|
1325
|
+
}
|
|
1326
|
+
if (value.fixes.length > 10) {
|
|
1327
|
+
console.log(` ... and ${value.fixes.length - 10} more`);
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
if (value.suggestions.length > 0 && (mode === OutputMode.VERBOSE || value.fixes.length === 0)) {
|
|
1331
|
+
console.log("\nSuggestions:");
|
|
1332
|
+
for (const suggestion of value.suggestions.slice(0, 10)) {
|
|
1333
|
+
console.log(` - ${suggestion.file}: ${suggestion.suggestion}`);
|
|
1334
|
+
}
|
|
1335
|
+
if (value.suggestions.length > 10) {
|
|
1336
|
+
console.log(` ... and ${value.suggestions.length - 10} more`);
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
if (value.dryRun && value.fixes.length > 0) {
|
|
1340
|
+
console.log("\nRun with --no-dry-run to apply fixes.");
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1241
1343
|
function createFixDriftCommand() {
|
|
1242
1344
|
const command = new Command10("fix-drift").description("Auto-fix entropy issues (doc drift, dead code)").option("--no-dry-run", "Actually apply fixes (default is dry-run mode)").action(async (opts, cmd) => {
|
|
1243
1345
|
const globalOpts = cmd.optsWithGlobals();
|
|
1244
|
-
const mode = globalOpts
|
|
1346
|
+
const mode = resolveOutputMode(globalOpts);
|
|
1245
1347
|
const formatter = new OutputFormatter(mode);
|
|
1246
1348
|
const result = await runFixDrift({
|
|
1247
1349
|
configPath: globalOpts.config,
|
|
@@ -1261,37 +1363,7 @@ function createFixDriftCommand() {
|
|
|
1261
1363
|
if (mode === OutputMode.JSON) {
|
|
1262
1364
|
console.log(JSON.stringify(result.value, null, 2));
|
|
1263
1365
|
} else if (mode !== OutputMode.QUIET || result.value.fixes.length > 0 || result.value.suggestions.length > 0) {
|
|
1264
|
-
|
|
1265
|
-
const statusMessage = value.dryRun ? "(dry-run)" : "";
|
|
1266
|
-
console.log(
|
|
1267
|
-
formatter.formatSummary(
|
|
1268
|
-
`Fix drift ${statusMessage}`,
|
|
1269
|
-
`${value.fixes.length} fixes, ${value.suggestions.length} suggestions`,
|
|
1270
|
-
value.fixes.length === 0 && value.suggestions.length === 0
|
|
1271
|
-
)
|
|
1272
|
-
);
|
|
1273
|
-
if (value.fixes.length > 0) {
|
|
1274
|
-
console.log("\nFixes:");
|
|
1275
|
-
for (const fix of value.fixes.slice(0, 10)) {
|
|
1276
|
-
const status = fix.applied ? "[applied]" : "[pending]";
|
|
1277
|
-
console.log(` ${status} ${fix.action}: ${fix.file}`);
|
|
1278
|
-
}
|
|
1279
|
-
if (value.fixes.length > 10) {
|
|
1280
|
-
console.log(` ... and ${value.fixes.length - 10} more`);
|
|
1281
|
-
}
|
|
1282
|
-
}
|
|
1283
|
-
if (value.suggestions.length > 0 && (mode === OutputMode.VERBOSE || value.fixes.length === 0)) {
|
|
1284
|
-
console.log("\nSuggestions:");
|
|
1285
|
-
for (const suggestion of value.suggestions.slice(0, 10)) {
|
|
1286
|
-
console.log(` - ${suggestion.file}: ${suggestion.suggestion}`);
|
|
1287
|
-
}
|
|
1288
|
-
if (value.suggestions.length > 10) {
|
|
1289
|
-
console.log(` ... and ${value.suggestions.length - 10} more`);
|
|
1290
|
-
}
|
|
1291
|
-
}
|
|
1292
|
-
if (value.dryRun && value.fixes.length > 0) {
|
|
1293
|
-
console.log("\nRun with --no-dry-run to apply fixes.");
|
|
1294
|
-
}
|
|
1366
|
+
printFixDriftResult(result.value, mode, formatter);
|
|
1295
1367
|
}
|
|
1296
1368
|
process.exit(ExitCode.SUCCESS);
|
|
1297
1369
|
});
|
|
@@ -1356,49 +1428,54 @@ var VALID_TRIGGERS = /* @__PURE__ */ new Set([
|
|
|
1356
1428
|
"on_plan_approved",
|
|
1357
1429
|
"auto"
|
|
1358
1430
|
]);
|
|
1431
|
+
function resolveTrigger(triggerOpt) {
|
|
1432
|
+
if (triggerOpt === "auto") return "auto";
|
|
1433
|
+
return VALID_TRIGGERS.has(triggerOpt) ? triggerOpt : "manual";
|
|
1434
|
+
}
|
|
1435
|
+
function createCommandExecutor() {
|
|
1436
|
+
return async (command) => {
|
|
1437
|
+
if (!ALLOWED_PERSONA_COMMANDS.has(command)) {
|
|
1438
|
+
return Err(new Error(`Unknown harness command: ${command}`));
|
|
1439
|
+
}
|
|
1440
|
+
try {
|
|
1441
|
+
childProcess.execFileSync("npx", ["harness", command], { stdio: "inherit" });
|
|
1442
|
+
return Ok(null);
|
|
1443
|
+
} catch (error) {
|
|
1444
|
+
return Err(new Error(error instanceof Error ? error.message : String(error)));
|
|
1445
|
+
}
|
|
1446
|
+
};
|
|
1447
|
+
}
|
|
1448
|
+
async function runPersonaMode(opts, quiet) {
|
|
1449
|
+
const personasDir = resolvePersonasDir();
|
|
1450
|
+
const filePath = path11.join(personasDir, `${opts.persona}.yaml`);
|
|
1451
|
+
const personaResult = loadPersona(filePath);
|
|
1452
|
+
if (!personaResult.ok) {
|
|
1453
|
+
logger.error(personaResult.error.message);
|
|
1454
|
+
process.exit(ExitCode.ERROR);
|
|
1455
|
+
}
|
|
1456
|
+
const report = await runPersona(personaResult.value, {
|
|
1457
|
+
trigger: resolveTrigger(opts.trigger),
|
|
1458
|
+
commandExecutor: createCommandExecutor(),
|
|
1459
|
+
skillExecutor: executeSkill,
|
|
1460
|
+
projectPath: process.cwd()
|
|
1461
|
+
});
|
|
1462
|
+
if (!quiet) {
|
|
1463
|
+
logger.info(`Persona '${report.persona}' status: ${report.status}`);
|
|
1464
|
+
for (const s of report.steps) {
|
|
1465
|
+
const icon = s.status === "pass" ? "v" : s.status === "fail" ? "x" : "-";
|
|
1466
|
+
const typeTag = s.type === "skill" ? " [skill]" : "";
|
|
1467
|
+
console.log(` [${icon}] ${s.name}${typeTag} (${s.durationMs}ms)`);
|
|
1468
|
+
if (s.artifactPath) console.log(` artifact: ${s.artifactPath}`);
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
process.exit(report.status === "fail" ? ExitCode.ERROR : ExitCode.SUCCESS);
|
|
1472
|
+
}
|
|
1359
1473
|
function createRunCommand() {
|
|
1360
1474
|
return new Command11("run").description("Run an agent task").argument("[task]", "Task to run (review, doc-review, test-review)").option("--timeout <ms>", "Timeout in milliseconds", "300000").option("--persona <name>", "Run a persona by name").option("--trigger <context>", "Trigger context (auto, on_pr, on_commit, manual)", "auto").action(async (task, opts, cmd) => {
|
|
1361
1475
|
const globalOpts = cmd.optsWithGlobals();
|
|
1362
1476
|
if (opts.persona) {
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
const personaResult = loadPersona(filePath);
|
|
1366
|
-
if (!personaResult.ok) {
|
|
1367
|
-
logger.error(personaResult.error.message);
|
|
1368
|
-
process.exit(ExitCode.ERROR);
|
|
1369
|
-
}
|
|
1370
|
-
const persona = personaResult.value;
|
|
1371
|
-
const projectPath = process.cwd();
|
|
1372
|
-
const trigger = opts.trigger === "auto" ? "auto" : VALID_TRIGGERS.has(opts.trigger) ? opts.trigger : "manual";
|
|
1373
|
-
const commandExecutor = async (command) => {
|
|
1374
|
-
if (!ALLOWED_PERSONA_COMMANDS.has(command)) {
|
|
1375
|
-
return Err(new Error(`Unknown harness command: ${command}`));
|
|
1376
|
-
}
|
|
1377
|
-
try {
|
|
1378
|
-
childProcess.execFileSync("npx", ["harness", command], { stdio: "inherit" });
|
|
1379
|
-
return Ok(null);
|
|
1380
|
-
} catch (error) {
|
|
1381
|
-
return Err(new Error(error instanceof Error ? error.message : String(error)));
|
|
1382
|
-
}
|
|
1383
|
-
};
|
|
1384
|
-
const report = await runPersona(persona, {
|
|
1385
|
-
trigger,
|
|
1386
|
-
commandExecutor,
|
|
1387
|
-
skillExecutor: executeSkill,
|
|
1388
|
-
projectPath
|
|
1389
|
-
});
|
|
1390
|
-
if (!globalOpts.quiet) {
|
|
1391
|
-
logger.info(`Persona '${report.persona}' status: ${report.status}`);
|
|
1392
|
-
for (const s of report.steps) {
|
|
1393
|
-
const icon = s.status === "pass" ? "v" : s.status === "fail" ? "x" : "-";
|
|
1394
|
-
const typeTag = s.type === "skill" ? " [skill]" : "";
|
|
1395
|
-
console.log(` [${icon}] ${s.name}${typeTag} (${s.durationMs}ms)`);
|
|
1396
|
-
if (s.artifactPath) {
|
|
1397
|
-
console.log(` artifact: ${s.artifactPath}`);
|
|
1398
|
-
}
|
|
1399
|
-
}
|
|
1400
|
-
}
|
|
1401
|
-
process.exit(report.status === "fail" ? ExitCode.ERROR : ExitCode.SUCCESS);
|
|
1477
|
+
await runPersonaMode(opts, globalOpts.quiet);
|
|
1478
|
+
return;
|
|
1402
1479
|
}
|
|
1403
1480
|
if (!task) {
|
|
1404
1481
|
logger.error("Either a task argument or --persona flag is required.");
|
|
@@ -1987,6 +2064,33 @@ function scanDirectory(dirPath, source) {
|
|
|
1987
2064
|
}
|
|
1988
2065
|
return skills;
|
|
1989
2066
|
}
|
|
2067
|
+
function collectCommunitySkills(seen, allSkills) {
|
|
2068
|
+
const globalDir = resolveGlobalSkillsDir();
|
|
2069
|
+
const skillsDir = path15.dirname(globalDir);
|
|
2070
|
+
const communityBase = path15.join(skillsDir, "community");
|
|
2071
|
+
const communityPlatformDir = path15.join(communityBase, "claude-code");
|
|
2072
|
+
const lockfilePath = path15.join(communityBase, "skills-lock.json");
|
|
2073
|
+
const lockfile = readLockfile2(lockfilePath);
|
|
2074
|
+
const communitySkills = scanDirectory(communityPlatformDir, "community");
|
|
2075
|
+
for (const skill of communitySkills) {
|
|
2076
|
+
const lockEntry = lockfile.skills[`@harness-skills/${skill.name}`];
|
|
2077
|
+
if (lockEntry) skill.version = lockEntry.version;
|
|
2078
|
+
}
|
|
2079
|
+
for (const [pkgName, entry] of Object.entries(lockfile.skills)) {
|
|
2080
|
+
const shortName = pkgName.replace("@harness-skills/", "");
|
|
2081
|
+
if (!seen.has(shortName)) {
|
|
2082
|
+
seen.add(shortName);
|
|
2083
|
+
allSkills.push({
|
|
2084
|
+
name: shortName,
|
|
2085
|
+
description: "",
|
|
2086
|
+
type: "",
|
|
2087
|
+
source: "community",
|
|
2088
|
+
version: entry.version
|
|
2089
|
+
});
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
return communitySkills;
|
|
2093
|
+
}
|
|
1990
2094
|
function collectSkills(opts) {
|
|
1991
2095
|
const seen = /* @__PURE__ */ new Set();
|
|
1992
2096
|
const allSkills = [];
|
|
@@ -2005,34 +2109,7 @@ function collectSkills(opts) {
|
|
|
2005
2109
|
}
|
|
2006
2110
|
}
|
|
2007
2111
|
if (opts.filter === "all" || opts.filter === "installed") {
|
|
2008
|
-
|
|
2009
|
-
const skillsDir = path15.dirname(globalDir);
|
|
2010
|
-
const communityBase = path15.join(skillsDir, "community");
|
|
2011
|
-
const communityPlatformDir = path15.join(communityBase, "claude-code");
|
|
2012
|
-
const lockfilePath = path15.join(communityBase, "skills-lock.json");
|
|
2013
|
-
const lockfile = readLockfile2(lockfilePath);
|
|
2014
|
-
const communitySkills = scanDirectory(communityPlatformDir, "community");
|
|
2015
|
-
for (const skill of communitySkills) {
|
|
2016
|
-
const pkgName = `@harness-skills/${skill.name}`;
|
|
2017
|
-
const lockEntry = lockfile.skills[pkgName];
|
|
2018
|
-
if (lockEntry) {
|
|
2019
|
-
skill.version = lockEntry.version;
|
|
2020
|
-
}
|
|
2021
|
-
}
|
|
2022
|
-
addUnique(communitySkills);
|
|
2023
|
-
for (const [pkgName, entry] of Object.entries(lockfile.skills)) {
|
|
2024
|
-
const shortName = pkgName.replace("@harness-skills/", "");
|
|
2025
|
-
if (!seen.has(shortName)) {
|
|
2026
|
-
seen.add(shortName);
|
|
2027
|
-
allSkills.push({
|
|
2028
|
-
name: shortName,
|
|
2029
|
-
description: "",
|
|
2030
|
-
type: "",
|
|
2031
|
-
source: "community",
|
|
2032
|
-
version: entry.version
|
|
2033
|
-
});
|
|
2034
|
-
}
|
|
2035
|
-
}
|
|
2112
|
+
addUnique(collectCommunitySkills(seen, allSkills));
|
|
2036
2113
|
}
|
|
2037
2114
|
if (opts.filter === "all") {
|
|
2038
2115
|
const globalDir = resolveGlobalSkillsDir();
|
|
@@ -2166,6 +2243,69 @@ ${options.priorState}`);
|
|
|
2166
2243
|
}
|
|
2167
2244
|
|
|
2168
2245
|
// src/commands/skill/run.ts
|
|
2246
|
+
function loadSkillMetadata(skillDir) {
|
|
2247
|
+
const yamlPath = path16.join(skillDir, "skill.yaml");
|
|
2248
|
+
if (!fs7.existsSync(yamlPath)) return null;
|
|
2249
|
+
try {
|
|
2250
|
+
const result = SkillMetadataSchema.safeParse(parse2(fs7.readFileSync(yamlPath, "utf-8")));
|
|
2251
|
+
return result.success ? result.data : null;
|
|
2252
|
+
} catch {
|
|
2253
|
+
return null;
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
function resolveComplexity(metadata, requested, projectPath) {
|
|
2257
|
+
if (!metadata?.phases || metadata.phases.length === 0) return void 0;
|
|
2258
|
+
if (requested === "auto") return detectComplexity(projectPath);
|
|
2259
|
+
return requested;
|
|
2260
|
+
}
|
|
2261
|
+
function loadPrinciples(projectPath) {
|
|
2262
|
+
const principlesPath = path16.join(projectPath, "docs", "principles.md");
|
|
2263
|
+
return fs7.existsSync(principlesPath) ? fs7.readFileSync(principlesPath, "utf-8") : void 0;
|
|
2264
|
+
}
|
|
2265
|
+
function readMostRecentFileInDir(dirPath) {
|
|
2266
|
+
const files = fs7.readdirSync(dirPath).map((f) => ({ name: f, mtime: fs7.statSync(path16.join(dirPath, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
2267
|
+
if (files.length > 0) return fs7.readFileSync(path16.join(dirPath, files[0].name), "utf-8");
|
|
2268
|
+
return void 0;
|
|
2269
|
+
}
|
|
2270
|
+
function loadPriorState(metadata, projectPath) {
|
|
2271
|
+
if (!metadata?.state.persistent || metadata.state.files.length === 0) return void 0;
|
|
2272
|
+
for (const stateFilePath of metadata.state.files) {
|
|
2273
|
+
const fullPath = path16.join(projectPath, stateFilePath);
|
|
2274
|
+
if (!fs7.existsSync(fullPath)) continue;
|
|
2275
|
+
const stat = fs7.statSync(fullPath);
|
|
2276
|
+
if (stat.isDirectory()) return readMostRecentFileInDir(fullPath);
|
|
2277
|
+
return fs7.readFileSync(fullPath, "utf-8");
|
|
2278
|
+
}
|
|
2279
|
+
return void 0;
|
|
2280
|
+
}
|
|
2281
|
+
function validatePhaseName(metadata, phase) {
|
|
2282
|
+
if (!metadata?.phases) return true;
|
|
2283
|
+
return metadata.phases.map((p) => p.name).includes(phase);
|
|
2284
|
+
}
|
|
2285
|
+
function resolvePhaseState(metadata, projectPath, phase) {
|
|
2286
|
+
if (!validatePhaseName(metadata, phase)) {
|
|
2287
|
+
const validPhases = metadata.phases.map((p) => p.name);
|
|
2288
|
+
logger.error(`Unknown phase: ${phase}. Valid phases: ${validPhases.join(", ")}`);
|
|
2289
|
+
return null;
|
|
2290
|
+
}
|
|
2291
|
+
const priorState = loadPriorState(metadata, projectPath);
|
|
2292
|
+
const stateWarning = !priorState && metadata?.state.persistent ? "No prior phase data found. Earlier phases have not been completed. Proceed with caution." : void 0;
|
|
2293
|
+
return { priorState, stateWarning };
|
|
2294
|
+
}
|
|
2295
|
+
function appendProjectState(content, metadata, projectPath, hasPathOpt) {
|
|
2296
|
+
if (!metadata?.state.persistent || !hasPathOpt) return content;
|
|
2297
|
+
const stateFile = path16.join(projectPath, ".harness", "state.json");
|
|
2298
|
+
if (!fs7.existsSync(stateFile)) return content;
|
|
2299
|
+
const stateContent = fs7.readFileSync(stateFile, "utf-8");
|
|
2300
|
+
return content + `
|
|
2301
|
+
|
|
2302
|
+
---
|
|
2303
|
+
## Project State
|
|
2304
|
+
\`\`\`json
|
|
2305
|
+
${stateContent}
|
|
2306
|
+
\`\`\`
|
|
2307
|
+
`;
|
|
2308
|
+
}
|
|
2169
2309
|
function createRunCommand2() {
|
|
2170
2310
|
return new Command22("run").description("Run a skill (outputs SKILL.md content with context preamble)").argument("<name>", "Skill name (e.g., harness-tdd)").option("--path <path>", "Project root path for context injection").option("--complexity <level>", "Complexity: auto, light, full", "auto").option("--phase <name>", "Start at a specific phase (for re-entry)").option("--party", "Enable multi-perspective evaluation").action(async (name, opts, _cmd) => {
|
|
2171
2311
|
const skillsDir = resolveSkillsDir();
|
|
@@ -2175,64 +2315,24 @@ function createRunCommand2() {
|
|
|
2175
2315
|
process.exit(ExitCode.ERROR);
|
|
2176
2316
|
return;
|
|
2177
2317
|
}
|
|
2178
|
-
const
|
|
2179
|
-
let metadata = null;
|
|
2180
|
-
if (fs7.existsSync(yamlPath)) {
|
|
2181
|
-
try {
|
|
2182
|
-
const raw = fs7.readFileSync(yamlPath, "utf-8");
|
|
2183
|
-
const parsed = parse2(raw);
|
|
2184
|
-
const result = SkillMetadataSchema.safeParse(parsed);
|
|
2185
|
-
if (result.success) metadata = result.data;
|
|
2186
|
-
} catch {
|
|
2187
|
-
}
|
|
2188
|
-
}
|
|
2189
|
-
let complexity;
|
|
2190
|
-
if (metadata?.phases && metadata.phases.length > 0) {
|
|
2191
|
-
const requested = opts.complexity ?? "auto";
|
|
2192
|
-
if (requested === "auto") {
|
|
2193
|
-
const projectPath2 = opts.path ? path16.resolve(opts.path) : process.cwd();
|
|
2194
|
-
complexity = detectComplexity(projectPath2);
|
|
2195
|
-
} else {
|
|
2196
|
-
complexity = requested;
|
|
2197
|
-
}
|
|
2198
|
-
}
|
|
2199
|
-
let principles;
|
|
2318
|
+
const metadata = loadSkillMetadata(skillDir);
|
|
2200
2319
|
const projectPath = opts.path ? path16.resolve(opts.path) : process.cwd();
|
|
2201
|
-
const
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2320
|
+
const complexity = resolveComplexity(
|
|
2321
|
+
metadata,
|
|
2322
|
+
opts.complexity ?? "auto",
|
|
2323
|
+
projectPath
|
|
2324
|
+
);
|
|
2325
|
+
const principles = loadPrinciples(projectPath);
|
|
2205
2326
|
let priorState;
|
|
2206
2327
|
let stateWarning;
|
|
2207
2328
|
if (opts.phase) {
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
process.exit(ExitCode.ERROR);
|
|
2213
|
-
return;
|
|
2214
|
-
}
|
|
2215
|
-
}
|
|
2216
|
-
if (metadata?.state.persistent && metadata.state.files.length > 0) {
|
|
2217
|
-
for (const stateFilePath of metadata.state.files) {
|
|
2218
|
-
const fullPath = path16.join(projectPath, stateFilePath);
|
|
2219
|
-
if (fs7.existsSync(fullPath)) {
|
|
2220
|
-
const stat = fs7.statSync(fullPath);
|
|
2221
|
-
if (stat.isDirectory()) {
|
|
2222
|
-
const files = fs7.readdirSync(fullPath).map((f) => ({ name: f, mtime: fs7.statSync(path16.join(fullPath, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
2223
|
-
if (files.length > 0) {
|
|
2224
|
-
priorState = fs7.readFileSync(path16.join(fullPath, files[0].name), "utf-8");
|
|
2225
|
-
}
|
|
2226
|
-
} else {
|
|
2227
|
-
priorState = fs7.readFileSync(fullPath, "utf-8");
|
|
2228
|
-
}
|
|
2229
|
-
break;
|
|
2230
|
-
}
|
|
2231
|
-
}
|
|
2232
|
-
if (!priorState) {
|
|
2233
|
-
stateWarning = "No prior phase data found. Earlier phases have not been completed. Proceed with caution.";
|
|
2234
|
-
}
|
|
2329
|
+
const phaseResult = resolvePhaseState(metadata, projectPath, opts.phase);
|
|
2330
|
+
if (!phaseResult) {
|
|
2331
|
+
process.exit(ExitCode.ERROR);
|
|
2332
|
+
return;
|
|
2235
2333
|
}
|
|
2334
|
+
priorState = phaseResult.priorState;
|
|
2335
|
+
stateWarning = phaseResult.stateWarning;
|
|
2236
2336
|
}
|
|
2237
2337
|
const preamble = buildPreamble({
|
|
2238
2338
|
...complexity !== void 0 && { complexity },
|
|
@@ -2249,21 +2349,12 @@ function createRunCommand2() {
|
|
|
2249
2349
|
process.exit(ExitCode.ERROR);
|
|
2250
2350
|
return;
|
|
2251
2351
|
}
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
---
|
|
2260
|
-
## Project State
|
|
2261
|
-
\`\`\`json
|
|
2262
|
-
${stateContent}
|
|
2263
|
-
\`\`\`
|
|
2264
|
-
`;
|
|
2265
|
-
}
|
|
2266
|
-
}
|
|
2352
|
+
const content = appendProjectState(
|
|
2353
|
+
fs7.readFileSync(skillMdPath, "utf-8"),
|
|
2354
|
+
metadata,
|
|
2355
|
+
projectPath,
|
|
2356
|
+
!!opts.path
|
|
2357
|
+
);
|
|
2267
2358
|
process.stdout.write(preamble + content);
|
|
2268
2359
|
process.exit(ExitCode.SUCCESS);
|
|
2269
2360
|
});
|
|
@@ -2281,6 +2372,48 @@ var REQUIRED_SECTIONS = [
|
|
|
2281
2372
|
"## Success Criteria",
|
|
2282
2373
|
"## Examples"
|
|
2283
2374
|
];
|
|
2375
|
+
function validateSkillMd(name, skillMdPath, skillType, errors) {
|
|
2376
|
+
if (!fs8.existsSync(skillMdPath)) {
|
|
2377
|
+
errors.push(`${name}: missing SKILL.md`);
|
|
2378
|
+
return;
|
|
2379
|
+
}
|
|
2380
|
+
const mdContent = fs8.readFileSync(skillMdPath, "utf-8");
|
|
2381
|
+
for (const section of REQUIRED_SECTIONS) {
|
|
2382
|
+
if (!mdContent.includes(section)) {
|
|
2383
|
+
errors.push(`${name}/SKILL.md: missing section "${section}"`);
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
if (!mdContent.trim().startsWith("# ")) {
|
|
2387
|
+
errors.push(`${name}/SKILL.md: must start with an h1 heading`);
|
|
2388
|
+
}
|
|
2389
|
+
if (skillType === "rigid") {
|
|
2390
|
+
if (!mdContent.includes("## Gates"))
|
|
2391
|
+
errors.push(`${name}/SKILL.md: rigid skill missing "## Gates" section`);
|
|
2392
|
+
if (!mdContent.includes("## Escalation"))
|
|
2393
|
+
errors.push(`${name}/SKILL.md: rigid skill missing "## Escalation" section`);
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
function validateSkillEntry(name, skillsDir, errors) {
|
|
2397
|
+
const skillDir = path17.join(skillsDir, name);
|
|
2398
|
+
const yamlPath = path17.join(skillDir, "skill.yaml");
|
|
2399
|
+
if (!fs8.existsSync(yamlPath)) {
|
|
2400
|
+
errors.push(`${name}: missing skill.yaml`);
|
|
2401
|
+
return false;
|
|
2402
|
+
}
|
|
2403
|
+
try {
|
|
2404
|
+
const raw = fs8.readFileSync(yamlPath, "utf-8");
|
|
2405
|
+
const result = SkillMetadataSchema.safeParse(parse3(raw));
|
|
2406
|
+
if (!result.success) {
|
|
2407
|
+
errors.push(`${name}/skill.yaml: ${result.error.message}`);
|
|
2408
|
+
return false;
|
|
2409
|
+
}
|
|
2410
|
+
validateSkillMd(name, path17.join(skillDir, "SKILL.md"), result.data.type, errors);
|
|
2411
|
+
return true;
|
|
2412
|
+
} catch (e) {
|
|
2413
|
+
errors.push(`${name}: parse error \u2014 ${e instanceof Error ? e.message : String(e)}`);
|
|
2414
|
+
return false;
|
|
2415
|
+
}
|
|
2416
|
+
}
|
|
2284
2417
|
function createValidateCommand3() {
|
|
2285
2418
|
return new Command23("validate").description("Validate all skill.yaml files and SKILL.md structure").action(async (_opts, cmd) => {
|
|
2286
2419
|
const globalOpts = cmd.optsWithGlobals();
|
|
@@ -2294,46 +2427,7 @@ function createValidateCommand3() {
|
|
|
2294
2427
|
const errors = [];
|
|
2295
2428
|
let validated = 0;
|
|
2296
2429
|
for (const name of entries) {
|
|
2297
|
-
|
|
2298
|
-
const yamlPath = path17.join(skillDir, "skill.yaml");
|
|
2299
|
-
const skillMdPath = path17.join(skillDir, "SKILL.md");
|
|
2300
|
-
if (!fs8.existsSync(yamlPath)) {
|
|
2301
|
-
errors.push(`${name}: missing skill.yaml`);
|
|
2302
|
-
continue;
|
|
2303
|
-
}
|
|
2304
|
-
try {
|
|
2305
|
-
const raw = fs8.readFileSync(yamlPath, "utf-8");
|
|
2306
|
-
const parsed = parse3(raw);
|
|
2307
|
-
const result = SkillMetadataSchema.safeParse(parsed);
|
|
2308
|
-
if (!result.success) {
|
|
2309
|
-
errors.push(`${name}/skill.yaml: ${result.error.message}`);
|
|
2310
|
-
continue;
|
|
2311
|
-
}
|
|
2312
|
-
if (fs8.existsSync(skillMdPath)) {
|
|
2313
|
-
const mdContent = fs8.readFileSync(skillMdPath, "utf-8");
|
|
2314
|
-
for (const section of REQUIRED_SECTIONS) {
|
|
2315
|
-
if (!mdContent.includes(section)) {
|
|
2316
|
-
errors.push(`${name}/SKILL.md: missing section "${section}"`);
|
|
2317
|
-
}
|
|
2318
|
-
}
|
|
2319
|
-
if (!mdContent.trim().startsWith("# ")) {
|
|
2320
|
-
errors.push(`${name}/SKILL.md: must start with an h1 heading`);
|
|
2321
|
-
}
|
|
2322
|
-
if (result.data.type === "rigid") {
|
|
2323
|
-
if (!mdContent.includes("## Gates")) {
|
|
2324
|
-
errors.push(`${name}/SKILL.md: rigid skill missing "## Gates" section`);
|
|
2325
|
-
}
|
|
2326
|
-
if (!mdContent.includes("## Escalation")) {
|
|
2327
|
-
errors.push(`${name}/SKILL.md: rigid skill missing "## Escalation" section`);
|
|
2328
|
-
}
|
|
2329
|
-
}
|
|
2330
|
-
} else {
|
|
2331
|
-
errors.push(`${name}: missing SKILL.md`);
|
|
2332
|
-
}
|
|
2333
|
-
validated++;
|
|
2334
|
-
} catch (e) {
|
|
2335
|
-
errors.push(`${name}: parse error \u2014 ${e instanceof Error ? e.message : String(e)}`);
|
|
2336
|
-
}
|
|
2430
|
+
if (validateSkillEntry(name, skillsDir, errors)) validated++;
|
|
2337
2431
|
}
|
|
2338
2432
|
if (globalOpts.json) {
|
|
2339
2433
|
logger.raw({ validated, errors });
|
|
@@ -3192,7 +3286,7 @@ function parseFailOn(failOn) {
|
|
|
3192
3286
|
function createCheckCommand() {
|
|
3193
3287
|
return new Command34("check").description("Run all harness checks for CI (validate, deps, docs, entropy, phase-gate, arch)").option("--skip <checks>", "Comma-separated checks to skip (e.g., entropy,docs)").option("--fail-on <severity>", "Fail on severity level: error (default) or warning", "error").action(async (opts, cmd) => {
|
|
3194
3288
|
const globalOpts = cmd.optsWithGlobals();
|
|
3195
|
-
const mode = globalOpts
|
|
3289
|
+
const mode = resolveOutputMode(globalOpts);
|
|
3196
3290
|
const skip = parseSkip(opts.skip);
|
|
3197
3291
|
const failOn = parseFailOn(opts.failOn);
|
|
3198
3292
|
const result = await runCICheck({
|
|
@@ -3446,6 +3540,21 @@ function prompt(question) {
|
|
|
3446
3540
|
});
|
|
3447
3541
|
});
|
|
3448
3542
|
}
|
|
3543
|
+
async function offerRegeneration() {
|
|
3544
|
+
console.log("");
|
|
3545
|
+
const regenAnswer = await prompt("Regenerate slash commands and agent definitions? (Y/n) ");
|
|
3546
|
+
if (regenAnswer === "n" || regenAnswer === "no") return;
|
|
3547
|
+
const scopeAnswer = await prompt("Generate for (G)lobal or (l)ocal project? (G/l) ");
|
|
3548
|
+
const isGlobal = scopeAnswer !== "l" && scopeAnswer !== "local";
|
|
3549
|
+
try {
|
|
3550
|
+
execFileSync4("harness", ["generate", ...isGlobal ? ["--global"] : []], {
|
|
3551
|
+
stdio: "inherit"
|
|
3552
|
+
});
|
|
3553
|
+
} catch {
|
|
3554
|
+
logger.warn("Generation failed. Run manually:");
|
|
3555
|
+
console.log(` ${chalk3.cyan(`harness generate${isGlobal ? " --global" : ""}`)}`);
|
|
3556
|
+
}
|
|
3557
|
+
}
|
|
3449
3558
|
function createUpdateCommand() {
|
|
3450
3559
|
return new Command37("update").description("Update all @harness-engineering packages to the latest version").option("--version <semver>", "Pin @harness-engineering/cli to a specific version").action(async (opts, cmd) => {
|
|
3451
3560
|
const globalOpts = cmd.optsWithGlobals();
|
|
@@ -3499,20 +3608,7 @@ function createUpdateCommand() {
|
|
|
3499
3608
|
console.log(` ${chalk3.cyan(installCmd)}`);
|
|
3500
3609
|
process.exit(ExitCode.ERROR);
|
|
3501
3610
|
}
|
|
3502
|
-
|
|
3503
|
-
const regenAnswer = await prompt("Regenerate slash commands and agent definitions? (Y/n) ");
|
|
3504
|
-
if (regenAnswer !== "n" && regenAnswer !== "no") {
|
|
3505
|
-
const scopeAnswer = await prompt("Generate for (G)lobal or (l)ocal project? (G/l) ");
|
|
3506
|
-
const isGlobal = scopeAnswer !== "l" && scopeAnswer !== "local";
|
|
3507
|
-
try {
|
|
3508
|
-
execFileSync4("harness", ["generate", ...isGlobal ? ["--global"] : []], {
|
|
3509
|
-
stdio: "inherit"
|
|
3510
|
-
});
|
|
3511
|
-
} catch {
|
|
3512
|
-
logger.warn("Generation failed. Run manually:");
|
|
3513
|
-
console.log(` ${chalk3.cyan(`harness generate${isGlobal ? " --global" : ""}`)}`);
|
|
3514
|
-
}
|
|
3515
|
-
}
|
|
3611
|
+
await offerRegeneration();
|
|
3516
3612
|
process.exit(ExitCode.SUCCESS);
|
|
3517
3613
|
});
|
|
3518
3614
|
}
|
|
@@ -3582,7 +3678,7 @@ function createGenerateCommand3() {
|
|
|
3582
3678
|
import { Command as Command39 } from "commander";
|
|
3583
3679
|
import * as path29 from "path";
|
|
3584
3680
|
async function runScan(projectPath) {
|
|
3585
|
-
const { GraphStore, CodeIngestor, TopologicalLinker, KnowledgeIngestor, GitIngestor } = await import("./dist-
|
|
3681
|
+
const { GraphStore, CodeIngestor, TopologicalLinker, KnowledgeIngestor, GitIngestor } = await import("./dist-B26DFXMP.js");
|
|
3586
3682
|
const store = new GraphStore();
|
|
3587
3683
|
const start = Date.now();
|
|
3588
3684
|
await new CodeIngestor(store).ingest(projectPath);
|
|
@@ -3663,7 +3759,7 @@ async function runIngest(projectPath, source, opts) {
|
|
|
3663
3759
|
SyncManager,
|
|
3664
3760
|
JiraConnector,
|
|
3665
3761
|
SlackConnector
|
|
3666
|
-
} = await import("./dist-
|
|
3762
|
+
} = await import("./dist-B26DFXMP.js");
|
|
3667
3763
|
const graphDir = path30.join(projectPath, ".harness", "graph");
|
|
3668
3764
|
const store = new GraphStore();
|
|
3669
3765
|
await store.load(graphDir);
|
|
@@ -3756,7 +3852,7 @@ function createIngestCommand() {
|
|
|
3756
3852
|
import { Command as Command41 } from "commander";
|
|
3757
3853
|
import * as path31 from "path";
|
|
3758
3854
|
async function runQuery(projectPath, rootNodeId, opts) {
|
|
3759
|
-
const { GraphStore, ContextQL } = await import("./dist-
|
|
3855
|
+
const { GraphStore, ContextQL } = await import("./dist-B26DFXMP.js");
|
|
3760
3856
|
const store = new GraphStore();
|
|
3761
3857
|
const graphDir = path31.join(projectPath, ".harness", "graph");
|
|
3762
3858
|
const loaded = await store.load(graphDir);
|
|
@@ -3805,7 +3901,7 @@ import { Command as Command42 } from "commander";
|
|
|
3805
3901
|
// src/commands/graph/status.ts
|
|
3806
3902
|
import * as path32 from "path";
|
|
3807
3903
|
async function runGraphStatus(projectPath) {
|
|
3808
|
-
const { GraphStore } = await import("./dist-
|
|
3904
|
+
const { GraphStore } = await import("./dist-B26DFXMP.js");
|
|
3809
3905
|
const graphDir = path32.join(projectPath, ".harness", "graph");
|
|
3810
3906
|
const store = new GraphStore();
|
|
3811
3907
|
const loaded = await store.load(graphDir);
|
|
@@ -3845,7 +3941,7 @@ async function runGraphStatus(projectPath) {
|
|
|
3845
3941
|
// src/commands/graph/export.ts
|
|
3846
3942
|
import * as path33 from "path";
|
|
3847
3943
|
async function runGraphExport(projectPath, format) {
|
|
3848
|
-
const { GraphStore } = await import("./dist-
|
|
3944
|
+
const { GraphStore } = await import("./dist-B26DFXMP.js");
|
|
3849
3945
|
const graphDir = path33.join(projectPath, ".harness", "graph");
|
|
3850
3946
|
const store = new GraphStore();
|
|
3851
3947
|
const loaded = await store.load(graphDir);
|
|
@@ -3924,7 +4020,7 @@ function createGraphCommand() {
|
|
|
3924
4020
|
import { Command as Command43 } from "commander";
|
|
3925
4021
|
function createMcpCommand() {
|
|
3926
4022
|
return new Command43("mcp").description("Start the MCP (Model Context Protocol) server on stdio").action(async () => {
|
|
3927
|
-
const { startServer: startServer2 } = await import("./mcp-
|
|
4023
|
+
const { startServer: startServer2 } = await import("./mcp-362EZHF4.js");
|
|
3928
4024
|
await startServer2();
|
|
3929
4025
|
});
|
|
3930
4026
|
}
|
|
@@ -4141,7 +4237,7 @@ function createImpactPreviewCommand() {
|
|
|
4141
4237
|
// src/commands/check-arch.ts
|
|
4142
4238
|
import { Command as Command45 } from "commander";
|
|
4143
4239
|
import { execSync as execSync4 } from "child_process";
|
|
4144
|
-
function
|
|
4240
|
+
function getCommitHash2(cwd) {
|
|
4145
4241
|
try {
|
|
4146
4242
|
return execSync4("git rev-parse --short HEAD", { cwd, encoding: "utf-8" }).toString().trim();
|
|
4147
4243
|
} catch {
|
|
@@ -4189,7 +4285,7 @@ async function runCheckArch(options) {
|
|
|
4189
4285
|
}
|
|
4190
4286
|
const manager = new ArchBaselineManager(cwd, archConfig.baselinePath);
|
|
4191
4287
|
if (options.updateBaseline) {
|
|
4192
|
-
const commitHash =
|
|
4288
|
+
const commitHash = getCommitHash2(cwd);
|
|
4193
4289
|
const baseline2 = manager.capture(results, commitHash);
|
|
4194
4290
|
manager.save(baseline2);
|
|
4195
4291
|
return Ok({
|