@orderful/droid 0.33.1 → 0.34.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 (79) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/bin/droid.js +689 -102
  3. package/dist/commands/config.d.ts.map +1 -1
  4. package/dist/commands/repos.d.ts +21 -0
  5. package/dist/commands/repos.d.ts.map +1 -0
  6. package/dist/commands/tui/components/SettingsDetails.d.ts +2 -1
  7. package/dist/commands/tui/components/SettingsDetails.d.ts.map +1 -1
  8. package/dist/commands/tui/types.d.ts +1 -1
  9. package/dist/commands/tui/types.d.ts.map +1 -1
  10. package/dist/commands/tui/views/ReposManagementScreen.d.ts +6 -0
  11. package/dist/commands/tui/views/ReposManagementScreen.d.ts.map +1 -0
  12. package/dist/commands/tui/views/ReposViewerScreen.d.ts +5 -0
  13. package/dist/commands/tui/views/ReposViewerScreen.d.ts.map +1 -0
  14. package/dist/commands/tui.d.ts.map +1 -1
  15. package/dist/index.js +156 -26
  16. package/dist/lib/config.d.ts +34 -1
  17. package/dist/lib/config.d.ts.map +1 -1
  18. package/dist/lib/types.d.ts +10 -1
  19. package/dist/lib/types.d.ts.map +1 -1
  20. package/dist/tools/brain/skills/brain/SKILL.md +2 -2
  21. package/dist/tools/brain/skills/brain/references/workflows.md +10 -10
  22. package/dist/tools/coach/skills/coach/SKILL.md +6 -6
  23. package/dist/tools/codex/skills/codex/SKILL.md +5 -5
  24. package/dist/tools/codex/skills/codex/references/creating.md +2 -2
  25. package/dist/tools/codex/skills/codex/references/decisions.md +2 -2
  26. package/dist/tools/codex/skills/codex/references/loading.md +1 -1
  27. package/dist/tools/codex/skills/codex/references/topics.md +2 -2
  28. package/dist/tools/codex/skills/codex/scripts/git-finish-write.d.ts +1 -1
  29. package/dist/tools/codex/skills/codex/scripts/git-finish-write.ts +2 -2
  30. package/dist/tools/codex/skills/codex/scripts/git-preamble.d.ts +1 -1
  31. package/dist/tools/codex/skills/codex/scripts/git-preamble.ts +3 -3
  32. package/dist/tools/codex/skills/codex/scripts/git-start-write.d.ts +1 -1
  33. package/dist/tools/codex/skills/codex/scripts/git-start-write.ts +2 -2
  34. package/dist/tools/comments/skills/comments/SKILL.md +9 -9
  35. package/dist/tools/plan/skills/plan/SKILL.md +2 -2
  36. package/dist/tools/plan/skills/plan/references/workflows.md +2 -2
  37. package/dist/tools/project/skills/project/SKILL.md +1 -1
  38. package/dist/tools/project/skills/project/references/creating.md +2 -2
  39. package/dist/tools/project/skills/project/references/loading.md +1 -1
  40. package/dist/tools/tech-design/skills/tech-design/SKILL.md +2 -2
  41. package/dist/tools/tech-design/skills/tech-design/references/publish.md +3 -3
  42. package/dist/tools/tech-design/skills/tech-design/references/start.md +29 -3
  43. package/dist/tools/tech-design/skills/tech-design/references/think.md +1 -1
  44. package/dist/tools/wrapup/skills/wrapup/references/subagent-prompts.md +3 -3
  45. package/package.json +1 -1
  46. package/src/bin/droid.ts +39 -0
  47. package/src/commands/config.ts +14 -1
  48. package/src/commands/repos.ts +185 -0
  49. package/src/commands/tui/components/SettingsDetails.tsx +42 -13
  50. package/src/commands/tui/types.ts +1 -1
  51. package/src/commands/tui/views/ReposManagementScreen.tsx +291 -0
  52. package/src/commands/tui/views/ReposViewerScreen.tsx +49 -0
  53. package/src/commands/tui/views/SkillConfigScreen.tsx +2 -2
  54. package/src/commands/tui.tsx +51 -4
  55. package/src/lib/config.test.ts +228 -1
  56. package/src/lib/config.ts +205 -4
  57. package/src/lib/types.ts +13 -1
  58. package/src/tools/brain/skills/brain/SKILL.md +2 -2
  59. package/src/tools/brain/skills/brain/references/workflows.md +10 -10
  60. package/src/tools/coach/skills/coach/SKILL.md +6 -6
  61. package/src/tools/codex/skills/codex/SKILL.md +5 -5
  62. package/src/tools/codex/skills/codex/references/creating.md +2 -2
  63. package/src/tools/codex/skills/codex/references/decisions.md +2 -2
  64. package/src/tools/codex/skills/codex/references/loading.md +1 -1
  65. package/src/tools/codex/skills/codex/references/topics.md +2 -2
  66. package/src/tools/codex/skills/codex/scripts/git-finish-write.ts +2 -2
  67. package/src/tools/codex/skills/codex/scripts/git-preamble.ts +3 -3
  68. package/src/tools/codex/skills/codex/scripts/git-start-write.ts +2 -2
  69. package/src/tools/comments/skills/comments/SKILL.md +9 -9
  70. package/src/tools/plan/skills/plan/SKILL.md +2 -2
  71. package/src/tools/plan/skills/plan/references/workflows.md +2 -2
  72. package/src/tools/project/skills/project/SKILL.md +1 -1
  73. package/src/tools/project/skills/project/references/creating.md +2 -2
  74. package/src/tools/project/skills/project/references/loading.md +1 -1
  75. package/src/tools/tech-design/skills/tech-design/SKILL.md +2 -2
  76. package/src/tools/tech-design/skills/tech-design/references/publish.md +3 -3
  77. package/src/tools/tech-design/skills/tech-design/references/start.md +29 -3
  78. package/src/tools/tech-design/skills/tech-design/references/think.md +1 -1
  79. package/src/tools/wrapup/skills/wrapup/references/subagent-prompts.md +3 -3
package/dist/bin/droid.js CHANGED
@@ -12,7 +12,13 @@ import { join as join8 } from "path";
12
12
  import { homedir as homedir4 } from "os";
13
13
 
14
14
  // src/lib/config.ts
15
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
15
+ import {
16
+ existsSync,
17
+ mkdirSync,
18
+ readFileSync,
19
+ readdirSync,
20
+ writeFileSync
21
+ } from "fs";
16
22
  import { homedir } from "os";
17
23
  import { join } from "path";
18
24
  import YAML from "yaml";
@@ -68,6 +74,54 @@ function migrateConfig(config) {
68
74
  platforms: config.platforms ?? {}
69
75
  };
70
76
  }
77
+ function migrateToolConfigs(config) {
78
+ const skillsDir = join(CONFIG_DIR, "skills");
79
+ if (!existsSync(skillsDir)) {
80
+ if (!config.migrations) {
81
+ config.migrations = {};
82
+ }
83
+ if (!config.migrations.tools_consolidated) {
84
+ config.migrations.tools_consolidated = true;
85
+ return true;
86
+ }
87
+ return false;
88
+ }
89
+ let migrated = false;
90
+ try {
91
+ const entries = readdirSync(skillsDir, { withFileTypes: true });
92
+ for (const entry of entries) {
93
+ if (!entry.isDirectory()) continue;
94
+ const skillName = entry.name;
95
+ const overridesPath = join(skillsDir, skillName, "overrides.yaml");
96
+ if (!existsSync(overridesPath)) continue;
97
+ try {
98
+ const content = readFileSync(overridesPath, "utf-8");
99
+ const overrides = YAML.parse(content);
100
+ if (overrides && Object.keys(overrides).length > 0) {
101
+ if (!config.tools) {
102
+ config.tools = {};
103
+ }
104
+ if (!config.tools[skillName]) {
105
+ config.tools[skillName] = overrides;
106
+ migrated = true;
107
+ }
108
+ }
109
+ } catch {
110
+ continue;
111
+ }
112
+ }
113
+ if (!config.migrations) {
114
+ config.migrations = {};
115
+ }
116
+ if (!config.migrations.tools_consolidated) {
117
+ config.migrations.tools_consolidated = true;
118
+ migrated = true;
119
+ }
120
+ return migrated;
121
+ } catch {
122
+ return false;
123
+ }
124
+ }
71
125
  function ensureConfigDir() {
72
126
  if (!existsSync(CONFIG_DIR)) {
73
127
  mkdirSync(CONFIG_DIR, { recursive: true });
@@ -84,9 +138,10 @@ function loadConfig() {
84
138
  try {
85
139
  const content = readFileSync(CONFIG_FILE, "utf-8");
86
140
  const rawConfig = YAML.parse(content);
87
- const needsMigration = "ai_tool" in rawConfig && !("platform" in rawConfig);
141
+ const needsLegacyMigration = "ai_tool" in rawConfig && !("platform" in rawConfig);
88
142
  const config = migrateConfig(rawConfig);
89
- if (needsMigration) {
143
+ const needsToolMigration = migrateToolConfigs(config);
144
+ if (needsLegacyMigration || needsToolMigration) {
90
145
  saveConfig(config);
91
146
  }
92
147
  return config;
@@ -140,6 +195,11 @@ function getSkillOverridesPath(skillName) {
140
195
  return join(CONFIG_DIR, "skills", normalizedName, "overrides.yaml");
141
196
  }
142
197
  function loadSkillOverrides(skillName) {
198
+ const normalizedName = normalizeSkillNameForConfig(skillName);
199
+ const toolSettings = getToolSettings(normalizedName);
200
+ if (Object.keys(toolSettings).length > 0) {
201
+ return toolSettings;
202
+ }
143
203
  const overridesPath = getSkillOverridesPath(skillName);
144
204
  if (!existsSync(overridesPath)) {
145
205
  return {};
@@ -161,6 +221,18 @@ function saveSkillOverrides(skillName, overrides) {
161
221
  const content = YAML.stringify(overrides, { indent: 2 });
162
222
  writeFileSync(overridesPath, content, "utf-8");
163
223
  }
224
+ function getToolSettings(name) {
225
+ const config = loadConfig();
226
+ return config.tools?.[name] ?? {};
227
+ }
228
+ function setToolSettings(name, settings) {
229
+ const config = loadConfig();
230
+ if (!config.tools) {
231
+ config.tools = {};
232
+ }
233
+ config.tools[name] = settings;
234
+ saveConfig(config);
235
+ }
164
236
  function getAutoUpdateConfig() {
165
237
  const config = loadConfig();
166
238
  return {
@@ -177,11 +249,56 @@ function setAutoUpdateConfig(updates) {
177
249
  };
178
250
  saveConfig(config);
179
251
  }
252
+ function expandTilde(path) {
253
+ if (path.startsWith("~/")) {
254
+ return join(homedir(), path.slice(2));
255
+ }
256
+ return path;
257
+ }
258
+ function getRepos() {
259
+ const config = loadConfig();
260
+ return config.repos ?? [];
261
+ }
262
+ function getRepo(name) {
263
+ const repos2 = getRepos();
264
+ return repos2.find((repo) => repo.name === name);
265
+ }
266
+ function getRepoPath(name) {
267
+ const repo = getRepo(name);
268
+ if (!repo) {
269
+ return void 0;
270
+ }
271
+ return expandTilde(repo.path);
272
+ }
273
+ function addRepo(repo) {
274
+ const config = loadConfig();
275
+ const repos2 = config.repos ?? [];
276
+ const existingIndex = repos2.findIndex((r) => r.name === repo.name);
277
+ if (existingIndex >= 0) {
278
+ repos2[existingIndex] = repo;
279
+ } else {
280
+ repos2.push(repo);
281
+ }
282
+ config.repos = repos2;
283
+ saveConfig(config);
284
+ }
285
+ function removeRepo(name) {
286
+ const config = loadConfig();
287
+ const repos2 = config.repos ?? [];
288
+ const existingIndex = repos2.findIndex((r) => r.name === name);
289
+ if (existingIndex >= 0) {
290
+ repos2.splice(existingIndex, 1);
291
+ config.repos = repos2;
292
+ saveConfig(config);
293
+ return true;
294
+ }
295
+ return false;
296
+ }
180
297
 
181
298
  // src/lib/skills.ts
182
299
  import {
183
300
  existsSync as existsSync6,
184
- readdirSync as readdirSync4,
301
+ readdirSync as readdirSync5,
185
302
  readFileSync as readFileSync6,
186
303
  mkdirSync as mkdirSync4,
187
304
  writeFileSync as writeFileSync4,
@@ -192,7 +309,7 @@ import { fileURLToPath as fileURLToPath4 } from "url";
192
309
  import YAML4 from "yaml";
193
310
 
194
311
  // src/lib/agents.ts
195
- import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync2, unlinkSync, mkdirSync as mkdirSync2 } from "fs";
312
+ import { existsSync as existsSync4, readdirSync as readdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync2, unlinkSync, mkdirSync as mkdirSync2 } from "fs";
196
313
  import { join as join5, dirname as dirname3 } from "path";
197
314
  import { fileURLToPath as fileURLToPath3 } from "url";
198
315
  import YAML3 from "yaml";
@@ -262,7 +379,7 @@ function getActivePlatforms(config) {
262
379
  }
263
380
 
264
381
  // src/lib/tools.ts
265
- import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync3 } from "fs";
382
+ import { existsSync as existsSync3, readdirSync as readdirSync2, readFileSync as readFileSync3 } from "fs";
266
383
  import { join as join4, dirname as dirname2 } from "path";
267
384
  import { fileURLToPath as fileURLToPath2 } from "url";
268
385
  import YAML2 from "yaml";
@@ -358,7 +475,7 @@ function getBundledTools() {
358
475
  if (!existsSync3(BUNDLED_TOOLS_DIR)) {
359
476
  return [];
360
477
  }
361
- const toolDirs = readdirSync(BUNDLED_TOOLS_DIR, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
478
+ const toolDirs = readdirSync2(BUNDLED_TOOLS_DIR, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
362
479
  const tools = [];
363
480
  for (const toolName of toolDirs) {
364
481
  const manifest = loadToolManifest(join4(BUNDLED_TOOLS_DIR, toolName));
@@ -561,7 +678,7 @@ import {
561
678
  mkdirSync as mkdirSync3,
562
679
  renameSync,
563
680
  rmSync,
564
- readdirSync as readdirSync3,
681
+ readdirSync as readdirSync4,
565
682
  readFileSync as readFileSync5,
566
683
  writeFileSync as writeFileSync3
567
684
  } from "fs";
@@ -617,7 +734,7 @@ function createPlatformSyncMigration(version2) {
617
734
  if (!existsSync5(skillsPath)) continue;
618
735
  config.platform = platformKey;
619
736
  const trackedTools = getPlatformTools(config);
620
- const installedDirs = readdirSync3(skillsPath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
737
+ const installedDirs = readdirSync4(skillsPath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
621
738
  for (const skillName of installedDirs) {
622
739
  const normalizedName = skillName.replace(/^droid-/, "");
623
740
  const isTracked = trackedTools[skillName] || trackedTools[`droid-${normalizedName}`] || trackedTools[normalizedName];
@@ -705,7 +822,7 @@ function createOpenCodeSkillsPathMigration(version2) {
705
822
  }
706
823
  return;
707
824
  }
708
- const skillDirs = readdirSync3(oldSkillsPath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
825
+ const skillDirs = readdirSync4(oldSkillsPath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
709
826
  for (const skillName of skillDirs) {
710
827
  const oldSkillDir = join6(oldSkillsPath, skillName);
711
828
  const newSkillDir = join6(newSkillsPath, skillName);
@@ -720,7 +837,7 @@ function createOpenCodeSkillsPathMigration(version2) {
720
837
  }
721
838
  }
722
839
  try {
723
- const remaining = readdirSync3(oldSkillsPath);
840
+ const remaining = readdirSync4(oldSkillsPath);
724
841
  if (remaining.length === 0) {
725
842
  rmSync(oldSkillsPath, { recursive: true });
726
843
  }
@@ -750,7 +867,7 @@ function createClaudeCodeCommandCleanupMigration(version2) {
750
867
  }
751
868
  }
752
869
  }
753
- const commandFiles = readdirSync3(commandsPath, { withFileTypes: true }).filter((dirent) => dirent.isFile() && dirent.name.endsWith(".md")).map((dirent) => dirent.name);
870
+ const commandFiles = readdirSync4(commandsPath, { withFileTypes: true }).filter((dirent) => dirent.isFile() && dirent.name.endsWith(".md")).map((dirent) => dirent.name);
754
871
  for (const file of commandFiles) {
755
872
  const commandName = file.replace(".md", "");
756
873
  if (!aliasCommands.has(commandName)) {
@@ -828,7 +945,7 @@ function createUnifiedSkillsPathMigration(version2) {
828
945
  if (!existsSync5(unifiedSkillsPath)) {
829
946
  mkdirSync3(unifiedSkillsPath, { recursive: true });
830
947
  }
831
- const skillDirs = readdirSync3(oldOpenCodeSkillsPath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
948
+ const skillDirs = readdirSync4(oldOpenCodeSkillsPath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
832
949
  for (const skillName of skillDirs) {
833
950
  const sourcePath = join6(oldOpenCodeSkillsPath, skillName);
834
951
  const destPath = join6(unifiedSkillsPath, skillName);
@@ -848,7 +965,7 @@ function createUnifiedSkillsPathMigration(version2) {
848
965
  }
849
966
  function copyDirRecursive(src, dest) {
850
967
  mkdirSync3(dest, { recursive: true });
851
- const entries = readdirSync3(src, { withFileTypes: true });
968
+ const entries = readdirSync4(src, { withFileTypes: true });
852
969
  for (const entry of entries) {
853
970
  const srcPath = join6(src, entry.name);
854
971
  const destPath = join6(dest, entry.name);
@@ -1072,7 +1189,7 @@ function findSkillPath(skillName) {
1072
1189
  if (!existsSync6(BUNDLED_SKILLS_DIR)) {
1073
1190
  return null;
1074
1191
  }
1075
- const toolDirs = readdirSync4(BUNDLED_SKILLS_DIR, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
1192
+ const toolDirs = readdirSync5(BUNDLED_SKILLS_DIR, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
1076
1193
  for (const toolName of toolDirs) {
1077
1194
  const skillsDir = join7(BUNDLED_SKILLS_DIR, toolName, "skills");
1078
1195
  if (!existsSync6(skillsDir)) continue;
@@ -1090,12 +1207,12 @@ function getBundledSkills() {
1090
1207
  if (!existsSync6(BUNDLED_SKILLS_DIR)) {
1091
1208
  return [];
1092
1209
  }
1093
- const toolDirs = readdirSync4(BUNDLED_SKILLS_DIR, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
1210
+ const toolDirs = readdirSync5(BUNDLED_SKILLS_DIR, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
1094
1211
  const skills = [];
1095
1212
  for (const toolName of toolDirs) {
1096
1213
  const skillsDir = join7(BUNDLED_SKILLS_DIR, toolName, "skills");
1097
1214
  if (!existsSync6(skillsDir)) continue;
1098
- const skillSubdirs = readdirSync4(skillsDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
1215
+ const skillSubdirs = readdirSync5(skillsDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
1099
1216
  for (const skillName of skillSubdirs) {
1100
1217
  const manifest = loadSkillManifest(join7(skillsDir, skillName));
1101
1218
  if (manifest) {
@@ -1257,7 +1374,7 @@ function installSkill(skillName) {
1257
1374
  if (!isAlreadyInstalled) {
1258
1375
  const toolName2 = basename(toolDir);
1259
1376
  if (existsSync6(commandsSource)) {
1260
- const commandFiles = readdirSync4(commandsSource).filter(
1377
+ const commandFiles = readdirSync5(commandsSource).filter(
1261
1378
  (f) => f.endsWith(".md") && f.toLowerCase() !== "readme.md"
1262
1379
  );
1263
1380
  for (const file of commandFiles) {
@@ -1275,7 +1392,7 @@ function installSkill(skillName) {
1275
1392
  }
1276
1393
  }
1277
1394
  if (existsSync6(agentsSource)) {
1278
- const agentFiles = readdirSync4(agentsSource, { withFileTypes: true }).filter((dirent) => dirent.isFile() && dirent.name.endsWith(".md")).map((dirent) => dirent.name.replace(".md", ""));
1395
+ const agentFiles = readdirSync5(agentsSource, { withFileTypes: true }).filter((dirent) => dirent.isFile() && dirent.name.endsWith(".md")).map((dirent) => dirent.name.replace(".md", ""));
1279
1396
  for (const agentName of agentFiles) {
1280
1397
  if (isAgentInstalled(agentName)) {
1281
1398
  return {
@@ -1304,7 +1421,7 @@ function installSkill(skillName) {
1304
1421
  if (!existsSync6(targetReferencesDir)) {
1305
1422
  mkdirSync4(targetReferencesDir, { recursive: true });
1306
1423
  }
1307
- const referenceFiles = readdirSync4(referencesSource).filter(
1424
+ const referenceFiles = readdirSync5(referencesSource).filter(
1308
1425
  (f) => f.endsWith(".md")
1309
1426
  );
1310
1427
  for (const file of referenceFiles) {
@@ -1320,7 +1437,7 @@ function installSkill(skillName) {
1320
1437
  if (!existsSync6(targetScriptsDir)) {
1321
1438
  mkdirSync4(targetScriptsDir, { recursive: true });
1322
1439
  }
1323
- const scriptFiles = readdirSync4(scriptsSource).filter(
1440
+ const scriptFiles = readdirSync5(scriptsSource).filter(
1324
1441
  (f) => f.endsWith(".ts") || f.endsWith(".js") || f.endsWith(".py")
1325
1442
  );
1326
1443
  for (const file of scriptFiles) {
@@ -1333,7 +1450,7 @@ function installSkill(skillName) {
1333
1450
  const activePlatforms = getActivePlatforms(config);
1334
1451
  const targetPlatforms = activePlatforms.length > 0 ? activePlatforms : [config.platform];
1335
1452
  if (existsSync6(commandsSource)) {
1336
- const commandFiles = readdirSync4(commandsSource).filter(
1453
+ const commandFiles = readdirSync5(commandsSource).filter(
1337
1454
  (f) => f.endsWith(".md") && f.toLowerCase() !== "readme.md"
1338
1455
  );
1339
1456
  for (const platform of targetPlatforms) {
@@ -1359,7 +1476,7 @@ function installSkill(skillName) {
1359
1476
  }
1360
1477
  const installedAgents = [];
1361
1478
  if (existsSync6(agentsSource)) {
1362
- const agentFiles = readdirSync4(agentsSource, { withFileTypes: true }).filter((dirent) => dirent.isFile() && dirent.name.endsWith(".md")).map((dirent) => dirent.name.replace(".md", ""));
1479
+ const agentFiles = readdirSync5(agentsSource, { withFileTypes: true }).filter((dirent) => dirent.isFile() && dirent.name.endsWith(".md")).map((dirent) => dirent.name.replace(".md", ""));
1363
1480
  for (const agentName of agentFiles) {
1364
1481
  const agentPath = join7(agentsSource, `${agentName}.md`);
1365
1482
  let anySuccess = false;
@@ -1416,7 +1533,7 @@ function uninstallSkill(skillName) {
1416
1533
  const skillPath = findSkillPath(skillName);
1417
1534
  const commandsSource = skillPath ? join7(skillPath.toolDir, "commands") : null;
1418
1535
  if (commandsSource && existsSync6(commandsSource)) {
1419
- const commandFiles = readdirSync4(commandsSource).filter(
1536
+ const commandFiles = readdirSync5(commandsSource).filter(
1420
1537
  (f) => f.endsWith(".md") && f.toLowerCase() !== "readme.md"
1421
1538
  );
1422
1539
  for (const platform of targetPlatforms) {
@@ -1438,7 +1555,7 @@ function uninstallSkill(skillName) {
1438
1555
  }
1439
1556
  const agentsSource = skillPath ? join7(skillPath.toolDir, "agents") : null;
1440
1557
  if (agentsSource && existsSync6(agentsSource)) {
1441
- const agentFiles = readdirSync4(agentsSource, { withFileTypes: true }).filter((dirent) => dirent.isFile() && dirent.name.endsWith(".md")).map((dirent) => dirent.name.replace(".md", ""));
1558
+ const agentFiles = readdirSync5(agentsSource, { withFileTypes: true }).filter((dirent) => dirent.isFile() && dirent.name.endsWith(".md")).map((dirent) => dirent.name.replace(".md", ""));
1442
1559
  for (const agentName of agentFiles) {
1443
1560
  agentsToRemove.add(agentName);
1444
1561
  }
@@ -1675,6 +1792,11 @@ function getToolConfig(toolName) {
1675
1792
  }
1676
1793
  async function configCommand(tool, options) {
1677
1794
  if (tool) {
1795
+ console.log(
1796
+ chalk3.yellow(
1797
+ `Warning: 'droid config <tool>' is deprecated. Use 'droid config --get tools.${tool}' instead.`
1798
+ )
1799
+ );
1678
1800
  const toolConfig = getToolConfig(tool);
1679
1801
  console.log(JSON.stringify(toolConfig, null, 2));
1680
1802
  return;
@@ -1714,6 +1836,11 @@ async function configCommand(tool, options) {
1714
1836
  process.exit(1);
1715
1837
  }
1716
1838
  const [, key, rawValue] = match;
1839
+ if (key === "repos" || key.startsWith("repos.")) {
1840
+ console.error(chalk3.red("Cannot set repos via --set."));
1841
+ console.log(chalk3.gray("Use: droid repos add/remove"));
1842
+ process.exit(1);
1843
+ }
1717
1844
  let value;
1718
1845
  try {
1719
1846
  value = JSON.parse(rawValue);
@@ -2092,8 +2219,8 @@ async function updateCommand(tool, options) {
2092
2219
  }
2093
2220
 
2094
2221
  // src/commands/tui.tsx
2095
- import { render, Box as Box13, Text as Text14, useInput as useInput7, useApp as useApp2 } from "ink";
2096
- import { useState as useState9, useEffect } from "react";
2222
+ import { render, Box as Box15, Text as Text16, useInput as useInput9, useApp as useApp2 } from "ink";
2223
+ import { useState as useState10, useEffect } from "react";
2097
2224
 
2098
2225
  // src/commands/tui/constants.ts
2099
2226
  var colors = {
@@ -2289,48 +2416,89 @@ var PLATFORM_LABELS2 = {
2289
2416
  function SettingsDetails({
2290
2417
  isFocused,
2291
2418
  detectedPlatforms,
2419
+ selectedAction,
2292
2420
  onRedetect: _onRedetect
2293
2421
  // TODO: Add re-detect button when no platforms found
2294
2422
  }) {
2295
2423
  const config = loadConfig();
2296
2424
  const autoUpdateConfig = getAutoUpdateConfig();
2425
+ const repos2 = getRepos();
2297
2426
  const platformsText = detectedPlatforms.length > 0 ? detectedPlatforms.map((p) => PLATFORM_LABELS2[p]).join(", ") : "None detected";
2298
2427
  return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", paddingLeft: 2, flexGrow: 1, children: [
2299
2428
  /* @__PURE__ */ jsx5(Text5, { color: colors.text, bold: true, children: "Settings" }),
2300
2429
  /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 1, children: [
2430
+ /* @__PURE__ */ jsx5(Text5, { color: colors.textDim, bold: true, children: "Global" }),
2301
2431
  /* @__PURE__ */ jsxs5(Text5, { children: [
2302
- /* @__PURE__ */ jsx5(Text5, { color: colors.textDim, children: "Platforms: " }),
2432
+ /* @__PURE__ */ jsx5(Text5, { color: colors.textDim, children: " Detected platforms: " }),
2303
2433
  /* @__PURE__ */ jsx5(Text5, { color: colors.text, children: platformsText })
2304
2434
  ] }),
2305
2435
  /* @__PURE__ */ jsxs5(Text5, { children: [
2306
- /* @__PURE__ */ jsx5(Text5, { color: colors.textDim, children: "Your @mention: " }),
2436
+ /* @__PURE__ */ jsx5(Text5, { color: colors.textDim, children: " Your @mention: " }),
2307
2437
  /* @__PURE__ */ jsx5(Text5, { color: colors.text, children: config.user_mention })
2308
2438
  ] }),
2309
2439
  /* @__PURE__ */ jsxs5(Text5, { children: [
2310
- /* @__PURE__ */ jsx5(Text5, { color: colors.textDim, children: "Auto-update tools: " }),
2440
+ /* @__PURE__ */ jsx5(Text5, { color: colors.textDim, children: " Auto-update tools: " }),
2311
2441
  /* @__PURE__ */ jsx5(Text5, { color: colors.text, children: autoUpdateConfig.tools ? "enabled" : "disabled" })
2312
2442
  ] }),
2313
2443
  /* @__PURE__ */ jsxs5(Text5, { children: [
2314
- /* @__PURE__ */ jsx5(Text5, { color: colors.textDim, children: "Auto-update app: " }),
2444
+ /* @__PURE__ */ jsx5(Text5, { color: colors.textDim, children: " Auto-update app: " }),
2315
2445
  /* @__PURE__ */ jsx5(Text5, { color: colors.text, children: autoUpdateConfig.app ? "enabled" : "disabled" })
2316
2446
  ] })
2317
2447
  ] }),
2318
- /* @__PURE__ */ jsx5(Box5, { marginTop: 2, children: /* @__PURE__ */ jsx5(Text5, { color: colors.textDim, children: "Config: ~/.droid/config.yaml" }) }),
2319
- isFocused && /* @__PURE__ */ jsx5(Box5, { marginTop: 2, children: /* @__PURE__ */ jsxs5(
2320
- Text5,
2321
- {
2322
- backgroundColor: colors.primary,
2323
- color: "#ffffff",
2324
- bold: true,
2325
- children: [
2326
- " ",
2327
- "Edit",
2328
- " "
2329
- ]
2330
- }
2331
- ) }),
2332
- isFocused && /* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text5, { color: colors.textDim, children: "enter edit \xB7 esc back" }) }),
2333
- !isFocused && /* @__PURE__ */ jsx5(Box5, { marginTop: 2, children: /* @__PURE__ */ jsx5(Text5, { color: colors.textDim, children: "press enter to edit" }) })
2448
+ /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 1, children: [
2449
+ /* @__PURE__ */ jsx5(Text5, { color: colors.textDim, bold: true, children: "Repos" }),
2450
+ repos2.length === 0 ? /* @__PURE__ */ jsx5(Text5, { color: colors.textDim, children: " No repos configured" }) : /* @__PURE__ */ jsxs5(Text5, { color: colors.textDim, children: [
2451
+ " ",
2452
+ repos2.map((r) => r.name).join(", "),
2453
+ " (",
2454
+ repos2.length,
2455
+ " total)"
2456
+ ] })
2457
+ ] }),
2458
+ /* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text5, { color: colors.textDim, children: "Config: ~/.droid/config.yaml" }) }),
2459
+ isFocused && /* @__PURE__ */ jsxs5(Box5, { marginTop: 2, flexDirection: "row", gap: 2, children: [
2460
+ /* @__PURE__ */ jsxs5(
2461
+ Text5,
2462
+ {
2463
+ backgroundColor: selectedAction === 0 ? colors.primary : void 0,
2464
+ color: selectedAction === 0 ? "#ffffff" : colors.textDim,
2465
+ bold: selectedAction === 0,
2466
+ children: [
2467
+ " ",
2468
+ "Edit Config",
2469
+ " "
2470
+ ]
2471
+ }
2472
+ ),
2473
+ /* @__PURE__ */ jsxs5(
2474
+ Text5,
2475
+ {
2476
+ backgroundColor: selectedAction === 1 ? colors.primary : void 0,
2477
+ color: selectedAction === 1 ? "#ffffff" : colors.textDim,
2478
+ bold: selectedAction === 1,
2479
+ children: [
2480
+ " ",
2481
+ "View Repos",
2482
+ " "
2483
+ ]
2484
+ }
2485
+ ),
2486
+ /* @__PURE__ */ jsxs5(
2487
+ Text5,
2488
+ {
2489
+ backgroundColor: selectedAction === 2 ? colors.primary : void 0,
2490
+ color: selectedAction === 2 ? "#ffffff" : colors.textDim,
2491
+ bold: selectedAction === 2,
2492
+ children: [
2493
+ " ",
2494
+ "Manage Repos",
2495
+ " "
2496
+ ]
2497
+ }
2498
+ )
2499
+ ] }),
2500
+ isFocused && /* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text5, { color: colors.textDim, children: "\u2190\u2192 select \xB7 enter confirm \xB7 esc back" }) }),
2501
+ !isFocused && /* @__PURE__ */ jsx5(Box5, { marginTop: 2, children: /* @__PURE__ */ jsx5(Text5, { color: colors.textDim, children: "press enter for options" }) })
2334
2502
  ] });
2335
2503
  }
2336
2504
 
@@ -3066,7 +3234,7 @@ function SkillConfigScreen({ skill, onComplete, onCancel }) {
3066
3234
  const [selectOptionIndex, setSelectOptionIndex] = useState6(0);
3067
3235
  const totalItems = configKeys.length + 1;
3068
3236
  const handleSave = () => {
3069
- saveSkillOverrides(skill.name, values);
3237
+ setToolSettings(skill.name, values);
3070
3238
  onComplete();
3071
3239
  };
3072
3240
  const handleSubmitEdit = () => {
@@ -3266,12 +3434,250 @@ function SkillConfigScreen({ skill, onComplete, onCancel }) {
3266
3434
  ] });
3267
3435
  }
3268
3436
 
3437
+ // src/commands/tui/views/ReposManagementScreen.tsx
3438
+ import { Box as Box13, Text as Text14, useInput as useInput7 } from "ink";
3439
+ import TextInput3 from "ink-text-input";
3440
+ import { useState as useState7 } from "react";
3441
+ import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
3442
+ function ReposManagementScreen({ onComplete: _onComplete, onCancel }) {
3443
+ const [repos2, setRepos] = useState7(() => getRepos());
3444
+ const [selectedIndex, setSelectedIndex] = useState7(0);
3445
+ const [screen, setScreen] = useState7("list");
3446
+ const [message, setMessage] = useState7(null);
3447
+ const [newRepoName, setNewRepoName] = useState7("");
3448
+ const [newRepoPath, setNewRepoPath] = useState7("");
3449
+ const [newRepoDesc, setNewRepoDesc] = useState7("");
3450
+ const [repoToDelete, setRepoToDelete] = useState7(null);
3451
+ const handleAddRepo = () => {
3452
+ if (!newRepoName || !newRepoPath) {
3453
+ setMessage({ text: "Name and path are required", type: "error" });
3454
+ return;
3455
+ }
3456
+ const newRepo = {
3457
+ name: newRepoName,
3458
+ path: newRepoPath,
3459
+ description: newRepoDesc || void 0
3460
+ };
3461
+ addRepo(newRepo);
3462
+ setRepos(getRepos());
3463
+ setMessage({ text: `Added ${newRepoName}`, type: "success" });
3464
+ setNewRepoName("");
3465
+ setNewRepoPath("");
3466
+ setNewRepoDesc("");
3467
+ setScreen("list");
3468
+ };
3469
+ const handleDeleteRepo = (repoName) => {
3470
+ removeRepo(repoName);
3471
+ setRepos(getRepos());
3472
+ setMessage({ text: `Removed ${repoName}`, type: "success" });
3473
+ setRepoToDelete(null);
3474
+ setScreen("list");
3475
+ if (selectedIndex >= repos2.length - 1) {
3476
+ setSelectedIndex(Math.max(0, repos2.length - 2));
3477
+ }
3478
+ };
3479
+ useInput7((input, key) => {
3480
+ if (message) setMessage(null);
3481
+ if (key.escape) {
3482
+ onCancel();
3483
+ return;
3484
+ }
3485
+ if (key.upArrow) {
3486
+ setSelectedIndex((prev) => Math.max(0, prev - 1));
3487
+ }
3488
+ if (key.downArrow) {
3489
+ const maxIndex = repos2.length;
3490
+ setSelectedIndex((prev) => Math.min(maxIndex, prev + 1));
3491
+ }
3492
+ if (key.return) {
3493
+ if (selectedIndex === repos2.length) {
3494
+ setScreen("add-name");
3495
+ } else if (selectedIndex < repos2.length) {
3496
+ setRepoToDelete(repos2[selectedIndex].name);
3497
+ setScreen("confirm-delete");
3498
+ }
3499
+ }
3500
+ }, { isActive: screen === "list" });
3501
+ useInput7((input, key) => {
3502
+ if (key.escape) {
3503
+ setNewRepoName("");
3504
+ setScreen("list");
3505
+ }
3506
+ }, { isActive: screen === "add-name" });
3507
+ useInput7((input, key) => {
3508
+ if (key.escape) {
3509
+ setNewRepoPath("");
3510
+ setScreen("add-name");
3511
+ }
3512
+ }, { isActive: screen === "add-path" });
3513
+ useInput7((input, key) => {
3514
+ if (key.escape) {
3515
+ setNewRepoDesc("");
3516
+ setScreen("add-path");
3517
+ }
3518
+ }, { isActive: screen === "add-desc" });
3519
+ useInput7((input, key) => {
3520
+ if (key.escape || input === "n") {
3521
+ setRepoToDelete(null);
3522
+ setScreen("list");
3523
+ }
3524
+ if (input === "y" && repoToDelete) {
3525
+ handleDeleteRepo(repoToDelete);
3526
+ }
3527
+ }, { isActive: screen === "confirm-delete" });
3528
+ if (screen === "add-name") {
3529
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", padding: 2, children: [
3530
+ /* @__PURE__ */ jsx14(Text14, { color: colors.text, bold: true, children: "Add Repository" }),
3531
+ /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, children: [
3532
+ /* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: "Repository name: " }),
3533
+ /* @__PURE__ */ jsx14(
3534
+ TextInput3,
3535
+ {
3536
+ value: newRepoName,
3537
+ onChange: setNewRepoName,
3538
+ onSubmit: () => {
3539
+ if (newRepoName) {
3540
+ setScreen("add-path");
3541
+ }
3542
+ }
3543
+ }
3544
+ )
3545
+ ] }),
3546
+ /* @__PURE__ */ jsx14(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: "esc cancel" }) })
3547
+ ] });
3548
+ }
3549
+ if (screen === "add-path") {
3550
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", padding: 2, children: [
3551
+ /* @__PURE__ */ jsx14(Text14, { color: colors.text, bold: true, children: "Add Repository" }),
3552
+ /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, children: [
3553
+ /* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: "Name: " }),
3554
+ /* @__PURE__ */ jsx14(Text14, { color: colors.text, children: newRepoName })
3555
+ ] }),
3556
+ /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, children: [
3557
+ /* @__PURE__ */ jsxs13(Text14, { color: colors.textDim, children: [
3558
+ "Path (e.g., ~/src/github.com/",
3559
+ newRepoName,
3560
+ "): "
3561
+ ] }),
3562
+ /* @__PURE__ */ jsx14(
3563
+ TextInput3,
3564
+ {
3565
+ value: newRepoPath,
3566
+ onChange: setNewRepoPath,
3567
+ onSubmit: () => {
3568
+ if (newRepoPath) {
3569
+ setScreen("add-desc");
3570
+ }
3571
+ },
3572
+ placeholder: `~/src/github.com/${newRepoName}`
3573
+ }
3574
+ )
3575
+ ] }),
3576
+ /* @__PURE__ */ jsx14(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: "esc back" }) })
3577
+ ] });
3578
+ }
3579
+ if (screen === "add-desc") {
3580
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", padding: 2, children: [
3581
+ /* @__PURE__ */ jsx14(Text14, { color: colors.text, bold: true, children: "Add Repository" }),
3582
+ /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, children: [
3583
+ /* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: "Name: " }),
3584
+ /* @__PURE__ */ jsx14(Text14, { color: colors.text, children: newRepoName })
3585
+ ] }),
3586
+ /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, children: [
3587
+ /* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: "Path: " }),
3588
+ /* @__PURE__ */ jsx14(Text14, { color: colors.text, children: newRepoPath })
3589
+ ] }),
3590
+ /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, children: [
3591
+ /* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: "Description (optional): " }),
3592
+ /* @__PURE__ */ jsx14(
3593
+ TextInput3,
3594
+ {
3595
+ value: newRepoDesc,
3596
+ onChange: setNewRepoDesc,
3597
+ onSubmit: handleAddRepo
3598
+ }
3599
+ )
3600
+ ] }),
3601
+ /* @__PURE__ */ jsx14(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: "enter save \xB7 esc back" }) })
3602
+ ] });
3603
+ }
3604
+ if (screen === "confirm-delete" && repoToDelete) {
3605
+ const repo = repos2.find((r) => r.name === repoToDelete);
3606
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", padding: 2, children: [
3607
+ /* @__PURE__ */ jsx14(Text14, { color: colors.text, bold: true, children: "Remove Repository" }),
3608
+ /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
3609
+ /* @__PURE__ */ jsx14(Text14, { color: colors.text, children: repo?.name }),
3610
+ /* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: repo?.path })
3611
+ ] }),
3612
+ /* @__PURE__ */ jsx14(Box13, { marginTop: 2, children: /* @__PURE__ */ jsx14(Text14, { color: colors.error, children: "Remove this repository from the registry?" }) }),
3613
+ /* @__PURE__ */ jsx14(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: "y yes \xB7 n no" }) })
3614
+ ] });
3615
+ }
3616
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", padding: 2, children: [
3617
+ /* @__PURE__ */ jsx14(Text14, { color: colors.text, bold: true, children: "Manage Repositories" }),
3618
+ message && /* @__PURE__ */ jsx14(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text14, { color: message.type === "success" ? colors.success : colors.error, children: message.text }) }),
3619
+ /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", marginTop: 1, children: [
3620
+ repos2.length === 0 ? /* @__PURE__ */ jsx14(Box13, { marginY: 1, children: /* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: "No repos configured" }) }) : repos2.map((repo, index) => /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", marginTop: index > 0 ? 1 : 0, children: [
3621
+ /* @__PURE__ */ jsx14(Box13, { children: /* @__PURE__ */ jsxs13(
3622
+ Text14,
3623
+ {
3624
+ color: selectedIndex === index ? colors.primary : colors.text,
3625
+ bold: selectedIndex === index,
3626
+ children: [
3627
+ selectedIndex === index ? "> " : " ",
3628
+ repo.name
3629
+ ]
3630
+ }
3631
+ ) }),
3632
+ /* @__PURE__ */ jsx14(Box13, { paddingLeft: 2, children: /* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: repo.path }) }),
3633
+ repo.description && /* @__PURE__ */ jsx14(Box13, { paddingLeft: 2, children: /* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: repo.description }) })
3634
+ ] }, repo.name)),
3635
+ /* @__PURE__ */ jsx14(Box13, { marginTop: repos2.length > 0 ? 2 : 0, children: /* @__PURE__ */ jsxs13(
3636
+ Text14,
3637
+ {
3638
+ color: selectedIndex === repos2.length ? colors.primary : colors.textDim,
3639
+ bold: selectedIndex === repos2.length,
3640
+ children: [
3641
+ selectedIndex === repos2.length ? "> " : " ",
3642
+ "+ Add New Repository"
3643
+ ]
3644
+ }
3645
+ ) })
3646
+ ] }),
3647
+ /* @__PURE__ */ jsx14(Box13, { marginTop: 2, children: /* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: repos2.length > 0 && selectedIndex < repos2.length ? "enter remove \xB7 esc back" : "\u2191\u2193 navigate \xB7 enter select \xB7 esc back" }) })
3648
+ ] });
3649
+ }
3650
+
3651
+ // src/commands/tui/views/ReposViewerScreen.tsx
3652
+ import { Box as Box14, Text as Text15, useInput as useInput8 } from "ink";
3653
+ import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
3654
+ function ReposViewerScreen({ onClose }) {
3655
+ const repos2 = getRepos();
3656
+ useInput8((input, key) => {
3657
+ if (key.escape) {
3658
+ onClose();
3659
+ }
3660
+ });
3661
+ return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", padding: 2, children: [
3662
+ /* @__PURE__ */ jsx15(Text15, { color: colors.text, bold: true, children: "Repositories" }),
3663
+ repos2.length === 0 ? /* @__PURE__ */ jsx15(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text15, { color: colors.textDim, children: "No repos configured" }) }) : /* @__PURE__ */ jsx15(Box14, { flexDirection: "column", marginTop: 1, children: repos2.map((repo, index) => /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", marginTop: index > 0 ? 2 : 0, children: [
3664
+ /* @__PURE__ */ jsx15(Text15, { color: colors.text, bold: true, children: repo.name }),
3665
+ /* @__PURE__ */ jsx15(Box14, { marginTop: 0, children: /* @__PURE__ */ jsxs14(Text15, { color: colors.textDim, children: [
3666
+ "Path: ",
3667
+ repo.path
3668
+ ] }) }),
3669
+ repo.description && /* @__PURE__ */ jsx15(Box14, { marginTop: 0, children: /* @__PURE__ */ jsx15(Text15, { color: colors.textDim, children: repo.description }) })
3670
+ ] }, repo.name)) }),
3671
+ /* @__PURE__ */ jsx15(Box14, { marginTop: 2, children: /* @__PURE__ */ jsx15(Text15, { color: colors.textDim, children: "esc back" }) })
3672
+ ] });
3673
+ }
3674
+
3269
3675
  // src/commands/tui/hooks/useAppUpdate.ts
3270
- import { useState as useState7, useMemo as useMemo5 } from "react";
3676
+ import { useState as useState8, useMemo as useMemo5 } from "react";
3271
3677
  import { useApp } from "ink";
3272
3678
  function useAppUpdate({ onUpdateSuccess, onUpdateFailure }) {
3273
3679
  const { exit } = useApp();
3274
- const [isUpdating, setIsUpdating] = useState7(false);
3680
+ const [isUpdating, setIsUpdating] = useState8(false);
3275
3681
  const updateInfo = useMemo5(() => getUpdateInfo(), []);
3276
3682
  const handleUpdate = () => {
3277
3683
  setIsUpdating(true);
@@ -3313,11 +3719,11 @@ ${dim}\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u
3313
3719
  }
3314
3720
 
3315
3721
  // src/commands/tui/hooks/useToolUpdates.ts
3316
- import { useState as useState8, useCallback } from "react";
3722
+ import { useState as useState9, useCallback } from "react";
3317
3723
  function useToolUpdates({ onUpdateComplete }) {
3318
- const [toolUpdates, setToolUpdates] = useState8([]);
3319
- const [isUpdatingTools, setIsUpdatingTools] = useState8(false);
3320
- const [autoUpdatedTools, setAutoUpdatedTools] = useState8([]);
3724
+ const [toolUpdates, setToolUpdates] = useState9([]);
3725
+ const [isUpdatingTools, setIsUpdatingTools] = useState9(false);
3726
+ const [autoUpdatedTools, setAutoUpdatedTools] = useState9([]);
3321
3727
  const tools = getBundledTools();
3322
3728
  const ensureSystemTools = useCallback(() => {
3323
3729
  const systemTools = tools.filter((t) => t.system === true);
@@ -3385,7 +3791,7 @@ function useToolUpdates({ onUpdateComplete }) {
3385
3791
  }
3386
3792
 
3387
3793
  // src/commands/tui.tsx
3388
- import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
3794
+ import { Fragment as Fragment2, jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
3389
3795
  var exitMessage = null;
3390
3796
  function App() {
3391
3797
  const { exit } = useApp2();
@@ -3393,17 +3799,17 @@ function App() {
3393
3799
  { id: "tools", label: "Tools" },
3394
3800
  { id: "settings", label: "Settings" }
3395
3801
  ];
3396
- const [activeTab, setActiveTab] = useState9("tools");
3397
- const [tabIndex, setTabIndex] = useState9(0);
3398
- const [view, setView] = useState9("welcome");
3399
- const [selectedIndex, setSelectedIndex] = useState9(0);
3400
- const [selectedAction, setSelectedAction] = useState9(0);
3401
- const [scrollOffset, setScrollOffset] = useState9(0);
3402
- const [message, setMessage] = useState9(null);
3403
- const [isEditingSettings, setIsEditingSettings] = useState9(false);
3404
- const [readmeContent, setReadmeContent] = useState9(null);
3405
- const [previousView, setPreviousView] = useState9("detail");
3406
- const [detectedPlatforms, setDetectedPlatforms] = useState9(() => detectAllPlatforms());
3802
+ const [activeTab, setActiveTab] = useState10("tools");
3803
+ const [tabIndex, setTabIndex] = useState10(0);
3804
+ const [view, setView] = useState10("welcome");
3805
+ const [selectedIndex, setSelectedIndex] = useState10(0);
3806
+ const [selectedAction, setSelectedAction] = useState10(0);
3807
+ const [scrollOffset, setScrollOffset] = useState10(0);
3808
+ const [message, setMessage] = useState10(null);
3809
+ const [isEditingSettings, setIsEditingSettings] = useState10(false);
3810
+ const [readmeContent, setReadmeContent] = useState10(null);
3811
+ const [previousView, setPreviousView] = useState10("detail");
3812
+ const [detectedPlatforms, setDetectedPlatforms] = useState10(() => detectAllPlatforms());
3407
3813
  const handleRedetectPlatforms = () => {
3408
3814
  setDetectedPlatforms(detectAllPlatforms());
3409
3815
  };
@@ -3472,7 +3878,7 @@ function App() {
3472
3878
  };
3473
3879
  const tools = getBundledTools();
3474
3880
  const skills = getBundledSkills();
3475
- useInput7(
3881
+ useInput9(
3476
3882
  (input, key) => {
3477
3883
  if (message) setMessage(null);
3478
3884
  if (input === "q") {
@@ -3528,9 +3934,21 @@ function App() {
3528
3934
  setSelectedAction(0);
3529
3935
  }
3530
3936
  if (activeTab === "settings") {
3937
+ if (key.leftArrow) {
3938
+ setSelectedAction((prev) => Math.max(0, prev - 1));
3939
+ }
3940
+ if (key.rightArrow) {
3941
+ setSelectedAction((prev) => Math.min(2, prev + 1));
3942
+ }
3531
3943
  if (key.return) {
3532
- setIsEditingSettings(true);
3533
- setView("setup");
3944
+ if (selectedAction === 0) {
3945
+ setIsEditingSettings(true);
3946
+ setView("setup");
3947
+ } else if (selectedAction === 1) {
3948
+ setView("view-repos");
3949
+ } else if (selectedAction === 2) {
3950
+ setView("repos");
3951
+ }
3534
3952
  }
3535
3953
  }
3536
3954
  if (key.leftArrow && activeTab === "tools") {
@@ -3608,7 +4026,7 @@ function App() {
3608
4026
  }
3609
4027
  },
3610
4028
  {
3611
- isActive: view !== "welcome" && view !== "tool-updates" && view !== "setup" && view !== "configure" && view !== "explorer"
4029
+ isActive: view !== "welcome" && view !== "tool-updates" && view !== "setup" && view !== "configure" && view !== "explorer" && view !== "repos" && view !== "view-repos"
3612
4030
  }
3613
4031
  );
3614
4032
  const selectedTool = activeTab === "tools" ? tools[selectedIndex] ?? null : null;
@@ -3616,7 +4034,7 @@ function App() {
3616
4034
  (s) => s.name === (selectedTool.includes.skills.find((sk) => sk.required)?.name || selectedTool.name)
3617
4035
  ) : null;
3618
4036
  if (view === "welcome") {
3619
- return /* @__PURE__ */ jsx14(
4037
+ return /* @__PURE__ */ jsx16(
3620
4038
  WelcomeScreen,
3621
4039
  {
3622
4040
  updateInfo,
@@ -3629,7 +4047,7 @@ function App() {
3629
4047
  );
3630
4048
  }
3631
4049
  if (view === "tool-updates" && toolUpdates.length > 0) {
3632
- return /* @__PURE__ */ jsx14(
4050
+ return /* @__PURE__ */ jsx16(
3633
4051
  ToolUpdatePrompt,
3634
4052
  {
3635
4053
  toolUpdates,
@@ -3641,7 +4059,7 @@ function App() {
3641
4059
  );
3642
4060
  }
3643
4061
  if (view === "setup") {
3644
- return /* @__PURE__ */ jsx14(
4062
+ return /* @__PURE__ */ jsx16(
3645
4063
  SetupScreen,
3646
4064
  {
3647
4065
  onComplete: () => {
@@ -3658,7 +4076,7 @@ function App() {
3658
4076
  );
3659
4077
  }
3660
4078
  if (view === "readme" && readmeContent) {
3661
- return /* @__PURE__ */ jsx14(
4079
+ return /* @__PURE__ */ jsx16(
3662
4080
  ReadmeViewer,
3663
4081
  {
3664
4082
  title: readmeContent.title,
@@ -3671,7 +4089,7 @@ function App() {
3671
4089
  );
3672
4090
  }
3673
4091
  if (view === "explorer" && selectedTool) {
3674
- return /* @__PURE__ */ jsx14(
4092
+ return /* @__PURE__ */ jsx16(
3675
4093
  ToolExplorer,
3676
4094
  {
3677
4095
  tool: selectedTool,
@@ -3687,7 +4105,7 @@ function App() {
3687
4105
  );
3688
4106
  }
3689
4107
  if (view === "configure" && selectedSkillForConfig) {
3690
- return /* @__PURE__ */ jsx14(
4108
+ return /* @__PURE__ */ jsx16(
3691
4109
  SkillConfigScreen,
3692
4110
  {
3693
4111
  skill: selectedSkillForConfig,
@@ -3704,43 +4122,70 @@ function App() {
3704
4122
  }
3705
4123
  );
3706
4124
  }
3707
- return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "row", padding: 1, children: [
3708
- /* @__PURE__ */ jsxs13(
3709
- Box13,
4125
+ if (view === "view-repos") {
4126
+ return /* @__PURE__ */ jsx16(
4127
+ ReposViewerScreen,
4128
+ {
4129
+ onClose: () => {
4130
+ setView("detail");
4131
+ }
4132
+ }
4133
+ );
4134
+ }
4135
+ if (view === "repos") {
4136
+ return /* @__PURE__ */ jsx16(
4137
+ ReposManagementScreen,
4138
+ {
4139
+ onComplete: () => {
4140
+ setMessage({
4141
+ text: "\u2713 Repos updated",
4142
+ type: "success"
4143
+ });
4144
+ setView("detail");
4145
+ },
4146
+ onCancel: () => {
4147
+ setView("detail");
4148
+ }
4149
+ }
4150
+ );
4151
+ }
4152
+ return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "row", padding: 1, children: [
4153
+ /* @__PURE__ */ jsxs15(
4154
+ Box15,
3710
4155
  {
3711
4156
  flexDirection: "column",
3712
4157
  width: 44,
3713
4158
  borderStyle: "single",
3714
4159
  borderColor: colors.border,
3715
4160
  children: [
3716
- /* @__PURE__ */ jsx14(Box13, { paddingX: 1, children: /* @__PURE__ */ jsxs13(Text14, { children: [
3717
- /* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: "[" }),
3718
- /* @__PURE__ */ jsx14(Text14, { color: colors.primary, children: "\u25CF" }),
3719
- /* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: " " }),
3720
- /* @__PURE__ */ jsx14(Text14, { color: colors.primary, children: "\u25CF" }),
3721
- /* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: "] " }),
3722
- /* @__PURE__ */ jsx14(Text14, { color: colors.textMuted, children: "droid" }),
3723
- /* @__PURE__ */ jsxs13(Text14, { color: colors.textDim, children: [
4161
+ /* @__PURE__ */ jsx16(Box15, { paddingX: 1, children: /* @__PURE__ */ jsxs15(Text16, { children: [
4162
+ /* @__PURE__ */ jsx16(Text16, { color: colors.textDim, children: "[" }),
4163
+ /* @__PURE__ */ jsx16(Text16, { color: colors.primary, children: "\u25CF" }),
4164
+ /* @__PURE__ */ jsx16(Text16, { color: colors.textDim, children: " " }),
4165
+ /* @__PURE__ */ jsx16(Text16, { color: colors.primary, children: "\u25CF" }),
4166
+ /* @__PURE__ */ jsx16(Text16, { color: colors.textDim, children: "] " }),
4167
+ /* @__PURE__ */ jsx16(Text16, { color: colors.textMuted, children: "droid" }),
4168
+ /* @__PURE__ */ jsxs15(Text16, { color: colors.textDim, children: [
3724
4169
  " v",
3725
4170
  getVersion()
3726
4171
  ] })
3727
4172
  ] }) }),
3728
- /* @__PURE__ */ jsx14(Box13, { paddingX: 1, children: /* @__PURE__ */ jsx14(
4173
+ /* @__PURE__ */ jsx16(Box15, { paddingX: 1, children: /* @__PURE__ */ jsx16(
3729
4174
  PlatformBadges,
3730
4175
  {
3731
4176
  detected: detectedPlatforms,
3732
4177
  ignored: loadConfig().ignored_platforms ?? []
3733
4178
  }
3734
4179
  ) }),
3735
- /* @__PURE__ */ jsx14(Box13, { paddingX: 1, marginTop: 1, children: /* @__PURE__ */ jsx14(TabBar, { tabs, activeTab }) }),
3736
- /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", marginTop: 1, children: [
3737
- activeTab === "tools" && /* @__PURE__ */ jsxs13(Fragment2, { children: [
3738
- scrollOffset > 0 && /* @__PURE__ */ jsx14(Box13, { paddingX: 1, children: /* @__PURE__ */ jsxs13(Text14, { color: colors.textDim, children: [
4180
+ /* @__PURE__ */ jsx16(Box15, { paddingX: 1, marginTop: 1, children: /* @__PURE__ */ jsx16(TabBar, { tabs, activeTab }) }),
4181
+ /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", marginTop: 1, children: [
4182
+ activeTab === "tools" && /* @__PURE__ */ jsxs15(Fragment2, { children: [
4183
+ scrollOffset > 0 && /* @__PURE__ */ jsx16(Box15, { paddingX: 1, children: /* @__PURE__ */ jsxs15(Text16, { color: colors.textDim, children: [
3739
4184
  "\u2191 ",
3740
4185
  scrollOffset,
3741
4186
  " more"
3742
4187
  ] }) }),
3743
- tools.slice(scrollOffset, scrollOffset + MAX_VISIBLE_ITEMS).map((tool, index) => /* @__PURE__ */ jsx14(
4188
+ tools.slice(scrollOffset, scrollOffset + MAX_VISIBLE_ITEMS).map((tool, index) => /* @__PURE__ */ jsx16(
3744
4189
  ToolItem,
3745
4190
  {
3746
4191
  tool,
@@ -3750,30 +4195,30 @@ function App() {
3750
4195
  },
3751
4196
  tool.name
3752
4197
  )),
3753
- scrollOffset + MAX_VISIBLE_ITEMS < tools.length && /* @__PURE__ */ jsx14(Box13, { paddingX: 1, children: /* @__PURE__ */ jsxs13(Text14, { color: colors.textDim, children: [
4198
+ scrollOffset + MAX_VISIBLE_ITEMS < tools.length && /* @__PURE__ */ jsx16(Box15, { paddingX: 1, children: /* @__PURE__ */ jsxs15(Text16, { color: colors.textDim, children: [
3754
4199
  "\u2193 ",
3755
4200
  tools.length - scrollOffset - MAX_VISIBLE_ITEMS,
3756
4201
  " more"
3757
4202
  ] }) }),
3758
- tools.length > MAX_VISIBLE_ITEMS && /* @__PURE__ */ jsx14(Box13, { paddingX: 1, marginTop: 1, children: /* @__PURE__ */ jsxs13(Text14, { color: colors.textDim, children: [
4203
+ tools.length > MAX_VISIBLE_ITEMS && /* @__PURE__ */ jsx16(Box15, { paddingX: 1, marginTop: 1, children: /* @__PURE__ */ jsxs15(Text16, { color: colors.textDim, children: [
3759
4204
  tools.length,
3760
4205
  " tools total"
3761
4206
  ] }) })
3762
4207
  ] }),
3763
- activeTab === "settings" && /* @__PURE__ */ jsx14(Box13, { paddingX: 1, children: /* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: "View and edit config" }) })
4208
+ activeTab === "settings" && /* @__PURE__ */ jsx16(Box15, { paddingX: 1, children: /* @__PURE__ */ jsx16(Text16, { color: colors.textDim, children: "View and edit config" }) })
3764
4209
  ] }),
3765
- message && /* @__PURE__ */ jsx14(Box13, { paddingX: 1, marginTop: 1, children: /* @__PURE__ */ jsx14(
3766
- Text14,
4210
+ message && /* @__PURE__ */ jsx16(Box15, { paddingX: 1, marginTop: 1, children: /* @__PURE__ */ jsx16(
4211
+ Text16,
3767
4212
  {
3768
4213
  color: message.type === "success" ? colors.success : colors.error,
3769
4214
  children: message.text
3770
4215
  }
3771
4216
  ) }),
3772
- /* @__PURE__ */ jsx14(Box13, { paddingX: 1, marginTop: 1, children: /* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: view === "menu" ? "\u2190\u2192 \u2191\u2193 enter q" : "\u2190\u2192 enter esc q" }) })
4217
+ /* @__PURE__ */ jsx16(Box15, { paddingX: 1, marginTop: 1, children: /* @__PURE__ */ jsx16(Text16, { color: colors.textDim, children: view === "menu" ? "\u2190\u2192 \u2191\u2193 enter q" : "\u2190\u2192 enter esc q" }) })
3773
4218
  ]
3774
4219
  }
3775
4220
  ),
3776
- activeTab === "tools" && /* @__PURE__ */ jsx14(
4221
+ activeTab === "tools" && /* @__PURE__ */ jsx16(
3777
4222
  ToolDetails,
3778
4223
  {
3779
4224
  tool: selectedTool,
@@ -3781,10 +4226,11 @@ function App() {
3781
4226
  selectedAction
3782
4227
  }
3783
4228
  ),
3784
- activeTab === "settings" && /* @__PURE__ */ jsx14(
4229
+ activeTab === "settings" && /* @__PURE__ */ jsx16(
3785
4230
  SettingsDetails,
3786
4231
  {
3787
4232
  isFocused: view === "detail",
4233
+ selectedAction,
3788
4234
  detectedPlatforms,
3789
4235
  onRedetect: detectedPlatforms.length === 0 ? handleRedetectPlatforms : void 0
3790
4236
  }
@@ -3794,7 +4240,7 @@ function App() {
3794
4240
  async function tuiCommand() {
3795
4241
  process.stdout.write("\x1B[?1049h");
3796
4242
  process.stdout.write("\x1B[H");
3797
- const { waitUntilExit } = render(/* @__PURE__ */ jsx14(App, {}));
4243
+ const { waitUntilExit } = render(/* @__PURE__ */ jsx16(App, {}));
3798
4244
  await waitUntilExit();
3799
4245
  process.stdout.write("\x1B[?1049l");
3800
4246
  if (exitMessage) {
@@ -3863,11 +4309,152 @@ async function execCommand(tool, script, args) {
3863
4309
  });
3864
4310
  }
3865
4311
 
4312
+ // src/commands/repos.ts
4313
+ import chalk10 from "chalk";
4314
+ import inquirer4 from "inquirer";
4315
+ async function reposListCommand(options) {
4316
+ const repos2 = getRepos();
4317
+ if (repos2.length === 0) {
4318
+ console.log(chalk10.yellow("No repos configured."));
4319
+ console.log(chalk10.gray("\nAdd a repo with:"));
4320
+ console.log(chalk10.gray(" droid repos add <name>"));
4321
+ return;
4322
+ }
4323
+ if (options?.json) {
4324
+ console.log(JSON.stringify(repos2, null, 2));
4325
+ return;
4326
+ }
4327
+ console.log(chalk10.bold("\n\u{1F4E6} Registered Repos\n"));
4328
+ for (const repo of repos2) {
4329
+ const expandedPath = getRepoPath(repo.name);
4330
+ console.log(chalk10.cyan(`${repo.name}`));
4331
+ console.log(chalk10.gray(` Path: ${expandedPath}`));
4332
+ if (repo.description) {
4333
+ console.log(chalk10.gray(` ${repo.description}`));
4334
+ }
4335
+ console.log();
4336
+ }
4337
+ }
4338
+ async function reposAddCommand(name, path, description) {
4339
+ let repoName = name;
4340
+ let repoPath = path;
4341
+ let repoDescription = description;
4342
+ if (!repoName) {
4343
+ const answers = await inquirer4.prompt([
4344
+ {
4345
+ type: "input",
4346
+ name: "name",
4347
+ message: "Repo name:",
4348
+ validate: (input) => input.trim() ? true : "Name is required"
4349
+ }
4350
+ ]);
4351
+ repoName = answers.name;
4352
+ }
4353
+ if (!repoPath) {
4354
+ const answers = await inquirer4.prompt([
4355
+ {
4356
+ type: "input",
4357
+ name: "path",
4358
+ message: "Repo path:",
4359
+ default: `~/src/github.com/${repoName}`,
4360
+ validate: (input) => input.trim() ? true : "Path is required"
4361
+ }
4362
+ ]);
4363
+ repoPath = answers.path;
4364
+ }
4365
+ if (!repoDescription) {
4366
+ const answers = await inquirer4.prompt([
4367
+ {
4368
+ type: "input",
4369
+ name: "description",
4370
+ message: "Description (optional):"
4371
+ }
4372
+ ]);
4373
+ repoDescription = answers.description || void 0;
4374
+ }
4375
+ if (!repoName || !repoPath) {
4376
+ console.error(chalk10.red("Name and path are required"));
4377
+ return;
4378
+ }
4379
+ const repo = {
4380
+ name: repoName,
4381
+ path: repoPath,
4382
+ description: repoDescription
4383
+ };
4384
+ addRepo(repo);
4385
+ const expandedPath = getRepoPath(repoName);
4386
+ console.log(chalk10.green(`
4387
+ \u2713 Added repo: ${repoName}`));
4388
+ console.log(chalk10.gray(` Path: ${expandedPath}`));
4389
+ if (repoDescription) {
4390
+ console.log(chalk10.gray(` ${repoDescription}`));
4391
+ }
4392
+ }
4393
+ async function reposRemoveCommand(name) {
4394
+ let repoName = name;
4395
+ if (!repoName) {
4396
+ const repos2 = getRepos();
4397
+ if (repos2.length === 0) {
4398
+ console.log(chalk10.yellow("No repos configured."));
4399
+ return;
4400
+ }
4401
+ const answers2 = await inquirer4.prompt([
4402
+ {
4403
+ type: "list",
4404
+ name: "name",
4405
+ message: "Select repo to remove:",
4406
+ choices: repos2.map((r) => r.name)
4407
+ }
4408
+ ]);
4409
+ repoName = answers2.name;
4410
+ }
4411
+ if (!repoName) {
4412
+ console.error(chalk10.red("Repo name is required"));
4413
+ return;
4414
+ }
4415
+ const answers = await inquirer4.prompt([
4416
+ {
4417
+ type: "confirm",
4418
+ name: "confirm",
4419
+ message: `Remove repo '${repoName}'?`,
4420
+ default: false
4421
+ }
4422
+ ]);
4423
+ if (!answers.confirm) {
4424
+ console.log(chalk10.gray("Cancelled"));
4425
+ return;
4426
+ }
4427
+ const existed = removeRepo(repoName);
4428
+ if (existed) {
4429
+ console.log(chalk10.green(`
4430
+ \u2713 Removed repo: ${repoName}`));
4431
+ } else {
4432
+ console.log(chalk10.yellow(`
4433
+ Repo '${repoName}' not found`));
4434
+ }
4435
+ }
4436
+ async function reposGetCommand(name) {
4437
+ const repo = getRepo(name);
4438
+ if (!repo) {
4439
+ console.error(chalk10.red(`Repo '${name}' not found`));
4440
+ process.exit(1);
4441
+ }
4442
+ console.log(JSON.stringify(repo, null, 2));
4443
+ }
4444
+
3866
4445
  // src/bin/droid.ts
3867
4446
  var version = getVersion();
3868
4447
  program.name("droid").description("Droid, teaching your AI new tricks").version(version);
3869
4448
  program.command("setup").description("Interactive wizard for global configuration").action(setupCommand);
3870
4449
  program.command("config").description("View or edit configuration").argument("[tool]", "Get merged config for a tool (for deterministic scripts)").option("-e, --edit", "Open config in editor").option("-g, --get <key>", "Get a specific config value").option("-s, --set <key=value>", "Set a config value").action(configCommand);
4450
+ var repos = program.command("repos").description("Manage repository registry");
4451
+ repos.command("list").description("List all registered repos").option("--json", "Output as JSON").action((options) => reposListCommand(options));
4452
+ repos.command("add [name]").description("Add a repo to the registry").option("-p, --path <path>", "Repository path").option("-d, --description <desc>", "Repository description").action(
4453
+ (name, options) => reposAddCommand(name, options.path, options.description)
4454
+ );
4455
+ repos.command("remove [name]").description("Remove a repo from the registry").action((name) => reposRemoveCommand(name));
4456
+ repos.command("get <name>").description("Get a specific repo (JSON output for scripts)").action((name) => reposGetCommand(name));
4457
+ repos.action(() => reposListCommand());
3871
4458
  program.command("tools").description("Browse and manage available tools").action(skillsCommand);
3872
4459
  program.command("install <tool>").description("Install a tool and run its setup wizard").action(installCommand);
3873
4460
  program.command("uninstall <tool>").description("Uninstall a tool").action(uninstallCommand);