add-ai-tools 1.2.2 → 1.2.3
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/index.mjs +71 -6
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -214,8 +214,10 @@ const BITBUCKET_URL_REGEX = /^https?:\/\/(?:[^@]+@)?(?:www\.)?bitbucket\.org\/([
|
|
|
214
214
|
* GitHub shorthand 매칭 정규식
|
|
215
215
|
* 예: owner/repo
|
|
216
216
|
* vercel-labs/agent-skills
|
|
217
|
+
* khw1031/core/skills
|
|
218
|
+
* owner/repo/deep/nested/path
|
|
217
219
|
*/
|
|
218
|
-
const GITHUB_SHORTHAND_REGEX = /^([a-zA-Z0-9_.-]+)\/([a-zA-Z0-9_.-]+)
|
|
220
|
+
const GITHUB_SHORTHAND_REGEX = /^([a-zA-Z0-9_.-]+)\/([a-zA-Z0-9_.-]+)(?:\/(.+))?$/;
|
|
219
221
|
/**
|
|
220
222
|
* Git URL 매칭 정규식 (SSH 또는 git:// 프로토콜)
|
|
221
223
|
* 예: git@github.com:owner/repo.git
|
|
@@ -308,12 +310,13 @@ function parseSource(input) {
|
|
|
308
310
|
}
|
|
309
311
|
const shorthandMatch = trimmed.match(GITHUB_SHORTHAND_REGEX);
|
|
310
312
|
if (shorthandMatch) {
|
|
311
|
-
const [, owner, repo] = shorthandMatch;
|
|
313
|
+
const [, owner, repo, subpath] = shorthandMatch;
|
|
312
314
|
return {
|
|
313
315
|
type: "github",
|
|
314
316
|
url: `https://github.com/${owner}/${repo}`,
|
|
315
317
|
owner,
|
|
316
318
|
repo,
|
|
319
|
+
subpath: subpath || void 0,
|
|
317
320
|
raw: input
|
|
318
321
|
};
|
|
319
322
|
}
|
|
@@ -987,12 +990,22 @@ const bitbucketFetcher = new BitbucketFetcher();
|
|
|
987
990
|
|
|
988
991
|
//#endregion
|
|
989
992
|
//#region src/prompts/InteractivePrompt.ts
|
|
993
|
+
const FILTER_THRESHOLD$1 = 15;
|
|
990
994
|
/**
|
|
991
995
|
* InteractivePrompt - 외부 소스 기반 설치 플로우
|
|
992
996
|
*
|
|
993
997
|
* 플로우: Agent → Source URL → Type 선택 → Resources 선택 → Scope → Confirm
|
|
994
998
|
*/
|
|
995
|
-
var InteractivePrompt = class {
|
|
999
|
+
var InteractivePrompt = class InteractivePrompt {
|
|
1000
|
+
/**
|
|
1001
|
+
* 키워드로 리소스 필터링 (name, type, description, metadata.category 대상, 대소문자 무시)
|
|
1002
|
+
*/
|
|
1003
|
+
static filterByKeyword(resources, keyword) {
|
|
1004
|
+
const lower = keyword.toLowerCase();
|
|
1005
|
+
return resources.filter((r) => {
|
|
1006
|
+
return r.name.toLowerCase().includes(lower) || r.type.toLowerCase().includes(lower) || r.description.toLowerCase().includes(lower) || r.metadata.category && r.metadata.category.toLowerCase().includes(lower);
|
|
1007
|
+
});
|
|
1008
|
+
}
|
|
996
1009
|
/**
|
|
997
1010
|
* Interactive 플로우 실행
|
|
998
1011
|
*/
|
|
@@ -1113,14 +1126,35 @@ var InteractivePrompt = class {
|
|
|
1113
1126
|
return firstLine;
|
|
1114
1127
|
}
|
|
1115
1128
|
/**
|
|
1129
|
+
* 리소스가 많을 때 키워드 필터링 프롬프트 표시
|
|
1130
|
+
*/
|
|
1131
|
+
async filterResourcesIfNeeded(resources) {
|
|
1132
|
+
if (resources.length <= FILTER_THRESHOLD$1) return resources;
|
|
1133
|
+
const { keyword } = await inquirer.prompt([{
|
|
1134
|
+
type: "input",
|
|
1135
|
+
name: "keyword",
|
|
1136
|
+
message: `${resources.length} resources found. Enter keyword to filter (press Enter to show all):`
|
|
1137
|
+
}]);
|
|
1138
|
+
const trimmed = keyword.trim();
|
|
1139
|
+
if (!trimmed) return resources;
|
|
1140
|
+
const filtered = InteractivePrompt.filterByKeyword(resources, trimmed);
|
|
1141
|
+
if (filtered.length === 0) {
|
|
1142
|
+
console.log(`No resources matched "${trimmed}". Showing all resources.`);
|
|
1143
|
+
return resources;
|
|
1144
|
+
}
|
|
1145
|
+
console.log(`Filtered to ${filtered.length} resource(s).`);
|
|
1146
|
+
return filtered;
|
|
1147
|
+
}
|
|
1148
|
+
/**
|
|
1116
1149
|
* 리소스 선택 (가져온 리소스 목록에서)
|
|
1117
1150
|
*/
|
|
1118
1151
|
async selectResources(availableResources, types) {
|
|
1119
|
-
|
|
1152
|
+
let filteredResources = availableResources.filter((r) => types.includes(r.type));
|
|
1120
1153
|
if (filteredResources.length === 0) {
|
|
1121
1154
|
console.log("\nNo resources found for selected types.");
|
|
1122
1155
|
return [];
|
|
1123
1156
|
}
|
|
1157
|
+
filteredResources = await this.filterResourcesIfNeeded(filteredResources);
|
|
1124
1158
|
const { resources } = await inquirer.prompt([{
|
|
1125
1159
|
type: "checkbox",
|
|
1126
1160
|
name: "resources",
|
|
@@ -1887,12 +1921,13 @@ const commandHandler = new CommandHandler();
|
|
|
1887
1921
|
|
|
1888
1922
|
//#endregion
|
|
1889
1923
|
//#region src/prompts/ZipPrompt.ts
|
|
1924
|
+
const FILTER_THRESHOLD = 15;
|
|
1890
1925
|
/**
|
|
1891
1926
|
* ZipPrompt - ZIP 내보내기용 선택 플로우
|
|
1892
1927
|
*
|
|
1893
1928
|
* 플로우: Types → Resources → Confirm
|
|
1894
1929
|
*/
|
|
1895
|
-
var ZipPrompt = class {
|
|
1930
|
+
var ZipPrompt = class ZipPrompt {
|
|
1896
1931
|
/**
|
|
1897
1932
|
* ZIP 플로우 실행
|
|
1898
1933
|
*/
|
|
@@ -1937,14 +1972,44 @@ var ZipPrompt = class {
|
|
|
1937
1972
|
return selected;
|
|
1938
1973
|
}
|
|
1939
1974
|
/**
|
|
1975
|
+
* 키워드로 리소스 필터링 (name, type, description, metadata.category 대상, 대소문자 무시)
|
|
1976
|
+
*/
|
|
1977
|
+
static filterByKeyword(resources, keyword) {
|
|
1978
|
+
const lower = keyword.toLowerCase();
|
|
1979
|
+
return resources.filter((r) => {
|
|
1980
|
+
return r.name.toLowerCase().includes(lower) || r.type.toLowerCase().includes(lower) || r.description.toLowerCase().includes(lower) || r.metadata.category && r.metadata.category.toLowerCase().includes(lower);
|
|
1981
|
+
});
|
|
1982
|
+
}
|
|
1983
|
+
/**
|
|
1984
|
+
* 리소스가 많을 때 키워드 필터링 프롬프트 표시
|
|
1985
|
+
*/
|
|
1986
|
+
async filterResourcesIfNeeded(resources) {
|
|
1987
|
+
if (resources.length <= FILTER_THRESHOLD) return resources;
|
|
1988
|
+
const { keyword } = await inquirer.prompt([{
|
|
1989
|
+
type: "input",
|
|
1990
|
+
name: "keyword",
|
|
1991
|
+
message: `${resources.length} resources found. Enter keyword to filter (press Enter to show all):`
|
|
1992
|
+
}]);
|
|
1993
|
+
const trimmed = keyword.trim();
|
|
1994
|
+
if (!trimmed) return resources;
|
|
1995
|
+
const filtered = ZipPrompt.filterByKeyword(resources, trimmed);
|
|
1996
|
+
if (filtered.length === 0) {
|
|
1997
|
+
console.log(`No resources matched "${trimmed}". Showing all resources.`);
|
|
1998
|
+
return resources;
|
|
1999
|
+
}
|
|
2000
|
+
console.log(`Filtered to ${filtered.length} resource(s).`);
|
|
2001
|
+
return filtered;
|
|
2002
|
+
}
|
|
2003
|
+
/**
|
|
1940
2004
|
* 리소스 복수 선택
|
|
1941
2005
|
*/
|
|
1942
2006
|
async selectResources(availableResources, types) {
|
|
1943
|
-
|
|
2007
|
+
let filteredResources = availableResources.filter((r) => types.includes(r.type));
|
|
1944
2008
|
if (filteredResources.length === 0) {
|
|
1945
2009
|
console.log("\nNo resources found for selected types.");
|
|
1946
2010
|
return [];
|
|
1947
2011
|
}
|
|
2012
|
+
filteredResources = await this.filterResourcesIfNeeded(filteredResources);
|
|
1948
2013
|
const { selected } = await inquirer.prompt([{
|
|
1949
2014
|
type: "checkbox",
|
|
1950
2015
|
name: "selected",
|