mcp-new 1.5.0 → 1.6.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/{chunk-YISSMIHU.js → chunk-LJNMSDBU.js} +975 -206
- package/dist/cli.js +955 -5
- package/dist/index.d.ts +23 -8
- package/dist/index.js +19 -46
- package/package.json +4 -2
- package/templates/ci/circleci/config.yml.ejs +219 -0
- package/templates/ci/github/ci.yml.ejs +184 -0
- package/templates/ci/gitlab/.gitlab-ci.yml.ejs +233 -0
package/dist/cli.js
CHANGED
|
@@ -2,23 +2,32 @@
|
|
|
2
2
|
import {
|
|
3
3
|
PRESETS,
|
|
4
4
|
addToolCommand,
|
|
5
|
+
clearPresetCache,
|
|
5
6
|
createCommand,
|
|
6
7
|
createInitialCommit,
|
|
7
8
|
createSpinner,
|
|
9
|
+
detectJavaBuildTool,
|
|
10
|
+
detectLanguageFromProject,
|
|
8
11
|
ensureDir,
|
|
9
12
|
exists,
|
|
13
|
+
generateCI,
|
|
10
14
|
generateFromWizard,
|
|
15
|
+
getCacheDir,
|
|
11
16
|
initCommand,
|
|
12
17
|
initGitRepository,
|
|
13
18
|
isGitInstalled,
|
|
19
|
+
isValidCIProvider,
|
|
20
|
+
listCachedPresets,
|
|
14
21
|
logger,
|
|
22
|
+
pluginRegistry,
|
|
23
|
+
promptCIProvider,
|
|
15
24
|
promptJavaBuildTool,
|
|
16
25
|
promptLanguage,
|
|
17
26
|
readDir,
|
|
18
27
|
readFile,
|
|
19
28
|
withSpinner,
|
|
20
29
|
writeFile
|
|
21
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-LJNMSDBU.js";
|
|
22
31
|
|
|
23
32
|
// src/cli.ts
|
|
24
33
|
import { Command } from "commander";
|
|
@@ -687,6 +696,876 @@ async function monorepoListCommand() {
|
|
|
687
696
|
}
|
|
688
697
|
}
|
|
689
698
|
|
|
699
|
+
// src/commands/add-ci.ts
|
|
700
|
+
import path4 from "path";
|
|
701
|
+
async function addCICommand(provider, options = {}) {
|
|
702
|
+
const projectDir = process.cwd();
|
|
703
|
+
try {
|
|
704
|
+
const hasPackageJson = await exists(path4.join(projectDir, "package.json"));
|
|
705
|
+
const hasPyproject = await exists(path4.join(projectDir, "pyproject.toml"));
|
|
706
|
+
const hasGoMod = await exists(path4.join(projectDir, "go.mod"));
|
|
707
|
+
const hasCargoToml = await exists(path4.join(projectDir, "Cargo.toml"));
|
|
708
|
+
const hasPomXml = await exists(path4.join(projectDir, "pom.xml"));
|
|
709
|
+
const hasBuildGradle = await exists(path4.join(projectDir, "build.gradle"));
|
|
710
|
+
const hasBuildGradleKts = await exists(path4.join(projectDir, "build.gradle.kts"));
|
|
711
|
+
const hasMixExs = await exists(path4.join(projectDir, "mix.exs"));
|
|
712
|
+
const hasProjectFile = hasPackageJson || hasPyproject || hasGoMod || hasCargoToml || hasPomXml || hasBuildGradle || hasBuildGradleKts || hasMixExs;
|
|
713
|
+
if (!hasProjectFile) {
|
|
714
|
+
logger.error(
|
|
715
|
+
"No project configuration file found. Please run this command from a project root directory."
|
|
716
|
+
);
|
|
717
|
+
process.exit(1);
|
|
718
|
+
}
|
|
719
|
+
let ciProvider;
|
|
720
|
+
const providerArg = provider || options.provider;
|
|
721
|
+
if (providerArg) {
|
|
722
|
+
if (!isValidCIProvider(providerArg)) {
|
|
723
|
+
logger.error(`Invalid CI provider: ${providerArg}. Valid options: github, gitlab, circleci`);
|
|
724
|
+
process.exit(1);
|
|
725
|
+
}
|
|
726
|
+
ciProvider = providerArg;
|
|
727
|
+
} else {
|
|
728
|
+
ciProvider = await promptCIProvider();
|
|
729
|
+
}
|
|
730
|
+
let language = await detectLanguageFromProject(projectDir);
|
|
731
|
+
if (!language) {
|
|
732
|
+
logger.warning("Could not detect project language. Please select manually:");
|
|
733
|
+
language = await promptLanguage();
|
|
734
|
+
}
|
|
735
|
+
let javaBuildTool = await detectJavaBuildTool(projectDir);
|
|
736
|
+
if ((language === "java" || language === "kotlin") && !javaBuildTool) {
|
|
737
|
+
javaBuildTool = await promptJavaBuildTool();
|
|
738
|
+
}
|
|
739
|
+
await generateCI({
|
|
740
|
+
projectDir,
|
|
741
|
+
provider: ciProvider,
|
|
742
|
+
language,
|
|
743
|
+
javaBuildTool,
|
|
744
|
+
projectName: path4.basename(projectDir)
|
|
745
|
+
});
|
|
746
|
+
logger.success(`CI/CD configuration added successfully!`);
|
|
747
|
+
const providerInstructions = {
|
|
748
|
+
github: [
|
|
749
|
+
"Your GitHub Actions workflow has been created at .github/workflows/ci.yml",
|
|
750
|
+
"It will automatically run on push and pull requests to main branch",
|
|
751
|
+
"Commit and push to see it in action"
|
|
752
|
+
],
|
|
753
|
+
gitlab: [
|
|
754
|
+
"Your GitLab CI configuration has been created at .gitlab-ci.yml",
|
|
755
|
+
"It will automatically run on push to any branch",
|
|
756
|
+
"Push to your GitLab repository to see it in action"
|
|
757
|
+
],
|
|
758
|
+
circleci: [
|
|
759
|
+
"Your CircleCI configuration has been created at .circleci/config.yml",
|
|
760
|
+
"Connect your repository to CircleCI to enable the pipeline",
|
|
761
|
+
"Visit https://circleci.com to set up your project"
|
|
762
|
+
]
|
|
763
|
+
};
|
|
764
|
+
logger.nextSteps(providerInstructions[ciProvider]);
|
|
765
|
+
} catch (error) {
|
|
766
|
+
if (error instanceof Error) {
|
|
767
|
+
logger.error(error.message);
|
|
768
|
+
} else {
|
|
769
|
+
logger.error("An unexpected error occurred");
|
|
770
|
+
}
|
|
771
|
+
process.exit(1);
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
// src/commands/docs.ts
|
|
776
|
+
import path8 from "path";
|
|
777
|
+
|
|
778
|
+
// src/docs-server/server.ts
|
|
779
|
+
import http from "http";
|
|
780
|
+
import path7 from "path";
|
|
781
|
+
|
|
782
|
+
// src/docs-server/markdown.ts
|
|
783
|
+
import { marked } from "marked";
|
|
784
|
+
marked.setOptions({
|
|
785
|
+
gfm: true,
|
|
786
|
+
breaks: true
|
|
787
|
+
});
|
|
788
|
+
function parseMarkdown(content) {
|
|
789
|
+
const html = marked.parse(content);
|
|
790
|
+
const titleMatch = content.match(/^#\s+(.+)$/m);
|
|
791
|
+
const title = titleMatch ? titleMatch[1] : "Untitled";
|
|
792
|
+
const headings = [];
|
|
793
|
+
const headingRegex = /^#{1,3}\s+(.+)$/gm;
|
|
794
|
+
let match;
|
|
795
|
+
while ((match = headingRegex.exec(content)) !== null) {
|
|
796
|
+
headings.push(match[1]);
|
|
797
|
+
}
|
|
798
|
+
return {
|
|
799
|
+
title,
|
|
800
|
+
content: html,
|
|
801
|
+
headings,
|
|
802
|
+
rawContent: content
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
function renderMarkdownToHTML(content, title) {
|
|
806
|
+
const parsed = parseMarkdown(content);
|
|
807
|
+
return `<!DOCTYPE html>
|
|
808
|
+
<html lang="en">
|
|
809
|
+
<head>
|
|
810
|
+
<meta charset="UTF-8">
|
|
811
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
812
|
+
<title>${title} - mcp-new Documentation</title>
|
|
813
|
+
<style>
|
|
814
|
+
* {
|
|
815
|
+
margin: 0;
|
|
816
|
+
padding: 0;
|
|
817
|
+
box-sizing: border-box;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
body {
|
|
821
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
|
|
822
|
+
line-height: 1.6;
|
|
823
|
+
color: #333;
|
|
824
|
+
background: #f5f5f5;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
.container {
|
|
828
|
+
display: flex;
|
|
829
|
+
min-height: 100vh;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
.sidebar {
|
|
833
|
+
width: 280px;
|
|
834
|
+
background: #1a1a2e;
|
|
835
|
+
color: #fff;
|
|
836
|
+
padding: 20px;
|
|
837
|
+
position: fixed;
|
|
838
|
+
height: 100vh;
|
|
839
|
+
overflow-y: auto;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
.sidebar h1 {
|
|
843
|
+
font-size: 1.5rem;
|
|
844
|
+
margin-bottom: 20px;
|
|
845
|
+
color: #4fc3f7;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
.sidebar nav ul {
|
|
849
|
+
list-style: none;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
.sidebar nav li {
|
|
853
|
+
margin: 8px 0;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
.sidebar nav a {
|
|
857
|
+
color: #b0bec5;
|
|
858
|
+
text-decoration: none;
|
|
859
|
+
display: block;
|
|
860
|
+
padding: 8px 12px;
|
|
861
|
+
border-radius: 4px;
|
|
862
|
+
transition: background 0.2s, color 0.2s;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
.sidebar nav a:hover,
|
|
866
|
+
.sidebar nav a.active {
|
|
867
|
+
background: rgba(79, 195, 247, 0.1);
|
|
868
|
+
color: #4fc3f7;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
.search-box {
|
|
872
|
+
margin-bottom: 20px;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
.search-box input {
|
|
876
|
+
width: 100%;
|
|
877
|
+
padding: 10px 12px;
|
|
878
|
+
border: none;
|
|
879
|
+
border-radius: 4px;
|
|
880
|
+
background: rgba(255,255,255,0.1);
|
|
881
|
+
color: #fff;
|
|
882
|
+
font-size: 14px;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
.search-box input::placeholder {
|
|
886
|
+
color: #78909c;
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
.main {
|
|
890
|
+
margin-left: 280px;
|
|
891
|
+
flex: 1;
|
|
892
|
+
padding: 40px;
|
|
893
|
+
max-width: 900px;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
.content {
|
|
897
|
+
background: #fff;
|
|
898
|
+
padding: 40px;
|
|
899
|
+
border-radius: 8px;
|
|
900
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
.content h1 {
|
|
904
|
+
font-size: 2.5rem;
|
|
905
|
+
margin-bottom: 20px;
|
|
906
|
+
color: #1a1a2e;
|
|
907
|
+
border-bottom: 2px solid #4fc3f7;
|
|
908
|
+
padding-bottom: 10px;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
.content h2 {
|
|
912
|
+
font-size: 1.8rem;
|
|
913
|
+
margin-top: 40px;
|
|
914
|
+
margin-bottom: 16px;
|
|
915
|
+
color: #1a1a2e;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
.content h3 {
|
|
919
|
+
font-size: 1.4rem;
|
|
920
|
+
margin-top: 30px;
|
|
921
|
+
margin-bottom: 12px;
|
|
922
|
+
color: #333;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
.content p {
|
|
926
|
+
margin-bottom: 16px;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
.content code {
|
|
930
|
+
background: #f0f0f0;
|
|
931
|
+
padding: 2px 6px;
|
|
932
|
+
border-radius: 3px;
|
|
933
|
+
font-family: 'Fira Code', 'Monaco', monospace;
|
|
934
|
+
font-size: 0.9em;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
.content pre {
|
|
938
|
+
background: #1a1a2e;
|
|
939
|
+
color: #f0f0f0;
|
|
940
|
+
padding: 20px;
|
|
941
|
+
border-radius: 6px;
|
|
942
|
+
overflow-x: auto;
|
|
943
|
+
margin: 20px 0;
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
.content pre code {
|
|
947
|
+
background: none;
|
|
948
|
+
padding: 0;
|
|
949
|
+
color: inherit;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
.content ul, .content ol {
|
|
953
|
+
margin: 16px 0;
|
|
954
|
+
padding-left: 30px;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
.content li {
|
|
958
|
+
margin: 8px 0;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
.content a {
|
|
962
|
+
color: #4fc3f7;
|
|
963
|
+
text-decoration: none;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
.content a:hover {
|
|
967
|
+
text-decoration: underline;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
.content blockquote {
|
|
971
|
+
border-left: 4px solid #4fc3f7;
|
|
972
|
+
padding-left: 20px;
|
|
973
|
+
margin: 20px 0;
|
|
974
|
+
color: #666;
|
|
975
|
+
font-style: italic;
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
.content table {
|
|
979
|
+
width: 100%;
|
|
980
|
+
border-collapse: collapse;
|
|
981
|
+
margin: 20px 0;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
.content th, .content td {
|
|
985
|
+
border: 1px solid #ddd;
|
|
986
|
+
padding: 12px;
|
|
987
|
+
text-align: left;
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
.content th {
|
|
991
|
+
background: #f5f5f5;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
.search-results {
|
|
995
|
+
display: none;
|
|
996
|
+
position: absolute;
|
|
997
|
+
top: 100%;
|
|
998
|
+
left: 0;
|
|
999
|
+
right: 0;
|
|
1000
|
+
background: #2a2a3e;
|
|
1001
|
+
border-radius: 4px;
|
|
1002
|
+
max-height: 300px;
|
|
1003
|
+
overflow-y: auto;
|
|
1004
|
+
margin-top: 4px;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
.search-results.active {
|
|
1008
|
+
display: block;
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
.search-result-item {
|
|
1012
|
+
padding: 10px 12px;
|
|
1013
|
+
border-bottom: 1px solid rgba(255,255,255,0.1);
|
|
1014
|
+
cursor: pointer;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
.search-result-item:hover {
|
|
1018
|
+
background: rgba(79, 195, 247, 0.1);
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
.search-result-item h4 {
|
|
1022
|
+
color: #fff;
|
|
1023
|
+
font-size: 14px;
|
|
1024
|
+
margin-bottom: 4px;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
.search-result-item p {
|
|
1028
|
+
color: #78909c;
|
|
1029
|
+
font-size: 12px;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
@media (max-width: 768px) {
|
|
1033
|
+
.sidebar {
|
|
1034
|
+
display: none;
|
|
1035
|
+
}
|
|
1036
|
+
.main {
|
|
1037
|
+
margin-left: 0;
|
|
1038
|
+
padding: 20px;
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
</style>
|
|
1042
|
+
</head>
|
|
1043
|
+
<body>
|
|
1044
|
+
<div class="container">
|
|
1045
|
+
<aside class="sidebar">
|
|
1046
|
+
<h1>mcp-new</h1>
|
|
1047
|
+
<div class="search-box" style="position: relative;">
|
|
1048
|
+
<input type="text" id="search" placeholder="Search docs..." autocomplete="off">
|
|
1049
|
+
<div id="search-results" class="search-results"></div>
|
|
1050
|
+
</div>
|
|
1051
|
+
<nav id="nav">
|
|
1052
|
+
<ul>
|
|
1053
|
+
${parsed.headings.map((h) => `<li><a href="#${slugify(h)}">${h}</a></li>`).join("\n ")}
|
|
1054
|
+
</ul>
|
|
1055
|
+
</nav>
|
|
1056
|
+
</aside>
|
|
1057
|
+
<main class="main">
|
|
1058
|
+
<article class="content">
|
|
1059
|
+
${parsed.content}
|
|
1060
|
+
</article>
|
|
1061
|
+
</main>
|
|
1062
|
+
</div>
|
|
1063
|
+
|
|
1064
|
+
<script>
|
|
1065
|
+
// SSE for hot reload
|
|
1066
|
+
const evtSource = new EventSource('/sse');
|
|
1067
|
+
evtSource.onmessage = function(event) {
|
|
1068
|
+
if (event.data === 'reload') {
|
|
1069
|
+
location.reload();
|
|
1070
|
+
}
|
|
1071
|
+
};
|
|
1072
|
+
|
|
1073
|
+
// Search functionality
|
|
1074
|
+
const searchInput = document.getElementById('search');
|
|
1075
|
+
const searchResults = document.getElementById('search-results');
|
|
1076
|
+
|
|
1077
|
+
searchInput.addEventListener('input', async (e) => {
|
|
1078
|
+
const query = e.target.value.trim();
|
|
1079
|
+
if (query.length < 2) {
|
|
1080
|
+
searchResults.classList.remove('active');
|
|
1081
|
+
return;
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
try {
|
|
1085
|
+
const res = await fetch('/api/search?q=' + encodeURIComponent(query));
|
|
1086
|
+
const results = await res.json();
|
|
1087
|
+
|
|
1088
|
+
if (results.length > 0) {
|
|
1089
|
+
searchResults.innerHTML = results.map(r =>
|
|
1090
|
+
'<div class="search-result-item" onclick="location.href=\\'' + r.path + '\\'"><h4>' + r.title + '</h4><p>' + r.snippet + '</p></div>'
|
|
1091
|
+
).join('');
|
|
1092
|
+
searchResults.classList.add('active');
|
|
1093
|
+
} else {
|
|
1094
|
+
searchResults.classList.remove('active');
|
|
1095
|
+
}
|
|
1096
|
+
} catch (err) {
|
|
1097
|
+
console.error('Search error:', err);
|
|
1098
|
+
}
|
|
1099
|
+
});
|
|
1100
|
+
|
|
1101
|
+
document.addEventListener('click', (e) => {
|
|
1102
|
+
if (!e.target.closest('.search-box')) {
|
|
1103
|
+
searchResults.classList.remove('active');
|
|
1104
|
+
}
|
|
1105
|
+
});
|
|
1106
|
+
</script>
|
|
1107
|
+
</body>
|
|
1108
|
+
</html>`;
|
|
1109
|
+
}
|
|
1110
|
+
function slugify(text) {
|
|
1111
|
+
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
// src/docs-server/search.ts
|
|
1115
|
+
import path5 from "path";
|
|
1116
|
+
var DocsSearchEngine = class {
|
|
1117
|
+
index = { documents: /* @__PURE__ */ new Map() };
|
|
1118
|
+
docsDir;
|
|
1119
|
+
constructor(docsDir) {
|
|
1120
|
+
this.docsDir = docsDir;
|
|
1121
|
+
}
|
|
1122
|
+
async buildIndex() {
|
|
1123
|
+
this.index.documents.clear();
|
|
1124
|
+
await this.indexDirectory(this.docsDir);
|
|
1125
|
+
}
|
|
1126
|
+
async indexDirectory(dir) {
|
|
1127
|
+
if (!await exists(dir)) {
|
|
1128
|
+
return;
|
|
1129
|
+
}
|
|
1130
|
+
const entries = await readDir(dir);
|
|
1131
|
+
for (const entry of entries) {
|
|
1132
|
+
const fullPath = path5.join(dir, entry);
|
|
1133
|
+
try {
|
|
1134
|
+
const subEntries = await readDir(fullPath);
|
|
1135
|
+
await this.indexDirectory(fullPath);
|
|
1136
|
+
} catch {
|
|
1137
|
+
if (entry.endsWith(".md")) {
|
|
1138
|
+
await this.indexFile(fullPath);
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
async indexFile(filePath) {
|
|
1144
|
+
try {
|
|
1145
|
+
const content = await readFile(filePath);
|
|
1146
|
+
const parsed = parseMarkdown(content);
|
|
1147
|
+
const relativePath = "/" + path5.relative(this.docsDir, filePath).replace(/\.md$/, "");
|
|
1148
|
+
const words = /* @__PURE__ */ new Set();
|
|
1149
|
+
const textContent = parsed.rawContent.toLowerCase();
|
|
1150
|
+
const wordMatches = textContent.match(/\b[a-z0-9]+\b/g);
|
|
1151
|
+
if (wordMatches) {
|
|
1152
|
+
wordMatches.forEach((w) => words.add(w));
|
|
1153
|
+
}
|
|
1154
|
+
this.index.documents.set(relativePath, {
|
|
1155
|
+
path: relativePath,
|
|
1156
|
+
title: parsed.title,
|
|
1157
|
+
content: parsed.rawContent,
|
|
1158
|
+
words
|
|
1159
|
+
});
|
|
1160
|
+
} catch (error) {
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
search(query, limit = 10) {
|
|
1164
|
+
const queryWords = query.toLowerCase().split(/\s+/).filter((w) => w.length > 1);
|
|
1165
|
+
if (queryWords.length === 0) {
|
|
1166
|
+
return [];
|
|
1167
|
+
}
|
|
1168
|
+
const results = [];
|
|
1169
|
+
for (const [docPath, doc] of this.index.documents) {
|
|
1170
|
+
let score = 0;
|
|
1171
|
+
const titleLower = doc.title.toLowerCase();
|
|
1172
|
+
for (const word of queryWords) {
|
|
1173
|
+
if (titleLower.includes(word)) {
|
|
1174
|
+
score += 10;
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
const contentLower = doc.content.toLowerCase();
|
|
1178
|
+
for (const word of queryWords) {
|
|
1179
|
+
if (doc.words.has(word)) {
|
|
1180
|
+
score += 1;
|
|
1181
|
+
}
|
|
1182
|
+
if (contentLower.includes(word)) {
|
|
1183
|
+
score += 2;
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
if (score > 0) {
|
|
1187
|
+
const snippet = this.extractSnippet(doc.content, queryWords[0]);
|
|
1188
|
+
results.push({
|
|
1189
|
+
path: docPath,
|
|
1190
|
+
title: doc.title,
|
|
1191
|
+
snippet,
|
|
1192
|
+
score
|
|
1193
|
+
});
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
results.sort((a, b) => b.score - a.score);
|
|
1197
|
+
return results.slice(0, limit);
|
|
1198
|
+
}
|
|
1199
|
+
extractSnippet(content, query) {
|
|
1200
|
+
const index = content.toLowerCase().indexOf(query.toLowerCase());
|
|
1201
|
+
if (index === -1) {
|
|
1202
|
+
return content.slice(0, 150) + "...";
|
|
1203
|
+
}
|
|
1204
|
+
const start = Math.max(0, index - 50);
|
|
1205
|
+
const end = Math.min(content.length, index + query.length + 100);
|
|
1206
|
+
let snippet = content.slice(start, end);
|
|
1207
|
+
if (start > 0) snippet = "..." + snippet;
|
|
1208
|
+
if (end < content.length) snippet = snippet + "...";
|
|
1209
|
+
return snippet.replace(/\n/g, " ").trim();
|
|
1210
|
+
}
|
|
1211
|
+
getDocuments() {
|
|
1212
|
+
return this.index.documents;
|
|
1213
|
+
}
|
|
1214
|
+
};
|
|
1215
|
+
|
|
1216
|
+
// src/docs-server/watcher.ts
|
|
1217
|
+
import fs3 from "fs";
|
|
1218
|
+
import path6 from "path";
|
|
1219
|
+
import { EventEmitter } from "events";
|
|
1220
|
+
var DocsWatcher = class extends EventEmitter {
|
|
1221
|
+
watchers = /* @__PURE__ */ new Map();
|
|
1222
|
+
debounceTimer = null;
|
|
1223
|
+
docsDir;
|
|
1224
|
+
constructor(docsDir) {
|
|
1225
|
+
super();
|
|
1226
|
+
this.docsDir = docsDir;
|
|
1227
|
+
}
|
|
1228
|
+
async start() {
|
|
1229
|
+
await this.watchDirectory(this.docsDir);
|
|
1230
|
+
}
|
|
1231
|
+
async watchDirectory(dir) {
|
|
1232
|
+
if (!await exists(dir)) {
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1235
|
+
const watcher = fs3.watch(dir, { recursive: false }, (eventType, filename) => {
|
|
1236
|
+
if (filename && filename.endsWith(".md")) {
|
|
1237
|
+
this.debouncedEmit();
|
|
1238
|
+
}
|
|
1239
|
+
});
|
|
1240
|
+
this.watchers.set(dir, watcher);
|
|
1241
|
+
try {
|
|
1242
|
+
const entries = await readDir(dir);
|
|
1243
|
+
for (const entry of entries) {
|
|
1244
|
+
const fullPath = path6.join(dir, entry);
|
|
1245
|
+
try {
|
|
1246
|
+
const subEntries = await readDir(fullPath);
|
|
1247
|
+
await this.watchDirectory(fullPath);
|
|
1248
|
+
} catch {
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
} catch {
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
debouncedEmit() {
|
|
1255
|
+
if (this.debounceTimer) {
|
|
1256
|
+
clearTimeout(this.debounceTimer);
|
|
1257
|
+
}
|
|
1258
|
+
this.debounceTimer = setTimeout(() => {
|
|
1259
|
+
this.emit("change");
|
|
1260
|
+
}, 100);
|
|
1261
|
+
}
|
|
1262
|
+
stop() {
|
|
1263
|
+
for (const watcher of this.watchers.values()) {
|
|
1264
|
+
watcher.close();
|
|
1265
|
+
}
|
|
1266
|
+
this.watchers.clear();
|
|
1267
|
+
if (this.debounceTimer) {
|
|
1268
|
+
clearTimeout(this.debounceTimer);
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
};
|
|
1272
|
+
|
|
1273
|
+
// src/docs-server/server.ts
|
|
1274
|
+
var DocsServer = class {
|
|
1275
|
+
server = null;
|
|
1276
|
+
searchEngine;
|
|
1277
|
+
watcher;
|
|
1278
|
+
sseClients = /* @__PURE__ */ new Set();
|
|
1279
|
+
options;
|
|
1280
|
+
constructor(options) {
|
|
1281
|
+
this.options = options;
|
|
1282
|
+
this.searchEngine = new DocsSearchEngine(options.docsDir);
|
|
1283
|
+
this.watcher = new DocsWatcher(options.docsDir);
|
|
1284
|
+
}
|
|
1285
|
+
async start() {
|
|
1286
|
+
await this.searchEngine.buildIndex();
|
|
1287
|
+
await this.watcher.start();
|
|
1288
|
+
this.watcher.on("change", async () => {
|
|
1289
|
+
await this.searchEngine.buildIndex();
|
|
1290
|
+
this.notifyClients();
|
|
1291
|
+
});
|
|
1292
|
+
this.server = http.createServer((req, res) => {
|
|
1293
|
+
this.handleRequest(req, res);
|
|
1294
|
+
});
|
|
1295
|
+
return new Promise((resolve) => {
|
|
1296
|
+
this.server.listen(this.options.port, () => {
|
|
1297
|
+
resolve();
|
|
1298
|
+
});
|
|
1299
|
+
});
|
|
1300
|
+
}
|
|
1301
|
+
stop() {
|
|
1302
|
+
if (this.server) {
|
|
1303
|
+
this.server.close();
|
|
1304
|
+
}
|
|
1305
|
+
this.watcher.stop();
|
|
1306
|
+
for (const client of this.sseClients) {
|
|
1307
|
+
client.end();
|
|
1308
|
+
}
|
|
1309
|
+
this.sseClients.clear();
|
|
1310
|
+
}
|
|
1311
|
+
async handleRequest(req, res) {
|
|
1312
|
+
const url = new URL(req.url || "/", `http://localhost:${this.options.port}`);
|
|
1313
|
+
const pathname = url.pathname;
|
|
1314
|
+
try {
|
|
1315
|
+
if (pathname === "/sse") {
|
|
1316
|
+
this.handleSSE(res);
|
|
1317
|
+
return;
|
|
1318
|
+
}
|
|
1319
|
+
if (pathname === "/api/search") {
|
|
1320
|
+
const query = url.searchParams.get("q") || "";
|
|
1321
|
+
const results = this.searchEngine.search(query);
|
|
1322
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1323
|
+
res.end(JSON.stringify(results));
|
|
1324
|
+
return;
|
|
1325
|
+
}
|
|
1326
|
+
if (pathname.startsWith("/static/")) {
|
|
1327
|
+
await this.serveStatic(pathname, res);
|
|
1328
|
+
return;
|
|
1329
|
+
}
|
|
1330
|
+
await this.serveMarkdown(pathname, res);
|
|
1331
|
+
} catch (error) {
|
|
1332
|
+
this.serveError(res, 500, "Internal Server Error");
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
handleSSE(res) {
|
|
1336
|
+
res.writeHead(200, {
|
|
1337
|
+
"Content-Type": "text/event-stream",
|
|
1338
|
+
"Cache-Control": "no-cache",
|
|
1339
|
+
Connection: "keep-alive"
|
|
1340
|
+
});
|
|
1341
|
+
this.sseClients.add(res);
|
|
1342
|
+
res.on("close", () => {
|
|
1343
|
+
this.sseClients.delete(res);
|
|
1344
|
+
});
|
|
1345
|
+
}
|
|
1346
|
+
notifyClients() {
|
|
1347
|
+
for (const client of this.sseClients) {
|
|
1348
|
+
client.write("data: reload\n\n");
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
async serveMarkdown(pathname, res) {
|
|
1352
|
+
let filePath = pathname === "/" ? "/index" : pathname;
|
|
1353
|
+
if (!filePath.endsWith(".md")) {
|
|
1354
|
+
filePath += ".md";
|
|
1355
|
+
}
|
|
1356
|
+
const fullPath = path7.join(this.options.docsDir, filePath);
|
|
1357
|
+
if (await exists(fullPath)) {
|
|
1358
|
+
const content = await readFile(fullPath);
|
|
1359
|
+
const title = path7.basename(filePath, ".md");
|
|
1360
|
+
const html = renderMarkdownToHTML(content, title);
|
|
1361
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
1362
|
+
res.end(html);
|
|
1363
|
+
return;
|
|
1364
|
+
}
|
|
1365
|
+
const indexPath = path7.join(this.options.docsDir, pathname, "index.md");
|
|
1366
|
+
if (await exists(indexPath)) {
|
|
1367
|
+
const content = await readFile(indexPath);
|
|
1368
|
+
const title = path7.basename(pathname) || "Home";
|
|
1369
|
+
const html = renderMarkdownToHTML(content, title);
|
|
1370
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
1371
|
+
res.end(html);
|
|
1372
|
+
return;
|
|
1373
|
+
}
|
|
1374
|
+
const dirPath = path7.join(this.options.docsDir, pathname);
|
|
1375
|
+
if (await exists(dirPath)) {
|
|
1376
|
+
const indexHtml = await this.generateDirectoryIndex(pathname);
|
|
1377
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
1378
|
+
res.end(indexHtml);
|
|
1379
|
+
return;
|
|
1380
|
+
}
|
|
1381
|
+
this.serveError(res, 404, "Page Not Found");
|
|
1382
|
+
}
|
|
1383
|
+
async generateDirectoryIndex(pathname) {
|
|
1384
|
+
const docs = this.searchEngine.getDocuments();
|
|
1385
|
+
const prefix = pathname === "/" ? "" : pathname;
|
|
1386
|
+
const links = [];
|
|
1387
|
+
for (const [docPath, doc] of docs) {
|
|
1388
|
+
if (docPath.startsWith(prefix) || prefix === "") {
|
|
1389
|
+
links.push(`- [${doc.title}](${docPath})`);
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
const content = `# Documentation
|
|
1393
|
+
|
|
1394
|
+
${links.join("\n")}`;
|
|
1395
|
+
return renderMarkdownToHTML(content, "Documentation");
|
|
1396
|
+
}
|
|
1397
|
+
async serveStatic(pathname, res) {
|
|
1398
|
+
const ext = path7.extname(pathname);
|
|
1399
|
+
const contentTypes = {
|
|
1400
|
+
".css": "text/css",
|
|
1401
|
+
".js": "application/javascript",
|
|
1402
|
+
".png": "image/png",
|
|
1403
|
+
".svg": "image/svg+xml"
|
|
1404
|
+
};
|
|
1405
|
+
const contentType = contentTypes[ext] || "application/octet-stream";
|
|
1406
|
+
const fullPath = path7.join(this.options.docsDir, pathname);
|
|
1407
|
+
if (await exists(fullPath)) {
|
|
1408
|
+
const content = await readFile(fullPath);
|
|
1409
|
+
res.writeHead(200, { "Content-Type": contentType });
|
|
1410
|
+
res.end(content);
|
|
1411
|
+
} else {
|
|
1412
|
+
this.serveError(res, 404, "Not Found");
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
serveError(res, status, message) {
|
|
1416
|
+
const html = renderMarkdownToHTML(`# ${status}
|
|
1417
|
+
|
|
1418
|
+
${message}`, `${status} Error`);
|
|
1419
|
+
res.writeHead(status, { "Content-Type": "text/html; charset=utf-8" });
|
|
1420
|
+
res.end(html);
|
|
1421
|
+
}
|
|
1422
|
+
};
|
|
1423
|
+
|
|
1424
|
+
// src/commands/docs.ts
|
|
1425
|
+
async function docsCommand(options = {}) {
|
|
1426
|
+
const port = parseInt(options.port || "3000", 10);
|
|
1427
|
+
if (isNaN(port) || port < 1 || port > 65535) {
|
|
1428
|
+
logger.error("Invalid port number. Please provide a port between 1 and 65535.");
|
|
1429
|
+
process.exit(1);
|
|
1430
|
+
}
|
|
1431
|
+
const possibleDocsDirs = [
|
|
1432
|
+
path8.join(process.cwd(), "docs"),
|
|
1433
|
+
path8.join(process.cwd(), "documentation"),
|
|
1434
|
+
path8.join(process.cwd(), "doc"),
|
|
1435
|
+
process.cwd()
|
|
1436
|
+
// Use current directory if it contains markdown files
|
|
1437
|
+
];
|
|
1438
|
+
let docsDir = null;
|
|
1439
|
+
for (const dir of possibleDocsDirs) {
|
|
1440
|
+
if (await exists(dir)) {
|
|
1441
|
+
const hasMarkdown = await hasMarkdownFiles(dir);
|
|
1442
|
+
if (hasMarkdown) {
|
|
1443
|
+
docsDir = dir;
|
|
1444
|
+
break;
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
if (!docsDir) {
|
|
1449
|
+
logger.error("No documentation directory found.");
|
|
1450
|
+
logger.info('Create a "docs" directory with .md files to use this command.');
|
|
1451
|
+
process.exit(1);
|
|
1452
|
+
}
|
|
1453
|
+
logger.title("mcp-new Documentation Server");
|
|
1454
|
+
logger.info(`Serving docs from: ${docsDir}`);
|
|
1455
|
+
const server = new DocsServer({
|
|
1456
|
+
port,
|
|
1457
|
+
docsDir
|
|
1458
|
+
});
|
|
1459
|
+
try {
|
|
1460
|
+
await server.start();
|
|
1461
|
+
logger.success(`Documentation server running at http://localhost:${port}`);
|
|
1462
|
+
logger.info("Hot reload enabled - changes will refresh automatically");
|
|
1463
|
+
logger.info("Press Ctrl+C to stop");
|
|
1464
|
+
process.on("SIGINT", () => {
|
|
1465
|
+
logger.info("\nShutting down...");
|
|
1466
|
+
server.stop();
|
|
1467
|
+
process.exit(0);
|
|
1468
|
+
});
|
|
1469
|
+
process.on("SIGTERM", () => {
|
|
1470
|
+
server.stop();
|
|
1471
|
+
process.exit(0);
|
|
1472
|
+
});
|
|
1473
|
+
} catch (error) {
|
|
1474
|
+
if (error instanceof Error) {
|
|
1475
|
+
if (error.message.includes("EADDRINUSE")) {
|
|
1476
|
+
logger.error(`Port ${port} is already in use. Try a different port with --port.`);
|
|
1477
|
+
} else {
|
|
1478
|
+
logger.error(error.message);
|
|
1479
|
+
}
|
|
1480
|
+
} else {
|
|
1481
|
+
logger.error("Failed to start documentation server");
|
|
1482
|
+
}
|
|
1483
|
+
process.exit(1);
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
async function hasMarkdownFiles(dir) {
|
|
1487
|
+
try {
|
|
1488
|
+
const { readdir } = await import("fs/promises");
|
|
1489
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
1490
|
+
for (const entry of entries) {
|
|
1491
|
+
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
1492
|
+
return true;
|
|
1493
|
+
}
|
|
1494
|
+
if (entry.isDirectory() && !entry.name.startsWith(".")) {
|
|
1495
|
+
const subDir = path8.join(dir, entry.name);
|
|
1496
|
+
if (await hasMarkdownFiles(subDir)) {
|
|
1497
|
+
return true;
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
} catch {
|
|
1502
|
+
return false;
|
|
1503
|
+
}
|
|
1504
|
+
return false;
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
// src/commands/preset-cache.ts
|
|
1508
|
+
async function presetCacheCommand(action) {
|
|
1509
|
+
try {
|
|
1510
|
+
if (!action) {
|
|
1511
|
+
action = "list";
|
|
1512
|
+
}
|
|
1513
|
+
switch (action) {
|
|
1514
|
+
case "clear":
|
|
1515
|
+
await handleClear();
|
|
1516
|
+
break;
|
|
1517
|
+
case "list":
|
|
1518
|
+
await handleList();
|
|
1519
|
+
break;
|
|
1520
|
+
case "path":
|
|
1521
|
+
handlePath();
|
|
1522
|
+
break;
|
|
1523
|
+
default:
|
|
1524
|
+
logger.error(`Unknown action: ${action}. Valid actions: clear, list, path`);
|
|
1525
|
+
process.exit(1);
|
|
1526
|
+
}
|
|
1527
|
+
} catch (error) {
|
|
1528
|
+
if (error instanceof Error) {
|
|
1529
|
+
logger.error(error.message);
|
|
1530
|
+
} else {
|
|
1531
|
+
logger.error("An unexpected error occurred");
|
|
1532
|
+
}
|
|
1533
|
+
process.exit(1);
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
async function handleClear() {
|
|
1537
|
+
const count = await clearPresetCache();
|
|
1538
|
+
if (count > 0) {
|
|
1539
|
+
logger.success(`Cleared ${count} cached preset(s)`);
|
|
1540
|
+
} else {
|
|
1541
|
+
logger.info("No cached presets to clear");
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
async function handleList() {
|
|
1545
|
+
const presets = await listCachedPresets();
|
|
1546
|
+
if (presets.length === 0) {
|
|
1547
|
+
logger.info("No presets cached");
|
|
1548
|
+
logger.info(`Cache directory: ${getCacheDir()}`);
|
|
1549
|
+
return;
|
|
1550
|
+
}
|
|
1551
|
+
logger.title("Cached Presets");
|
|
1552
|
+
for (const preset of presets) {
|
|
1553
|
+
const age = Date.now() - preset.cachedAt;
|
|
1554
|
+
const hoursAgo = Math.round(age / (1e3 * 60 * 60));
|
|
1555
|
+
const ageStr = hoursAgo < 1 ? "less than an hour ago" : `${hoursAgo} hour(s) ago`;
|
|
1556
|
+
console.log(`
|
|
1557
|
+
${preset.manifest.name} (${preset.manifest.version})`);
|
|
1558
|
+
console.log(` Source: ${preset.source.type}:${preset.source.identifier}`);
|
|
1559
|
+
console.log(` Cached: ${ageStr}`);
|
|
1560
|
+
console.log(` Tools: ${preset.manifest.tools.map((t) => t.name).join(", ")}`);
|
|
1561
|
+
}
|
|
1562
|
+
console.log(`
|
|
1563
|
+
Cache directory: ${getCacheDir()}`);
|
|
1564
|
+
}
|
|
1565
|
+
function handlePath() {
|
|
1566
|
+
console.log(getCacheDir());
|
|
1567
|
+
}
|
|
1568
|
+
|
|
690
1569
|
// src/cli.ts
|
|
691
1570
|
var program = new Command();
|
|
692
1571
|
var logo = `
|
|
@@ -741,7 +1620,7 @@ ${chalk4.bold("Learn More:")}
|
|
|
741
1620
|
MCP Spec: ${chalk4.underline("https://spec.modelcontextprotocol.io")}
|
|
742
1621
|
`;
|
|
743
1622
|
program.name("mcp-new").description("CLI tool for generating MCP (Model Context Protocol) servers").version("1.5.0").addHelpText("beforeAll", logo).addHelpText("after", examples);
|
|
744
|
-
program.argument("[project-name]", "Name of the project to create").option("-t, --typescript", "Use TypeScript template").option("-p, --python", "Use Python template").option("-g, --go", "Use Go template").option("-r, --rust", "Use Rust template").option("-j, --java", "Use Java template").option("-k, --kotlin", "Use Kotlin template").option("-c, --csharp", "Use C# (.NET) template").option("-e, --elixir", "Use Elixir template").option("--maven", "Use Maven build tool (for Java/Kotlin)").option("--gradle", "Use Gradle build tool (for Java/Kotlin)").option("--skip-install", "Skip dependency installation").option("--from-openapi <path>", "Generate from OpenAPI/Swagger specification").option("--from-prompt", "Generate tools using AI from text description").option("--preset <name>", "Use a preset template (database, rest-api, filesystem)").option("-y, --yes", "Skip prompts and use defaults").action(createCommand);
|
|
1623
|
+
program.argument("[project-name]", "Name of the project to create").option("-t, --typescript", "Use TypeScript template").option("-p, --python", "Use Python template").option("-g, --go", "Use Go template").option("-r, --rust", "Use Rust template").option("-j, --java", "Use Java template").option("-k, --kotlin", "Use Kotlin template").option("-c, --csharp", "Use C# (.NET) template").option("-e, --elixir", "Use Elixir template").option("--maven", "Use Maven build tool (for Java/Kotlin)").option("--gradle", "Use Gradle build tool (for Java/Kotlin)").option("--skip-install", "Skip dependency installation").option("--from-openapi <path>", "Generate from OpenAPI/Swagger specification").option("--from-prompt", "Generate tools using AI from text description").option("--preset <name>", "Use a preset template (database, rest-api, filesystem, or @org/package, github:user/repo)").option("--ci <provider>", "Add CI/CD configuration (github, gitlab, circleci)").option("-y, --yes", "Skip prompts and use defaults").action(createCommand);
|
|
745
1624
|
program.command("init").description("Initialize MCP server in the current directory").option("-t, --typescript", "Use TypeScript template").option("-p, --python", "Use Python template").option("-g, --go", "Use Go template").option("-r, --rust", "Use Rust template").option("-j, --java", "Use Java template").option("-k, --kotlin", "Use Kotlin template").option("-c, --csharp", "Use C# (.NET) template").option("-e, --elixir", "Use Elixir template").option("--maven", "Use Maven build tool (for Java/Kotlin)").option("--gradle", "Use Gradle build tool (for Java/Kotlin)").option("--skip-install", "Skip dependency installation").option("-f, --force", "Initialize even if directory contains files").addHelpText(
|
|
746
1625
|
"after",
|
|
747
1626
|
`
|
|
@@ -811,6 +1690,70 @@ ${chalk4.bold("Supported languages:")}
|
|
|
811
1690
|
\u2022 Rust (cargo)
|
|
812
1691
|
`
|
|
813
1692
|
).action(upgradeCommand);
|
|
1693
|
+
program.command("preset-cache [action]").description("Manage external preset cache").addHelpText(
|
|
1694
|
+
"after",
|
|
1695
|
+
`
|
|
1696
|
+
${chalk4.bold("Actions:")}
|
|
1697
|
+
|
|
1698
|
+
${chalk4.green("list")} List cached presets (default)
|
|
1699
|
+
${chalk4.green("clear")} Clear all cached presets
|
|
1700
|
+
${chalk4.green("path")} Show cache directory path
|
|
1701
|
+
|
|
1702
|
+
${chalk4.bold("Examples:")}
|
|
1703
|
+
|
|
1704
|
+
${chalk4.gray("# List cached presets")}
|
|
1705
|
+
${chalk4.cyan("$")} mcp-new preset-cache list
|
|
1706
|
+
|
|
1707
|
+
${chalk4.gray("# Clear preset cache")}
|
|
1708
|
+
${chalk4.cyan("$")} mcp-new preset-cache clear
|
|
1709
|
+
|
|
1710
|
+
${chalk4.bold("External Presets:")}
|
|
1711
|
+
|
|
1712
|
+
Use external presets with the --preset flag:
|
|
1713
|
+
${chalk4.cyan("$")} mcp-new my-project --preset @company/custom-preset
|
|
1714
|
+
${chalk4.cyan("$")} mcp-new my-project --preset github:user/repo
|
|
1715
|
+
`
|
|
1716
|
+
).action(presetCacheCommand);
|
|
1717
|
+
program.command("docs").description("Start an interactive documentation server").option("-p, --port <port>", "Port to run the server on", "3000").addHelpText(
|
|
1718
|
+
"after",
|
|
1719
|
+
`
|
|
1720
|
+
${chalk4.bold("Examples:")}
|
|
1721
|
+
|
|
1722
|
+
${chalk4.gray("# Start docs server on default port (3000)")}
|
|
1723
|
+
${chalk4.cyan("$")} mcp-new docs
|
|
1724
|
+
|
|
1725
|
+
${chalk4.gray("# Start docs server on custom port")}
|
|
1726
|
+
${chalk4.cyan("$")} mcp-new docs --port 4000
|
|
1727
|
+
|
|
1728
|
+
${chalk4.bold("Features:")}
|
|
1729
|
+
${chalk4.green("Hot reload")} - Changes refresh automatically
|
|
1730
|
+
${chalk4.green("Search")} - Full-text search across all docs
|
|
1731
|
+
${chalk4.green("Markdown")} - Renders GitHub-flavored markdown
|
|
1732
|
+
`
|
|
1733
|
+
).action(docsCommand);
|
|
1734
|
+
program.command("add-ci [provider]").description("Add CI/CD configuration to an existing project").addHelpText(
|
|
1735
|
+
"after",
|
|
1736
|
+
`
|
|
1737
|
+
${chalk4.bold("Examples:")}
|
|
1738
|
+
|
|
1739
|
+
${chalk4.gray("# Add CI interactively")}
|
|
1740
|
+
${chalk4.cyan("$")} mcp-new add-ci
|
|
1741
|
+
|
|
1742
|
+
${chalk4.gray("# Add GitHub Actions")}
|
|
1743
|
+
${chalk4.cyan("$")} mcp-new add-ci github
|
|
1744
|
+
|
|
1745
|
+
${chalk4.gray("# Add GitLab CI")}
|
|
1746
|
+
${chalk4.cyan("$")} mcp-new add-ci gitlab
|
|
1747
|
+
|
|
1748
|
+
${chalk4.gray("# Add CircleCI")}
|
|
1749
|
+
${chalk4.cyan("$")} mcp-new add-ci circleci
|
|
1750
|
+
|
|
1751
|
+
${chalk4.bold("Supported providers:")}
|
|
1752
|
+
${chalk4.green("github")} GitHub Actions
|
|
1753
|
+
${chalk4.green("gitlab")} GitLab CI
|
|
1754
|
+
${chalk4.green("circleci")} CircleCI
|
|
1755
|
+
`
|
|
1756
|
+
).action(addCICommand);
|
|
814
1757
|
var monorepo = program.command("monorepo").description("Manage MCP monorepo workspaces");
|
|
815
1758
|
monorepo.command("init [workspace-name]").description("Initialize a new MCP monorepo workspace").option("-f, --force", "Initialize even if directory contains files").addHelpText(
|
|
816
1759
|
"after",
|
|
@@ -845,7 +1788,14 @@ ${chalk4.bold("Examples:")}
|
|
|
845
1788
|
monorepoAddCommand(serverName, opts);
|
|
846
1789
|
});
|
|
847
1790
|
monorepo.command("list").description("List all packages in the workspace").action(monorepoListCommand);
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
program.
|
|
1791
|
+
async function main() {
|
|
1792
|
+
await pluginRegistry.initialize();
|
|
1793
|
+
program.parse();
|
|
1794
|
+
if (process.argv.length === 2) {
|
|
1795
|
+
program.help();
|
|
1796
|
+
}
|
|
851
1797
|
}
|
|
1798
|
+
main().catch((error) => {
|
|
1799
|
+
console.error("Error:", error.message);
|
|
1800
|
+
process.exit(1);
|
|
1801
|
+
});
|