@orderful/droid 0.23.0 → 0.25.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/.eslintrc.json +6 -4
- package/AGENTS.md +58 -0
- package/CHANGELOG.md +44 -0
- package/README.md +11 -6
- package/dist/bin/droid.js +384 -170
- package/dist/commands/config.d.ts +15 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/exec.d.ts +10 -0
- package/dist/commands/exec.d.ts.map +1 -0
- package/dist/commands/tui.d.ts.map +1 -1
- package/dist/index.js +171 -33
- package/dist/lib/migrations.d.ts.map +1 -1
- package/dist/lib/skills.d.ts.map +1 -1
- package/dist/tools/codex/TOOL.yaml +2 -2
- package/dist/tools/codex/agents/codex-document-processor.md +8 -4
- package/dist/tools/codex/commands/codex.md +18 -10
- package/dist/tools/codex/skills/droid-codex/SKILL.md +140 -67
- package/dist/tools/codex/skills/droid-codex/references/creating.md +13 -51
- package/dist/tools/codex/skills/droid-codex/references/decisions.md +15 -19
- package/dist/tools/codex/skills/droid-codex/references/loading.md +49 -13
- package/dist/tools/codex/skills/droid-codex/references/topics.md +14 -12
- package/dist/tools/codex/skills/droid-codex/scripts/git-finish-write.d.ts +31 -0
- package/dist/tools/codex/skills/droid-codex/scripts/git-finish-write.d.ts.map +1 -0
- package/dist/tools/codex/skills/droid-codex/scripts/git-finish-write.ts +236 -0
- package/dist/tools/codex/skills/droid-codex/scripts/git-preamble.d.ts +20 -0
- package/dist/tools/codex/skills/droid-codex/scripts/git-preamble.d.ts.map +1 -0
- package/dist/tools/codex/skills/droid-codex/scripts/git-preamble.ts +156 -0
- package/dist/tools/codex/skills/droid-codex/scripts/git-scripts.test.ts +364 -0
- package/dist/tools/codex/skills/droid-codex/scripts/git-start-write.d.ts +23 -0
- package/dist/tools/codex/skills/droid-codex/scripts/git-start-write.d.ts.map +1 -0
- package/dist/tools/codex/skills/droid-codex/scripts/git-start-write.ts +172 -0
- package/package.json +1 -1
- package/src/bin/droid.ts +9 -0
- package/src/commands/config.ts +38 -4
- package/src/commands/exec.ts +96 -0
- package/src/commands/install.ts +1 -1
- package/src/commands/setup.ts +6 -6
- package/src/commands/tui.tsx +254 -175
- package/src/lib/migrations.ts +103 -10
- package/src/lib/quotes.ts +6 -6
- package/src/lib/skills.ts +168 -45
- package/src/tools/codex/TOOL.yaml +2 -2
- package/src/tools/codex/agents/codex-document-processor.md +8 -4
- package/src/tools/codex/commands/codex.md +18 -10
- package/src/tools/codex/skills/droid-codex/SKILL.md +140 -67
- package/src/tools/codex/skills/droid-codex/references/creating.md +13 -51
- package/src/tools/codex/skills/droid-codex/references/decisions.md +15 -19
- package/src/tools/codex/skills/droid-codex/references/loading.md +49 -13
- package/src/tools/codex/skills/droid-codex/references/topics.md +14 -12
- package/src/tools/codex/skills/droid-codex/scripts/git-finish-write.ts +236 -0
- package/src/tools/codex/skills/droid-codex/scripts/git-preamble.ts +156 -0
- package/src/tools/codex/skills/droid-codex/scripts/git-scripts.test.ts +364 -0
- package/src/tools/codex/skills/droid-codex/scripts/git-start-write.ts +172 -0
package/dist/bin/droid.js
CHANGED
|
@@ -18,6 +18,9 @@ import { join } from "path";
|
|
|
18
18
|
import YAML from "yaml";
|
|
19
19
|
|
|
20
20
|
// src/lib/types.ts
|
|
21
|
+
function getAITag() {
|
|
22
|
+
return "@droid";
|
|
23
|
+
}
|
|
21
24
|
function getPlatformTools(config) {
|
|
22
25
|
return config.platforms[config.platform]?.tools ?? {};
|
|
23
26
|
}
|
|
@@ -176,7 +179,14 @@ function setAutoUpdateConfig(updates) {
|
|
|
176
179
|
}
|
|
177
180
|
|
|
178
181
|
// src/lib/skills.ts
|
|
179
|
-
import {
|
|
182
|
+
import {
|
|
183
|
+
existsSync as existsSync5,
|
|
184
|
+
readdirSync as readdirSync4,
|
|
185
|
+
readFileSync as readFileSync5,
|
|
186
|
+
mkdirSync as mkdirSync4,
|
|
187
|
+
writeFileSync as writeFileSync3,
|
|
188
|
+
rmSync as rmSync2
|
|
189
|
+
} from "fs";
|
|
180
190
|
import { join as join7, dirname as dirname5, basename } from "path";
|
|
181
191
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
182
192
|
import YAML4 from "yaml";
|
|
@@ -517,7 +527,14 @@ function uninstallAgent(agentName) {
|
|
|
517
527
|
}
|
|
518
528
|
|
|
519
529
|
// src/lib/migrations.ts
|
|
520
|
-
import {
|
|
530
|
+
import {
|
|
531
|
+
existsSync as existsSync4,
|
|
532
|
+
appendFileSync,
|
|
533
|
+
mkdirSync as mkdirSync3,
|
|
534
|
+
renameSync,
|
|
535
|
+
rmSync,
|
|
536
|
+
readdirSync as readdirSync3
|
|
537
|
+
} from "fs";
|
|
521
538
|
import { join as join6, dirname as dirname4 } from "path";
|
|
522
539
|
var MIGRATIONS_LOG_FILE = ".migrations.log";
|
|
523
540
|
function getMigrationsLogPath() {
|
|
@@ -555,11 +572,54 @@ function createConfigDirMigration(skillName, version2) {
|
|
|
555
572
|
}
|
|
556
573
|
};
|
|
557
574
|
}
|
|
575
|
+
function createPlatformSyncMigration(version2) {
|
|
576
|
+
return {
|
|
577
|
+
version: version2,
|
|
578
|
+
description: "Sync installed tools from disk to config",
|
|
579
|
+
up: () => {
|
|
580
|
+
const config = loadConfig();
|
|
581
|
+
const bundledTools = getBundledTools();
|
|
582
|
+
let configChanged = false;
|
|
583
|
+
const originalPlatform = config.platform;
|
|
584
|
+
for (const platformKey of ["claude-code" /* ClaudeCode */, "opencode" /* OpenCode */]) {
|
|
585
|
+
const skillsPath = getSkillsPath(platformKey);
|
|
586
|
+
if (!existsSync4(skillsPath)) continue;
|
|
587
|
+
config.platform = platformKey;
|
|
588
|
+
const trackedTools = getPlatformTools(config);
|
|
589
|
+
const installedDirs = readdirSync3(skillsPath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
590
|
+
for (const skillName of installedDirs) {
|
|
591
|
+
const normalizedName = skillName.replace(/^droid-/, "");
|
|
592
|
+
const isTracked = trackedTools[skillName] || trackedTools[`droid-${normalizedName}`] || trackedTools[normalizedName];
|
|
593
|
+
if (isTracked) continue;
|
|
594
|
+
const matchingTool = bundledTools.find(
|
|
595
|
+
(tool) => tool.includes.skills.some((s) => s.name === skillName)
|
|
596
|
+
);
|
|
597
|
+
if (matchingTool) {
|
|
598
|
+
trackedTools[skillName] = {
|
|
599
|
+
version: matchingTool.version,
|
|
600
|
+
installed_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
601
|
+
};
|
|
602
|
+
configChanged = true;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
if (configChanged) {
|
|
606
|
+
setPlatformTools(config, trackedTools);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
config.platform = originalPlatform;
|
|
610
|
+
if (configChanged) {
|
|
611
|
+
saveConfig(config);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
};
|
|
615
|
+
}
|
|
558
616
|
var TOOL_MIGRATIONS = {
|
|
559
617
|
brain: [createConfigDirMigration("droid-brain", "0.2.3")],
|
|
560
618
|
comments: [createConfigDirMigration("droid-comments", "0.2.6")],
|
|
561
619
|
project: [createConfigDirMigration("droid-project", "0.1.5")],
|
|
562
|
-
coach: [createConfigDirMigration("droid-coach", "0.1.3")]
|
|
620
|
+
coach: [createConfigDirMigration("droid-coach", "0.1.3")],
|
|
621
|
+
// Global migration for the droid meta-tool
|
|
622
|
+
droid: [createPlatformSyncMigration("0.25.0")]
|
|
563
623
|
};
|
|
564
624
|
function getToolMigrations(toolName) {
|
|
565
625
|
return TOOL_MIGRATIONS[toolName] ?? [];
|
|
@@ -594,8 +654,17 @@ function runMigrations(toolName, fromVersion, toVersion) {
|
|
|
594
654
|
logMigration(toolName, fromVersion, migration.version, "OK");
|
|
595
655
|
} catch (error) {
|
|
596
656
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
597
|
-
logMigration(
|
|
598
|
-
|
|
657
|
+
logMigration(
|
|
658
|
+
toolName,
|
|
659
|
+
fromVersion,
|
|
660
|
+
migration.version,
|
|
661
|
+
"FAILED",
|
|
662
|
+
errorMessage
|
|
663
|
+
);
|
|
664
|
+
return {
|
|
665
|
+
success: false,
|
|
666
|
+
error: `Migration ${migration.version} failed: ${errorMessage}`
|
|
667
|
+
};
|
|
599
668
|
}
|
|
600
669
|
}
|
|
601
670
|
setLastMigratedVersion(toolName, toVersion);
|
|
@@ -692,7 +761,7 @@ function findSkillPath(skillName) {
|
|
|
692
761
|
if (!existsSync5(BUNDLED_SKILLS_DIR)) {
|
|
693
762
|
return null;
|
|
694
763
|
}
|
|
695
|
-
const toolDirs =
|
|
764
|
+
const toolDirs = readdirSync4(BUNDLED_SKILLS_DIR, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
696
765
|
for (const toolName of toolDirs) {
|
|
697
766
|
const skillsDir = join7(BUNDLED_SKILLS_DIR, toolName, "skills");
|
|
698
767
|
if (!existsSync5(skillsDir)) continue;
|
|
@@ -710,12 +779,12 @@ function getBundledSkills() {
|
|
|
710
779
|
if (!existsSync5(BUNDLED_SKILLS_DIR)) {
|
|
711
780
|
return [];
|
|
712
781
|
}
|
|
713
|
-
const toolDirs =
|
|
782
|
+
const toolDirs = readdirSync4(BUNDLED_SKILLS_DIR, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
714
783
|
const skills = [];
|
|
715
784
|
for (const toolName of toolDirs) {
|
|
716
785
|
const skillsDir = join7(BUNDLED_SKILLS_DIR, toolName, "skills");
|
|
717
786
|
if (!existsSync5(skillsDir)) continue;
|
|
718
|
-
const skillSubdirs =
|
|
787
|
+
const skillSubdirs = readdirSync4(skillsDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
719
788
|
for (const skillName of skillSubdirs) {
|
|
720
789
|
const manifest = loadSkillManifest(join7(skillsDir, skillName));
|
|
721
790
|
if (manifest) {
|
|
@@ -758,10 +827,16 @@ function updateSkill(skillName) {
|
|
|
758
827
|
return { success: false, message: `Skill '${skillName}' is not installed` };
|
|
759
828
|
}
|
|
760
829
|
if (!status.bundledVersion) {
|
|
761
|
-
return {
|
|
830
|
+
return {
|
|
831
|
+
success: false,
|
|
832
|
+
message: `Skill '${skillName}' not found in bundled skills`
|
|
833
|
+
};
|
|
762
834
|
}
|
|
763
835
|
if (!status.hasUpdate) {
|
|
764
|
-
return {
|
|
836
|
+
return {
|
|
837
|
+
success: false,
|
|
838
|
+
message: `Skill '${skillName}' is already at latest version (${status.installedVersion})`
|
|
839
|
+
};
|
|
765
840
|
}
|
|
766
841
|
const result = installSkill(skillName);
|
|
767
842
|
if (result.success) {
|
|
@@ -781,7 +856,10 @@ function installSkill(skillName) {
|
|
|
781
856
|
const { toolDir, skillDir } = skillPath;
|
|
782
857
|
const manifest = loadSkillManifest(skillDir);
|
|
783
858
|
if (!manifest) {
|
|
784
|
-
return {
|
|
859
|
+
return {
|
|
860
|
+
success: false,
|
|
861
|
+
message: `Invalid skill manifest for '${skillName}'`
|
|
862
|
+
};
|
|
785
863
|
}
|
|
786
864
|
if (manifest.dependencies) {
|
|
787
865
|
for (const dep of manifest.dependencies) {
|
|
@@ -798,30 +876,41 @@ function installSkill(skillName) {
|
|
|
798
876
|
const commandsPath = getCommandsInstallPath(config.platform);
|
|
799
877
|
const tools = getPlatformTools(config);
|
|
800
878
|
if (skillName.startsWith("droid-")) {
|
|
801
|
-
const
|
|
802
|
-
const oldSkillDir = join7(skillsPath,
|
|
879
|
+
const oldSkillName2 = skillName.replace(/^droid-/, "");
|
|
880
|
+
const oldSkillDir = join7(skillsPath, oldSkillName2);
|
|
803
881
|
if (existsSync5(oldSkillDir)) {
|
|
804
882
|
try {
|
|
805
883
|
rmSync2(oldSkillDir, { recursive: true });
|
|
806
884
|
} catch (error) {
|
|
807
|
-
console.warn(
|
|
885
|
+
console.warn(
|
|
886
|
+
`Warning: Could not remove old skill directory ${oldSkillDir}: ${error}`
|
|
887
|
+
);
|
|
808
888
|
}
|
|
809
889
|
}
|
|
810
|
-
if (tools[
|
|
811
|
-
delete tools[
|
|
890
|
+
if (tools[oldSkillName2]) {
|
|
891
|
+
delete tools[oldSkillName2];
|
|
812
892
|
setPlatformTools(config, tools);
|
|
813
893
|
saveConfig(config);
|
|
814
894
|
}
|
|
815
895
|
}
|
|
816
896
|
const commandsSource = join7(toolDir, "commands");
|
|
817
897
|
const agentsSource = join7(toolDir, "agents");
|
|
818
|
-
|
|
898
|
+
const oldSkillName = skillName.startsWith("droid-") ? skillName.replace(/^droid-/, "") : null;
|
|
899
|
+
const isAlreadyInstalled = tools[skillName] || oldSkillName && tools[oldSkillName];
|
|
900
|
+
if (!isAlreadyInstalled) {
|
|
901
|
+
const toolName2 = basename(toolDir);
|
|
902
|
+
const normalizedToolName = toolName2.replace(/^droid-/, "");
|
|
819
903
|
if (existsSync5(commandsSource)) {
|
|
820
|
-
const commandFiles =
|
|
904
|
+
const commandFiles = readdirSync4(commandsSource).filter(
|
|
905
|
+
(f) => f.endsWith(".md") && f.toLowerCase() !== "readme.md"
|
|
906
|
+
);
|
|
821
907
|
for (const file of commandFiles) {
|
|
822
908
|
const targetCommandPath = join7(commandsPath, file);
|
|
823
909
|
if (existsSync5(targetCommandPath)) {
|
|
824
910
|
const commandName = file.replace(".md", "");
|
|
911
|
+
if (commandName === toolName2 || commandName === normalizedToolName) {
|
|
912
|
+
continue;
|
|
913
|
+
}
|
|
825
914
|
return {
|
|
826
915
|
success: false,
|
|
827
916
|
message: `Cannot install: command /${commandName} already exists at ${targetCommandPath}`
|
|
@@ -830,8 +919,8 @@ function installSkill(skillName) {
|
|
|
830
919
|
}
|
|
831
920
|
}
|
|
832
921
|
if (existsSync5(agentsSource)) {
|
|
833
|
-
const
|
|
834
|
-
for (const agentName of
|
|
922
|
+
const agentFiles = readdirSync4(agentsSource, { withFileTypes: true }).filter((dirent) => dirent.isFile() && dirent.name.endsWith(".md")).map((dirent) => dirent.name.replace(".md", ""));
|
|
923
|
+
for (const agentName of agentFiles) {
|
|
835
924
|
if (isAgentInstalled(agentName)) {
|
|
836
925
|
return {
|
|
837
926
|
success: false,
|
|
@@ -859,7 +948,9 @@ function installSkill(skillName) {
|
|
|
859
948
|
if (!existsSync5(targetReferencesDir)) {
|
|
860
949
|
mkdirSync4(targetReferencesDir, { recursive: true });
|
|
861
950
|
}
|
|
862
|
-
const referenceFiles =
|
|
951
|
+
const referenceFiles = readdirSync4(referencesSource).filter(
|
|
952
|
+
(f) => f.endsWith(".md")
|
|
953
|
+
);
|
|
863
954
|
for (const file of referenceFiles) {
|
|
864
955
|
const sourcePath = join7(referencesSource, file);
|
|
865
956
|
const targetPath = join7(targetReferencesDir, file);
|
|
@@ -867,11 +958,29 @@ function installSkill(skillName) {
|
|
|
867
958
|
writeFileSync3(targetPath, content);
|
|
868
959
|
}
|
|
869
960
|
}
|
|
961
|
+
const scriptsSource = join7(skillDir, "scripts");
|
|
962
|
+
if (existsSync5(scriptsSource)) {
|
|
963
|
+
const targetScriptsDir = join7(targetSkillDir, "scripts");
|
|
964
|
+
if (!existsSync5(targetScriptsDir)) {
|
|
965
|
+
mkdirSync4(targetScriptsDir, { recursive: true });
|
|
966
|
+
}
|
|
967
|
+
const scriptFiles = readdirSync4(scriptsSource).filter(
|
|
968
|
+
(f) => f.endsWith(".ts") || f.endsWith(".js") || f.endsWith(".py")
|
|
969
|
+
);
|
|
970
|
+
for (const file of scriptFiles) {
|
|
971
|
+
const sourcePath = join7(scriptsSource, file);
|
|
972
|
+
const targetPath = join7(targetScriptsDir, file);
|
|
973
|
+
const content = readFileSync5(sourcePath, "utf-8");
|
|
974
|
+
writeFileSync3(targetPath, content);
|
|
975
|
+
}
|
|
976
|
+
}
|
|
870
977
|
if (existsSync5(commandsSource)) {
|
|
871
978
|
if (!existsSync5(commandsPath)) {
|
|
872
979
|
mkdirSync4(commandsPath, { recursive: true });
|
|
873
980
|
}
|
|
874
|
-
const commandFiles =
|
|
981
|
+
const commandFiles = readdirSync4(commandsSource).filter(
|
|
982
|
+
(f) => f.endsWith(".md") && f.toLowerCase() !== "readme.md"
|
|
983
|
+
);
|
|
875
984
|
for (const file of commandFiles) {
|
|
876
985
|
const sourcePath = join7(commandsSource, file);
|
|
877
986
|
const targetPath = join7(commandsPath, file);
|
|
@@ -881,10 +990,10 @@ function installSkill(skillName) {
|
|
|
881
990
|
}
|
|
882
991
|
const installedAgents = [];
|
|
883
992
|
if (existsSync5(agentsSource)) {
|
|
884
|
-
const
|
|
885
|
-
for (const agentName of
|
|
886
|
-
const
|
|
887
|
-
const result = installAgentFromPath(
|
|
993
|
+
const agentFiles = readdirSync4(agentsSource, { withFileTypes: true }).filter((dirent) => dirent.isFile() && dirent.name.endsWith(".md")).map((dirent) => dirent.name.replace(".md", ""));
|
|
994
|
+
for (const agentName of agentFiles) {
|
|
995
|
+
const agentPath = join7(agentsSource, `${agentName}.md`);
|
|
996
|
+
const result = installAgentFromPath(agentPath, agentName);
|
|
888
997
|
if (result.success) {
|
|
889
998
|
installedAgents.push(agentName);
|
|
890
999
|
}
|
|
@@ -905,9 +1014,14 @@ function installSkill(skillName) {
|
|
|
905
1014
|
const toolName = basename(toolDir);
|
|
906
1015
|
const migrationResult = runToolMigrations(toolName, manifest.version);
|
|
907
1016
|
if (!migrationResult.success) {
|
|
908
|
-
console.warn(
|
|
1017
|
+
console.warn(
|
|
1018
|
+
`Warning: Migration failed for ${toolName}: ${migrationResult.error}`
|
|
1019
|
+
);
|
|
909
1020
|
}
|
|
910
|
-
return {
|
|
1021
|
+
return {
|
|
1022
|
+
success: true,
|
|
1023
|
+
message: `Installed ${skillName} v${manifest.version}`
|
|
1024
|
+
};
|
|
911
1025
|
}
|
|
912
1026
|
function uninstallSkill(skillName) {
|
|
913
1027
|
const config = loadConfig();
|
|
@@ -924,7 +1038,9 @@ function uninstallSkill(skillName) {
|
|
|
924
1038
|
const commandsPath = getCommandsInstallPath(config.platform);
|
|
925
1039
|
const commandsSource = skillPath ? join7(skillPath.toolDir, "commands") : null;
|
|
926
1040
|
if (commandsSource && existsSync5(commandsSource)) {
|
|
927
|
-
const commandFiles =
|
|
1041
|
+
const commandFiles = readdirSync4(commandsSource).filter(
|
|
1042
|
+
(f) => f.endsWith(".md") && f.toLowerCase() !== "readme.md"
|
|
1043
|
+
);
|
|
928
1044
|
for (const file of commandFiles) {
|
|
929
1045
|
const commandPath = join7(commandsPath, file);
|
|
930
1046
|
if (existsSync5(commandPath)) {
|
|
@@ -1140,17 +1256,17 @@ async function setupCommand() {
|
|
|
1140
1256
|
console.log(chalk2.yellow(" You may need to manually configure your platform"));
|
|
1141
1257
|
} else if (answers.platform === "claude-code" /* ClaudeCode */) {
|
|
1142
1258
|
if (added.length > 0) {
|
|
1143
|
-
console.log(chalk2.green(
|
|
1259
|
+
console.log(chalk2.green("\u2713 Added droid permissions to Claude Code settings"));
|
|
1144
1260
|
} else if (alreadyPresent) {
|
|
1145
|
-
console.log(chalk2.gray(
|
|
1261
|
+
console.log(chalk2.gray(" Droid permissions already configured in Claude Code"));
|
|
1146
1262
|
}
|
|
1147
1263
|
} else if (answers.platform === "opencode" /* OpenCode */) {
|
|
1148
1264
|
if (added.length > 0) {
|
|
1149
|
-
console.log(chalk2.green(
|
|
1150
|
-
console.log(chalk2.gray(
|
|
1151
|
-
console.log(chalk2.gray(
|
|
1265
|
+
console.log(chalk2.green("\u2713 Added opencode-skills plugin to OpenCode config"));
|
|
1266
|
+
console.log(chalk2.gray(" This enables Claude Code-style skills in OpenCode"));
|
|
1267
|
+
console.log(chalk2.gray(" Restart OpenCode to activate the plugin"));
|
|
1152
1268
|
} else if (alreadyPresent) {
|
|
1153
|
-
console.log(chalk2.gray(
|
|
1269
|
+
console.log(chalk2.gray(" opencode-skills plugin already configured in OpenCode"));
|
|
1154
1270
|
}
|
|
1155
1271
|
}
|
|
1156
1272
|
console.log(chalk2.gray("\nRun `droid skills` to browse and install skills."));
|
|
@@ -1159,8 +1275,23 @@ async function setupCommand() {
|
|
|
1159
1275
|
// src/commands/config.ts
|
|
1160
1276
|
import chalk3 from "chalk";
|
|
1161
1277
|
import { execSync as execSync3 } from "child_process";
|
|
1162
|
-
|
|
1163
|
-
|
|
1278
|
+
function getToolConfig(toolName) {
|
|
1279
|
+
const globalConfig = loadConfig();
|
|
1280
|
+
const overrides = loadSkillOverrides(toolName);
|
|
1281
|
+
return {
|
|
1282
|
+
user_mention: globalConfig.user_mention,
|
|
1283
|
+
ai_mention: getAITag(),
|
|
1284
|
+
...overrides
|
|
1285
|
+
// Tool handles its own defaults
|
|
1286
|
+
};
|
|
1287
|
+
}
|
|
1288
|
+
async function configCommand(tool, options) {
|
|
1289
|
+
if (tool) {
|
|
1290
|
+
const toolConfig = getToolConfig(tool);
|
|
1291
|
+
console.log(JSON.stringify(toolConfig, null, 2));
|
|
1292
|
+
return;
|
|
1293
|
+
}
|
|
1294
|
+
if (options?.edit) {
|
|
1164
1295
|
const configPath = getConfigPath();
|
|
1165
1296
|
const editor = process.env.EDITOR || "vim";
|
|
1166
1297
|
if (!configExists()) {
|
|
@@ -1175,7 +1306,7 @@ async function configCommand(options) {
|
|
|
1175
1306
|
}
|
|
1176
1307
|
return;
|
|
1177
1308
|
}
|
|
1178
|
-
if (options
|
|
1309
|
+
if (options?.get) {
|
|
1179
1310
|
const value = getConfigValue(options.get);
|
|
1180
1311
|
if (value === void 0) {
|
|
1181
1312
|
console.log(chalk3.yellow(`Config key '${options.get}' not found`));
|
|
@@ -1188,7 +1319,7 @@ async function configCommand(options) {
|
|
|
1188
1319
|
}
|
|
1189
1320
|
return;
|
|
1190
1321
|
}
|
|
1191
|
-
if (options
|
|
1322
|
+
if (options?.set) {
|
|
1192
1323
|
const match = options.set.match(/^([^=]+)=(.*)$/);
|
|
1193
1324
|
if (!match) {
|
|
1194
1325
|
console.error(chalk3.red("Invalid format. Use: --set key=value"));
|
|
@@ -1464,7 +1595,7 @@ async function installCommand(toolName) {
|
|
|
1464
1595
|
}
|
|
1465
1596
|
console.log(chalk6.gray("\nNext steps:"));
|
|
1466
1597
|
console.log(chalk6.gray(" - Run your AI tool to start using it"));
|
|
1467
|
-
console.log(chalk6.gray(
|
|
1598
|
+
console.log(chalk6.gray(" - Reconfigure anytime with `droid` \u2192 Configure"));
|
|
1468
1599
|
} else {
|
|
1469
1600
|
console.error(chalk6.red(`\u2717 ${result.message}`));
|
|
1470
1601
|
process.exit(1);
|
|
@@ -2842,6 +2973,10 @@ function App() {
|
|
|
2842
2973
|
}
|
|
2843
2974
|
}
|
|
2844
2975
|
});
|
|
2976
|
+
useEffect(() => {
|
|
2977
|
+
const droidVersion = getVersion();
|
|
2978
|
+
runToolMigrations("droid", droidVersion);
|
|
2979
|
+
}, []);
|
|
2845
2980
|
useEffect(() => {
|
|
2846
2981
|
const autoUpdateConfig = getAutoUpdateConfig();
|
|
2847
2982
|
if (autoUpdateConfig.app && updateInfo.hasUpdate && view === "welcome" && !isUpdating) {
|
|
@@ -2890,142 +3025,149 @@ function App() {
|
|
|
2890
3025
|
};
|
|
2891
3026
|
const tools = getBundledTools();
|
|
2892
3027
|
const skills = getBundledSkills();
|
|
2893
|
-
useInput7(
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
if (view === "menu") {
|
|
2900
|
-
if (key.leftArrow) {
|
|
2901
|
-
const newIndex = Math.max(0, tabIndex - 1);
|
|
2902
|
-
setTabIndex(newIndex);
|
|
2903
|
-
setActiveTab(tabs[newIndex].id);
|
|
2904
|
-
setSelectedIndex(0);
|
|
2905
|
-
setScrollOffset(0);
|
|
2906
|
-
}
|
|
2907
|
-
if (key.rightArrow) {
|
|
2908
|
-
const newIndex = Math.min(tabs.length - 1, tabIndex + 1);
|
|
2909
|
-
setTabIndex(newIndex);
|
|
2910
|
-
setActiveTab(tabs[newIndex].id);
|
|
2911
|
-
setSelectedIndex(0);
|
|
2912
|
-
setScrollOffset(0);
|
|
2913
|
-
}
|
|
2914
|
-
if (key.upArrow) {
|
|
2915
|
-
setSelectedIndex((prev) => {
|
|
2916
|
-
const newIndex = Math.max(0, prev - 1);
|
|
2917
|
-
if (newIndex < scrollOffset) {
|
|
2918
|
-
setScrollOffset(newIndex);
|
|
2919
|
-
}
|
|
2920
|
-
return newIndex;
|
|
2921
|
-
});
|
|
2922
|
-
setSelectedAction(0);
|
|
2923
|
-
}
|
|
2924
|
-
if (key.downArrow) {
|
|
2925
|
-
const maxIndex = activeTab === "tools" ? tools.length - 1 : 0;
|
|
2926
|
-
setSelectedIndex((prev) => {
|
|
2927
|
-
const newIndex = Math.min(maxIndex, prev + 1);
|
|
2928
|
-
if (newIndex >= scrollOffset + MAX_VISIBLE_ITEMS) {
|
|
2929
|
-
setScrollOffset(newIndex - MAX_VISIBLE_ITEMS + 1);
|
|
2930
|
-
}
|
|
2931
|
-
return newIndex;
|
|
2932
|
-
});
|
|
2933
|
-
setSelectedAction(0);
|
|
3028
|
+
useInput7(
|
|
3029
|
+
(input, key) => {
|
|
3030
|
+
if (message) setMessage(null);
|
|
3031
|
+
if (input === "q") {
|
|
3032
|
+
exit();
|
|
3033
|
+
return;
|
|
2934
3034
|
}
|
|
2935
|
-
if (
|
|
2936
|
-
if (
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
3035
|
+
if (view === "menu") {
|
|
3036
|
+
if (key.leftArrow) {
|
|
3037
|
+
const newIndex = Math.max(0, tabIndex - 1);
|
|
3038
|
+
setTabIndex(newIndex);
|
|
3039
|
+
setActiveTab(tabs[newIndex].id);
|
|
3040
|
+
setSelectedIndex(0);
|
|
3041
|
+
setScrollOffset(0);
|
|
2940
3042
|
}
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
if (activeTab === "settings") {
|
|
2948
|
-
if (key.return) {
|
|
2949
|
-
setIsEditingSettings(true);
|
|
2950
|
-
setView("setup");
|
|
3043
|
+
if (key.rightArrow) {
|
|
3044
|
+
const newIndex = Math.min(tabs.length - 1, tabIndex + 1);
|
|
3045
|
+
setTabIndex(newIndex);
|
|
3046
|
+
setActiveTab(tabs[newIndex].id);
|
|
3047
|
+
setSelectedIndex(0);
|
|
3048
|
+
setScrollOffset(0);
|
|
2951
3049
|
}
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
let maxActions = 0;
|
|
2958
|
-
const tool = tools[selectedIndex];
|
|
2959
|
-
const installed = tool ? isToolInstalled(tool.name) : false;
|
|
2960
|
-
const hasUpdate = tool ? getToolUpdateStatus(tool.name).hasUpdate : false;
|
|
2961
|
-
const isSystem = tool ? tool.system === true : false;
|
|
2962
|
-
maxActions = installed ? hasUpdate ? isSystem ? 2 : 3 : isSystem ? 1 : 2 : 1;
|
|
2963
|
-
setSelectedAction((prev) => Math.min(maxActions, prev + 1));
|
|
2964
|
-
}
|
|
2965
|
-
if (key.return && activeTab === "tools") {
|
|
2966
|
-
const tool = tools[selectedIndex];
|
|
2967
|
-
if (tool) {
|
|
2968
|
-
const installed = isToolInstalled(tool.name);
|
|
2969
|
-
const toolUpdateStatus = getToolUpdateStatus(tool.name);
|
|
2970
|
-
const isSystemTool = tool.system === true;
|
|
2971
|
-
const toolActions = installed ? [
|
|
2972
|
-
{ id: "explore" },
|
|
2973
|
-
...toolUpdateStatus.hasUpdate ? [{ id: "update" }] : [],
|
|
2974
|
-
{ id: "configure" },
|
|
2975
|
-
...!isSystemTool ? [{ id: "uninstall" }] : []
|
|
2976
|
-
] : [{ id: "explore" }, { id: "install" }];
|
|
2977
|
-
const actionId = toolActions[selectedAction]?.id;
|
|
2978
|
-
if (actionId === "explore") {
|
|
2979
|
-
setView("explorer");
|
|
2980
|
-
} else if (actionId === "update") {
|
|
2981
|
-
const primarySkill = tool.includes.skills.find((s) => s.required)?.name || tool.name;
|
|
2982
|
-
const result = updateSkill(primarySkill);
|
|
2983
|
-
setMessage({
|
|
2984
|
-
text: result.success ? `\u2713 Updated ${tool.name}` : `\u2717 ${result.message}`,
|
|
2985
|
-
type: result.success ? "success" : "error"
|
|
2986
|
-
});
|
|
2987
|
-
if (result.success) {
|
|
2988
|
-
setSelectedAction(0);
|
|
3050
|
+
if (key.upArrow) {
|
|
3051
|
+
setSelectedIndex((prev) => {
|
|
3052
|
+
const newIndex = Math.max(0, prev - 1);
|
|
3053
|
+
if (newIndex < scrollOffset) {
|
|
3054
|
+
setScrollOffset(newIndex);
|
|
2989
3055
|
}
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
setView("menu");
|
|
3001
|
-
setSelectedAction(0);
|
|
3056
|
+
return newIndex;
|
|
3057
|
+
});
|
|
3058
|
+
setSelectedAction(0);
|
|
3059
|
+
}
|
|
3060
|
+
if (key.downArrow) {
|
|
3061
|
+
const maxIndex = activeTab === "tools" ? tools.length - 1 : 0;
|
|
3062
|
+
setSelectedIndex((prev) => {
|
|
3063
|
+
const newIndex = Math.min(maxIndex, prev + 1);
|
|
3064
|
+
if (newIndex >= scrollOffset + MAX_VISIBLE_ITEMS) {
|
|
3065
|
+
setScrollOffset(newIndex - MAX_VISIBLE_ITEMS + 1);
|
|
3002
3066
|
}
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3067
|
+
return newIndex;
|
|
3068
|
+
});
|
|
3069
|
+
setSelectedAction(0);
|
|
3070
|
+
}
|
|
3071
|
+
if (key.return) {
|
|
3072
|
+
if (activeTab === "tools" && tools.length > 0) {
|
|
3073
|
+
setView("detail");
|
|
3074
|
+
} else if (activeTab === "settings") {
|
|
3075
|
+
setView("detail");
|
|
3076
|
+
}
|
|
3077
|
+
}
|
|
3078
|
+
} else if (view === "detail") {
|
|
3079
|
+
if (key.escape || key.backspace) {
|
|
3080
|
+
setView("menu");
|
|
3081
|
+
setSelectedAction(0);
|
|
3082
|
+
}
|
|
3083
|
+
if (activeTab === "settings") {
|
|
3084
|
+
if (key.return) {
|
|
3085
|
+
setIsEditingSettings(true);
|
|
3086
|
+
setView("setup");
|
|
3087
|
+
}
|
|
3088
|
+
}
|
|
3089
|
+
if (key.leftArrow && activeTab === "tools") {
|
|
3090
|
+
setSelectedAction((prev) => Math.max(0, prev - 1));
|
|
3091
|
+
}
|
|
3092
|
+
if (key.rightArrow && activeTab === "tools") {
|
|
3093
|
+
let maxActions = 0;
|
|
3094
|
+
const tool = tools[selectedIndex];
|
|
3095
|
+
const installed = tool ? isToolInstalled(tool.name) : false;
|
|
3096
|
+
const hasUpdate = tool ? getToolUpdateStatus(tool.name).hasUpdate : false;
|
|
3097
|
+
const isSystem = tool ? tool.system === true : false;
|
|
3098
|
+
maxActions = installed ? hasUpdate ? isSystem ? 2 : 3 : isSystem ? 1 : 2 : 1;
|
|
3099
|
+
setSelectedAction((prev) => Math.min(maxActions, prev + 1));
|
|
3100
|
+
}
|
|
3101
|
+
if (key.return && activeTab === "tools") {
|
|
3102
|
+
const tool = tools[selectedIndex];
|
|
3103
|
+
if (tool) {
|
|
3104
|
+
const installed = isToolInstalled(tool.name);
|
|
3105
|
+
const toolUpdateStatus = getToolUpdateStatus(tool.name);
|
|
3106
|
+
const isSystemTool = tool.system === true;
|
|
3107
|
+
const toolActions = installed ? [
|
|
3108
|
+
{ id: "explore" },
|
|
3109
|
+
...toolUpdateStatus.hasUpdate ? [{ id: "update" }] : [],
|
|
3110
|
+
{ id: "configure" },
|
|
3111
|
+
...!isSystemTool ? [{ id: "uninstall" }] : []
|
|
3112
|
+
] : [{ id: "explore" }, { id: "install" }];
|
|
3113
|
+
const actionId = toolActions[selectedAction]?.id;
|
|
3114
|
+
if (actionId === "explore") {
|
|
3115
|
+
setView("explorer");
|
|
3116
|
+
} else if (actionId === "update") {
|
|
3117
|
+
const primarySkill = tool.includes.skills.find((s) => s.required)?.name || tool.name;
|
|
3118
|
+
const result = updateSkill(primarySkill);
|
|
3119
|
+
setMessage({
|
|
3120
|
+
text: result.success ? `\u2713 Updated ${tool.name}` : `\u2717 ${result.message}`,
|
|
3121
|
+
type: result.success ? "success" : "error"
|
|
3122
|
+
});
|
|
3123
|
+
if (result.success) {
|
|
3124
|
+
setSelectedAction(0);
|
|
3125
|
+
}
|
|
3126
|
+
} else if (actionId === "configure") {
|
|
3127
|
+
setView("configure");
|
|
3128
|
+
} else if (actionId === "uninstall") {
|
|
3129
|
+
const primarySkill = tool.includes.skills.find((s) => s.required)?.name || tool.name;
|
|
3130
|
+
const result = uninstallSkill(primarySkill);
|
|
3131
|
+
setMessage({
|
|
3132
|
+
text: result.success ? `\u2713 Uninstalled ${tool.name}` : `\u2717 ${result.message}`,
|
|
3133
|
+
type: result.success ? "success" : "error"
|
|
3134
|
+
});
|
|
3135
|
+
if (result.success) {
|
|
3018
3136
|
setView("menu");
|
|
3019
3137
|
setSelectedAction(0);
|
|
3020
3138
|
}
|
|
3139
|
+
} else if (actionId === "install") {
|
|
3140
|
+
const primarySkill = tool.includes.skills.find((s) => s.required)?.name || tool.name;
|
|
3141
|
+
const result = installSkill(primarySkill);
|
|
3142
|
+
setMessage({
|
|
3143
|
+
text: result.success ? `\u2713 Installed ${tool.name}` : `\u2717 ${result.message}`,
|
|
3144
|
+
type: result.success ? "success" : "error"
|
|
3145
|
+
});
|
|
3146
|
+
if (result.success) {
|
|
3147
|
+
const configSchema = tool.config_schema || {};
|
|
3148
|
+
const hasRequiredConfig = Object.values(configSchema).some(
|
|
3149
|
+
(option) => option.default === void 0
|
|
3150
|
+
);
|
|
3151
|
+
if (hasRequiredConfig) {
|
|
3152
|
+
setView("configure");
|
|
3153
|
+
} else {
|
|
3154
|
+
setView("menu");
|
|
3155
|
+
setSelectedAction(0);
|
|
3156
|
+
}
|
|
3157
|
+
}
|
|
3021
3158
|
}
|
|
3022
3159
|
}
|
|
3023
3160
|
}
|
|
3024
3161
|
}
|
|
3162
|
+
},
|
|
3163
|
+
{
|
|
3164
|
+
isActive: view !== "welcome" && view !== "tool-updates" && view !== "setup" && view !== "configure" && view !== "explorer"
|
|
3025
3165
|
}
|
|
3026
|
-
|
|
3166
|
+
);
|
|
3027
3167
|
const selectedTool = activeTab === "tools" ? tools[selectedIndex] ?? null : null;
|
|
3028
|
-
const selectedSkillForConfig = selectedTool ? skills.find(
|
|
3168
|
+
const selectedSkillForConfig = selectedTool ? skills.find(
|
|
3169
|
+
(s) => s.name === (selectedTool.includes.skills.find((sk) => sk.required)?.name || selectedTool.name)
|
|
3170
|
+
) : null;
|
|
3029
3171
|
if (view === "welcome") {
|
|
3030
3172
|
return /* @__PURE__ */ jsx13(
|
|
3031
3173
|
WelcomeScreen,
|
|
@@ -3102,7 +3244,10 @@ function App() {
|
|
|
3102
3244
|
{
|
|
3103
3245
|
skill: selectedSkillForConfig,
|
|
3104
3246
|
onComplete: () => {
|
|
3105
|
-
setMessage({
|
|
3247
|
+
setMessage({
|
|
3248
|
+
text: `\u2713 Configuration saved for ${selectedTool?.name || selectedSkillForConfig.name}`,
|
|
3249
|
+
type: "success"
|
|
3250
|
+
});
|
|
3106
3251
|
setView("detail");
|
|
3107
3252
|
},
|
|
3108
3253
|
onCancel: () => {
|
|
@@ -3163,18 +3308,26 @@ function App() {
|
|
|
3163
3308
|
] }),
|
|
3164
3309
|
activeTab === "settings" && /* @__PURE__ */ jsx13(Box12, { paddingX: 1, children: /* @__PURE__ */ jsx13(Text13, { color: colors.textDim, children: "View and edit config" }) })
|
|
3165
3310
|
] }),
|
|
3166
|
-
message && /* @__PURE__ */ jsx13(Box12, { paddingX: 1, marginTop: 1, children: /* @__PURE__ */ jsx13(
|
|
3311
|
+
message && /* @__PURE__ */ jsx13(Box12, { paddingX: 1, marginTop: 1, children: /* @__PURE__ */ jsx13(
|
|
3312
|
+
Text13,
|
|
3313
|
+
{
|
|
3314
|
+
color: message.type === "success" ? colors.success : colors.error,
|
|
3315
|
+
children: message.text
|
|
3316
|
+
}
|
|
3317
|
+
) }),
|
|
3167
3318
|
/* @__PURE__ */ jsx13(Box12, { paddingX: 1, marginTop: 1, children: /* @__PURE__ */ jsx13(Text13, { color: colors.textDim, children: view === "menu" ? "\u2190\u2192 \u2191\u2193 enter q" : "\u2190\u2192 enter esc q" }) })
|
|
3168
3319
|
]
|
|
3169
3320
|
}
|
|
3170
3321
|
),
|
|
3171
|
-
activeTab === "tools" && /* @__PURE__ */ jsx13(
|
|
3172
|
-
|
|
3173
|
-
SettingsDetails,
|
|
3322
|
+
activeTab === "tools" && /* @__PURE__ */ jsx13(
|
|
3323
|
+
ToolDetails,
|
|
3174
3324
|
{
|
|
3175
|
-
|
|
3325
|
+
tool: selectedTool,
|
|
3326
|
+
isFocused: view === "detail",
|
|
3327
|
+
selectedAction
|
|
3176
3328
|
}
|
|
3177
|
-
)
|
|
3329
|
+
),
|
|
3330
|
+
activeTab === "settings" && /* @__PURE__ */ jsx13(SettingsDetails, { isFocused: view === "detail" })
|
|
3178
3331
|
] });
|
|
3179
3332
|
}
|
|
3180
3333
|
async function tuiCommand() {
|
|
@@ -3189,16 +3342,77 @@ async function tuiCommand() {
|
|
|
3189
3342
|
}
|
|
3190
3343
|
}
|
|
3191
3344
|
|
|
3345
|
+
// src/commands/exec.ts
|
|
3346
|
+
import chalk9 from "chalk";
|
|
3347
|
+
import { spawn } from "child_process";
|
|
3348
|
+
import { existsSync as existsSync8 } from "fs";
|
|
3349
|
+
import { join as join10 } from "path";
|
|
3350
|
+
function getRuntime(toolPath) {
|
|
3351
|
+
if (toolPath.endsWith(".ts") || toolPath.endsWith(".js")) {
|
|
3352
|
+
return { cmd: "bun", args: ["run", toolPath] };
|
|
3353
|
+
}
|
|
3354
|
+
if (toolPath.endsWith(".py")) {
|
|
3355
|
+
return { cmd: "python3", args: [toolPath] };
|
|
3356
|
+
}
|
|
3357
|
+
return null;
|
|
3358
|
+
}
|
|
3359
|
+
async function execCommand(tool, script, args) {
|
|
3360
|
+
const config = loadConfig();
|
|
3361
|
+
const skillsPath = getSkillsPath(config.platform);
|
|
3362
|
+
const toolDir = join10(skillsPath, tool);
|
|
3363
|
+
if (!existsSync8(toolDir)) {
|
|
3364
|
+
console.error(chalk9.red(`Tool '${tool}' not found at ${toolDir}`));
|
|
3365
|
+
process.exit(1);
|
|
3366
|
+
}
|
|
3367
|
+
const scriptsDir = join10(toolDir, "scripts");
|
|
3368
|
+
if (!existsSync8(scriptsDir)) {
|
|
3369
|
+
console.error(chalk9.red(`No scripts directory in tool '${tool}'`));
|
|
3370
|
+
process.exit(1);
|
|
3371
|
+
}
|
|
3372
|
+
const extensions = [".ts", ".js", ".py"];
|
|
3373
|
+
let scriptPath = null;
|
|
3374
|
+
for (const ext of extensions) {
|
|
3375
|
+
const candidate = join10(scriptsDir, script + ext);
|
|
3376
|
+
if (existsSync8(candidate)) {
|
|
3377
|
+
scriptPath = candidate;
|
|
3378
|
+
break;
|
|
3379
|
+
}
|
|
3380
|
+
}
|
|
3381
|
+
if (!scriptPath) {
|
|
3382
|
+
console.error(chalk9.red(`Script '${script}' not found in ${scriptsDir}`));
|
|
3383
|
+
console.error(chalk9.gray(`Looked for: ${extensions.map((e) => script + e).join(", ")}`));
|
|
3384
|
+
process.exit(1);
|
|
3385
|
+
}
|
|
3386
|
+
const runtime = getRuntime(scriptPath);
|
|
3387
|
+
if (!runtime) {
|
|
3388
|
+
console.error(chalk9.red(`Unsupported script type: ${scriptPath}`));
|
|
3389
|
+
process.exit(1);
|
|
3390
|
+
}
|
|
3391
|
+
const fullArgs = [...runtime.args, ...args];
|
|
3392
|
+
const child = spawn(runtime.cmd, fullArgs, {
|
|
3393
|
+
stdio: "inherit",
|
|
3394
|
+
cwd: process.cwd()
|
|
3395
|
+
});
|
|
3396
|
+
child.on("error", (err) => {
|
|
3397
|
+
console.error(chalk9.red(`Failed to execute tool: ${err.message}`));
|
|
3398
|
+
process.exit(1);
|
|
3399
|
+
});
|
|
3400
|
+
child.on("close", (code) => {
|
|
3401
|
+
process.exit(code ?? 0);
|
|
3402
|
+
});
|
|
3403
|
+
}
|
|
3404
|
+
|
|
3192
3405
|
// src/bin/droid.ts
|
|
3193
3406
|
var version = getVersion();
|
|
3194
3407
|
program.name("droid").description("Droid, teaching your AI new tricks").version(version);
|
|
3195
3408
|
program.command("setup").description("Interactive wizard for global configuration").action(setupCommand);
|
|
3196
|
-
program.command("config").description("View or edit configuration").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);
|
|
3409
|
+
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);
|
|
3197
3410
|
program.command("tools").description("Browse and manage available tools").action(skillsCommand);
|
|
3198
3411
|
program.command("install <tool>").description("Install a tool and run its setup wizard").action(installCommand);
|
|
3199
3412
|
program.command("uninstall <tool>").description("Uninstall a tool").action(uninstallCommand);
|
|
3200
3413
|
program.command("update").description("Update droid and installed tools").option("--tools", "Only update tools").option("--cli", "Only update the CLI").argument("[tool]", "Update a specific tool").action(updateCommand);
|
|
3201
3414
|
program.command("tui").description("Launch interactive TUI dashboard").action(tuiCommand);
|
|
3415
|
+
program.command("exec <tool> <script>").description("Execute a tool script").argument("[args...]", "Arguments to pass to the script").allowUnknownOption().action(execCommand);
|
|
3202
3416
|
if (process.argv.length === 2) {
|
|
3203
3417
|
tuiCommand();
|
|
3204
3418
|
} else {
|