@kurokeita/add-skill 1.18.0 → 1.20.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/bin/cli.js CHANGED
@@ -1,27 +1,27 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // bin/cli.ts
4
- import { intro as intro5, isCancel as isCancel5, outro as outro5, select as select5 } from "@clack/prompts";
4
+ import { intro as intro5, isCancel as isCancel6, outro as outro5, select as select6 } from "@clack/prompts";
5
5
  import { Command } from "commander";
6
- import pc5 from "picocolors";
6
+ import pc6 from "picocolors";
7
7
 
8
8
  // src/commands/add.ts
9
- import os3 from "node:os";
9
+ import os4 from "node:os";
10
10
  import path6 from "node:path";
11
11
  import {
12
12
  autocompleteMultiselect,
13
13
  cancel,
14
14
  confirm,
15
15
  intro,
16
- isCancel,
16
+ isCancel as isCancel2,
17
17
  multiselect,
18
- note,
18
+ note as note2,
19
19
  outro,
20
- select,
20
+ select as select2,
21
21
  spinner
22
22
  } from "@clack/prompts";
23
23
  import fs4 from "fs-extra";
24
- import pc from "picocolors";
24
+ import pc2 from "picocolors";
25
25
 
26
26
  // src/utils/github.ts
27
27
  import os from "node:os";
@@ -148,12 +148,50 @@ var PLATFORM_PATHS_WORKFLOWS = {
148
148
  gemini: path2.join(os2.homedir(), ".gemini/commands"),
149
149
  windsurf: path2.join(os2.homedir(), ".codeium/windsurf/global_workflows")
150
150
  };
151
+ var PROJECT_RELATIVE_PLATFORM_PATHS_SKILLS = {
152
+ antigravity: ".gemini/antigravity/skills",
153
+ "claude-code": ".claude/skills",
154
+ codex: ".codex/skills",
155
+ copilot: ".copilot/skills",
156
+ gemini: ".gemini/skills",
157
+ windsurf: ".codeium/windsurf/skills"
158
+ };
159
+ var PROJECT_RELATIVE_PLATFORM_PATHS_AGENTS = {
160
+ "claude-code": ".claude/agents",
161
+ codex: ".codex/skills",
162
+ copilot: ".copilot/agents",
163
+ gemini: ".gemini/agents"
164
+ };
165
+ var PROJECT_RELATIVE_PLATFORM_PATHS_WORKFLOWS = {
166
+ antigravity: ".gemini/antigravity/workflows",
167
+ "claude-code": ".claude/skills",
168
+ codex: ".codex/skills",
169
+ copilot: ".copilot/prompts",
170
+ gemini: ".gemini/commands",
171
+ windsurf: ".codeium/windsurf/workflows"
172
+ };
173
+ function resolveProjectPaths(relative, root) {
174
+ const out = {};
175
+ for (const [platform, rel] of Object.entries(relative)) {
176
+ if (rel) out[platform] = path2.join(root, rel);
177
+ }
178
+ return out;
179
+ }
180
+ function getProjectPlatformPathsSkills(root) {
181
+ return resolveProjectPaths(PROJECT_RELATIVE_PLATFORM_PATHS_SKILLS, root);
182
+ }
183
+ function getProjectPlatformPathsAgents(root) {
184
+ return resolveProjectPaths(PROJECT_RELATIVE_PLATFORM_PATHS_AGENTS, root);
185
+ }
186
+ function getProjectPlatformPathsWorkflows(root) {
187
+ return resolveProjectPaths(PROJECT_RELATIVE_PLATFORM_PATHS_WORKFLOWS, root);
188
+ }
151
189
  var TYPE_DIRS = {
152
190
  skill: path2.join(PROJECT_ROOT, "skills"),
153
191
  agent: path2.join(PROJECT_ROOT, "agents"),
154
192
  workflow: path2.join(PROJECT_ROOT, "workflows")
155
193
  };
156
- function getTargetPaths(type) {
194
+ function getGlobalTargetPaths(type) {
157
195
  switch (type) {
158
196
  case "agent":
159
197
  return PLATFORM_PATHS_AGENTS;
@@ -163,6 +201,23 @@ function getTargetPaths(type) {
163
201
  return PLATFORM_PATHS_SKILLS;
164
202
  }
165
203
  }
204
+ function getProjectTargetPaths(type, root) {
205
+ switch (type) {
206
+ case "agent":
207
+ return getProjectPlatformPathsAgents(root);
208
+ case "workflow":
209
+ return getProjectPlatformPathsWorkflows(root);
210
+ default:
211
+ return getProjectPlatformPathsSkills(root);
212
+ }
213
+ }
214
+ function getTargetPaths(type, scope = "global", projectRoot) {
215
+ if (scope === "project") {
216
+ const root = projectRoot ?? process.cwd();
217
+ return getProjectTargetPaths(type, root);
218
+ }
219
+ return getGlobalTargetPaths(type);
220
+ }
166
221
 
167
222
  // src/utils/platforms/antigravity.ts
168
223
  var AntigravityHandler = class {
@@ -683,6 +738,197 @@ function enableAutocompleteMultiSelectShiftAToggle() {
683
738
  autocompletePromptPrototype.__aiManagerShiftAPatched__ = true;
684
739
  }
685
740
 
741
+ // src/utils/scope-prompt.ts
742
+ import { isCancel, note, select } from "@clack/prompts";
743
+ import pc from "picocolors";
744
+
745
+ // src/utils/scope.ts
746
+ import { execFileSync } from "node:child_process";
747
+ import os3 from "node:os";
748
+ function isInsideGitWorkTree(cwd) {
749
+ try {
750
+ const out = execFileSync("git", ["rev-parse", "--is-inside-work-tree"], {
751
+ cwd,
752
+ stdio: ["ignore", "pipe", "ignore"],
753
+ encoding: "utf-8"
754
+ });
755
+ return out.trim() === "true";
756
+ } catch {
757
+ return false;
758
+ }
759
+ }
760
+ function resolveScope(scope, options = {}) {
761
+ const cwd = options.cwd ?? process.cwd();
762
+ if (scope === "global") {
763
+ return { ok: true, scope: "global", root: options.homedir ?? os3.homedir() };
764
+ }
765
+ const home = options.homedir ?? os3.homedir();
766
+ if (cwd === home) {
767
+ return { ok: false, reason: "homedir" };
768
+ }
769
+ const gitCheck = options.gitCheck ?? isInsideGitWorkTree;
770
+ if (!gitCheck(cwd)) {
771
+ return { ok: false, reason: "not-a-git-repo" };
772
+ }
773
+ return { ok: true, scope: "project", root: cwd };
774
+ }
775
+ function describeRefusal(reason) {
776
+ switch (reason) {
777
+ case "homedir":
778
+ return "Project scope is not allowed when the current directory is your home directory.";
779
+ case "not-a-git-repo":
780
+ return "Project scope requires running inside a git repository.";
781
+ }
782
+ }
783
+
784
+ // src/utils/scope-prompt.ts
785
+ function isValidScopeFlag(value) {
786
+ return value === "global" || value === "project";
787
+ }
788
+ function isValidListRemoveScopeFlag(value) {
789
+ return value === "global" || value === "project" || value === "both";
790
+ }
791
+ async function pickScope(initial) {
792
+ const result = await select({
793
+ message: "Choose install scope:",
794
+ options: [
795
+ {
796
+ label: "Global",
797
+ value: "global",
798
+ hint: "install under your home directory (default)"
799
+ },
800
+ {
801
+ label: "Project",
802
+ value: "project",
803
+ hint: "install under the current project directory"
804
+ }
805
+ ],
806
+ initialValue: initial
807
+ });
808
+ if (isCancel(result)) return "__cancel__";
809
+ return result;
810
+ }
811
+ async function offerGlobalFallback(reason) {
812
+ note(reason, "Project scope unavailable");
813
+ const choice = await select({
814
+ message: "What would you like to do?",
815
+ options: [
816
+ { label: "Install at global scope instead", value: "global" },
817
+ { label: "Cancel", value: "cancel" }
818
+ ],
819
+ initialValue: "global"
820
+ });
821
+ if (isCancel(choice) || choice === "cancel") return "__cancel__";
822
+ return "global";
823
+ }
824
+ async function chooseInstallScope(options = {}) {
825
+ const requested = options.flag ?? await pickScope(options.initial ?? "global");
826
+ if (requested === "__cancel__") return { cancelled: true };
827
+ const resolution = resolveScope(requested, options);
828
+ if (resolution.ok) {
829
+ return {
830
+ cancelled: false,
831
+ scope: resolution.scope,
832
+ root: resolution.root
833
+ };
834
+ }
835
+ if (options.flag === "project") {
836
+ const reason = describeRefusal(resolution.reason);
837
+ note(pc.yellow(reason), "Project scope unavailable");
838
+ return { rejected: true, reason };
839
+ }
840
+ const fallback = await offerGlobalFallback(describeRefusal(resolution.reason));
841
+ if (fallback === "__cancel__") return { cancelled: true };
842
+ const fallbackResolution = resolveScope("global", options);
843
+ if (!fallbackResolution.ok) return { cancelled: true };
844
+ return {
845
+ cancelled: false,
846
+ scope: fallbackResolution.scope,
847
+ root: fallbackResolution.root
848
+ };
849
+ }
850
+ async function pickListRemoveScope(action) {
851
+ const verb = action === "list" ? "List" : "Remove from";
852
+ const result = await select({
853
+ message: `Choose scope to ${action === "list" ? "list" : "remove from"}:`,
854
+ options: [
855
+ {
856
+ label: "Global",
857
+ value: "global",
858
+ hint: `${verb} items installed under your home directory`
859
+ },
860
+ {
861
+ label: "Project",
862
+ value: "project",
863
+ hint: `${verb} items under the current project`
864
+ },
865
+ {
866
+ label: "Both",
867
+ value: "both",
868
+ hint: `${verb} items at both scopes`
869
+ }
870
+ ],
871
+ initialValue: "global"
872
+ });
873
+ if (isCancel(result)) return "__cancel__";
874
+ return result;
875
+ }
876
+ async function offerGlobalOnlyFallback(reason, action) {
877
+ note(reason, "Project scope unavailable");
878
+ const verb = action === "list" ? "List" : "Remove from";
879
+ const choice = await select({
880
+ message: "What would you like to do?",
881
+ options: [
882
+ { label: `${verb} global scope only`, value: "global" },
883
+ { label: "Cancel", value: "cancel" }
884
+ ],
885
+ initialValue: "global"
886
+ });
887
+ if (isCancel(choice) || choice === "cancel") return "__cancel__";
888
+ return "global";
889
+ }
890
+ async function chooseListRemoveScope(options) {
891
+ const requested = options.flag ?? await pickListRemoveScope(options.action);
892
+ if (requested === "__cancel__") return { cancelled: true };
893
+ if (requested === "global") {
894
+ const resolved = resolveScope("global", options);
895
+ if (!resolved.ok) return { cancelled: true };
896
+ return {
897
+ cancelled: false,
898
+ scope: "global",
899
+ homedir: resolved.root
900
+ };
901
+ }
902
+ const projectResolution = resolveScope("project", options);
903
+ if (projectResolution.ok) {
904
+ const homeResolution2 = resolveScope("global", options);
905
+ if (!homeResolution2.ok) return { cancelled: true };
906
+ return {
907
+ cancelled: false,
908
+ scope: requested,
909
+ homedir: homeResolution2.root,
910
+ projectRoot: projectResolution.root
911
+ };
912
+ }
913
+ if (options.flag) {
914
+ const reason = describeRefusal(projectResolution.reason);
915
+ note(pc.yellow(reason), "Project scope unavailable");
916
+ return { rejected: true, reason };
917
+ }
918
+ const fallback = await offerGlobalOnlyFallback(
919
+ describeRefusal(projectResolution.reason),
920
+ options.action
921
+ );
922
+ if (fallback === "__cancel__") return { cancelled: true };
923
+ const homeResolution = resolveScope("global", options);
924
+ if (!homeResolution.ok) return { cancelled: true };
925
+ return {
926
+ cancelled: false,
927
+ scope: "global",
928
+ homedir: homeResolution.root
929
+ };
930
+ }
931
+
686
932
  // src/commands/add.ts
687
933
  enableAutocompleteMultiSelectShiftAToggle();
688
934
  function getPlatformOptions(type) {
@@ -690,7 +936,7 @@ function getPlatformOptions(type) {
690
936
  return Object.entries(paths).filter(([_, pathStr]) => !!pathStr).map(([platform, pathStr]) => ({
691
937
  label: PLATFORM_LABELS[platform],
692
938
  value: platform,
693
- hint: pathStr.replace(os3.homedir(), "~")
939
+ hint: pathStr.replace(os4.homedir(), "~")
694
940
  }));
695
941
  }
696
942
  async function installItem(itemName, overwrite, sourcePath, targetBaseDir) {
@@ -707,13 +953,13 @@ async function installItem(itemName, overwrite, sourcePath, targetBaseDir) {
707
953
  }
708
954
  async function add(type, url, options) {
709
955
  if (!options?.skipIntro) {
710
- intro(pc.bgCyan(pc.black(" AI Manager : Add ")));
956
+ intro(pc2.bgCyan(pc2.black(" AI Manager : Add ")));
711
957
  }
712
958
  let currentType = type;
713
959
  const isSingleShot = !!type || !!url;
714
960
  while (true) {
715
961
  if (!currentType && !url) {
716
- const selectedType = await select({
962
+ const selectedType = await select2({
717
963
  message: "What would you like to add?",
718
964
  options: [
719
965
  { label: "Skills", value: "skill" },
@@ -722,7 +968,7 @@ async function add(type, url, options) {
722
968
  { label: "Exit", value: "exit" }
723
969
  ]
724
970
  });
725
- if (isCancel(selectedType) || selectedType === "exit") {
971
+ if (isCancel2(selectedType) || selectedType === "exit") {
726
972
  break;
727
973
  }
728
974
  currentType = selectedType;
@@ -743,7 +989,7 @@ async function add(type, url, options) {
743
989
  const result = await fetchSkillFromGitHub(url);
744
990
  tempDir = result.tempDir;
745
991
  selectedItems = [result.skillName];
746
- s2.stop(pc.green(`Fetched ${normalizedType}: ${result.skillName}`));
992
+ s2.stop(pc2.green(`Fetched ${normalizedType}: ${result.skillName}`));
747
993
  } catch (e) {
748
994
  s2.error("Failed to fetch");
749
995
  throw e;
@@ -760,7 +1006,7 @@ async function add(type, url, options) {
760
1006
  (entry) => entry.isDirectory() || (normalizedType === "workflow" || normalizedType === "agent") && entry.isFile() && entry.name.endsWith(".md")
761
1007
  ).map((entry) => ({ label: entry.name, value: entry.name })).sort((a, b) => a.label.localeCompare(b.label));
762
1008
  if (availableItems.length === 0) {
763
- note(`No ${normalizedType}s found in directory.`, "Information");
1009
+ note2(`No ${normalizedType}s found in directory.`, "Information");
764
1010
  if (isSingleShot) break;
765
1011
  currentType = void 0;
766
1012
  continue;
@@ -769,14 +1015,13 @@ async function add(type, url, options) {
769
1015
  message: `Select ${normalizedType}s to install:`,
770
1016
  options: availableItems
771
1017
  });
772
- if (isCancel(items)) {
1018
+ if (isCancel2(items)) {
773
1019
  if (isSingleShot) break;
774
1020
  currentType = void 0;
775
1021
  continue;
776
1022
  }
777
1023
  selectedItems = items;
778
1024
  }
779
- const supportedPaths = getTargetPaths(normalizedType);
780
1025
  const currentPlatformOptions = getPlatformOptions(normalizedType);
781
1026
  if (currentPlatformOptions.length === 0) {
782
1027
  cancel(`No supported platforms found for type '${normalizedType}'.`);
@@ -788,13 +1033,46 @@ async function add(type, url, options) {
788
1033
  options: currentPlatformOptions,
789
1034
  required: true
790
1035
  });
791
- if (isCancel(platforms)) {
1036
+ if (isCancel2(platforms)) {
792
1037
  if (tempDir) await fs4.remove(tempDir);
793
1038
  if (isSingleShot) break;
794
1039
  currentType = void 0;
795
1040
  continue;
796
1041
  }
797
1042
  const selectedPlatforms = platforms;
1043
+ const scopeChoice = await chooseInstallScope({ flag: options?.scope });
1044
+ if ("rejected" in scopeChoice) {
1045
+ if (tempDir) await fs4.remove(tempDir);
1046
+ cancel(
1047
+ `Scope --scope=${options?.scope} unavailable: ${scopeChoice.reason}`
1048
+ );
1049
+ process.exit(1);
1050
+ return;
1051
+ }
1052
+ if (scopeChoice.cancelled) {
1053
+ if (tempDir) await fs4.remove(tempDir);
1054
+ if (isSingleShot) break;
1055
+ currentType = void 0;
1056
+ continue;
1057
+ }
1058
+ const { scope: chosenScope, root: scopeRoot } = scopeChoice;
1059
+ const supportedPaths = getTargetPaths(
1060
+ normalizedType,
1061
+ chosenScope,
1062
+ scopeRoot
1063
+ );
1064
+ if (chosenScope === "project") {
1065
+ const proceed = await confirm({
1066
+ message: `Install to project scope at ${pc2.cyan(scopeRoot)}?`,
1067
+ initialValue: true
1068
+ });
1069
+ if (isCancel2(proceed) || !proceed) {
1070
+ if (tempDir) await fs4.remove(tempDir);
1071
+ if (isSingleShot) break;
1072
+ currentType = void 0;
1073
+ continue;
1074
+ }
1075
+ }
798
1076
  const existingItems = [];
799
1077
  for (const platform of selectedPlatforms) {
800
1078
  const targetBase = supportedPaths[platform];
@@ -811,15 +1089,15 @@ async function add(type, url, options) {
811
1089
  let overwrite = true;
812
1090
  if (existingItems.length > 0) {
813
1091
  const limit = 5;
814
- const displayList = existingItems.slice(0, limit).map((e) => `${pc.bold(e.item)} (${e.platform})`).join(", ");
1092
+ const displayList = existingItems.slice(0, limit).map((e) => `${pc2.bold(e.item)} (${e.platform})`).join(", ");
815
1093
  const remainder = existingItems.length - limit;
816
1094
  const message = remainder > 0 ? `The following items already exist: ${displayList}, and ${remainder} others.` : `The following items already exist: ${displayList}.`;
817
- note(message, "Attention");
1095
+ note2(message, "Attention");
818
1096
  const shouldOverwrite = await confirm({
819
1097
  message: "Do you want to overwrite existing items?",
820
1098
  initialValue: false
821
1099
  });
822
- if (isCancel(shouldOverwrite)) {
1100
+ if (isCancel2(shouldOverwrite)) {
823
1101
  if (tempDir) await fs4.remove(tempDir);
824
1102
  if (isSingleShot) break;
825
1103
  currentType = void 0;
@@ -827,8 +1105,8 @@ async function add(type, url, options) {
827
1105
  }
828
1106
  overwrite = shouldOverwrite;
829
1107
  }
830
- note(
831
- `Installing ${selectedItems.length} ${normalizedType}s to ${selectedPlatforms.length} platforms...`,
1108
+ note2(
1109
+ `Installing ${selectedItems.length} ${normalizedType}s to ${selectedPlatforms.length} platforms (scope: ${chosenScope})...`,
832
1110
  "Summary"
833
1111
  );
834
1112
  const s = spinner();
@@ -840,7 +1118,7 @@ async function add(type, url, options) {
840
1118
  const targetBase = supportedPaths[platform];
841
1119
  if (!targetBase) continue;
842
1120
  for (const item of selectedItems) {
843
- const message = `Installing ${pc.bold(item)} to ${pc.cyan(platform)}...`;
1121
+ const message = `Installing ${pc2.bold(item)} to ${pc2.cyan(platform)}...`;
844
1122
  s.message(message);
845
1123
  try {
846
1124
  let currentSourcePath;
@@ -903,17 +1181,17 @@ async function add(type, url, options) {
903
1181
  }
904
1182
  if (errors.length > 0) {
905
1183
  s.stop(
906
- pc.yellow(
1184
+ pc2.yellow(
907
1185
  `Completed with errors. Installed: ${installedCount}, Skipped: ${skippedCount}, Errors: ${errors.length}`
908
1186
  )
909
1187
  );
910
- console.error(pc.red("\nErrors encountered:"));
1188
+ console.error(pc2.red("\nErrors encountered:"));
911
1189
  for (const e of errors) {
912
- console.error(pc.red(`- ${e}`));
1190
+ console.error(pc2.red(`- ${e}`));
913
1191
  }
914
1192
  } else {
915
1193
  s.stop(
916
- pc.green(
1194
+ pc2.green(
917
1195
  `Successfully installed ${installedCount} ${normalizedType}s. (${skippedCount} skipped)`
918
1196
  )
919
1197
  );
@@ -938,21 +1216,21 @@ import {
938
1216
  cancel as cancel2,
939
1217
  confirm as confirm2,
940
1218
  intro as intro2,
941
- isCancel as isCancel2,
1219
+ isCancel as isCancel3,
942
1220
  outro as outro2,
943
- select as select2,
1221
+ select as select3,
944
1222
  spinner as spinner2,
945
1223
  text
946
1224
  } from "@clack/prompts";
947
1225
  import fs5 from "fs-extra";
948
- import pc2 from "picocolors";
1226
+ import pc3 from "picocolors";
949
1227
  async function importItem(type, url, options) {
950
1228
  if (!options?.skipIntro) {
951
- intro2(pc2.bgCyan(pc2.black(" AI Manager : Import ")));
1229
+ intro2(pc3.bgCyan(pc3.black(" AI Manager : Import ")));
952
1230
  }
953
1231
  let currentType = type;
954
1232
  if (!currentType) {
955
- const selectedType = await select2({
1233
+ const selectedType = await select3({
956
1234
  message: "What would you like to import?",
957
1235
  options: [
958
1236
  { label: "Skill", value: "skill" },
@@ -960,7 +1238,7 @@ async function importItem(type, url, options) {
960
1238
  { label: "Workflow", value: "workflow" }
961
1239
  ]
962
1240
  });
963
- if (isCancel2(selectedType)) return;
1241
+ if (isCancel3(selectedType)) return;
964
1242
  currentType = selectedType;
965
1243
  }
966
1244
  const normalizedType = currentType.toLowerCase().endsWith("s") ? currentType.slice(0, -1) : currentType;
@@ -981,7 +1259,7 @@ async function importItem(type, url, options) {
981
1259
  return "Must be a GitHub URL.";
982
1260
  }
983
1261
  });
984
- if (isCancel2(inputUrl)) return;
1262
+ if (isCancel3(inputUrl)) return;
985
1263
  currentUrl = inputUrl;
986
1264
  }
987
1265
  let tempDir = null;
@@ -996,7 +1274,7 @@ async function importItem(type, url, options) {
996
1274
  if (!tempDir) throw new Error("Failed to create temp directory");
997
1275
  itemName = result.skillName;
998
1276
  isFile = result.isFile;
999
- s.stop(pc2.green(`Fetched: ${itemName}`));
1277
+ s.stop(pc3.green(`Fetched: ${itemName}`));
1000
1278
  } catch (e) {
1001
1279
  s.error("Failed to fetch");
1002
1280
  throw e;
@@ -1020,7 +1298,7 @@ async function importItem(type, url, options) {
1020
1298
  message,
1021
1299
  initialValue: false
1022
1300
  });
1023
- if (isCancel2(shouldOverwrite) || !shouldOverwrite) {
1301
+ if (isCancel3(shouldOverwrite) || !shouldOverwrite) {
1024
1302
  await fs5.remove(tempDir);
1025
1303
  return;
1026
1304
  }
@@ -1030,7 +1308,7 @@ async function importItem(type, url, options) {
1030
1308
  message: `${normalizedType} '${itemName}' already exists in the repo. Overwrite?`,
1031
1309
  initialValue: false
1032
1310
  });
1033
- if (isCancel2(shouldOverwrite) || !shouldOverwrite) {
1311
+ if (isCancel3(shouldOverwrite) || !shouldOverwrite) {
1034
1312
  await fs5.remove(tempDir);
1035
1313
  return;
1036
1314
  }
@@ -1048,7 +1326,7 @@ async function importItem(type, url, options) {
1048
1326
  await fs5.copy(tempDir, targetPath, { overwrite: true });
1049
1327
  }
1050
1328
  }
1051
- s.stop(pc2.green(`Successfully imported ${itemName}!`));
1329
+ s.stop(pc3.green(`Successfully imported ${itemName}!`));
1052
1330
  await fs5.remove(tempDir);
1053
1331
  if (!options?.skipIntro) {
1054
1332
  outro2(`${normalizedType} available at: ${targetPath}`);
@@ -1062,82 +1340,135 @@ async function importItem(type, url, options) {
1062
1340
  }
1063
1341
 
1064
1342
  // src/commands/list.ts
1065
- import { intro as intro3, isCancel as isCancel3, outro as outro3, select as select3 } from "@clack/prompts";
1343
+ import os5 from "node:os";
1344
+ import { cancel as cancel3, intro as intro3, isCancel as isCancel4, outro as outro3, select as select4 } from "@clack/prompts";
1066
1345
  import fs6 from "fs-extra";
1067
- import pc3 from "picocolors";
1068
- async function performListing(type, local) {
1069
- const normalizedType = type.toLowerCase().endsWith("s") ? type.slice(0, -1) : type.toLowerCase();
1070
- if (local) {
1071
- console.log(pc3.bold(pc3.blue(`Installed ${normalizedType}s (Local):`)));
1072
- const targetPaths = getTargetPaths(normalizedType);
1073
- let foundAny = false;
1074
- for (const [platform, pathStr] of Object.entries(targetPaths)) {
1075
- const fullPath = pathStr;
1076
- if (await fs6.pathExists(fullPath)) {
1077
- const entries = await fs6.readdir(fullPath, {
1078
- withFileTypes: true
1079
- });
1080
- const items = [];
1081
- for (const entry of entries) {
1082
- if (platform === "codex") {
1083
- if (await codexEntryMatchesType(fullPath, entry, normalizedType)) {
1084
- items.push(entry.name);
1085
- }
1086
- continue;
1087
- }
1088
- if (entry.isDirectory() || entry.isFile() && entry.name.endsWith(".md")) {
1089
- items.push(entry.name);
1090
- }
1091
- }
1092
- items.sort();
1093
- if (items.length > 0) {
1094
- foundAny = true;
1095
- console.log(pc3.cyan(` ${platform}:`));
1096
- for (const item of items) {
1097
- console.log(` - ${item}`);
1098
- }
1099
- }
1346
+ import pc4 from "picocolors";
1347
+ async function collectItemsForPlatform(platform, fullPath, normalizedType) {
1348
+ const items = [];
1349
+ const entries = await fs6.readdir(fullPath, { withFileTypes: true });
1350
+ for (const entry of entries) {
1351
+ if (platform === "codex") {
1352
+ if (await codexEntryMatchesType(fullPath, entry, normalizedType)) {
1353
+ items.push(entry.name);
1100
1354
  }
1355
+ continue;
1101
1356
  }
1102
- if (!foundAny) {
1103
- console.log(pc3.dim(` No installed ${normalizedType}s found.`));
1357
+ if (entry.isDirectory() || entry.isFile() && entry.name.endsWith(".md")) {
1358
+ items.push(entry.name);
1104
1359
  }
1105
- console.log("");
1106
- } else {
1107
- if (!TYPE_DIRS[normalizedType]) {
1108
- console.error(
1109
- pc3.red(
1110
- `Unknown type: ${type}. Supported types: skill, agent, workflow`
1111
- )
1112
- );
1113
- return;
1360
+ }
1361
+ items.sort();
1362
+ return items;
1363
+ }
1364
+ function displayPath(absolute, root, scope) {
1365
+ if (scope === "global") return absolute.replace(os5.homedir(), "~");
1366
+ const rel = absolute.startsWith(root) ? `.${absolute.slice(root.length)}` : absolute;
1367
+ return rel;
1368
+ }
1369
+ async function listLocalForScopes(normalizedType, sections) {
1370
+ console.log(pc4.bold(pc4.blue(`Installed ${normalizedType}s (Local):`)));
1371
+ let foundAny = false;
1372
+ const platformsByOrder = [];
1373
+ for (const section of sections) {
1374
+ for (const platform of Object.keys(section.paths)) {
1375
+ if (!platformsByOrder.includes(platform)) platformsByOrder.push(platform);
1114
1376
  }
1115
- const dirPath = TYPE_DIRS[normalizedType];
1116
- if (!await fs6.pathExists(dirPath)) {
1117
- console.log(
1118
- pc3.yellow(`No ${normalizedType} directory found at: ${dirPath}`)
1377
+ }
1378
+ for (const platform of platformsByOrder) {
1379
+ let printedHeader = false;
1380
+ for (const section of sections) {
1381
+ const fullPath = section.paths[platform];
1382
+ if (!fullPath) continue;
1383
+ if (!await fs6.pathExists(fullPath)) continue;
1384
+ const items = await collectItemsForPlatform(
1385
+ platform,
1386
+ fullPath,
1387
+ normalizedType
1119
1388
  );
1120
- return;
1121
- }
1122
- const entries = await fs6.readdir(dirPath, { withFileTypes: true });
1123
- const items = entries.filter(
1124
- (entry) => entry.isDirectory() || normalizedType !== "skill" && entry.isFile() && entry.name.endsWith(".md")
1125
- ).map((entry) => entry.name).sort();
1126
- if (items.length > 0) {
1127
- console.log(pc3.bold(pc3.blue(`Available ${normalizedType}s:`)));
1128
- for (const item of items) {
1129
- console.log(`- ${item}`);
1389
+ if (items.length === 0) continue;
1390
+ foundAny = true;
1391
+ if (!printedHeader) {
1392
+ console.log(pc4.cyan(` ${platform}:`));
1393
+ printedHeader = true;
1130
1394
  }
1131
- console.log(pc3.dim(`Total: ${items.length} ${normalizedType}s
1132
- `));
1133
- } else {
1134
- console.log(pc3.dim(`No ${normalizedType}s found.`));
1395
+ if (sections.length > 1) {
1396
+ const scopeLabel = section.scope === "global" ? "Global" : "Project";
1397
+ const display = displayPath(fullPath, section.root, section.scope);
1398
+ console.log(pc4.dim(` ${scopeLabel} (${display}):`));
1399
+ for (const item of items) {
1400
+ console.log(` - ${item}`);
1401
+ }
1402
+ } else {
1403
+ for (const item of items) {
1404
+ console.log(` - ${item}`);
1405
+ }
1406
+ }
1407
+ }
1408
+ }
1409
+ if (!foundAny) {
1410
+ console.log(pc4.dim(` No installed ${normalizedType}s found.`));
1411
+ }
1412
+ console.log("");
1413
+ }
1414
+ function buildSections(normalizedType, scope, homedir, projectRoot) {
1415
+ const sections = [];
1416
+ if (scope === "global" || scope === "both") {
1417
+ sections.push({
1418
+ scope: "global",
1419
+ root: homedir,
1420
+ paths: getTargetPaths(normalizedType, "global")
1421
+ });
1422
+ }
1423
+ if (scope === "project" || scope === "both") {
1424
+ if (projectRoot) {
1425
+ sections.push({
1426
+ scope: "project",
1427
+ root: projectRoot,
1428
+ paths: getTargetPaths(normalizedType, "project", projectRoot)
1429
+ });
1430
+ }
1431
+ }
1432
+ return sections;
1433
+ }
1434
+ async function performListing(type, local) {
1435
+ const normalizedType = type.toLowerCase().endsWith("s") ? type.slice(0, -1) : type.toLowerCase();
1436
+ if (local) {
1437
+ throw new Error(
1438
+ "performListing should not be called for local mode; use listLocalForScopes"
1439
+ );
1440
+ }
1441
+ if (!TYPE_DIRS[normalizedType]) {
1442
+ console.error(
1443
+ pc4.red(`Unknown type: ${type}. Supported types: skill, agent, workflow`)
1444
+ );
1445
+ return;
1446
+ }
1447
+ const dirPath = TYPE_DIRS[normalizedType];
1448
+ if (!await fs6.pathExists(dirPath)) {
1449
+ console.log(
1450
+ pc4.yellow(`No ${normalizedType} directory found at: ${dirPath}`)
1451
+ );
1452
+ return;
1453
+ }
1454
+ const entries = await fs6.readdir(dirPath, { withFileTypes: true });
1455
+ const items = entries.filter(
1456
+ (entry) => entry.isDirectory() || normalizedType !== "skill" && entry.isFile() && entry.name.endsWith(".md")
1457
+ ).map((entry) => entry.name).sort();
1458
+ if (items.length > 0) {
1459
+ console.log(pc4.bold(pc4.blue(`Available ${normalizedType}s:`)));
1460
+ for (const item of items) {
1461
+ console.log(`- ${item}`);
1135
1462
  }
1463
+ console.log(pc4.dim(`Total: ${items.length} ${normalizedType}s
1464
+ `));
1465
+ } else {
1466
+ console.log(pc4.dim(`No ${normalizedType}s found.`));
1136
1467
  }
1137
1468
  }
1138
1469
  async function list(type, options) {
1139
1470
  if (!options?.skipIntro) {
1140
- intro3(pc3.bgCyan(pc3.black(" AI Manager : List ")));
1471
+ intro3(pc4.bgCyan(pc4.black(" AI Manager : List ")));
1141
1472
  }
1142
1473
  let currentType = type;
1143
1474
  let isLocal = !!options?.local;
@@ -1145,7 +1476,7 @@ async function list(type, options) {
1145
1476
  try {
1146
1477
  while (true) {
1147
1478
  if (!currentType) {
1148
- const selected = await select3({
1479
+ const selected = await select4({
1149
1480
  message: `What would you like to list? (View: ${isLocal ? "Local" : "Repository"})`,
1150
1481
  options: [
1151
1482
  { label: "All Skills", value: "skill" },
@@ -1158,7 +1489,7 @@ async function list(type, options) {
1158
1489
  { label: "Exit", value: "exit" }
1159
1490
  ]
1160
1491
  });
1161
- if (isCancel3(selected) || selected === "exit") {
1492
+ if (isCancel4(selected) || selected === "exit") {
1162
1493
  break;
1163
1494
  }
1164
1495
  if (selected === "toggle") {
@@ -1168,14 +1499,43 @@ async function list(type, options) {
1168
1499
  currentType = selected;
1169
1500
  }
1170
1501
  const typesToList = currentType === "all" ? ["skill", "agent", "workflow"] : [currentType];
1171
- for (const t of typesToList) {
1172
- await performListing(t, isLocal);
1502
+ if (isLocal) {
1503
+ const scopeChoice = await chooseListRemoveScope({
1504
+ action: "list",
1505
+ flag: options?.scope
1506
+ });
1507
+ if ("rejected" in scopeChoice) {
1508
+ cancel3(
1509
+ `Scope --scope=${options?.scope} unavailable: ${scopeChoice.reason}`
1510
+ );
1511
+ process.exit(1);
1512
+ return;
1513
+ }
1514
+ if (scopeChoice.cancelled) {
1515
+ if (isSingleShot) break;
1516
+ currentType = void 0;
1517
+ continue;
1518
+ }
1519
+ for (const t of typesToList) {
1520
+ const normalizedType = t.toLowerCase().endsWith("s") ? t.slice(0, -1) : t.toLowerCase();
1521
+ const sections = buildSections(
1522
+ normalizedType,
1523
+ scopeChoice.scope,
1524
+ scopeChoice.homedir,
1525
+ scopeChoice.projectRoot
1526
+ );
1527
+ await listLocalForScopes(normalizedType, sections);
1528
+ }
1529
+ } else {
1530
+ for (const t of typesToList) {
1531
+ await performListing(t, false);
1532
+ }
1173
1533
  }
1174
1534
  if (isSingleShot) break;
1175
1535
  currentType = void 0;
1176
1536
  }
1177
1537
  } catch (error) {
1178
- console.error(pc3.red("Error listing items:"), error);
1538
+ console.error(pc4.red("Error listing items:"), error);
1179
1539
  }
1180
1540
  if (!options?.skipIntro) {
1181
1541
  outro3("Done!");
@@ -1186,27 +1546,79 @@ async function list(type, options) {
1186
1546
  import path8 from "node:path";
1187
1547
  import {
1188
1548
  autocompleteMultiselect as autocompleteMultiselect2,
1549
+ cancel as cancel4,
1189
1550
  confirm as confirm3,
1190
1551
  intro as intro4,
1191
- isCancel as isCancel4,
1552
+ isCancel as isCancel5,
1192
1553
  multiselect as multiselect2,
1193
- note as note2,
1554
+ note as note3,
1194
1555
  outro as outro4,
1195
- select as select4,
1556
+ select as select5,
1196
1557
  spinner as spinner3
1197
1558
  } from "@clack/prompts";
1198
1559
  import fs7 from "fs-extra";
1199
- import pc4 from "picocolors";
1560
+ import pc5 from "picocolors";
1200
1561
  enableAutocompleteMultiSelectShiftAToggle();
1562
+ function buildScopedTargetPaths(normalizedType, scope, projectRoot) {
1563
+ const out = [];
1564
+ if (scope === "global" || scope === "both") {
1565
+ out.push({
1566
+ scope: "global",
1567
+ paths: getTargetPaths(normalizedType, "global")
1568
+ });
1569
+ }
1570
+ if ((scope === "project" || scope === "both") && projectRoot) {
1571
+ out.push({
1572
+ scope: "project",
1573
+ paths: getTargetPaths(normalizedType, "project", projectRoot)
1574
+ });
1575
+ }
1576
+ return out;
1577
+ }
1578
+ async function scanInstalledItems(scopedPaths, normalizedType) {
1579
+ const seen = /* @__PURE__ */ new Set();
1580
+ const items = [];
1581
+ const showScopePrefix = scopedPaths.length > 1;
1582
+ for (const { scope, paths } of scopedPaths) {
1583
+ for (const [platform, pathStr] of Object.entries(paths)) {
1584
+ if (!pathStr) continue;
1585
+ if (!await fs7.pathExists(pathStr)) continue;
1586
+ const entries = await fs7.readdir(pathStr, { withFileTypes: true });
1587
+ for (const entry of entries) {
1588
+ let qualifies = false;
1589
+ if (platform === "codex") {
1590
+ qualifies = await codexEntryMatchesType(
1591
+ pathStr,
1592
+ entry,
1593
+ normalizedType
1594
+ );
1595
+ } else if (entry.isDirectory() || normalizedType === "workflow" && entry.isFile() && entry.name.endsWith(".md") || normalizedType === "agent" && entry.isFile() && entry.name.endsWith(".md")) {
1596
+ qualifies = true;
1597
+ }
1598
+ if (!qualifies) continue;
1599
+ const key = showScopePrefix ? `${scope}:${entry.name}` : entry.name;
1600
+ if (seen.has(key)) continue;
1601
+ seen.add(key);
1602
+ items.push({
1603
+ key,
1604
+ name: entry.name,
1605
+ scope,
1606
+ label: showScopePrefix ? `[${scope}] ${entry.name}` : entry.name
1607
+ });
1608
+ }
1609
+ }
1610
+ }
1611
+ return items.sort((a, b) => a.label.localeCompare(b.label));
1612
+ }
1201
1613
  async function remove(type, options) {
1202
1614
  if (!options?.skipIntro) {
1203
- intro4(pc4.bgCyan(pc4.black(" AI Manager : Remove ")));
1615
+ intro4(pc5.bgCyan(pc5.black(" AI Manager : Remove ")));
1204
1616
  }
1205
1617
  let currentType = type;
1206
1618
  const isSingleShot = !!type;
1207
1619
  while (true) {
1208
1620
  if (!currentType) {
1209
- const selectedType = await select4({
1621
+ const selectedType = await select5({
1210
1622
  message: "What would you like to remove?",
1211
1623
  options: [
1212
1624
  { label: "Skills", value: "skill" },
@@ -1215,57 +1627,65 @@ async function remove(type, options) {
1215
1627
  { label: "Exit", value: "exit" }
1216
1628
  ]
1217
1629
  });
1218
- if (isCancel4(selectedType) || selectedType === "exit") {
1630
+ if (isCancel5(selectedType) || selectedType === "exit") {
1219
1631
  break;
1220
1632
  }
1221
1633
  currentType = selectedType;
1222
1634
  }
1223
1635
  const normalizedType = currentType.toLowerCase().endsWith("s") ? currentType.slice(0, -1) : currentType;
1224
- const targetPaths = getTargetPaths(normalizedType);
1225
- const uniqueItems = /* @__PURE__ */ new Set();
1636
+ const scopeChoice = await chooseListRemoveScope({
1637
+ action: "remove",
1638
+ flag: options?.scope
1639
+ });
1640
+ if ("rejected" in scopeChoice) {
1641
+ cancel4(
1642
+ `Scope --scope=${options?.scope} unavailable: ${scopeChoice.reason}`
1643
+ );
1644
+ process.exit(1);
1645
+ return;
1646
+ }
1647
+ if (scopeChoice.cancelled) {
1648
+ if (isSingleShot) break;
1649
+ currentType = void 0;
1650
+ continue;
1651
+ }
1652
+ const scopedPaths = buildScopedTargetPaths(
1653
+ normalizedType,
1654
+ scopeChoice.scope,
1655
+ scopeChoice.projectRoot
1656
+ );
1226
1657
  const s = spinner3();
1227
1658
  s.start("Scanning for installed items...");
1228
- for (const [platform, pathStr] of Object.entries(targetPaths)) {
1229
- if (await fs7.pathExists(pathStr)) {
1230
- const entries = await fs7.readdir(pathStr, {
1231
- withFileTypes: true
1232
- });
1233
- for (const entry of entries) {
1234
- if (platform === "codex") {
1235
- if (await codexEntryMatchesType(
1236
- pathStr,
1237
- entry,
1238
- normalizedType
1239
- )) {
1240
- uniqueItems.add(entry.name);
1241
- }
1242
- continue;
1243
- }
1244
- if (entry.isDirectory() || normalizedType === "workflow" && entry.isFile() && entry.name.endsWith(".md") || normalizedType === "agent" && entry.isFile() && entry.name.endsWith(".md")) {
1245
- uniqueItems.add(entry.name);
1246
- }
1247
- }
1248
- }
1249
- }
1250
- s.stop(`Found ${uniqueItems.size} unique installed ${normalizedType}s.`);
1251
- if (uniqueItems.size === 0) {
1252
- note2(`No installed ${normalizedType}s found.`, "Information");
1659
+ const scannedItems = await scanInstalledItems(scopedPaths, normalizedType);
1660
+ s.stop(`Found ${scannedItems.length} installed ${normalizedType}s.`);
1661
+ if (scannedItems.length === 0) {
1662
+ note3(`No installed ${normalizedType}s found.`, "Information");
1253
1663
  if (isSingleShot) break;
1254
1664
  currentType = void 0;
1255
1665
  continue;
1256
1666
  }
1257
- const sortedItems = Array.from(uniqueItems).sort();
1258
1667
  const itemSelections = await autocompleteMultiselect2({
1259
1668
  message: `Select ${normalizedType}s to remove:`,
1260
- options: sortedItems.map((item) => ({ value: item, label: item }))
1669
+ options: scannedItems.map((item) => ({
1670
+ value: item.key,
1671
+ label: item.label
1672
+ }))
1261
1673
  });
1262
- if (isCancel4(itemSelections)) {
1674
+ if (isCancel5(itemSelections)) {
1263
1675
  if (isSingleShot) break;
1264
1676
  currentType = void 0;
1265
1677
  continue;
1266
1678
  }
1267
- const selectedItems = itemSelections;
1268
- const platformOptions = Object.entries(targetPaths).filter(([_, pathStr]) => !!pathStr).map(([platform]) => ({
1679
+ const itemsByKey = new Map(scannedItems.map((i) => [i.key, i]));
1680
+ const selectedScannedItems = itemSelections.map((key) => itemsByKey.get(key)).filter((i) => !!i);
1681
+ const supportedPlatforms = /* @__PURE__ */ new Set();
1682
+ for (const { paths } of scopedPaths) {
1683
+ for (const platform of Object.keys(paths)) {
1684
+ if (paths[platform])
1685
+ supportedPlatforms.add(platform);
1686
+ }
1687
+ }
1688
+ const platformOptions = [...supportedPlatforms].map((platform) => ({
1269
1689
  label: PLATFORM_LABELS[platform],
1270
1690
  value: platform
1271
1691
  }));
@@ -1274,17 +1694,17 @@ async function remove(type, options) {
1274
1694
  options: platformOptions,
1275
1695
  required: true
1276
1696
  });
1277
- if (isCancel4(platformSelections)) {
1697
+ if (isCancel5(platformSelections)) {
1278
1698
  if (isSingleShot) break;
1279
1699
  currentType = void 0;
1280
1700
  continue;
1281
1701
  }
1282
1702
  const selectedPlatforms = platformSelections;
1283
1703
  const confirmDelete = await confirm3({
1284
- message: `Are you sure you want to remove ${selectedItems.length} item(s) from ${selectedPlatforms.length} platform(s)?`,
1704
+ message: `Are you sure you want to remove ${selectedScannedItems.length} item(s) from ${selectedPlatforms.length} platform(s)?`,
1285
1705
  initialValue: false
1286
1706
  });
1287
- if (isCancel4(confirmDelete) || !confirmDelete) {
1707
+ if (isCancel5(confirmDelete) || !confirmDelete) {
1288
1708
  if (isSingleShot) break;
1289
1709
  currentType = void 0;
1290
1710
  continue;
@@ -1294,19 +1714,25 @@ async function remove(type, options) {
1294
1714
  let removedCount = 0;
1295
1715
  let notFoundCount = 0;
1296
1716
  const errors = [];
1717
+ const pathsByScope = /* @__PURE__ */ new Map();
1718
+ for (const { scope, paths } of scopedPaths) {
1719
+ pathsByScope.set(scope, paths);
1720
+ }
1297
1721
  for (const platform of selectedPlatforms) {
1298
- const targetBase = targetPaths[platform];
1299
- if (!targetBase) continue;
1300
- for (const item of selectedItems) {
1301
- const targetPath = path8.join(targetBase, item);
1722
+ for (const item of selectedScannedItems) {
1723
+ const targetBase = pathsByScope.get(item.scope)?.[platform];
1724
+ if (!targetBase) continue;
1725
+ const targetPath = path8.join(targetBase, item.name);
1302
1726
  if (await fs7.pathExists(targetPath)) {
1303
- sDel.message(`Removing ${pc4.bold(item)} from ${pc4.cyan(platform)}...`);
1727
+ sDel.message(
1728
+ `Removing ${pc5.bold(item.label)} from ${pc5.cyan(platform)}...`
1729
+ );
1304
1730
  try {
1305
1731
  await fs7.remove(targetPath);
1306
1732
  removedCount++;
1307
1733
  } catch (err) {
1308
1734
  const msg = err instanceof Error ? err.message : String(err);
1309
- errors.push(`${item} (${platform}): ${msg}`);
1735
+ errors.push(`${item.label} (${platform}): ${msg}`);
1310
1736
  }
1311
1737
  } else {
1312
1738
  notFoundCount++;
@@ -1315,17 +1741,17 @@ async function remove(type, options) {
1315
1741
  }
1316
1742
  if (errors.length > 0) {
1317
1743
  sDel.stop(
1318
- pc4.yellow(
1744
+ pc5.yellow(
1319
1745
  `Completed with errors. Removed: ${removedCount}, Not Found: ${notFoundCount}, Errors: ${errors.length}`
1320
1746
  )
1321
1747
  );
1322
- console.error(pc4.red("\nErrors encountered:"));
1748
+ console.error(pc5.red("\nErrors encountered:"));
1323
1749
  for (const e of errors) {
1324
- console.error(pc4.red(`- ${e}`));
1750
+ console.error(pc5.red(`- ${e}`));
1325
1751
  }
1326
1752
  } else {
1327
1753
  sDel.stop(
1328
- pc4.green(
1754
+ pc5.green(
1329
1755
  `Successfully removed ${removedCount} items. (${notFoundCount} not found)`
1330
1756
  )
1331
1757
  );
@@ -1341,10 +1767,28 @@ async function remove(type, options) {
1341
1767
  // bin/cli.ts
1342
1768
  var program = new Command();
1343
1769
  program.name("ai-agent").description("CLI to manage AI agents, skills, and workflows").version("1.4.0");
1770
+ function parseScopeFlag(value) {
1771
+ if (value === void 0) return void 0;
1772
+ if (isValidScopeFlag(value)) return value;
1773
+ console.error(
1774
+ pc6.red(`Invalid --scope value: ${value}. Expected "global" or "project".`)
1775
+ );
1776
+ process.exit(1);
1777
+ }
1778
+ function parseListRemoveScopeFlag(value) {
1779
+ if (value === void 0) return void 0;
1780
+ if (isValidListRemoveScopeFlag(value)) return value;
1781
+ console.error(
1782
+ pc6.red(
1783
+ `Invalid --scope value: ${value}. Expected "global", "project", or "both".`
1784
+ )
1785
+ );
1786
+ process.exit(1);
1787
+ }
1344
1788
  async function interactiveMain() {
1345
- intro5(pc5.bgCyan(pc5.black(" AI Manager ")));
1789
+ intro5(pc6.bgCyan(pc6.black(" AI Manager ")));
1346
1790
  while (true) {
1347
- const action = await select5({
1791
+ const action = await select6({
1348
1792
  message: "What would you like to do?",
1349
1793
  options: [
1350
1794
  { label: "Add Item (Install)", value: "add" },
@@ -1354,7 +1798,7 @@ async function interactiveMain() {
1354
1798
  { label: "Exit", value: "exit" }
1355
1799
  ]
1356
1800
  });
1357
- if (isCancel5(action) || action === "exit") {
1801
+ if (isCancel6(action) || action === "exit") {
1358
1802
  break;
1359
1803
  }
1360
1804
  switch (action) {
@@ -1374,15 +1818,28 @@ async function interactiveMain() {
1374
1818
  }
1375
1819
  outro5("Goodbye!");
1376
1820
  }
1377
- program.command("list [type]").description("List available items (skills, agents, workflows)").option("-l, --local", "List installed items locally").action(list);
1821
+ program.command("list [type]").description("List available items (skills, agents, workflows)").option("-l, --local", "List installed items locally").option(
1822
+ "-s, --scope <scope>",
1823
+ 'Scope when listing local installs: "global", "project", or "both"'
1824
+ ).action(async (type, opts) => {
1825
+ const scope = parseListRemoveScopeFlag(opts?.scope);
1826
+ await list(type, { local: opts?.local, scope });
1827
+ });
1378
1828
  program.command("add [type] [url]").description(
1379
1829
  "Add an item (skill, agent, workflow) to platforms (Interactive or from GitHub URL)"
1380
- ).action(add);
1830
+ ).option("-s, --scope <scope>", 'Install scope: "global" or "project"').action(async (type, url, opts) => {
1831
+ const scope = parseScopeFlag(opts?.scope);
1832
+ await add(type, url, { scope });
1833
+ });
1381
1834
  program.command("import [type] [url]").description("Import an item from GitHub to the repo").action(async (type, url) => {
1382
1835
  await importItem(type || "", url || "");
1383
1836
  });
1384
- program.command("remove [type]").description("Remove locally installed items (skills, agents, workflows)").action(async (type) => {
1385
- await remove(type || "");
1837
+ program.command("remove [type]").description("Remove locally installed items (skills, agents, workflows)").option(
1838
+ "-s, --scope <scope>",
1839
+ 'Scope to remove from: "global", "project", or "both"'
1840
+ ).action(async (type, opts) => {
1841
+ const scope = parseListRemoveScopeFlag(opts?.scope);
1842
+ await remove(type || "", { scope });
1386
1843
  });
1387
1844
  if (process.argv.length <= 2) {
1388
1845
  await interactiveMain();