@orderful/droid 0.18.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/dist/bin/droid.js +189 -82
- package/dist/index.js +175 -72
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/migrations.d.ts +30 -0
- package/dist/lib/migrations.d.ts.map +1 -0
- package/dist/lib/skill-config.d.ts.map +1 -1
- package/dist/lib/skills.d.ts.map +1 -1
- package/dist/lib/types.d.ts +10 -0
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/tools/brain/TOOL.yaml +1 -1
- package/dist/tools/coach/TOOL.yaml +1 -1
- package/dist/tools/codex/TOOL.yaml +32 -0
- package/dist/tools/codex/commands/codex.md +70 -0
- package/dist/tools/codex/skills/droid-codex/SKILL.md +266 -0
- package/dist/tools/codex/skills/droid-codex/references/creating.md +150 -0
- package/dist/tools/codex/skills/droid-codex/references/decisions.md +128 -0
- package/dist/tools/codex/skills/droid-codex/references/loading.md +163 -0
- package/dist/tools/codex/skills/droid-codex/references/topics.md +213 -0
- package/dist/tools/comments/TOOL.yaml +1 -1
- package/dist/tools/droid/skills/droid/SKILL.md +8 -0
- package/dist/tools/project/TOOL.yaml +1 -1
- package/package.json +1 -1
- package/src/lib/config.ts +13 -2
- package/src/lib/migrations.test.ts +163 -0
- package/src/lib/migrations.ts +182 -0
- package/src/lib/skill-config.ts +3 -1
- package/src/lib/skills.ts +10 -1
- package/src/lib/types.ts +11 -0
- package/src/tools/brain/TOOL.yaml +1 -1
- package/src/tools/coach/TOOL.yaml +1 -1
- package/src/tools/codex/TOOL.yaml +32 -0
- package/src/tools/codex/commands/codex.md +70 -0
- package/src/tools/codex/skills/droid-codex/SKILL.md +266 -0
- package/src/tools/codex/skills/droid-codex/references/creating.md +150 -0
- package/src/tools/codex/skills/droid-codex/references/decisions.md +128 -0
- package/src/tools/codex/skills/droid-codex/references/loading.md +163 -0
- package/src/tools/codex/skills/droid-codex/references/topics.md +213 -0
- package/src/tools/comments/TOOL.yaml +1 -1
- package/src/tools/droid/skills/droid/SKILL.md +8 -0
- package/src/tools/project/TOOL.yaml +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# @orderful/droid
|
|
2
2
|
|
|
3
|
+
## 0.20.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#109](https://github.com/Orderful/droid/pull/109) [`1014243`](https://github.com/Orderful/droid/commit/10142438bcd75723027d12ec7bdc23f012643ee3) Thanks [@frytyler](https://github.com/frytyler)! - Add codex tool for shared organizational knowledge
|
|
8
|
+
|
|
9
|
+
New tool providing access to the orderful-codex repo containing PRDs, tech designs, patterns, and explored topics. Features include:
|
|
10
|
+
- Load project context with `/codex {name}`
|
|
11
|
+
- Search across all categories
|
|
12
|
+
- Capture decisions during implementation
|
|
13
|
+
- Add explored topics with freshness tracking
|
|
14
|
+
- Auto-generate CONTEXT.md from project artifacts
|
|
15
|
+
|
|
16
|
+
## 0.19.0
|
|
17
|
+
|
|
18
|
+
### Minor Changes
|
|
19
|
+
|
|
20
|
+
- [#104](https://github.com/Orderful/droid/pull/104) [`b6eaef4`](https://github.com/Orderful/droid/commit/b6eaef4fb3b003d41b5451e7efdba633a50b525e) Thanks [@frytyler](https://github.com/frytyler)! - Add tool migration system and fix skill config paths
|
|
21
|
+
- **Migration system**: Tools can now define migrations that run after install/update. Migrations are tracked per-tool in config and logged to `~/.droid/.migrations.log`.
|
|
22
|
+
- **Config path fix**: Skill overrides now save to unprefixed paths (`~/.droid/skills/brain/` not `~/.droid/skills/droid-brain/`), matching what SKILL.md tells Claude to read.
|
|
23
|
+
- **Automatic migration**: Existing users with prefixed config directories will have them automatically migrated on tool update.
|
|
24
|
+
|
|
25
|
+
Tool version bumps:
|
|
26
|
+
- brain: 0.2.2 → 0.2.3
|
|
27
|
+
- comments: 0.2.5 → 0.2.6
|
|
28
|
+
- project: 0.1.4 → 0.1.5
|
|
29
|
+
- coach: 0.1.2 → 0.1.3
|
|
30
|
+
|
|
3
31
|
## 0.18.0
|
|
4
32
|
|
|
5
33
|
### Minor Changes
|
package/dist/bin/droid.js
CHANGED
|
@@ -7,8 +7,8 @@ import { program } from "commander";
|
|
|
7
7
|
import inquirer from "inquirer";
|
|
8
8
|
import chalk2 from "chalk";
|
|
9
9
|
import { execSync as execSync2 } from "child_process";
|
|
10
|
-
import { existsSync as
|
|
11
|
-
import { join as
|
|
10
|
+
import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5 } from "fs";
|
|
11
|
+
import { join as join8 } from "path";
|
|
12
12
|
import { homedir as homedir3 } from "os";
|
|
13
13
|
|
|
14
14
|
// src/lib/config.ts
|
|
@@ -126,8 +126,15 @@ function setConfigValue(key, value) {
|
|
|
126
126
|
function getConfigPath() {
|
|
127
127
|
return CONFIG_FILE;
|
|
128
128
|
}
|
|
129
|
+
function getConfigDir() {
|
|
130
|
+
return CONFIG_DIR;
|
|
131
|
+
}
|
|
132
|
+
function normalizeSkillNameForConfig(skillName) {
|
|
133
|
+
return skillName.replace(/^droid-/, "");
|
|
134
|
+
}
|
|
129
135
|
function getSkillOverridesPath(skillName) {
|
|
130
|
-
|
|
136
|
+
const normalizedName = normalizeSkillNameForConfig(skillName);
|
|
137
|
+
return join(CONFIG_DIR, "skills", normalizedName, "overrides.yaml");
|
|
131
138
|
}
|
|
132
139
|
function loadSkillOverrides(skillName) {
|
|
133
140
|
const overridesPath = getSkillOverridesPath(skillName);
|
|
@@ -142,8 +149,9 @@ function loadSkillOverrides(skillName) {
|
|
|
142
149
|
}
|
|
143
150
|
}
|
|
144
151
|
function saveSkillOverrides(skillName, overrides) {
|
|
152
|
+
const normalizedName = normalizeSkillNameForConfig(skillName);
|
|
145
153
|
const overridesPath = getSkillOverridesPath(skillName);
|
|
146
|
-
const skillDir = join(CONFIG_DIR, "skills",
|
|
154
|
+
const skillDir = join(CONFIG_DIR, "skills", normalizedName);
|
|
147
155
|
if (!existsSync(skillDir)) {
|
|
148
156
|
mkdirSync(skillDir, { recursive: true });
|
|
149
157
|
}
|
|
@@ -168,8 +176,8 @@ function setAutoUpdateConfig(updates) {
|
|
|
168
176
|
}
|
|
169
177
|
|
|
170
178
|
// src/lib/skills.ts
|
|
171
|
-
import { existsSync as
|
|
172
|
-
import { join as
|
|
179
|
+
import { existsSync as existsSync5, readdirSync as readdirSync3, readFileSync as readFileSync5, mkdirSync as mkdirSync4, writeFileSync as writeFileSync3, rmSync as rmSync2 } from "fs";
|
|
180
|
+
import { join as join7, dirname as dirname5, basename } from "path";
|
|
173
181
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
174
182
|
import YAML4 from "yaml";
|
|
175
183
|
|
|
@@ -508,11 +516,104 @@ function uninstallAgent(agentName) {
|
|
|
508
516
|
}
|
|
509
517
|
}
|
|
510
518
|
|
|
519
|
+
// src/lib/migrations.ts
|
|
520
|
+
import { existsSync as existsSync4, appendFileSync, mkdirSync as mkdirSync3, renameSync, rmSync } from "fs";
|
|
521
|
+
import { join as join6, dirname as dirname4 } from "path";
|
|
522
|
+
var MIGRATIONS_LOG_FILE = ".migrations.log";
|
|
523
|
+
function getMigrationsLogPath() {
|
|
524
|
+
return join6(getConfigDir(), MIGRATIONS_LOG_FILE);
|
|
525
|
+
}
|
|
526
|
+
function logMigration(toolName, fromVersion, toVersion, status, error) {
|
|
527
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
528
|
+
const logEntry = error ? `${timestamp} ${toolName} ${fromVersion} \u2192 ${toVersion} ${status}: ${error}
|
|
529
|
+
` : `${timestamp} ${toolName} ${fromVersion} \u2192 ${toVersion} ${status}
|
|
530
|
+
`;
|
|
531
|
+
const logPath = getMigrationsLogPath();
|
|
532
|
+
const logDir = dirname4(logPath);
|
|
533
|
+
if (!existsSync4(logDir)) {
|
|
534
|
+
mkdirSync3(logDir, { recursive: true });
|
|
535
|
+
}
|
|
536
|
+
appendFileSync(logPath, logEntry);
|
|
537
|
+
}
|
|
538
|
+
function createConfigDirMigration(skillName, version2) {
|
|
539
|
+
const unprefixedName = skillName.replace(/^droid-/, "");
|
|
540
|
+
return {
|
|
541
|
+
version: version2,
|
|
542
|
+
description: `Move ${skillName} config to unprefixed location`,
|
|
543
|
+
up: (configDir) => {
|
|
544
|
+
const oldDir = join6(configDir, "skills", skillName);
|
|
545
|
+
const newDir = join6(configDir, "skills", unprefixedName);
|
|
546
|
+
if (existsSync4(oldDir) && !existsSync4(newDir)) {
|
|
547
|
+
const parentDir = dirname4(newDir);
|
|
548
|
+
if (!existsSync4(parentDir)) {
|
|
549
|
+
mkdirSync3(parentDir, { recursive: true });
|
|
550
|
+
}
|
|
551
|
+
renameSync(oldDir, newDir);
|
|
552
|
+
} else if (existsSync4(oldDir) && existsSync4(newDir)) {
|
|
553
|
+
rmSync(oldDir, { recursive: true });
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
var TOOL_MIGRATIONS = {
|
|
559
|
+
brain: [createConfigDirMigration("droid-brain", "0.2.3")],
|
|
560
|
+
comments: [createConfigDirMigration("droid-comments", "0.2.6")],
|
|
561
|
+
project: [createConfigDirMigration("droid-project", "0.1.5")],
|
|
562
|
+
coach: [createConfigDirMigration("droid-coach", "0.1.3")]
|
|
563
|
+
};
|
|
564
|
+
function getToolMigrations(toolName) {
|
|
565
|
+
return TOOL_MIGRATIONS[toolName] ?? [];
|
|
566
|
+
}
|
|
567
|
+
function getLastMigratedVersion(toolName) {
|
|
568
|
+
const config = loadConfig();
|
|
569
|
+
return config.migrations?.[toolName] ?? "0.0.0";
|
|
570
|
+
}
|
|
571
|
+
function setLastMigratedVersion(toolName, version2) {
|
|
572
|
+
const config = loadConfig();
|
|
573
|
+
if (!config.migrations) {
|
|
574
|
+
config.migrations = {};
|
|
575
|
+
}
|
|
576
|
+
config.migrations[toolName] = version2;
|
|
577
|
+
saveConfig(config);
|
|
578
|
+
}
|
|
579
|
+
function runMigrations(toolName, fromVersion, toVersion) {
|
|
580
|
+
const migrations = getToolMigrations(toolName);
|
|
581
|
+
const pendingMigrations = migrations.filter((m) => {
|
|
582
|
+
const afterFrom = compareSemver(m.version, fromVersion) > 0;
|
|
583
|
+
const beforeOrAtTo = compareSemver(m.version, toVersion) <= 0;
|
|
584
|
+
return afterFrom && beforeOrAtTo;
|
|
585
|
+
});
|
|
586
|
+
if (pendingMigrations.length === 0) {
|
|
587
|
+
setLastMigratedVersion(toolName, toVersion);
|
|
588
|
+
return { success: true };
|
|
589
|
+
}
|
|
590
|
+
const configDir = getConfigDir();
|
|
591
|
+
for (const migration of pendingMigrations) {
|
|
592
|
+
try {
|
|
593
|
+
migration.up(configDir);
|
|
594
|
+
logMigration(toolName, fromVersion, migration.version, "OK");
|
|
595
|
+
} catch (error) {
|
|
596
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
597
|
+
logMigration(toolName, fromVersion, migration.version, "FAILED", errorMessage);
|
|
598
|
+
return { success: false, error: `Migration ${migration.version} failed: ${errorMessage}` };
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
setLastMigratedVersion(toolName, toVersion);
|
|
602
|
+
return { success: true };
|
|
603
|
+
}
|
|
604
|
+
function runToolMigrations(toolName, installedVersion) {
|
|
605
|
+
const lastMigrated = getLastMigratedVersion(toolName);
|
|
606
|
+
if (compareSemver(installedVersion, lastMigrated) <= 0) {
|
|
607
|
+
return { success: true };
|
|
608
|
+
}
|
|
609
|
+
return runMigrations(toolName, lastMigrated, installedVersion);
|
|
610
|
+
}
|
|
611
|
+
|
|
511
612
|
// src/lib/skills.ts
|
|
512
613
|
var DROID_SKILLS_START = "<!-- droid-skills-start -->";
|
|
513
614
|
var DROID_SKILLS_END = "<!-- droid-skills-end -->";
|
|
514
|
-
var __dirname4 =
|
|
515
|
-
var BUNDLED_SKILLS_DIR =
|
|
615
|
+
var __dirname4 = dirname5(fileURLToPath4(import.meta.url));
|
|
616
|
+
var BUNDLED_SKILLS_DIR = join7(__dirname4, "../tools");
|
|
516
617
|
function getSkillsInstallPath(platform) {
|
|
517
618
|
return getSkillsPath(platform);
|
|
518
619
|
}
|
|
@@ -525,7 +626,7 @@ function getPlatformConfigPath(platform) {
|
|
|
525
626
|
function updatePlatformConfigSkills(platform, installedSkills) {
|
|
526
627
|
const configPath = getPlatformConfigPath(platform);
|
|
527
628
|
let content = "";
|
|
528
|
-
if (
|
|
629
|
+
if (existsSync5(configPath)) {
|
|
529
630
|
content = readFileSync5(configPath, "utf-8");
|
|
530
631
|
}
|
|
531
632
|
const skillLines = installedSkills.map((name) => {
|
|
@@ -544,9 +645,9 @@ ${DROID_SKILLS_END}` : "";
|
|
|
544
645
|
} else if (skillsSection) {
|
|
545
646
|
content = content.trim() + "\n\n" + skillsSection + "\n";
|
|
546
647
|
}
|
|
547
|
-
const configDir =
|
|
548
|
-
if (!
|
|
549
|
-
|
|
648
|
+
const configDir = dirname5(configPath);
|
|
649
|
+
if (!existsSync5(configDir)) {
|
|
650
|
+
mkdirSync4(configDir, { recursive: true });
|
|
550
651
|
}
|
|
551
652
|
writeFileSync3(configPath, content, "utf-8");
|
|
552
653
|
}
|
|
@@ -567,8 +668,8 @@ function parseSkillFrontmatter(content) {
|
|
|
567
668
|
}
|
|
568
669
|
}
|
|
569
670
|
function loadSkillManifest(skillDir) {
|
|
570
|
-
const skillMdPath =
|
|
571
|
-
if (!
|
|
671
|
+
const skillMdPath = join7(skillDir, "SKILL.md");
|
|
672
|
+
if (!existsSync5(skillMdPath)) {
|
|
572
673
|
return null;
|
|
573
674
|
}
|
|
574
675
|
const content = readFileSync5(skillMdPath, "utf-8");
|
|
@@ -576,7 +677,7 @@ function loadSkillManifest(skillDir) {
|
|
|
576
677
|
if (!frontmatter || !frontmatter.name) {
|
|
577
678
|
return null;
|
|
578
679
|
}
|
|
579
|
-
const toolDir =
|
|
680
|
+
const toolDir = dirname5(dirname5(skillDir));
|
|
580
681
|
const toolManifest = loadToolManifest(toolDir);
|
|
581
682
|
return {
|
|
582
683
|
name: frontmatter.name,
|
|
@@ -588,17 +689,17 @@ function loadSkillManifest(skillDir) {
|
|
|
588
689
|
};
|
|
589
690
|
}
|
|
590
691
|
function findSkillPath(skillName) {
|
|
591
|
-
if (!
|
|
692
|
+
if (!existsSync5(BUNDLED_SKILLS_DIR)) {
|
|
592
693
|
return null;
|
|
593
694
|
}
|
|
594
695
|
const toolDirs = readdirSync3(BUNDLED_SKILLS_DIR, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
595
696
|
for (const toolName of toolDirs) {
|
|
596
|
-
const skillsDir =
|
|
597
|
-
if (!
|
|
598
|
-
const skillDir =
|
|
599
|
-
if (
|
|
697
|
+
const skillsDir = join7(BUNDLED_SKILLS_DIR, toolName, "skills");
|
|
698
|
+
if (!existsSync5(skillsDir)) continue;
|
|
699
|
+
const skillDir = join7(skillsDir, skillName);
|
|
700
|
+
if (existsSync5(skillDir) && existsSync5(join7(skillDir, "SKILL.md"))) {
|
|
600
701
|
return {
|
|
601
|
-
toolDir:
|
|
702
|
+
toolDir: join7(BUNDLED_SKILLS_DIR, toolName),
|
|
602
703
|
skillDir
|
|
603
704
|
};
|
|
604
705
|
}
|
|
@@ -606,17 +707,17 @@ function findSkillPath(skillName) {
|
|
|
606
707
|
return null;
|
|
607
708
|
}
|
|
608
709
|
function getBundledSkills() {
|
|
609
|
-
if (!
|
|
710
|
+
if (!existsSync5(BUNDLED_SKILLS_DIR)) {
|
|
610
711
|
return [];
|
|
611
712
|
}
|
|
612
713
|
const toolDirs = readdirSync3(BUNDLED_SKILLS_DIR, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
613
714
|
const skills = [];
|
|
614
715
|
for (const toolName of toolDirs) {
|
|
615
|
-
const skillsDir =
|
|
616
|
-
if (!
|
|
716
|
+
const skillsDir = join7(BUNDLED_SKILLS_DIR, toolName, "skills");
|
|
717
|
+
if (!existsSync5(skillsDir)) continue;
|
|
617
718
|
const skillSubdirs = readdirSync3(skillsDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
618
719
|
for (const skillName of skillSubdirs) {
|
|
619
|
-
const manifest = loadSkillManifest(
|
|
720
|
+
const manifest = loadSkillManifest(join7(skillsDir, skillName));
|
|
620
721
|
if (manifest) {
|
|
621
722
|
skills.push(manifest);
|
|
622
723
|
}
|
|
@@ -693,15 +794,15 @@ function installSkill(skillName) {
|
|
|
693
794
|
}
|
|
694
795
|
}
|
|
695
796
|
const skillsPath = getSkillsInstallPath(config.platform);
|
|
696
|
-
const targetSkillDir =
|
|
797
|
+
const targetSkillDir = join7(skillsPath, skillName);
|
|
697
798
|
const commandsPath = getCommandsInstallPath(config.platform);
|
|
698
799
|
const tools = getPlatformTools(config);
|
|
699
800
|
if (skillName.startsWith("droid-")) {
|
|
700
801
|
const oldSkillName = skillName.replace(/^droid-/, "");
|
|
701
|
-
const oldSkillDir =
|
|
702
|
-
if (
|
|
802
|
+
const oldSkillDir = join7(skillsPath, oldSkillName);
|
|
803
|
+
if (existsSync5(oldSkillDir)) {
|
|
703
804
|
try {
|
|
704
|
-
|
|
805
|
+
rmSync2(oldSkillDir, { recursive: true });
|
|
705
806
|
} catch (error) {
|
|
706
807
|
console.warn(`Warning: Could not remove old skill directory ${oldSkillDir}: ${error}`);
|
|
707
808
|
}
|
|
@@ -712,14 +813,14 @@ function installSkill(skillName) {
|
|
|
712
813
|
saveConfig(config);
|
|
713
814
|
}
|
|
714
815
|
}
|
|
715
|
-
const commandsSource =
|
|
716
|
-
const agentsSource =
|
|
816
|
+
const commandsSource = join7(toolDir, "commands");
|
|
817
|
+
const agentsSource = join7(toolDir, "agents");
|
|
717
818
|
if (!tools[skillName]) {
|
|
718
|
-
if (
|
|
819
|
+
if (existsSync5(commandsSource)) {
|
|
719
820
|
const commandFiles = readdirSync3(commandsSource).filter((f) => f.endsWith(".md") && f.toLowerCase() !== "readme.md");
|
|
720
821
|
for (const file of commandFiles) {
|
|
721
|
-
const targetCommandPath =
|
|
722
|
-
if (
|
|
822
|
+
const targetCommandPath = join7(commandsPath, file);
|
|
823
|
+
if (existsSync5(targetCommandPath)) {
|
|
723
824
|
const commandName = file.replace(".md", "");
|
|
724
825
|
return {
|
|
725
826
|
success: false,
|
|
@@ -728,7 +829,7 @@ function installSkill(skillName) {
|
|
|
728
829
|
}
|
|
729
830
|
}
|
|
730
831
|
}
|
|
731
|
-
if (
|
|
832
|
+
if (existsSync5(agentsSource)) {
|
|
732
833
|
const agentDirs = readdirSync3(agentsSource, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
733
834
|
for (const agentName of agentDirs) {
|
|
734
835
|
if (isAgentInstalled(agentName)) {
|
|
@@ -740,49 +841,49 @@ function installSkill(skillName) {
|
|
|
740
841
|
}
|
|
741
842
|
}
|
|
742
843
|
}
|
|
743
|
-
if (!
|
|
744
|
-
|
|
844
|
+
if (!existsSync5(skillsPath)) {
|
|
845
|
+
mkdirSync4(skillsPath, { recursive: true });
|
|
745
846
|
}
|
|
746
|
-
const skillMdSource =
|
|
747
|
-
if (
|
|
748
|
-
if (!
|
|
749
|
-
|
|
847
|
+
const skillMdSource = join7(skillDir, "SKILL.md");
|
|
848
|
+
if (existsSync5(skillMdSource)) {
|
|
849
|
+
if (!existsSync5(targetSkillDir)) {
|
|
850
|
+
mkdirSync4(targetSkillDir, { recursive: true });
|
|
750
851
|
}
|
|
751
|
-
const skillMdTarget =
|
|
852
|
+
const skillMdTarget = join7(targetSkillDir, "SKILL.md");
|
|
752
853
|
const content = readFileSync5(skillMdSource, "utf-8");
|
|
753
854
|
writeFileSync3(skillMdTarget, content);
|
|
754
855
|
}
|
|
755
|
-
const referencesSource =
|
|
756
|
-
if (
|
|
757
|
-
const targetReferencesDir =
|
|
758
|
-
if (!
|
|
759
|
-
|
|
856
|
+
const referencesSource = join7(skillDir, "references");
|
|
857
|
+
if (existsSync5(referencesSource)) {
|
|
858
|
+
const targetReferencesDir = join7(targetSkillDir, "references");
|
|
859
|
+
if (!existsSync5(targetReferencesDir)) {
|
|
860
|
+
mkdirSync4(targetReferencesDir, { recursive: true });
|
|
760
861
|
}
|
|
761
862
|
const referenceFiles = readdirSync3(referencesSource).filter((f) => f.endsWith(".md"));
|
|
762
863
|
for (const file of referenceFiles) {
|
|
763
|
-
const sourcePath =
|
|
764
|
-
const targetPath =
|
|
864
|
+
const sourcePath = join7(referencesSource, file);
|
|
865
|
+
const targetPath = join7(targetReferencesDir, file);
|
|
765
866
|
const content = readFileSync5(sourcePath, "utf-8");
|
|
766
867
|
writeFileSync3(targetPath, content);
|
|
767
868
|
}
|
|
768
869
|
}
|
|
769
|
-
if (
|
|
770
|
-
if (!
|
|
771
|
-
|
|
870
|
+
if (existsSync5(commandsSource)) {
|
|
871
|
+
if (!existsSync5(commandsPath)) {
|
|
872
|
+
mkdirSync4(commandsPath, { recursive: true });
|
|
772
873
|
}
|
|
773
874
|
const commandFiles = readdirSync3(commandsSource).filter((f) => f.endsWith(".md") && f.toLowerCase() !== "readme.md");
|
|
774
875
|
for (const file of commandFiles) {
|
|
775
|
-
const sourcePath =
|
|
776
|
-
const targetPath =
|
|
876
|
+
const sourcePath = join7(commandsSource, file);
|
|
877
|
+
const targetPath = join7(commandsPath, file);
|
|
777
878
|
const content = readFileSync5(sourcePath, "utf-8");
|
|
778
879
|
writeFileSync3(targetPath, content);
|
|
779
880
|
}
|
|
780
881
|
}
|
|
781
882
|
const installedAgents = [];
|
|
782
|
-
if (
|
|
883
|
+
if (existsSync5(agentsSource)) {
|
|
783
884
|
const agentDirs = readdirSync3(agentsSource, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
784
885
|
for (const agentName of agentDirs) {
|
|
785
|
-
const agentDir =
|
|
886
|
+
const agentDir = join7(agentsSource, agentName);
|
|
786
887
|
const result = installAgentFromPath(agentDir, agentName);
|
|
787
888
|
if (result.success) {
|
|
788
889
|
installedAgents.push(agentName);
|
|
@@ -801,6 +902,11 @@ function installSkill(skillName) {
|
|
|
801
902
|
saveConfig(config);
|
|
802
903
|
const installedSkillNames = Object.keys(updatedTools);
|
|
803
904
|
updatePlatformConfigSkills(config.platform, installedSkillNames);
|
|
905
|
+
const toolName = basename(toolDir);
|
|
906
|
+
const migrationResult = runToolMigrations(toolName, manifest.version);
|
|
907
|
+
if (!migrationResult.success) {
|
|
908
|
+
console.warn(`Warning: Migration failed for ${toolName}: ${migrationResult.error}`);
|
|
909
|
+
}
|
|
804
910
|
return { success: true, message: `Installed ${skillName} v${manifest.version}` };
|
|
805
911
|
}
|
|
806
912
|
function uninstallSkill(skillName) {
|
|
@@ -810,19 +916,19 @@ function uninstallSkill(skillName) {
|
|
|
810
916
|
return { success: false, message: `Skill '${skillName}' is not installed` };
|
|
811
917
|
}
|
|
812
918
|
const skillsPath = getSkillsInstallPath(config.platform);
|
|
813
|
-
const skillDir =
|
|
814
|
-
if (
|
|
815
|
-
|
|
919
|
+
const skillDir = join7(skillsPath, skillName);
|
|
920
|
+
if (existsSync5(skillDir)) {
|
|
921
|
+
rmSync2(skillDir, { recursive: true });
|
|
816
922
|
}
|
|
817
923
|
const skillPath = findSkillPath(skillName);
|
|
818
924
|
const commandsPath = getCommandsInstallPath(config.platform);
|
|
819
|
-
const commandsSource = skillPath ?
|
|
820
|
-
if (commandsSource &&
|
|
925
|
+
const commandsSource = skillPath ? join7(skillPath.toolDir, "commands") : null;
|
|
926
|
+
if (commandsSource && existsSync5(commandsSource)) {
|
|
821
927
|
const commandFiles = readdirSync3(commandsSource).filter((f) => f.endsWith(".md") && f.toLowerCase() !== "readme.md");
|
|
822
928
|
for (const file of commandFiles) {
|
|
823
|
-
const commandPath =
|
|
824
|
-
if (
|
|
825
|
-
|
|
929
|
+
const commandPath = join7(commandsPath, file);
|
|
930
|
+
if (existsSync5(commandPath)) {
|
|
931
|
+
rmSync2(commandPath);
|
|
826
932
|
}
|
|
827
933
|
}
|
|
828
934
|
}
|
|
@@ -872,13 +978,13 @@ var OPENCODE_SKILLS_PLUGIN = "opencode-skills";
|
|
|
872
978
|
function configurePlatformPermissions(platform) {
|
|
873
979
|
const added = [];
|
|
874
980
|
if (platform === "claude-code" /* ClaudeCode */) {
|
|
875
|
-
const settingsPath =
|
|
876
|
-
const claudeDir =
|
|
877
|
-
if (!
|
|
878
|
-
|
|
981
|
+
const settingsPath = join8(homedir3(), ".claude", "settings.json");
|
|
982
|
+
const claudeDir = join8(homedir3(), ".claude");
|
|
983
|
+
if (!existsSync6(claudeDir)) {
|
|
984
|
+
mkdirSync5(claudeDir, { recursive: true });
|
|
879
985
|
}
|
|
880
986
|
let settings = {};
|
|
881
|
-
if (
|
|
987
|
+
if (existsSync6(settingsPath)) {
|
|
882
988
|
try {
|
|
883
989
|
settings = JSON.parse(readFileSync6(settingsPath, "utf-8"));
|
|
884
990
|
} catch {
|
|
@@ -909,13 +1015,13 @@ function configurePlatformPermissions(platform) {
|
|
|
909
1015
|
return { added, alreadyPresent: added.length === 0 };
|
|
910
1016
|
}
|
|
911
1017
|
if (platform === "opencode" /* OpenCode */) {
|
|
912
|
-
const globalConfigDir =
|
|
913
|
-
const globalConfigPath =
|
|
914
|
-
if (!
|
|
915
|
-
|
|
1018
|
+
const globalConfigDir = join8(homedir3(), ".config", "opencode");
|
|
1019
|
+
const globalConfigPath = join8(globalConfigDir, "opencode.json");
|
|
1020
|
+
if (!existsSync6(globalConfigDir)) {
|
|
1021
|
+
mkdirSync5(globalConfigDir, { recursive: true });
|
|
916
1022
|
}
|
|
917
1023
|
let config = {};
|
|
918
|
-
if (
|
|
1024
|
+
if (existsSync6(globalConfigPath)) {
|
|
919
1025
|
try {
|
|
920
1026
|
config = JSON.parse(readFileSync6(globalConfigPath, "utf-8"));
|
|
921
1027
|
} catch {
|
|
@@ -1180,8 +1286,9 @@ async function promptForSkillConfig(skillName, configSchema, askFirst = true) {
|
|
|
1180
1286
|
}
|
|
1181
1287
|
if (Object.keys(overrides).length > 0) {
|
|
1182
1288
|
saveSkillOverrides(skillName, overrides);
|
|
1289
|
+
const displayName = skillName.replace(/^droid-/, "");
|
|
1183
1290
|
console.log(chalk4.green(`
|
|
1184
|
-
\u2713 Configuration saved to ~/.droid/skills/${
|
|
1291
|
+
\u2713 Configuration saved to ~/.droid/skills/${displayName}/overrides.yaml`));
|
|
1185
1292
|
} else {
|
|
1186
1293
|
console.log(chalk4.gray("\nNo custom configuration set (using defaults)."));
|
|
1187
1294
|
}
|
|
@@ -2240,8 +2347,8 @@ function ReadmeViewer({ title, content, onClose }) {
|
|
|
2240
2347
|
// src/commands/tui/views/ToolExplorer.tsx
|
|
2241
2348
|
import { Box as Box10, Text as Text11, useInput as useInput5 } from "ink";
|
|
2242
2349
|
import { useState as useState5, useMemo as useMemo3 } from "react";
|
|
2243
|
-
import { existsSync as
|
|
2244
|
-
import { join as
|
|
2350
|
+
import { existsSync as existsSync7, readFileSync as readFileSync7 } from "fs";
|
|
2351
|
+
import { join as join9 } from "path";
|
|
2245
2352
|
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2246
2353
|
function ToolExplorer({ tool, onViewSource, onClose }) {
|
|
2247
2354
|
const [selectedIndex, setSelectedIndex] = useState5(0);
|
|
@@ -2252,21 +2359,21 @@ function ToolExplorer({ tool, onViewSource, onClose }) {
|
|
|
2252
2359
|
result.push({
|
|
2253
2360
|
type: "skill",
|
|
2254
2361
|
name: skill.name,
|
|
2255
|
-
path:
|
|
2362
|
+
path: join9(toolDir, tool.name, "skills", skill.name, "SKILL.md")
|
|
2256
2363
|
});
|
|
2257
2364
|
}
|
|
2258
2365
|
for (const cmd of tool.includes.commands) {
|
|
2259
2366
|
result.push({
|
|
2260
2367
|
type: "command",
|
|
2261
2368
|
name: `/${cmd}`,
|
|
2262
|
-
path:
|
|
2369
|
+
path: join9(toolDir, tool.name, "commands", `${cmd}.md`)
|
|
2263
2370
|
});
|
|
2264
2371
|
}
|
|
2265
2372
|
for (const agent of tool.includes.agents) {
|
|
2266
2373
|
result.push({
|
|
2267
2374
|
type: "agent",
|
|
2268
2375
|
name: agent,
|
|
2269
|
-
path:
|
|
2376
|
+
path: join9(toolDir, tool.name, "agents", agent, "AGENT.md")
|
|
2270
2377
|
});
|
|
2271
2378
|
}
|
|
2272
2379
|
return result;
|
|
@@ -2284,12 +2391,12 @@ function ToolExplorer({ tool, onViewSource, onClose }) {
|
|
|
2284
2391
|
}
|
|
2285
2392
|
if (key.return && items.length > 0) {
|
|
2286
2393
|
const item = items[selectedIndex];
|
|
2287
|
-
if (
|
|
2394
|
+
if (existsSync7(item.path)) {
|
|
2288
2395
|
const content = readFileSync7(item.path, "utf-8");
|
|
2289
2396
|
onViewSource(`${tool.name} / ${item.name}`, content);
|
|
2290
2397
|
} else {
|
|
2291
2398
|
const yamlPath = item.path.replace(".md", ".yaml");
|
|
2292
|
-
if (
|
|
2399
|
+
if (existsSync7(yamlPath)) {
|
|
2293
2400
|
const content = readFileSync7(yamlPath, "utf-8");
|
|
2294
2401
|
onViewSource(`${tool.name} / ${item.name}`, content);
|
|
2295
2402
|
}
|