@kurokeita/add-skill 2.6.1 → 3.0.1

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.
Files changed (140) hide show
  1. package/README.md +43 -64
  2. package/dist/bin/cli.js +270 -478
  3. package/dist/skills/statusline-setup/.claude-plugin/plugin.json +1 -1
  4. package/dist/skills/statusline-setup/SKILL.md +48 -448
  5. package/dist/skills/statusline-setup/mod/hooks/register.tsx +93 -103
  6. package/dist/skills/statusline-setup/mod/tests/work.test.ts +28 -10
  7. package/dist/skills/statusline-setup/mod/types/index.d.ts +2 -1
  8. package/dist/skills/universalize-agents/reference/mapping.md +3 -2
  9. package/package.json +3 -3
  10. package/dist/agents/backend-specialist.md +0 -277
  11. package/dist/agents/code-archaeologist.md +0 -114
  12. package/dist/agents/database-architect.md +0 -238
  13. package/dist/agents/debugger.md +0 -231
  14. package/dist/agents/devops-engineer.md +0 -242
  15. package/dist/agents/documentation-writer.md +0 -104
  16. package/dist/agents/explorer-agent.md +0 -79
  17. package/dist/agents/frontend-specialist.md +0 -594
  18. package/dist/agents/game-developer.md +0 -162
  19. package/dist/agents/mobile-developer.md +0 -383
  20. package/dist/agents/orchestrator.md +0 -435
  21. package/dist/agents/penetration-tester.md +0 -188
  22. package/dist/agents/performance-optimizer.md +0 -191
  23. package/dist/agents/product-manager.md +0 -122
  24. package/dist/agents/product-owner.md +0 -106
  25. package/dist/agents/project-planner.md +0 -408
  26. package/dist/agents/qa-automation-engineer.md +0 -109
  27. package/dist/agents/security-auditor.md +0 -171
  28. package/dist/agents/test-engineer.md +0 -158
  29. package/dist/skills/agent-identifier/SKILL.md +0 -431
  30. package/dist/skills/agent-identifier/examples/agent-creation-prompt.md +0 -247
  31. package/dist/skills/agent-identifier/examples/complete-agent-examples.md +0 -432
  32. package/dist/skills/agent-identifier/references/agent-creation-system-prompt.md +0 -215
  33. package/dist/skills/agent-identifier/references/system-prompt-design.md +0 -419
  34. package/dist/skills/agent-identifier/references/triggering-examples.md +0 -508
  35. package/dist/skills/agent-identifier/scripts/validate-agent.sh +0 -217
  36. package/dist/skills/code-review-excellence/SKILL.md +0 -525
  37. package/dist/skills/component-refactoring/SKILL.md +0 -492
  38. package/dist/skills/component-refactoring/references/complexity-patterns.md +0 -493
  39. package/dist/skills/component-refactoring/references/component-splitting.md +0 -477
  40. package/dist/skills/component-refactoring/references/hook-extraction.md +0 -317
  41. package/dist/skills/context7-guidelines/SKILL.md +0 -31
  42. package/dist/skills/feature-design-assistant/SKILL.md +0 -371
  43. package/dist/skills/find-bugs/SKILL.md +0 -75
  44. package/dist/skills/frontend-design/SKILL.md +0 -45
  45. package/dist/skills/go-concurrency-patterns/SKILL.md +0 -657
  46. package/dist/skills/grill-me/SKILL.md +0 -9
  47. package/dist/skills/handoff/SKILL.md +0 -16
  48. package/dist/skills/koreader-plugin-development/SKILL.md +0 -141
  49. package/dist/skills/koreader-plugin-development/examples/2-example-patch.lua +0 -17
  50. package/dist/skills/koreader-plugin-development/examples/_meta.lua +0 -6
  51. package/dist/skills/koreader-plugin-development/examples/helloworld.lua +0 -36
  52. package/dist/skills/koreader-plugin-development/references/debugging.md +0 -92
  53. package/dist/skills/koreader-plugin-development/references/events-and-widgets.md +0 -102
  54. package/dist/skills/koreader-plugin-development/references/patches.md +0 -118
  55. package/dist/skills/koreader-plugin-development/references/plugin-anatomy.md +0 -97
  56. package/dist/skills/make-instruction/SKILL.md +0 -68
  57. package/dist/skills/make-prompt/SKILL.md +0 -70
  58. package/dist/skills/make-skill/SKILL.md +0 -147
  59. package/dist/skills/prd-to-tasks/SKILL.md +0 -164
  60. package/dist/skills/react-native-async-patterns/SKILL.md +0 -256
  61. package/dist/skills/react-native-performance/SKILL.md +0 -425
  62. package/dist/skills/react-native-testing/SKILL.md +0 -458
  63. package/dist/skills/react-native-zustand-patterns/SKILL.md +0 -343
  64. package/dist/skills/skill-creator/SKILL.md +0 -385
  65. package/dist/skills/skill-creator/scripts/init_skill.cjs +0 -235
  66. package/dist/skills/skill-creator/scripts/package_skill.cjs +0 -84
  67. package/dist/skills/skill-creator/scripts/validate_skill.cjs +0 -127
  68. package/dist/skills/skill-development/SKILL.md +0 -676
  69. package/dist/skills/skill-development/references/skill-creator-original.md +0 -210
  70. package/dist/skills/sql-optimization-patterns/SKILL.md +0 -509
  71. package/dist/skills/test-driven-development/SKILL.md +0 -114
  72. package/dist/skills/test-driven-development/deep-modules.md +0 -33
  73. package/dist/skills/test-driven-development/interface-design.md +0 -35
  74. package/dist/skills/test-driven-development/mocking.md +0 -68
  75. package/dist/skills/test-driven-development/refactoring.md +0 -10
  76. package/dist/skills/test-driven-development/tests.md +0 -61
  77. package/dist/skills/vercel-react-best-practices/AGENTS.md +0 -2410
  78. package/dist/skills/vercel-react-best-practices/SKILL.md +0 -127
  79. package/dist/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +0 -55
  80. package/dist/skills/vercel-react-best-practices/rules/advanced-use-latest.md +0 -49
  81. package/dist/skills/vercel-react-best-practices/rules/async-api-routes.md +0 -38
  82. package/dist/skills/vercel-react-best-practices/rules/async-defer-await.md +0 -80
  83. package/dist/skills/vercel-react-best-practices/rules/async-dependencies.md +0 -36
  84. package/dist/skills/vercel-react-best-practices/rules/async-parallel.md +0 -28
  85. package/dist/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +0 -99
  86. package/dist/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +0 -59
  87. package/dist/skills/vercel-react-best-practices/rules/bundle-conditional.md +0 -31
  88. package/dist/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +0 -49
  89. package/dist/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +0 -35
  90. package/dist/skills/vercel-react-best-practices/rules/bundle-preload.md +0 -50
  91. package/dist/skills/vercel-react-best-practices/rules/client-event-listeners.md +0 -74
  92. package/dist/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +0 -71
  93. package/dist/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +0 -48
  94. package/dist/skills/vercel-react-best-practices/rules/client-swr-dedup.md +0 -56
  95. package/dist/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +0 -82
  96. package/dist/skills/vercel-react-best-practices/rules/js-cache-function-results.md +0 -80
  97. package/dist/skills/vercel-react-best-practices/rules/js-cache-property-access.md +0 -28
  98. package/dist/skills/vercel-react-best-practices/rules/js-cache-storage.md +0 -70
  99. package/dist/skills/vercel-react-best-practices/rules/js-combine-iterations.md +0 -32
  100. package/dist/skills/vercel-react-best-practices/rules/js-early-exit.md +0 -50
  101. package/dist/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +0 -45
  102. package/dist/skills/vercel-react-best-practices/rules/js-index-maps.md +0 -37
  103. package/dist/skills/vercel-react-best-practices/rules/js-length-check-first.md +0 -50
  104. package/dist/skills/vercel-react-best-practices/rules/js-min-max-loop.md +0 -82
  105. package/dist/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +0 -24
  106. package/dist/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +0 -57
  107. package/dist/skills/vercel-react-best-practices/rules/rendering-activity.md +0 -26
  108. package/dist/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -47
  109. package/dist/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +0 -40
  110. package/dist/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +0 -38
  111. package/dist/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +0 -46
  112. package/dist/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +0 -82
  113. package/dist/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +0 -28
  114. package/dist/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +0 -39
  115. package/dist/skills/vercel-react-best-practices/rules/rerender-dependencies.md +0 -45
  116. package/dist/skills/vercel-react-best-practices/rules/rerender-derived-state.md +0 -29
  117. package/dist/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +0 -74
  118. package/dist/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +0 -58
  119. package/dist/skills/vercel-react-best-practices/rules/rerender-memo.md +0 -44
  120. package/dist/skills/vercel-react-best-practices/rules/rerender-transitions.md +0 -40
  121. package/dist/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +0 -73
  122. package/dist/skills/vercel-react-best-practices/rules/server-cache-lru.md +0 -41
  123. package/dist/skills/vercel-react-best-practices/rules/server-cache-react.md +0 -76
  124. package/dist/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +0 -83
  125. package/dist/skills/vercel-react-best-practices/rules/server-serialization.md +0 -38
  126. package/dist/skills/web-design-guidelines/SKILL.md +0 -40
  127. package/dist/skills/workflow-patterns/SKILL.md +0 -623
  128. package/dist/skills/write-prd/SKILL.md +0 -162
  129. package/dist/workflows/brainstorm.md +0 -113
  130. package/dist/workflows/create.md +0 -60
  131. package/dist/workflows/debug.md +0 -107
  132. package/dist/workflows/deploy.md +0 -178
  133. package/dist/workflows/enhance.md +0 -64
  134. package/dist/workflows/github-pull-request-create.md +0 -134
  135. package/dist/workflows/orchestrate.md +0 -246
  136. package/dist/workflows/plan.md +0 -90
  137. package/dist/workflows/preview.md +0 -83
  138. package/dist/workflows/status.md +0 -87
  139. package/dist/workflows/test.md +0 -144
  140. package/dist/workflows/ui-ux-pro-max.md +0 -315
package/dist/bin/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // bin/cli.ts
4
- import { intro as intro5, isCancel as isCancel6, outro as outro5, select as select6 } from "@clack/prompts";
4
+ import { intro as intro5, isCancel as isCancel6, outro as outro5, select as select3 } from "@clack/prompts";
5
5
  import { Command } from "commander";
6
6
  import pc6 from "picocolors";
7
7
 
@@ -17,7 +17,6 @@ import {
17
17
  multiselect,
18
18
  note as note2,
19
19
  outro,
20
- select as select2,
21
20
  spinner
22
21
  } from "@clack/prompts";
23
22
  import fs5 from "fs-extra";
@@ -37,9 +36,7 @@ import { fileURLToPath } from "node:url";
37
36
  var __filename = fileURLToPath(import.meta.url);
38
37
  var __dirname = path.dirname(__filename);
39
38
  function hasBundledAssets(rootDir) {
40
- return ["skills", "agents", "workflows"].some(
41
- (dir) => fs.existsSync(path.join(rootDir, dir))
42
- );
39
+ return fs.existsSync(path.join(rootDir, "skills"));
43
40
  }
44
41
  function resolveProjectRoot(moduleDir) {
45
42
  const sourceRoot = path.resolve(moduleDir, "../..");
@@ -65,20 +62,6 @@ var PLATFORM_PATHS_SKILLS = {
65
62
  gemini: path.join(os.homedir(), ".gemini/skills"),
66
63
  windsurf: path.join(os.homedir(), ".codeium/windsurf/skills")
67
64
  };
68
- var PLATFORM_PATHS_AGENTS = {
69
- "claude-code": path.join(os.homedir(), ".claude/agents"),
70
- codex: path.join(os.homedir(), ".codex/skills"),
71
- copilot: path.join(os.homedir(), ".copilot/agents"),
72
- gemini: path.join(os.homedir(), ".gemini/agents")
73
- };
74
- var PLATFORM_PATHS_WORKFLOWS = {
75
- antigravity: path.join(os.homedir(), ".gemini/antigravity/global_workflows"),
76
- "claude-code": path.join(os.homedir(), ".claude/commands"),
77
- codex: path.join(os.homedir(), ".codex/skills"),
78
- copilot: path.join(os.homedir(), ".copilot/prompts"),
79
- gemini: path.join(os.homedir(), ".gemini/commands"),
80
- windsurf: path.join(os.homedir(), ".codeium/windsurf/global_workflows")
81
- };
82
65
  var PROJECT_RELATIVE_PLATFORM_PATHS_SKILLS = {
83
66
  antigravity: ".gemini/antigravity/skills",
84
67
  "claude-code": ".claude/skills",
@@ -87,20 +70,6 @@ var PROJECT_RELATIVE_PLATFORM_PATHS_SKILLS = {
87
70
  gemini: ".gemini/skills",
88
71
  windsurf: ".codeium/windsurf/skills"
89
72
  };
90
- var PROJECT_RELATIVE_PLATFORM_PATHS_AGENTS = {
91
- "claude-code": ".claude/agents",
92
- codex: ".codex/skills",
93
- copilot: ".copilot/agents",
94
- gemini: ".gemini/agents"
95
- };
96
- var PROJECT_RELATIVE_PLATFORM_PATHS_WORKFLOWS = {
97
- antigravity: ".gemini/antigravity/workflows",
98
- "claude-code": ".claude/commands",
99
- codex: ".codex/skills",
100
- copilot: ".copilot/prompts",
101
- gemini: ".gemini/commands",
102
- windsurf: ".codeium/windsurf/workflows"
103
- };
104
73
  function resolveProjectPaths(relative, root) {
105
74
  const out = {};
106
75
  for (const [platform, rel] of Object.entries(relative)) {
@@ -111,21 +80,8 @@ function resolveProjectPaths(relative, root) {
111
80
  function getProjectPlatformPathsSkills(root) {
112
81
  return resolveProjectPaths(PROJECT_RELATIVE_PLATFORM_PATHS_SKILLS, root);
113
82
  }
114
- function getProjectPlatformPathsAgents(root) {
115
- return resolveProjectPaths(PROJECT_RELATIVE_PLATFORM_PATHS_AGENTS, root);
116
- }
117
- function getProjectPlatformPathsWorkflows(root) {
118
- return resolveProjectPaths(PROJECT_RELATIVE_PLATFORM_PATHS_WORKFLOWS, root);
119
- }
120
83
  var TYPE_DIRS = {
121
- skill: path.join(PROJECT_ROOT, "skills"),
122
- agent: path.join(PROJECT_ROOT, "agents"),
123
- workflow: path.join(PROJECT_ROOT, "workflows")
124
- };
125
- var TYPE_SUBDIRS = {
126
- skill: "skills",
127
- agent: "agents",
128
- workflow: "commands"
84
+ skill: path.join(PROJECT_ROOT, "skills")
129
85
  };
130
86
  var AGENT_SETUP_SCRIPTS_DIR = path.join(
131
87
  PROJECT_ROOT,
@@ -143,25 +99,16 @@ function getAgentsBase(scope, root) {
143
99
  }
144
100
 
145
101
  // src/utils/agent-setup.ts
146
- var LINK_SUBDIRS = ["skills", "agents", "commands"];
102
+ var LINK_SUBDIRS = ["skills"];
147
103
  function getScopePaths(scope, root) {
148
104
  if (scope === "project") {
149
- return {
150
- skills: getProjectPlatformPathsSkills(root),
151
- agents: getProjectPlatformPathsAgents(root),
152
- commands: getProjectPlatformPathsWorkflows(root)
153
- };
105
+ return { skills: getProjectPlatformPathsSkills(root) };
154
106
  }
155
- return {
156
- skills: PLATFORM_PATHS_SKILLS,
157
- agents: PLATFORM_PATHS_AGENTS,
158
- commands: PLATFORM_PATHS_WORKFLOWS
159
- };
107
+ return { skills: PLATFORM_PATHS_SKILLS };
160
108
  }
161
109
  function buildLinkMap(scope, root, presentSubdirs, platforms) {
162
110
  const scopePaths = getScopePaths(scope, root);
163
111
  const lines = [];
164
- const seen = /* @__PURE__ */ new Set();
165
112
  for (const sub of LINK_SUBDIRS) {
166
113
  if (!presentSubdirs.includes(sub)) continue;
167
114
  const platformDirs = scopePaths[sub];
@@ -169,10 +116,7 @@ function buildLinkMap(scope, root, presentSubdirs, platforms) {
169
116
  if (!dest) continue;
170
117
  if (platforms && !platforms.includes(platform)) continue;
171
118
  const formattedDest = scope === "project" ? path2.relative(root, dest).replace(/\\/g, "/") : dest;
172
- const line = `${sub}|${formattedDest}`;
173
- if (seen.has(line)) continue;
174
- seen.add(line);
175
- lines.push(line);
119
+ lines.push(`${sub}|${formattedDest}`);
176
120
  }
177
121
  }
178
122
  return lines.join("\n");
@@ -894,196 +838,156 @@ async function add(type, url, options) {
894
838
  if (!options?.skipIntro) {
895
839
  intro(pc2.bgCyan(pc2.black(" AI Manager : Add ")));
896
840
  }
897
- let currentType = type;
898
- const isSingleShot = !!type || !!url;
899
- while (true) {
900
- if (!currentType && !url) {
901
- const selectedType = await select2({
902
- message: "What would you like to add?",
903
- options: [
904
- { label: "Skills", value: "skill" },
905
- { label: "Agents", value: "agent" },
906
- { label: "Workflows", value: "workflow" },
907
- { label: "Exit", value: "exit" }
908
- ]
909
- });
910
- if (isCancel2(selectedType) || selectedType === "exit") {
911
- break;
841
+ await installSkills(type, url, options);
842
+ if (!options?.skipIntro) {
843
+ outro("You're all set!");
844
+ }
845
+ }
846
+ async function installSkills(type, url, options) {
847
+ const normalizedType = type ? type.toLowerCase().endsWith("s") && type.length > 1 ? type.slice(0, -1) : type : "skill";
848
+ if (!TYPE_DIRS[normalizedType]) {
849
+ cancel(`Unknown type: ${type}. Supported: skill`);
850
+ process.exit(1);
851
+ return;
852
+ }
853
+ let tempDir = null;
854
+ let isGitHubFile = false;
855
+ let selectedItems = [];
856
+ try {
857
+ if (url) {
858
+ const s2 = spinner();
859
+ s2.start("Fetching skill from GitHub...");
860
+ try {
861
+ const result = await fetchSkillFromGitHub(url);
862
+ tempDir = result.tempDir;
863
+ isGitHubFile = result.isFile;
864
+ selectedItems = [result.skillName];
865
+ s2.stop(pc2.green(`Fetched skill: ${result.skillName}`));
866
+ } catch (e) {
867
+ s2.error("Failed to fetch");
868
+ throw e;
912
869
  }
913
- currentType = selectedType;
870
+ } else {
871
+ const sourceDir = TYPE_DIRS.skill;
872
+ if (!await fs5.pathExists(sourceDir)) {
873
+ cancel("skill directory not found!");
874
+ process.exit(1);
875
+ return;
876
+ }
877
+ const entries = await fs5.readdir(sourceDir, { withFileTypes: true });
878
+ const availableItems = entries.filter((entry) => entry.isDirectory()).map((entry) => ({ label: entry.name, value: entry.name })).sort((a, b) => a.label.localeCompare(b.label));
879
+ if (availableItems.length === 0) {
880
+ note2("No skills found in directory.", "Information");
881
+ return;
882
+ }
883
+ const items = await autocompleteMultiselect({
884
+ message: "Select skills to install:",
885
+ options: availableItems
886
+ });
887
+ if (isCancel2(items)) return;
888
+ selectedItems = items;
914
889
  }
915
- const normalizedType = currentType?.toLowerCase().endsWith("s") && currentType.length > 1 ? currentType.slice(0, -1) : currentType ?? "";
916
- if (!TYPE_DIRS[normalizedType] && !url) {
917
- cancel(`Unknown type: ${currentType}. Supported: skill, agent, workflow`);
890
+ const scopeChoice = await chooseInstallScope({ flag: options?.scope });
891
+ if ("rejected" in scopeChoice) {
892
+ if (tempDir) await fs5.remove(tempDir);
893
+ cancel(
894
+ `Scope --scope=${options?.scope} unavailable: ${scopeChoice.reason}`
895
+ );
918
896
  process.exit(1);
919
897
  return;
920
898
  }
921
- let tempDir = null;
922
- let isGitHubFile = false;
923
- let selectedItems = [];
924
- try {
925
- if (url) {
926
- const s2 = spinner();
927
- s2.start(`Fetching ${normalizedType} from GitHub...`);
928
- try {
929
- const result = await fetchSkillFromGitHub(url);
930
- tempDir = result.tempDir;
931
- isGitHubFile = result.isFile;
932
- selectedItems = [result.skillName];
933
- s2.stop(pc2.green(`Fetched ${normalizedType}: ${result.skillName}`));
934
- } catch (e) {
935
- s2.error("Failed to fetch");
936
- throw e;
937
- }
938
- } else {
939
- const sourceDir = TYPE_DIRS[normalizedType];
940
- if (!await fs5.pathExists(sourceDir)) {
941
- cancel(`${normalizedType} directory not found!`);
942
- process.exit(1);
943
- return;
944
- }
945
- const entries = await fs5.readdir(sourceDir, { withFileTypes: true });
946
- const availableItems = entries.filter(
947
- (entry) => entry.isDirectory() || (normalizedType === "workflow" || normalizedType === "agent") && entry.isFile() && entry.name.endsWith(".md")
948
- ).map((entry) => ({ label: entry.name, value: entry.name })).sort((a, b) => a.label.localeCompare(b.label));
949
- if (availableItems.length === 0) {
950
- note2(`No ${normalizedType}s found in directory.`, "Information");
951
- if (isSingleShot) break;
952
- currentType = void 0;
953
- continue;
954
- }
955
- const items = await autocompleteMultiselect({
956
- message: `Select ${normalizedType}s to install:`,
957
- options: availableItems
958
- });
959
- if (isCancel2(items)) {
960
- if (isSingleShot) break;
961
- currentType = void 0;
962
- continue;
963
- }
964
- selectedItems = items;
965
- }
966
- const scopeChoice = await chooseInstallScope({ flag: options?.scope });
967
- if ("rejected" in scopeChoice) {
899
+ if (scopeChoice.cancelled) {
900
+ if (tempDir) await fs5.remove(tempDir);
901
+ return;
902
+ }
903
+ const { scope: chosenScope, root: scopeRoot } = scopeChoice;
904
+ const agentsBase = getAgentsBase(chosenScope, scopeRoot);
905
+ const targetBase = path5.join(agentsBase, "skills");
906
+ if (chosenScope === "project") {
907
+ const proceed = await confirm({
908
+ message: `Install to project scope at ${pc2.cyan(scopeRoot)}?`,
909
+ initialValue: true
910
+ });
911
+ if (isCancel2(proceed) || !proceed) {
968
912
  if (tempDir) await fs5.remove(tempDir);
969
- cancel(
970
- `Scope --scope=${options?.scope} unavailable: ${scopeChoice.reason}`
971
- );
972
- process.exit(1);
973
913
  return;
974
914
  }
975
- if (scopeChoice.cancelled) {
976
- if (tempDir) await fs5.remove(tempDir);
977
- if (isSingleShot) break;
978
- currentType = void 0;
979
- continue;
915
+ }
916
+ const preExisting = [];
917
+ for (const item of selectedItems) {
918
+ const targetName = path5.parse(item).name;
919
+ if (await fs5.pathExists(path5.join(targetBase, targetName))) {
920
+ preExisting.push({ entry: targetName, subdir: "skills" });
980
921
  }
981
- const { scope: chosenScope, root: scopeRoot } = scopeChoice;
982
- const agentsBase = getAgentsBase(chosenScope, scopeRoot);
983
- const subdir = TYPE_SUBDIRS[normalizedType] ?? "skills";
984
- const targetBase = path5.join(agentsBase, subdir);
985
- if (chosenScope === "project") {
986
- const proceed = await confirm({
987
- message: `Install to project scope at ${pc2.cyan(scopeRoot)}?`,
988
- initialValue: true
989
- });
990
- if (isCancel2(proceed) || !proceed) {
991
- if (tempDir) await fs5.remove(tempDir);
992
- if (isSingleShot) break;
993
- currentType = void 0;
994
- continue;
995
- }
922
+ }
923
+ const skipEntries = /* @__PURE__ */ new Set();
924
+ if (preExisting.length > 0) {
925
+ const toOverwrite = await multiselect({
926
+ message: "These entries already exist in .agents. Choose which to OVERWRITE (unselected entries are kept and skipped):",
927
+ options: preExisting.map((p) => ({ label: p.entry, value: p.entry })),
928
+ required: false
929
+ });
930
+ if (isCancel2(toOverwrite)) {
931
+ if (tempDir) await fs5.remove(tempDir);
932
+ return;
996
933
  }
997
- const subdirName = subdir;
998
- const preExisting = [];
999
- for (const item of selectedItems) {
1000
- const targetName = normalizedType === "skill" ? path5.parse(item).name : item;
1001
- if (await fs5.pathExists(path5.join(targetBase, targetName))) {
1002
- preExisting.push({ entry: targetName, subdir: subdirName });
1003
- }
934
+ const keep = new Set(toOverwrite);
935
+ for (const { entry } of preExisting) {
936
+ if (!keep.has(entry)) skipEntries.add(entry);
1004
937
  }
1005
- const skipEntries = /* @__PURE__ */ new Set();
1006
- if (preExisting.length > 0) {
1007
- const toOverwrite = await multiselect({
1008
- message: "These entries already exist in .agents. Choose which to OVERWRITE (unselected entries are kept and skipped):",
1009
- options: preExisting.map((p) => ({ label: p.entry, value: p.entry })),
1010
- required: false
1011
- });
1012
- if (isCancel2(toOverwrite)) {
1013
- if (tempDir) await fs5.remove(tempDir);
1014
- if (isSingleShot) break;
1015
- currentType = void 0;
1016
- continue;
1017
- }
1018
- const keep = new Set(toOverwrite);
1019
- for (const { entry } of preExisting) {
1020
- if (!keep.has(entry)) skipEntries.add(entry);
938
+ }
939
+ note2(
940
+ `Installing ${selectedItems.length} skills to ${targetBase} (scope: ${chosenScope})...`,
941
+ "Summary"
942
+ );
943
+ const s = spinner();
944
+ s.start("Installing...");
945
+ const errors = [];
946
+ const installed = [];
947
+ await fs5.ensureDir(targetBase);
948
+ for (const item of selectedItems) {
949
+ const targetName = path5.parse(item).name;
950
+ if (skipEntries.has(targetName)) continue;
951
+ s.message(`Installing ${pc2.bold(item)}...`);
952
+ try {
953
+ const sourcePath = url && tempDir ? isGitHubFile ? path5.join(tempDir, item) : tempDir : path5.join(TYPE_DIRS.skill, item);
954
+ if (!await fs5.pathExists(sourcePath)) {
955
+ throw new Error(`Item '${item}' not found at ${sourcePath}`);
1021
956
  }
957
+ const targetPath = path5.join(targetBase, targetName);
958
+ await fs5.copy(sourcePath, targetPath, { overwrite: true });
959
+ installed.push(targetPath);
960
+ } catch (err) {
961
+ const errorMessage = err instanceof Error ? err.message : String(err);
962
+ errors.push(`${item}: ${errorMessage}`);
1022
963
  }
1023
- note2(
1024
- `Installing ${selectedItems.length} ${normalizedType}s to ${targetBase} (scope: ${chosenScope})...`,
1025
- "Summary"
964
+ }
965
+ if (tempDir) {
966
+ await fs5.remove(tempDir);
967
+ tempDir = null;
968
+ }
969
+ if (errors.length > 0) {
970
+ s.stop(
971
+ pc2.yellow(
972
+ `Completed with errors. Installed: ${installed.length}, Errors: ${errors.length}`
973
+ )
1026
974
  );
1027
- const s = spinner();
1028
- s.start("Installing...");
1029
- const errors = [];
1030
- const installed = [];
1031
- await fs5.ensureDir(targetBase);
1032
- for (const item of selectedItems) {
1033
- const targetName = normalizedType === "skill" ? path5.parse(item).name : item;
1034
- if (skipEntries.has(targetName)) continue;
1035
- s.message(`Installing ${pc2.bold(item)}...`);
1036
- try {
1037
- const sourcePath = url && tempDir ? isGitHubFile ? path5.join(tempDir, item) : tempDir : path5.join(TYPE_DIRS[normalizedType], item);
1038
- if (!await fs5.pathExists(sourcePath)) {
1039
- throw new Error(`Item '${item}' not found at ${sourcePath}`);
1040
- }
1041
- const targetPath = path5.join(targetBase, targetName);
1042
- await fs5.copy(sourcePath, targetPath, { overwrite: true });
1043
- installed.push(targetPath);
1044
- } catch (err) {
1045
- const errorMessage = err instanceof Error ? err.message : String(err);
1046
- errors.push(`${item}: ${errorMessage}`);
1047
- }
1048
- }
1049
- if (tempDir) {
1050
- await fs5.remove(tempDir);
1051
- tempDir = null;
1052
- }
1053
- if (errors.length > 0) {
1054
- s.stop(
1055
- pc2.yellow(
1056
- `Completed with errors. Installed: ${installed.length}, Errors: ${errors.length}`
1057
- )
1058
- );
1059
- console.error(pc2.red("\nErrors encountered:"));
1060
- for (const e of errors) {
1061
- console.error(pc2.red(`- ${e}`));
1062
- }
1063
- } else {
1064
- s.stop(
1065
- pc2.green(
1066
- `Successfully installed ${installed.length} ${normalizedType}s.`
1067
- )
1068
- );
1069
- }
1070
- if (installed.length > 0) {
1071
- await maybeWireAgentSetup(agentsBase, chosenScope, scopeRoot);
1072
- if (normalizedType === "skill") {
1073
- await maybeInstallSkillHooks(installed, chosenScope, scopeRoot, !!url);
1074
- }
975
+ console.error(pc2.red("\nErrors encountered:"));
976
+ for (const e of errors) {
977
+ console.error(pc2.red(`- ${e}`));
1075
978
  }
1076
- } catch (error) {
1077
- if (tempDir) await fs5.remove(tempDir);
1078
- cancel(`An error occurred: ${error}`);
1079
- process.exit(1);
1080
- return;
979
+ } else {
980
+ s.stop(pc2.green(`Successfully installed ${installed.length} skills.`));
1081
981
  }
1082
- if (isSingleShot) break;
1083
- currentType = void 0;
1084
- }
1085
- if (!options?.skipIntro) {
1086
- outro("You're all set!");
982
+ if (installed.length > 0) {
983
+ await maybeWireAgentSetup(agentsBase, chosenScope, scopeRoot);
984
+ await maybeInstallSkillHooks(installed, chosenScope, scopeRoot, !!url);
985
+ }
986
+ } catch (error) {
987
+ if (tempDir) await fs5.remove(tempDir);
988
+ cancel(`An error occurred: ${error}`);
989
+ process.exit(1);
990
+ return;
1087
991
  }
1088
992
  }
1089
993
  async function maybeWireAgentSetup(agentsBase, scope, root) {
@@ -1175,7 +1079,6 @@ import {
1175
1079
  intro as intro2,
1176
1080
  isCancel as isCancel3,
1177
1081
  outro as outro2,
1178
- select as select3,
1179
1082
  spinner as spinner2,
1180
1083
  text
1181
1084
  } from "@clack/prompts";
@@ -1185,23 +1088,11 @@ async function importItem(type, url, options) {
1185
1088
  if (!options?.skipIntro) {
1186
1089
  intro2(pc3.bgCyan(pc3.black(" AI Manager : Import ")));
1187
1090
  }
1188
- let currentType = type;
1189
- if (!currentType) {
1190
- const selectedType = await select3({
1191
- message: "What would you like to import?",
1192
- options: [
1193
- { label: "Skill", value: "skill" },
1194
- { label: "Agent", value: "agent" },
1195
- { label: "Workflow", value: "workflow" }
1196
- ]
1197
- });
1198
- if (isCancel3(selectedType)) return;
1199
- currentType = selectedType;
1200
- }
1091
+ const currentType = type || "skill";
1201
1092
  const normalizedType = currentType.toLowerCase().endsWith("s") ? currentType.slice(0, -1) : currentType;
1202
1093
  const targetBaseDir = TYPE_DIRS[normalizedType];
1203
1094
  if (!targetBaseDir) {
1204
- cancel2(`Unknown type: ${currentType}. Supported: skill, agent, workflow`);
1095
+ cancel2(`Unknown type: ${currentType}. Supported: skill`);
1205
1096
  process.exit(1);
1206
1097
  return;
1207
1098
  }
@@ -1236,31 +1127,8 @@ async function importItem(type, url, options) {
1236
1127
  s.error("Failed to fetch");
1237
1128
  throw e;
1238
1129
  }
1239
- const shouldFlatten = (normalizedType === "agent" || normalizedType === "workflow") && !isFile;
1240
- const targetPath = shouldFlatten ? targetBaseDir : path6.join(targetBaseDir, itemName);
1241
- if (shouldFlatten) {
1242
- const srcFiles = await fs6.readdir(tempDir);
1243
- const conflicts = [];
1244
- for (const file of srcFiles) {
1245
- if (await fs6.pathExists(path6.join(targetBaseDir, file))) {
1246
- conflicts.push(file);
1247
- }
1248
- }
1249
- if (conflicts.length > 0) {
1250
- const limit = 5;
1251
- const displayList = conflicts.slice(0, limit).join(", ");
1252
- const remainder = conflicts.length - limit;
1253
- const message = remainder > 0 ? `Files ${displayList} (and ${remainder} others) already exist in ${targetBaseDir}. Overwrite?` : `Files ${displayList} already exist in ${targetBaseDir}. Overwrite?`;
1254
- const shouldOverwrite = await confirm2({
1255
- message,
1256
- initialValue: false
1257
- });
1258
- if (isCancel3(shouldOverwrite) || !shouldOverwrite) {
1259
- await fs6.remove(tempDir);
1260
- return;
1261
- }
1262
- }
1263
- } else if (await fs6.pathExists(targetPath)) {
1130
+ const targetPath = path6.join(targetBaseDir, itemName);
1131
+ if (await fs6.pathExists(targetPath)) {
1264
1132
  const shouldOverwrite = await confirm2({
1265
1133
  message: `${normalizedType} '${itemName}' already exists in the repo. Overwrite?`,
1266
1134
  initialValue: false
@@ -1277,11 +1145,7 @@ async function importItem(type, url, options) {
1277
1145
  overwrite: true
1278
1146
  });
1279
1147
  } else {
1280
- if (shouldFlatten) {
1281
- await fs6.copy(tempDir, targetBaseDir, { overwrite: true });
1282
- } else {
1283
- await fs6.copy(tempDir, targetPath, { overwrite: true });
1284
- }
1148
+ await fs6.copy(tempDir, targetPath, { overwrite: true });
1285
1149
  }
1286
1150
  s.stop(pc3.green(`Successfully imported ${itemName}!`));
1287
1151
  await fs6.remove(tempDir);
@@ -1299,7 +1163,7 @@ async function importItem(type, url, options) {
1299
1163
  // src/commands/list.ts
1300
1164
  import os6 from "node:os";
1301
1165
  import path7 from "node:path";
1302
- import { cancel as cancel3, intro as intro3, isCancel as isCancel4, outro as outro3, select as select4 } from "@clack/prompts";
1166
+ import { cancel as cancel3, intro as intro3, isCancel as isCancel4, outro as outro3, select as select2 } from "@clack/prompts";
1303
1167
  import fs7 from "fs-extra";
1304
1168
  import pc4 from "picocolors";
1305
1169
  async function collectEntries(subdirPath) {
@@ -1312,12 +1176,11 @@ function displayBase(base, scope) {
1312
1176
  if (scope === "global") return base.replace(os6.homedir(), "~");
1313
1177
  return base;
1314
1178
  }
1315
- async function listLocalForScopes(normalizedType, sections) {
1316
- const subdir = TYPE_SUBDIRS[normalizedType];
1317
- console.log(pc4.bold(pc4.blue(`Installed ${normalizedType}s (Local):`)));
1179
+ async function listLocalForScopes(sections) {
1180
+ console.log(pc4.bold(pc4.blue("Installed skills (Local):")));
1318
1181
  let foundAny = false;
1319
1182
  for (const section of sections) {
1320
- const subdirPath = path7.join(section.base, subdir);
1183
+ const subdirPath = path7.join(section.base, "skills");
1321
1184
  if (!await fs7.pathExists(subdirPath)) continue;
1322
1185
  const items = await collectEntries(subdirPath);
1323
1186
  if (items.length === 0) continue;
@@ -1336,7 +1199,7 @@ async function listLocalForScopes(normalizedType, sections) {
1336
1199
  }
1337
1200
  }
1338
1201
  if (!foundAny) {
1339
- console.log(pc4.dim(` No installed ${normalizedType}s found.`));
1202
+ console.log(pc4.dim(" No installed skills found."));
1340
1203
  }
1341
1204
  console.log("");
1342
1205
  }
@@ -1353,14 +1216,7 @@ function buildSections(scope, projectRoot) {
1353
1216
  }
1354
1217
  return sections;
1355
1218
  }
1356
- async function performListing(type) {
1357
- const normalizedType = type.toLowerCase().endsWith("s") ? type.slice(0, -1) : type.toLowerCase();
1358
- if (!TYPE_DIRS[normalizedType]) {
1359
- console.error(
1360
- pc4.red(`Unknown type: ${type}. Supported types: skill, agent, workflow`)
1361
- );
1362
- return;
1363
- }
1219
+ async function performListing(normalizedType) {
1364
1220
  const dirPath = TYPE_DIRS[normalizedType];
1365
1221
  if (!await fs7.pathExists(dirPath)) {
1366
1222
  console.log(
@@ -1369,9 +1225,7 @@ async function performListing(type) {
1369
1225
  return;
1370
1226
  }
1371
1227
  const entries = await fs7.readdir(dirPath, { withFileTypes: true });
1372
- const items = entries.filter(
1373
- (entry) => entry.isDirectory() || normalizedType !== "skill" && entry.isFile() && entry.name.endsWith(".md")
1374
- ).map((entry) => entry.name).sort();
1228
+ const items = entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
1375
1229
  if (items.length > 0) {
1376
1230
  console.log(pc4.bold(pc4.blue(`Available ${normalizedType}s:`)));
1377
1231
  for (const item of items) {
@@ -1393,12 +1247,10 @@ async function list(type, options) {
1393
1247
  try {
1394
1248
  while (true) {
1395
1249
  if (!currentType) {
1396
- const selected = await select4({
1250
+ const selected = await select2({
1397
1251
  message: `What would you like to list? (View: ${isLocal ? "Local" : "Repository"})`,
1398
1252
  options: [
1399
1253
  { label: "All Skills", value: "skill" },
1400
- { label: "All Agents", value: "agent" },
1401
- { label: "All Workflows", value: "workflow" },
1402
1254
  {
1403
1255
  label: `Switch to ${isLocal ? "Repository" : "Local"} View`,
1404
1256
  value: "toggle"
@@ -1415,7 +1267,13 @@ async function list(type, options) {
1415
1267
  }
1416
1268
  currentType = selected;
1417
1269
  }
1418
- const typesToList = currentType === "all" ? ["skill", "agent", "workflow"] : [currentType];
1270
+ const normalizedType = currentType.toLowerCase().endsWith("s") ? currentType.slice(0, -1) : currentType.toLowerCase();
1271
+ if (!TYPE_DIRS[normalizedType]) {
1272
+ console.error(
1273
+ pc4.red(`Unknown type: ${currentType}. Supported types: skill`)
1274
+ );
1275
+ break;
1276
+ }
1419
1277
  if (isLocal) {
1420
1278
  const scopeChoice = await chooseListRemoveScope({
1421
1279
  action: "list",
@@ -1433,18 +1291,11 @@ async function list(type, options) {
1433
1291
  currentType = void 0;
1434
1292
  continue;
1435
1293
  }
1436
- for (const t of typesToList) {
1437
- const normalizedType = t.toLowerCase().endsWith("s") ? t.slice(0, -1) : t.toLowerCase();
1438
- const sections = buildSections(
1439
- scopeChoice.scope,
1440
- scopeChoice.projectRoot
1441
- );
1442
- await listLocalForScopes(normalizedType, sections);
1443
- }
1294
+ await listLocalForScopes(
1295
+ buildSections(scopeChoice.scope, scopeChoice.projectRoot)
1296
+ );
1444
1297
  } else {
1445
- for (const t of typesToList) {
1446
- await performListing(t);
1447
- }
1298
+ await performListing(normalizedType);
1448
1299
  }
1449
1300
  if (isSingleShot) break;
1450
1301
  currentType = void 0;
@@ -1467,7 +1318,6 @@ import {
1467
1318
  isCancel as isCancel5,
1468
1319
  note as note3,
1469
1320
  outro as outro4,
1470
- select as select5,
1471
1321
  spinner as spinner3
1472
1322
  } from "@clack/prompts";
1473
1323
  import fs8 from "fs-extra";
@@ -1491,17 +1341,16 @@ function buildScopedBases(scope, homedir, projectRoot) {
1491
1341
  }
1492
1342
  return out;
1493
1343
  }
1494
- async function scanInstalledItems(scopedBases, subdir, normalizedType) {
1344
+ async function scanInstalledItems(scopedBases) {
1495
1345
  const seen = /* @__PURE__ */ new Set();
1496
1346
  const items = [];
1497
1347
  const showScopePrefix = scopedBases.length > 1;
1498
1348
  for (const { scope, base } of scopedBases) {
1499
- const subdirPath = path8.join(base, subdir);
1349
+ const subdirPath = path8.join(base, "skills");
1500
1350
  if (!await fs8.pathExists(subdirPath)) continue;
1501
1351
  const entries = await fs8.readdir(subdirPath, { withFileTypes: true });
1502
1352
  for (const entry of entries) {
1503
- const qualifies = entry.isDirectory() || normalizedType !== "skill" && entry.isFile() && entry.name.endsWith(".md");
1504
- if (!qualifies) continue;
1353
+ if (!entry.isDirectory()) continue;
1505
1354
  const key = showScopePrefix ? `${scope}:${entry.name}` : entry.name;
1506
1355
  if (seen.has(key)) continue;
1507
1356
  seen.add(key);
@@ -1515,25 +1364,8 @@ async function scanInstalledItems(scopedBases, subdir, normalizedType) {
1515
1364
  }
1516
1365
  return items.sort((a, b) => a.label.localeCompare(b.label));
1517
1366
  }
1518
- function getPlatformDirs(scope, root, normalizedType) {
1519
- if (scope === "project") {
1520
- switch (normalizedType) {
1521
- case "agent":
1522
- return getProjectPlatformPathsAgents(root);
1523
- case "workflow":
1524
- return getProjectPlatformPathsWorkflows(root);
1525
- default:
1526
- return getProjectPlatformPathsSkills(root);
1527
- }
1528
- }
1529
- switch (normalizedType) {
1530
- case "agent":
1531
- return PLATFORM_PATHS_AGENTS;
1532
- case "workflow":
1533
- return PLATFORM_PATHS_WORKFLOWS;
1534
- default:
1535
- return PLATFORM_PATHS_SKILLS;
1536
- }
1367
+ function getPlatformDirs(scope, root) {
1368
+ return scope === "project" ? getProjectPlatformPathsSkills(root) : PLATFORM_PATHS_SKILLS;
1537
1369
  }
1538
1370
  async function pruneDanglingLinks(platformDirs, entry, removedAgentsPath) {
1539
1371
  for (const dir of Object.values(platformDirs)) {
@@ -1554,147 +1386,109 @@ async function remove(type, options) {
1554
1386
  if (!options?.skipIntro) {
1555
1387
  intro4(pc5.bgCyan(pc5.black(" AI Manager : Remove ")));
1556
1388
  }
1557
- let currentType = type;
1558
- const isSingleShot = !!type;
1559
- while (true) {
1560
- if (!currentType) {
1561
- const selectedType = await select5({
1562
- message: "What would you like to remove?",
1563
- options: [
1564
- { label: "Skills", value: "skill" },
1565
- { label: "Agents", value: "agent" },
1566
- { label: "Workflows", value: "workflow" },
1567
- { label: "Exit", value: "exit" }
1568
- ]
1569
- });
1570
- if (isCancel5(selectedType) || selectedType === "exit") {
1571
- break;
1572
- }
1573
- currentType = selectedType;
1574
- }
1575
- const normalizedType = currentType.toLowerCase().endsWith("s") ? currentType.slice(0, -1) : currentType;
1576
- const subdir = TYPE_SUBDIRS[normalizedType] ?? "skills";
1577
- const scopeChoice = await chooseListRemoveScope({
1578
- action: "remove",
1579
- flag: options?.scope
1580
- });
1581
- if ("rejected" in scopeChoice) {
1582
- cancel4(
1583
- `Scope --scope=${options?.scope} unavailable: ${scopeChoice.reason}`
1584
- );
1585
- process.exit(1);
1586
- return;
1587
- }
1588
- if (scopeChoice.cancelled) {
1589
- if (isSingleShot) break;
1590
- currentType = void 0;
1591
- continue;
1592
- }
1593
- const scopedBases = buildScopedBases(
1594
- scopeChoice.scope,
1595
- scopeChoice.homedir,
1596
- scopeChoice.projectRoot
1597
- );
1598
- const s = spinner3();
1599
- s.start("Scanning for installed items...");
1600
- const scannedItems = await scanInstalledItems(
1601
- scopedBases,
1602
- subdir,
1603
- normalizedType
1604
- );
1605
- s.stop(`Found ${scannedItems.length} installed ${normalizedType}s.`);
1606
- if (scannedItems.length === 0) {
1607
- note3(`No installed ${normalizedType}s found.`, "Information");
1608
- if (isSingleShot) break;
1609
- currentType = void 0;
1610
- continue;
1611
- }
1612
- const itemSelections = await autocompleteMultiselect2({
1613
- message: `Select ${normalizedType}s to remove:`,
1614
- options: scannedItems.map((item) => ({
1615
- value: item.key,
1616
- label: item.label
1617
- }))
1618
- });
1619
- if (isCancel5(itemSelections)) {
1620
- if (isSingleShot) break;
1621
- currentType = void 0;
1622
- continue;
1623
- }
1624
- const itemsByKey = new Map(scannedItems.map((i) => [i.key, i]));
1625
- const selectedScannedItems = itemSelections.map((key) => itemsByKey.get(key)).filter((i) => !!i);
1626
- const confirmDelete = await confirm3({
1627
- message: `Are you sure you want to remove ${selectedScannedItems.length} item(s) from .agents?`,
1628
- initialValue: false
1629
- });
1630
- if (isCancel5(confirmDelete) || !confirmDelete) {
1631
- if (isSingleShot) break;
1632
- currentType = void 0;
1633
- continue;
1634
- }
1635
- const sDel = spinner3();
1636
- sDel.start("Removing items...");
1637
- let removedCount = 0;
1638
- let notFoundCount = 0;
1639
- const errors = [];
1640
- const basesByScope = /* @__PURE__ */ new Map();
1641
- for (const sb of scopedBases) {
1642
- basesByScope.set(sb.scope, sb);
1643
- }
1644
- for (const item of selectedScannedItems) {
1645
- const scoped = basesByScope.get(item.scope);
1646
- if (!scoped) continue;
1647
- const agentsPath = path8.join(scoped.base, subdir, item.name);
1648
- if (await fs8.pathExists(agentsPath)) {
1649
- sDel.message(`Removing ${pc5.bold(item.label)} from .agents...`);
1650
- try {
1651
- await fs8.remove(agentsPath);
1652
- removedCount++;
1653
- const platformDirs = getPlatformDirs(
1654
- item.scope,
1655
- scoped.root,
1656
- normalizedType
1657
- );
1658
- await pruneDanglingLinks(platformDirs, item.name, agentsPath);
1659
- } catch (err) {
1660
- const msg = err instanceof Error ? err.message : String(err);
1661
- errors.push(`${item.label}: ${msg}`);
1662
- }
1663
- } else {
1664
- notFoundCount++;
1665
- }
1666
- }
1667
- if (errors.length > 0) {
1668
- sDel.stop(
1669
- pc5.yellow(
1670
- `Completed with errors. Removed: ${removedCount}, Not Found: ${notFoundCount}, Errors: ${errors.length}`
1671
- )
1672
- );
1673
- console.error(pc5.red("\nErrors encountered:"));
1674
- for (const e of errors) {
1675
- console.error(pc5.red(`- ${e}`));
1389
+ await removeSkills(type, options);
1390
+ if (!options?.skipIntro) {
1391
+ outro4("Done!");
1392
+ }
1393
+ }
1394
+ async function removeSkills(type, options) {
1395
+ const normalizedType = type?.toLowerCase().endsWith("s") ? type.slice(0, -1) : type;
1396
+ if (normalizedType && !TYPE_DIRS[normalizedType]) {
1397
+ cancel4(`Unknown type: ${type}. Supported: skill`);
1398
+ process.exit(1);
1399
+ return;
1400
+ }
1401
+ const scopeChoice = await chooseListRemoveScope({
1402
+ action: "remove",
1403
+ flag: options?.scope
1404
+ });
1405
+ if ("rejected" in scopeChoice) {
1406
+ cancel4(`Scope --scope=${options?.scope} unavailable: ${scopeChoice.reason}`);
1407
+ process.exit(1);
1408
+ return;
1409
+ }
1410
+ if (scopeChoice.cancelled) return;
1411
+ const scopedBases = buildScopedBases(
1412
+ scopeChoice.scope,
1413
+ scopeChoice.homedir,
1414
+ scopeChoice.projectRoot
1415
+ );
1416
+ const s = spinner3();
1417
+ s.start("Scanning for installed items...");
1418
+ const scannedItems = await scanInstalledItems(scopedBases);
1419
+ s.stop(`Found ${scannedItems.length} installed skills.`);
1420
+ if (scannedItems.length === 0) {
1421
+ note3("No installed skills found.", "Information");
1422
+ return;
1423
+ }
1424
+ const itemSelections = await autocompleteMultiselect2({
1425
+ message: "Select skills to remove:",
1426
+ options: scannedItems.map((item) => ({
1427
+ value: item.key,
1428
+ label: item.label
1429
+ }))
1430
+ });
1431
+ if (isCancel5(itemSelections)) return;
1432
+ const itemsByKey = new Map(scannedItems.map((i) => [i.key, i]));
1433
+ const selectedScannedItems = itemSelections.map((key) => itemsByKey.get(key)).filter((i) => !!i);
1434
+ const confirmDelete = await confirm3({
1435
+ message: `Are you sure you want to remove ${selectedScannedItems.length} item(s) from .agents?`,
1436
+ initialValue: false
1437
+ });
1438
+ if (isCancel5(confirmDelete) || !confirmDelete) return;
1439
+ const sDel = spinner3();
1440
+ sDel.start("Removing items...");
1441
+ let removedCount = 0;
1442
+ let notFoundCount = 0;
1443
+ const errors = [];
1444
+ const basesByScope = /* @__PURE__ */ new Map();
1445
+ for (const sb of scopedBases) {
1446
+ basesByScope.set(sb.scope, sb);
1447
+ }
1448
+ for (const item of selectedScannedItems) {
1449
+ const scoped = basesByScope.get(item.scope);
1450
+ if (!scoped) continue;
1451
+ const agentsPath = path8.join(scoped.base, "skills", item.name);
1452
+ if (await fs8.pathExists(agentsPath)) {
1453
+ sDel.message(`Removing ${pc5.bold(item.label)} from .agents...`);
1454
+ try {
1455
+ await fs8.remove(agentsPath);
1456
+ removedCount++;
1457
+ const platformDirs = getPlatformDirs(item.scope, scoped.root);
1458
+ await pruneDanglingLinks(platformDirs, item.name, agentsPath);
1459
+ } catch (err) {
1460
+ const msg = err instanceof Error ? err.message : String(err);
1461
+ errors.push(`${item.label}: ${msg}`);
1676
1462
  }
1677
1463
  } else {
1678
- sDel.stop(
1679
- pc5.green(
1680
- `Successfully removed ${removedCount} items. (${notFoundCount} not found)`
1681
- )
1682
- );
1464
+ notFoundCount++;
1683
1465
  }
1684
- if (isSingleShot) break;
1685
- currentType = void 0;
1686
1466
  }
1687
- if (!options?.skipIntro) {
1688
- outro4("Done!");
1467
+ if (errors.length > 0) {
1468
+ sDel.stop(
1469
+ pc5.yellow(
1470
+ `Completed with errors. Removed: ${removedCount}, Not Found: ${notFoundCount}, Errors: ${errors.length}`
1471
+ )
1472
+ );
1473
+ console.error(pc5.red("\nErrors encountered:"));
1474
+ for (const e of errors) {
1475
+ console.error(pc5.red(`- ${e}`));
1476
+ }
1477
+ } else {
1478
+ sDel.stop(
1479
+ pc5.green(
1480
+ `Successfully removed ${removedCount} items. (${notFoundCount} not found)`
1481
+ )
1482
+ );
1689
1483
  }
1690
1484
  }
1691
1485
 
1692
1486
  // package.json
1693
- var version = "2.6.1";
1487
+ var version = "3.0.1";
1694
1488
 
1695
1489
  // bin/cli.ts
1696
1490
  var program = new Command();
1697
- program.name("ai-agent").description("CLI to manage AI agents, skills, and workflows").version(version);
1491
+ program.name("ai-agent").description("CLI to manage AI agent skills").version(version);
1698
1492
  function parseScopeFlag(value) {
1699
1493
  if (value === void 0) return void 0;
1700
1494
  if (isValidScopeFlag(value)) return value;
@@ -1716,13 +1510,13 @@ function parseListRemoveScopeFlag(value) {
1716
1510
  async function interactiveMain() {
1717
1511
  intro5(pc6.bgCyan(pc6.black(" AI Manager ")));
1718
1512
  while (true) {
1719
- const action = await select6({
1513
+ const action = await select3({
1720
1514
  message: "What would you like to do?",
1721
1515
  options: [
1722
- { label: "Add Item (Install)", value: "add" },
1723
- { label: "List Items", value: "list" },
1516
+ { label: "Add Skills (Install)", value: "add" },
1517
+ { label: "List Skills", value: "list" },
1724
1518
  { label: "Import from GitHub", value: "import" },
1725
- { label: "Remove Items", value: "remove" },
1519
+ { label: "Remove Skills", value: "remove" },
1726
1520
  { label: "Exit", value: "exit" }
1727
1521
  ]
1728
1522
  });
@@ -1746,23 +1540,21 @@ async function interactiveMain() {
1746
1540
  }
1747
1541
  outro5("Goodbye!");
1748
1542
  }
1749
- program.command("list [type]").description("List available items (skills, agents, workflows)").option("-l, --local", "List installed items locally").option(
1543
+ program.command("list [type]").description("List available skills").option("-l, --local", "List installed items locally").option(
1750
1544
  "-s, --scope <scope>",
1751
1545
  'Scope when listing local installs: "global", "project", or "both"'
1752
1546
  ).action(async (type, opts) => {
1753
1547
  const scope = parseListRemoveScopeFlag(opts?.scope);
1754
1548
  await list(type, { local: opts?.local, scope });
1755
1549
  });
1756
- program.command("add [type] [url]").description(
1757
- "Add an item (skill, agent, workflow) to platforms (Interactive or from GitHub URL)"
1758
- ).option("-s, --scope <scope>", 'Install scope: "global" or "project"').action(async (type, url, opts) => {
1550
+ program.command("add [type] [url]").description("Add a skill to platforms (Interactive or from GitHub URL)").option("-s, --scope <scope>", 'Install scope: "global" or "project"').action(async (type, url, opts) => {
1759
1551
  const scope = parseScopeFlag(opts?.scope);
1760
1552
  await add(type, url, { scope });
1761
1553
  });
1762
- program.command("import [type] [url]").description("Import an item from GitHub to the repo").action(async (type, url) => {
1554
+ program.command("import [type] [url]").description("Import a skill from GitHub to the repo").action(async (type, url) => {
1763
1555
  await importItem(type || "", url || "");
1764
1556
  });
1765
- program.command("remove [type]").description("Remove locally installed items (skills, agents, workflows)").option(
1557
+ program.command("remove [type]").description("Remove locally installed skills").option(
1766
1558
  "-s, --scope <scope>",
1767
1559
  'Scope to remove from: "global", "project", or "both"'
1768
1560
  ).action(async (type, opts) => {