@orderful/droid 0.27.2 → 0.27.4
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 +37 -0
- package/dist/bin/droid.js +63 -18
- package/dist/index.js +55 -2
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/migrations.d.ts.map +1 -1
- package/dist/lib/tools.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/lib/config.ts +25 -8
- package/src/lib/migrations.ts +88 -7
- package/src/lib/tools.ts +1 -16
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
# @orderful/droid
|
|
2
2
|
|
|
3
|
+
## 0.27.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`c5bd82e`](https://github.com/Orderful/droid/commit/c5bd82e96202bd13fa71e57e45b5b2039ad95e6b) Thanks [@frytyler](https://github.com/frytyler)! - Add filesystem sync migration to fix untracked installations
|
|
8
|
+
|
|
9
|
+
**New migration (v0.27.4):**
|
|
10
|
+
|
|
11
|
+
Scans installed skills on the filesystem and adds any that aren't tracked in config. This is a one-time cleanup to fix inconsistencies from the v0.27.x migration series.
|
|
12
|
+
|
|
13
|
+
**What it does:**
|
|
14
|
+
- Scans `~/.claude/skills/` and `~/.config/opencode/skills/`
|
|
15
|
+
- Identifies installed skills missing from config
|
|
16
|
+
- Adds them with correct versions from bundled tool manifests
|
|
17
|
+
- Only processes known droid tool skills (ignores custom directories)
|
|
18
|
+
|
|
19
|
+
**Impact:**
|
|
20
|
+
|
|
21
|
+
Tools that were physically installed but not tracked (like `brain` and `comments`) will now show as properly installed with checkmarks in the TUI.
|
|
22
|
+
|
|
23
|
+
## 0.27.3
|
|
24
|
+
|
|
25
|
+
### Patch Changes
|
|
26
|
+
|
|
27
|
+
- [#152](https://github.com/Orderful/droid/pull/152) [`8bd3a4f`](https://github.com/Orderful/droid/commit/8bd3a4f4c6ef1352ed683be584693124a202f35a) Thanks [@frytyler](https://github.com/frytyler)! - Fix config skill name migration actually persisting changes to disk
|
|
28
|
+
|
|
29
|
+
**Bug fixes:**
|
|
30
|
+
- **Per-platform change tracking**: Migration now uses a `platformChanged` flag to track changes independently for each platform, ensuring all platform configs are properly saved
|
|
31
|
+
- **Prevent config overwrites**: `runPackageMigrations` now reloads config before saving the version marker, preventing stale data from overwriting migration changes
|
|
32
|
+
- **Remove conflicting legacy code**: Deleted v0.18.0 migration fallback that was actively undoing the config renaming by deleting newly-migrated unprefixed entries
|
|
33
|
+
|
|
34
|
+
**Impact:**
|
|
35
|
+
|
|
36
|
+
The v0.27.2 config migration now successfully renames tool entries (e.g. `droid-codex` → `codex`) and persists changes to `~/.droid/config.yaml`. Tools will correctly show as installed in the TUI after upgrade.
|
|
37
|
+
|
|
38
|
+
This completes the fix for tools showing as "not installed" after upgrading to v0.27.x.
|
|
39
|
+
|
|
3
40
|
## 0.27.2
|
|
4
41
|
|
|
5
42
|
### Patch Changes
|
package/dist/bin/droid.js
CHANGED
|
@@ -352,16 +352,6 @@ function getInstalledToolVersion(toolName) {
|
|
|
352
352
|
if (installedTools[skillName]) {
|
|
353
353
|
return installedTools[skillName].version;
|
|
354
354
|
}
|
|
355
|
-
if (skillName.startsWith("droid-")) {
|
|
356
|
-
const oldSkillName = skillName.replace(/^droid-/, "");
|
|
357
|
-
if (installedTools[oldSkillName]) {
|
|
358
|
-
const version2 = installedTools[oldSkillName].version;
|
|
359
|
-
delete installedTools[oldSkillName];
|
|
360
|
-
setPlatformTools(config, installedTools);
|
|
361
|
-
saveConfig(config);
|
|
362
|
-
return version2;
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
355
|
}
|
|
366
356
|
return null;
|
|
367
357
|
}
|
|
@@ -628,6 +618,7 @@ function createConfigSkillNameMigration(version2) {
|
|
|
628
618
|
config.platform = platformKey;
|
|
629
619
|
const trackedTools = getPlatformTools(config);
|
|
630
620
|
const skillNames = Object.keys(trackedTools);
|
|
621
|
+
let platformChanged = false;
|
|
631
622
|
for (const skillName of skillNames) {
|
|
632
623
|
if (!skillName.startsWith("droid-") || skillName === "droid") {
|
|
633
624
|
continue;
|
|
@@ -636,10 +627,61 @@ function createConfigSkillNameMigration(version2) {
|
|
|
636
627
|
if (!trackedTools[unprefixedName]) {
|
|
637
628
|
trackedTools[unprefixedName] = trackedTools[skillName];
|
|
638
629
|
delete trackedTools[skillName];
|
|
630
|
+
platformChanged = true;
|
|
639
631
|
configChanged = true;
|
|
640
632
|
}
|
|
641
633
|
}
|
|
642
|
-
if (
|
|
634
|
+
if (platformChanged) {
|
|
635
|
+
setPlatformTools(config, trackedTools);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
config.platform = originalPlatform;
|
|
639
|
+
if (configChanged) {
|
|
640
|
+
saveConfig(config);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
function createFilesystemSyncMigration(version2) {
|
|
646
|
+
return {
|
|
647
|
+
version: version2,
|
|
648
|
+
description: "Sync config with actually installed skills on filesystem",
|
|
649
|
+
up: () => {
|
|
650
|
+
const config = loadConfig();
|
|
651
|
+
const originalPlatform = config.platform;
|
|
652
|
+
let configChanged = false;
|
|
653
|
+
for (const platformKey of ["claude-code" /* ClaudeCode */, "opencode" /* OpenCode */]) {
|
|
654
|
+
if (!config.platforms[platformKey]) continue;
|
|
655
|
+
const skillsPath = getSkillsPath(platformKey);
|
|
656
|
+
if (!existsSync4(skillsPath)) continue;
|
|
657
|
+
config.platform = platformKey;
|
|
658
|
+
const trackedTools = getPlatformTools(config);
|
|
659
|
+
let platformChanged = false;
|
|
660
|
+
const bundledTools = getBundledTools();
|
|
661
|
+
const allToolNames = new Set(
|
|
662
|
+
bundledTools.flatMap(
|
|
663
|
+
(tool) => tool.includes.skills.map((s) => s.name)
|
|
664
|
+
)
|
|
665
|
+
);
|
|
666
|
+
const installedDirs = readdirSync3(skillsPath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
667
|
+
for (const dirName of installedDirs) {
|
|
668
|
+
if (!allToolNames.has(dirName)) continue;
|
|
669
|
+
if (trackedTools[dirName]) continue;
|
|
670
|
+
let version3 = "0.0.0";
|
|
671
|
+
const matchingTool = bundledTools.find(
|
|
672
|
+
(tool) => tool.includes.skills.some((s) => s.name === dirName && s.required)
|
|
673
|
+
);
|
|
674
|
+
if (matchingTool) {
|
|
675
|
+
version3 = matchingTool.version;
|
|
676
|
+
}
|
|
677
|
+
trackedTools[dirName] = {
|
|
678
|
+
version: version3,
|
|
679
|
+
installed_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
680
|
+
};
|
|
681
|
+
platformChanged = true;
|
|
682
|
+
configChanged = true;
|
|
683
|
+
}
|
|
684
|
+
if (platformChanged) {
|
|
643
685
|
setPlatformTools(config, trackedTools);
|
|
644
686
|
}
|
|
645
687
|
}
|
|
@@ -652,7 +694,8 @@ function createConfigSkillNameMigration(version2) {
|
|
|
652
694
|
}
|
|
653
695
|
var PACKAGE_MIGRATIONS = [
|
|
654
696
|
createPlatformSyncMigration("0.25.0"),
|
|
655
|
-
createConfigSkillNameMigration("0.27.2")
|
|
697
|
+
createConfigSkillNameMigration("0.27.2"),
|
|
698
|
+
createFilesystemSyncMigration("0.27.4")
|
|
656
699
|
];
|
|
657
700
|
var TOOL_MIGRATIONS = {
|
|
658
701
|
brain: [createConfigDirMigration("droid-brain", "0.2.3")],
|
|
@@ -740,9 +783,10 @@ function runPackageMigrations(packageVersion) {
|
|
|
740
783
|
return afterFrom && beforeOrAtTo;
|
|
741
784
|
});
|
|
742
785
|
if (pendingMigrations.length === 0) {
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
786
|
+
const freshConfig = loadConfig();
|
|
787
|
+
freshConfig.migrations = freshConfig.migrations || {};
|
|
788
|
+
freshConfig.migrations.package = packageVersion;
|
|
789
|
+
saveConfig(freshConfig);
|
|
746
790
|
return { success: true };
|
|
747
791
|
}
|
|
748
792
|
const configDir = getConfigDir();
|
|
@@ -765,9 +809,10 @@ function runPackageMigrations(packageVersion) {
|
|
|
765
809
|
};
|
|
766
810
|
}
|
|
767
811
|
}
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
812
|
+
const updatedConfig = loadConfig();
|
|
813
|
+
updatedConfig.migrations = updatedConfig.migrations || {};
|
|
814
|
+
updatedConfig.migrations.package = packageVersion;
|
|
815
|
+
saveConfig(updatedConfig);
|
|
771
816
|
return { success: true };
|
|
772
817
|
}
|
|
773
818
|
|
package/dist/index.js
CHANGED
|
@@ -591,6 +591,7 @@ function createConfigSkillNameMigration(version) {
|
|
|
591
591
|
config.platform = platformKey;
|
|
592
592
|
const trackedTools = getPlatformTools(config);
|
|
593
593
|
const skillNames = Object.keys(trackedTools);
|
|
594
|
+
let platformChanged = false;
|
|
594
595
|
for (const skillName of skillNames) {
|
|
595
596
|
if (!skillName.startsWith("droid-") || skillName === "droid") {
|
|
596
597
|
continue;
|
|
@@ -599,10 +600,61 @@ function createConfigSkillNameMigration(version) {
|
|
|
599
600
|
if (!trackedTools[unprefixedName]) {
|
|
600
601
|
trackedTools[unprefixedName] = trackedTools[skillName];
|
|
601
602
|
delete trackedTools[skillName];
|
|
603
|
+
platformChanged = true;
|
|
602
604
|
configChanged = true;
|
|
603
605
|
}
|
|
604
606
|
}
|
|
605
|
-
if (
|
|
607
|
+
if (platformChanged) {
|
|
608
|
+
setPlatformTools(config, trackedTools);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
config.platform = originalPlatform;
|
|
612
|
+
if (configChanged) {
|
|
613
|
+
saveConfig(config);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
function createFilesystemSyncMigration(version) {
|
|
619
|
+
return {
|
|
620
|
+
version,
|
|
621
|
+
description: "Sync config with actually installed skills on filesystem",
|
|
622
|
+
up: () => {
|
|
623
|
+
const config = loadConfig();
|
|
624
|
+
const originalPlatform = config.platform;
|
|
625
|
+
let configChanged = false;
|
|
626
|
+
for (const platformKey of ["claude-code" /* ClaudeCode */, "opencode" /* OpenCode */]) {
|
|
627
|
+
if (!config.platforms[platformKey]) continue;
|
|
628
|
+
const skillsPath = getSkillsPath(platformKey);
|
|
629
|
+
if (!existsSync4(skillsPath)) continue;
|
|
630
|
+
config.platform = platformKey;
|
|
631
|
+
const trackedTools = getPlatformTools(config);
|
|
632
|
+
let platformChanged = false;
|
|
633
|
+
const bundledTools = getBundledTools();
|
|
634
|
+
const allToolNames = new Set(
|
|
635
|
+
bundledTools.flatMap(
|
|
636
|
+
(tool) => tool.includes.skills.map((s) => s.name)
|
|
637
|
+
)
|
|
638
|
+
);
|
|
639
|
+
const installedDirs = readdirSync3(skillsPath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
640
|
+
for (const dirName of installedDirs) {
|
|
641
|
+
if (!allToolNames.has(dirName)) continue;
|
|
642
|
+
if (trackedTools[dirName]) continue;
|
|
643
|
+
let version2 = "0.0.0";
|
|
644
|
+
const matchingTool = bundledTools.find(
|
|
645
|
+
(tool) => tool.includes.skills.some((s) => s.name === dirName && s.required)
|
|
646
|
+
);
|
|
647
|
+
if (matchingTool) {
|
|
648
|
+
version2 = matchingTool.version;
|
|
649
|
+
}
|
|
650
|
+
trackedTools[dirName] = {
|
|
651
|
+
version: version2,
|
|
652
|
+
installed_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
653
|
+
};
|
|
654
|
+
platformChanged = true;
|
|
655
|
+
configChanged = true;
|
|
656
|
+
}
|
|
657
|
+
if (platformChanged) {
|
|
606
658
|
setPlatformTools(config, trackedTools);
|
|
607
659
|
}
|
|
608
660
|
}
|
|
@@ -615,7 +667,8 @@ function createConfigSkillNameMigration(version) {
|
|
|
615
667
|
}
|
|
616
668
|
var PACKAGE_MIGRATIONS = [
|
|
617
669
|
createPlatformSyncMigration("0.25.0"),
|
|
618
|
-
createConfigSkillNameMigration("0.27.2")
|
|
670
|
+
createConfigSkillNameMigration("0.27.2"),
|
|
671
|
+
createFilesystemSyncMigration("0.27.4")
|
|
619
672
|
];
|
|
620
673
|
var TOOL_MIGRATIONS = {
|
|
621
674
|
brain: [createConfigDirMigration("droid-brain", "0.2.3")],
|
package/dist/lib/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAIA,OAAO,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,WAAW,EAEhB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACtB,MAAM,SAAS,CAAC;AAmDjB;;GAEG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAItC;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAEtC;AAED;;;GAGG;AACH,wBAAgB,UAAU,IAAI,WAAW,CA4BxC;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAKpD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAanD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAiBhE;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAWD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAG/D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,CAapE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,cAAc,GACxB,IAAI,CAWN;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,gBAAgB,CAMtD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAQ5E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../../src/lib/migrations.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,KAAK,SAAS,EAIf,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../../src/lib/migrations.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,KAAK,SAAS,EAIf,MAAM,SAAS,CAAC;AA8SjB;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,CAE/D;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAc/D;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,IAAI,CAmBN;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CA2CtC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,gBAAgB,EAAE,MAAM,GACvB;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAStC;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,cAAc,EAAE,MAAM,GAAG;IAC5D,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAyDA"}
|
package/dist/lib/tools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/lib/tools.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,KAAK,YAAY,
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/lib/tools.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,KAAK,YAAY,EAGlB,MAAM,SAAS,CAAC;AAMjB;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAyBrE;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,YAAY,EAAE,CAmBhD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAczD;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAmBvE;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,CAuBpE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,cAAc,EAAE,CA2BtD"}
|
package/package.json
CHANGED
package/src/lib/config.ts
CHANGED
|
@@ -2,14 +2,21 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
|
2
2
|
import { homedir } from 'os';
|
|
3
3
|
import { join } from 'path';
|
|
4
4
|
import YAML from 'yaml';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
Platform,
|
|
7
|
+
BuiltInOutput,
|
|
8
|
+
type DroidConfig,
|
|
9
|
+
type LegacyDroidConfig,
|
|
10
|
+
type SkillOverrides,
|
|
11
|
+
type AutoUpdateConfig,
|
|
12
|
+
} from './types';
|
|
6
13
|
|
|
7
14
|
const CONFIG_DIR = join(homedir(), '.droid');
|
|
8
15
|
const CONFIG_FILE = join(CONFIG_DIR, 'config.yaml');
|
|
9
16
|
|
|
10
17
|
const DEFAULT_AUTO_UPDATE: AutoUpdateConfig = {
|
|
11
|
-
app: false,
|
|
12
|
-
tools: true,
|
|
18
|
+
app: false, // Opt-in: user must enable
|
|
19
|
+
tools: true, // Opt-out: enabled by default (tools only update when app updates)
|
|
13
20
|
};
|
|
14
21
|
|
|
15
22
|
const DEFAULT_CONFIG: DroidConfig = {
|
|
@@ -25,14 +32,17 @@ const DEFAULT_CONFIG: DroidConfig = {
|
|
|
25
32
|
* v1: ai_tool + skills flat
|
|
26
33
|
* v2: platform + platforms map with per-platform tools
|
|
27
34
|
*/
|
|
28
|
-
function migrateConfig(
|
|
35
|
+
function migrateConfig(
|
|
36
|
+
config: Partial<DroidConfig> & Partial<LegacyDroidConfig>,
|
|
37
|
+
): DroidConfig {
|
|
29
38
|
// Check if this is a legacy config (has ai_tool, no platform)
|
|
30
39
|
if ('ai_tool' in config && !('platform' in config)) {
|
|
31
40
|
const legacyConfig = config as LegacyDroidConfig;
|
|
32
41
|
return {
|
|
33
42
|
platform: legacyConfig.ai_tool,
|
|
34
43
|
user_mention: legacyConfig.user_mention ?? DEFAULT_CONFIG.user_mention,
|
|
35
|
-
output_preference:
|
|
44
|
+
output_preference:
|
|
45
|
+
legacyConfig.output_preference ?? DEFAULT_CONFIG.output_preference,
|
|
36
46
|
git_username: legacyConfig.git_username ?? DEFAULT_CONFIG.git_username,
|
|
37
47
|
platforms: {
|
|
38
48
|
[legacyConfig.ai_tool]: {
|
|
@@ -79,7 +89,8 @@ export function loadConfig(): DroidConfig {
|
|
|
79
89
|
|
|
80
90
|
try {
|
|
81
91
|
const content = readFileSync(CONFIG_FILE, 'utf-8');
|
|
82
|
-
const rawConfig = YAML.parse(content) as Partial<DroidConfig> &
|
|
92
|
+
const rawConfig = YAML.parse(content) as Partial<DroidConfig> &
|
|
93
|
+
Partial<LegacyDroidConfig>;
|
|
83
94
|
|
|
84
95
|
// Check if migration is needed
|
|
85
96
|
// TODO: Remove after v0.14.0 (target: late Jan 2025)
|
|
@@ -133,7 +144,10 @@ export function getConfigValue(key: string): unknown {
|
|
|
133
144
|
export function setConfigValue(key: string, value: unknown): void {
|
|
134
145
|
const config = loadConfig();
|
|
135
146
|
const keys = key.split('.');
|
|
136
|
-
let current: Record<string, unknown> = config as unknown as Record<
|
|
147
|
+
let current: Record<string, unknown> = config as unknown as Record<
|
|
148
|
+
string,
|
|
149
|
+
unknown
|
|
150
|
+
>;
|
|
137
151
|
|
|
138
152
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
139
153
|
if (current[keys[i]] === undefined) {
|
|
@@ -198,7 +212,10 @@ export function loadSkillOverrides(skillName: string): SkillOverrides {
|
|
|
198
212
|
/**
|
|
199
213
|
* Save skill-specific overrides
|
|
200
214
|
*/
|
|
201
|
-
export function saveSkillOverrides(
|
|
215
|
+
export function saveSkillOverrides(
|
|
216
|
+
skillName: string,
|
|
217
|
+
overrides: SkillOverrides,
|
|
218
|
+
): void {
|
|
202
219
|
const normalizedName = normalizeSkillNameForConfig(skillName);
|
|
203
220
|
const overridesPath = getSkillOverridesPath(skillName);
|
|
204
221
|
const skillDir = join(CONFIG_DIR, 'skills', normalizedName);
|
package/src/lib/migrations.ts
CHANGED
|
@@ -179,6 +179,7 @@ function createConfigSkillNameMigration(version: string): Migration {
|
|
|
179
179
|
config.platform = platformKey;
|
|
180
180
|
const trackedTools = getPlatformTools(config);
|
|
181
181
|
const skillNames = Object.keys(trackedTools);
|
|
182
|
+
let platformChanged = false;
|
|
182
183
|
|
|
183
184
|
for (const skillName of skillNames) {
|
|
184
185
|
// Skip if already unprefixed or is the special 'droid' tool
|
|
@@ -192,11 +193,86 @@ function createConfigSkillNameMigration(version: string): Migration {
|
|
|
192
193
|
if (!trackedTools[unprefixedName]) {
|
|
193
194
|
trackedTools[unprefixedName] = trackedTools[skillName];
|
|
194
195
|
delete trackedTools[skillName];
|
|
196
|
+
platformChanged = true;
|
|
195
197
|
configChanged = true;
|
|
196
198
|
}
|
|
197
199
|
}
|
|
198
200
|
|
|
199
|
-
if (
|
|
201
|
+
if (platformChanged) {
|
|
202
|
+
setPlatformTools(config, trackedTools);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
config.platform = originalPlatform;
|
|
207
|
+
if (configChanged) {
|
|
208
|
+
saveConfig(config);
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Sync config with filesystem - add any installed skills that aren't tracked
|
|
216
|
+
* This is a one-time cleanup migration to fix config inconsistencies from v0.27.x
|
|
217
|
+
*/
|
|
218
|
+
function createFilesystemSyncMigration(version: string): Migration {
|
|
219
|
+
return {
|
|
220
|
+
version,
|
|
221
|
+
description: 'Sync config with actually installed skills on filesystem',
|
|
222
|
+
up: () => {
|
|
223
|
+
const config = loadConfig();
|
|
224
|
+
const originalPlatform = config.platform;
|
|
225
|
+
let configChanged = false;
|
|
226
|
+
|
|
227
|
+
// Check both platforms
|
|
228
|
+
for (const platformKey of [Platform.ClaudeCode, Platform.OpenCode]) {
|
|
229
|
+
if (!config.platforms[platformKey]) continue;
|
|
230
|
+
|
|
231
|
+
const skillsPath = getSkillsPath(platformKey);
|
|
232
|
+
if (!existsSync(skillsPath)) continue;
|
|
233
|
+
|
|
234
|
+
config.platform = platformKey;
|
|
235
|
+
const trackedTools = getPlatformTools(config);
|
|
236
|
+
let platformChanged = false;
|
|
237
|
+
|
|
238
|
+
// Get all tool names from manifests
|
|
239
|
+
const bundledTools = getBundledTools();
|
|
240
|
+
const allToolNames = new Set(
|
|
241
|
+
bundledTools.flatMap((tool) =>
|
|
242
|
+
tool.includes.skills.map((s) => s.name),
|
|
243
|
+
),
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
// Scan filesystem for installed skills
|
|
247
|
+
const installedDirs = readdirSync(skillsPath, { withFileTypes: true })
|
|
248
|
+
.filter((dirent) => dirent.isDirectory())
|
|
249
|
+
.map((dirent) => dirent.name);
|
|
250
|
+
|
|
251
|
+
for (const dirName of installedDirs) {
|
|
252
|
+
// Skip if not a known tool skill
|
|
253
|
+
if (!allToolNames.has(dirName)) continue;
|
|
254
|
+
|
|
255
|
+
// Skip if already tracked
|
|
256
|
+
if (trackedTools[dirName]) continue;
|
|
257
|
+
|
|
258
|
+
// Try to get version from bundled tool
|
|
259
|
+
let version = '0.0.0';
|
|
260
|
+
const matchingTool = bundledTools.find((tool) =>
|
|
261
|
+
tool.includes.skills.some((s) => s.name === dirName && s.required),
|
|
262
|
+
);
|
|
263
|
+
if (matchingTool) {
|
|
264
|
+
version = matchingTool.version;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
trackedTools[dirName] = {
|
|
268
|
+
version,
|
|
269
|
+
installed_at: new Date().toISOString(),
|
|
270
|
+
};
|
|
271
|
+
platformChanged = true;
|
|
272
|
+
configChanged = true;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (platformChanged) {
|
|
200
276
|
setPlatformTools(config, trackedTools);
|
|
201
277
|
}
|
|
202
278
|
}
|
|
@@ -218,6 +294,7 @@ function createConfigSkillNameMigration(version: string): Migration {
|
|
|
218
294
|
const PACKAGE_MIGRATIONS: Migration[] = [
|
|
219
295
|
createPlatformSyncMigration('0.25.0'),
|
|
220
296
|
createConfigSkillNameMigration('0.27.2'),
|
|
297
|
+
createFilesystemSyncMigration('0.27.4'),
|
|
221
298
|
];
|
|
222
299
|
|
|
223
300
|
/**
|
|
@@ -387,9 +464,11 @@ export function runPackageMigrations(packageVersion: string): {
|
|
|
387
464
|
|
|
388
465
|
if (pendingMigrations.length === 0) {
|
|
389
466
|
// No migrations to run, but still update the version marker
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
467
|
+
// Reload config in case it was modified elsewhere
|
|
468
|
+
const freshConfig = loadConfig();
|
|
469
|
+
freshConfig.migrations = freshConfig.migrations || {};
|
|
470
|
+
freshConfig.migrations.package = packageVersion;
|
|
471
|
+
saveConfig(freshConfig);
|
|
393
472
|
return { success: true };
|
|
394
473
|
}
|
|
395
474
|
|
|
@@ -418,8 +497,10 @@ export function runPackageMigrations(packageVersion: string): {
|
|
|
418
497
|
}
|
|
419
498
|
|
|
420
499
|
// All migrations succeeded, update version marker
|
|
421
|
-
config
|
|
422
|
-
|
|
423
|
-
|
|
500
|
+
// Reload config in case migrations modified it
|
|
501
|
+
const updatedConfig = loadConfig();
|
|
502
|
+
updatedConfig.migrations = updatedConfig.migrations || {};
|
|
503
|
+
updatedConfig.migrations.package = packageVersion;
|
|
504
|
+
saveConfig(updatedConfig);
|
|
424
505
|
return { success: true };
|
|
425
506
|
}
|
package/src/lib/tools.ts
CHANGED
|
@@ -2,12 +2,11 @@ import { existsSync, readdirSync, readFileSync } from 'fs';
|
|
|
2
2
|
import { join, dirname } from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import YAML from 'yaml';
|
|
5
|
-
import { loadConfig
|
|
5
|
+
import { loadConfig } from './config';
|
|
6
6
|
import {
|
|
7
7
|
type ToolManifest,
|
|
8
8
|
type ToolIncludes,
|
|
9
9
|
getPlatformTools,
|
|
10
|
-
setPlatformTools,
|
|
11
10
|
} from './types';
|
|
12
11
|
import { compareSemver } from './version';
|
|
13
12
|
|
|
@@ -113,20 +112,6 @@ export function getInstalledToolVersion(toolName: string): string | null {
|
|
|
113
112
|
if (installedTools[skillName]) {
|
|
114
113
|
return installedTools[skillName].version;
|
|
115
114
|
}
|
|
116
|
-
|
|
117
|
-
// Migration fallback (v0.18.0): Check for old skill name without droid- prefix
|
|
118
|
-
// This allows tools to show as "update available" rather than "not installed"
|
|
119
|
-
if (skillName.startsWith('droid-')) {
|
|
120
|
-
const oldSkillName = skillName.replace(/^droid-/, '');
|
|
121
|
-
if (installedTools[oldSkillName]) {
|
|
122
|
-
const version = installedTools[oldSkillName].version;
|
|
123
|
-
// Clean up stale config entry now that we've detected it
|
|
124
|
-
delete installedTools[oldSkillName];
|
|
125
|
-
setPlatformTools(config, installedTools);
|
|
126
|
-
saveConfig(config);
|
|
127
|
-
return version;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
115
|
}
|
|
131
116
|
|
|
132
117
|
return null;
|