@orderful/droid 0.15.0 → 0.16.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.
- package/.claude/CLAUDE.md +18 -40
- package/AGENTS.md +75 -0
- package/CHANGELOG.md +25 -0
- package/dist/bin/droid.js +3064 -54
- package/dist/commands/setup.d.ts +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/tui/components/Badge.d.ts +13 -0
- package/dist/commands/tui/components/Badge.d.ts.map +1 -0
- package/dist/commands/tui/components/Markdown.d.ts +5 -0
- package/dist/commands/tui/components/Markdown.d.ts.map +1 -0
- package/dist/commands/tui/components/SettingsDetails.d.ts +5 -0
- package/dist/commands/tui/components/SettingsDetails.d.ts.map +1 -0
- package/dist/commands/tui/components/TabBar.d.ts +10 -0
- package/dist/commands/tui/components/TabBar.d.ts.map +1 -0
- package/dist/commands/tui/components/ToolDetails.d.ts +8 -0
- package/dist/commands/tui/components/ToolDetails.d.ts.map +1 -0
- package/dist/commands/tui/components/ToolItem.d.ts +9 -0
- package/dist/commands/tui/components/ToolItem.d.ts.map +1 -0
- package/dist/commands/tui/constants.d.ts +16 -0
- package/dist/commands/tui/constants.d.ts.map +1 -0
- package/dist/commands/tui/hooks/useAppUpdate.d.ts +13 -0
- package/dist/commands/tui/hooks/useAppUpdate.d.ts.map +1 -0
- package/dist/commands/tui/hooks/useToolUpdates.d.ts +22 -0
- package/dist/commands/tui/hooks/useToolUpdates.d.ts.map +1 -0
- package/dist/commands/tui/types.d.ts +5 -0
- package/dist/commands/tui/types.d.ts.map +1 -0
- package/dist/commands/tui/views/ReadmeViewer.d.ts +7 -0
- package/dist/commands/tui/views/ReadmeViewer.d.ts.map +1 -0
- package/dist/commands/tui/views/SetupScreen.d.ts +8 -0
- package/dist/commands/tui/views/SetupScreen.d.ts.map +1 -0
- package/dist/commands/tui/views/SkillConfigScreen.d.ts +8 -0
- package/dist/commands/tui/views/SkillConfigScreen.d.ts.map +1 -0
- package/dist/commands/tui/views/ToolExplorer.d.ts +8 -0
- package/dist/commands/tui/views/ToolExplorer.d.ts.map +1 -0
- package/dist/commands/tui/views/ToolUpdatePrompt.d.ts +10 -0
- package/dist/commands/tui/views/ToolUpdatePrompt.d.ts.map +1 -0
- package/dist/commands/tui/views/WelcomeScreen.d.ts +11 -0
- package/dist/commands/tui/views/WelcomeScreen.d.ts.map +1 -0
- package/dist/commands/tui.d.ts.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +952 -6
- package/dist/lib/agents.d.ts +1 -1
- package/dist/lib/agents.d.ts.map +1 -1
- package/dist/lib/config.d.ts +1 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/platforms.d.ts +1 -1
- package/dist/lib/platforms.d.ts.map +1 -1
- package/dist/lib/skill-config.d.ts +1 -1
- package/dist/lib/skill-config.d.ts.map +1 -1
- package/dist/lib/skills.d.ts +1 -1
- package/dist/lib/skills.d.ts.map +1 -1
- package/dist/lib/tools.d.ts +1 -1
- package/dist/lib/tools.d.ts.map +1 -1
- package/package.json +3 -3
- package/scripts/build.ts +78 -0
- package/src/bin/droid.ts +8 -8
- package/src/commands/config.ts +1 -1
- package/src/commands/install.ts +3 -3
- package/src/commands/setup.test.ts +1 -1
- package/src/commands/setup.ts +3 -3
- package/src/commands/skills.ts +4 -4
- package/src/commands/tui/components/Badge.tsx +86 -0
- package/src/commands/tui/components/Markdown.tsx +48 -0
- package/src/commands/tui/components/SettingsDetails.tsx +70 -0
- package/src/commands/tui/components/TabBar.tsx +26 -0
- package/src/commands/tui/components/ToolDetails.tsx +117 -0
- package/src/commands/tui/components/ToolItem.tsx +39 -0
- package/src/commands/tui/constants.ts +17 -0
- package/src/commands/tui/hooks/useAppUpdate.ts +67 -0
- package/src/commands/tui/hooks/useToolUpdates.ts +110 -0
- package/src/commands/tui/types.ts +4 -0
- package/src/commands/tui/views/ReadmeViewer.tsx +93 -0
- package/src/commands/tui/views/SetupScreen.tsx +242 -0
- package/src/commands/tui/views/SkillConfigScreen.tsx +278 -0
- package/src/commands/tui/views/ToolExplorer.tsx +190 -0
- package/src/commands/tui/views/ToolUpdatePrompt.tsx +109 -0
- package/src/commands/tui/views/WelcomeScreen.tsx +149 -0
- package/src/commands/tui.tsx +65 -1587
- package/src/commands/uninstall.ts +2 -2
- package/src/commands/update.ts +1 -1
- package/src/index.ts +4 -4
- package/src/lib/agents.ts +4 -4
- package/src/lib/config.ts +1 -1
- package/src/lib/platforms.ts +1 -1
- package/src/lib/skill-config.ts +2 -2
- package/src/lib/skills.test.ts +2 -2
- package/src/lib/skills.ts +5 -5
- package/src/lib/tools.ts +3 -3
- package/src/lib/types.test.ts +1 -1
- package/src/lib/version.test.ts +1 -1
- package/dist/bin/droid.js.map +0 -1
- package/dist/commands/config.js +0 -67
- package/dist/commands/config.js.map +0 -1
- package/dist/commands/install.js +0 -45
- package/dist/commands/install.js.map +0 -1
- package/dist/commands/setup.js +0 -269
- package/dist/commands/setup.js.map +0 -1
- package/dist/commands/skills.js +0 -144
- package/dist/commands/skills.js.map +0 -1
- package/dist/commands/tui.js +0 -1008
- package/dist/commands/tui.js.map +0 -1
- package/dist/commands/uninstall.js +0 -26
- package/dist/commands/uninstall.js.map +0 -1
- package/dist/commands/update.js +0 -45
- package/dist/commands/update.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/agents.js +0 -248
- package/dist/lib/agents.js.map +0 -1
- package/dist/lib/config.js +0 -196
- package/dist/lib/config.js.map +0 -1
- package/dist/lib/platforms.js +0 -52
- package/dist/lib/platforms.js.map +0 -1
- package/dist/lib/quotes.js +0 -24
- package/dist/lib/quotes.js.map +0 -1
- package/dist/lib/skill-config.js +0 -80
- package/dist/lib/skill-config.js.map +0 -1
- package/dist/lib/skills.js +0 -582
- package/dist/lib/skills.js.map +0 -1
- package/dist/lib/tools.js +0 -145
- package/dist/lib/tools.js.map +0 -1
- package/dist/lib/types.js +0 -50
- package/dist/lib/types.js.map +0 -1
- package/dist/lib/version.js +0 -100
- package/dist/lib/version.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,952 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
// src/lib/types.ts
|
|
2
|
+
var Platform = /* @__PURE__ */ ((Platform3) => {
|
|
3
|
+
Platform3["ClaudeCode"] = "claude-code";
|
|
4
|
+
Platform3["OpenCode"] = "opencode";
|
|
5
|
+
return Platform3;
|
|
6
|
+
})(Platform || {});
|
|
7
|
+
var AIToolValue = Platform;
|
|
8
|
+
function getAITag() {
|
|
9
|
+
return "@droid";
|
|
10
|
+
}
|
|
11
|
+
var BuiltInOutput = /* @__PURE__ */ ((BuiltInOutput2) => {
|
|
12
|
+
BuiltInOutput2["Terminal"] = "terminal";
|
|
13
|
+
BuiltInOutput2["Editor"] = "editor";
|
|
14
|
+
return BuiltInOutput2;
|
|
15
|
+
})(BuiltInOutput || {});
|
|
16
|
+
var SkillStatus = /* @__PURE__ */ ((SkillStatus2) => {
|
|
17
|
+
SkillStatus2["Stable"] = "stable";
|
|
18
|
+
SkillStatus2["Beta"] = "beta";
|
|
19
|
+
SkillStatus2["Alpha"] = "alpha";
|
|
20
|
+
return SkillStatus2;
|
|
21
|
+
})(SkillStatus || {});
|
|
22
|
+
var ConfigOptionType = /* @__PURE__ */ ((ConfigOptionType2) => {
|
|
23
|
+
ConfigOptionType2["String"] = "string";
|
|
24
|
+
ConfigOptionType2["Boolean"] = "boolean";
|
|
25
|
+
ConfigOptionType2["Select"] = "select";
|
|
26
|
+
return ConfigOptionType2;
|
|
27
|
+
})(ConfigOptionType || {});
|
|
28
|
+
function getPlatformTools(config) {
|
|
29
|
+
return config.platforms[config.platform]?.tools ?? {};
|
|
30
|
+
}
|
|
31
|
+
function setPlatformTools(config, tools) {
|
|
32
|
+
if (!config.platforms[config.platform]) {
|
|
33
|
+
config.platforms[config.platform] = { tools: {} };
|
|
34
|
+
}
|
|
35
|
+
config.platforms[config.platform].tools = tools;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// src/lib/config.ts
|
|
39
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
40
|
+
import { homedir } from "os";
|
|
41
|
+
import { join } from "path";
|
|
42
|
+
import YAML from "yaml";
|
|
43
|
+
var CONFIG_DIR = join(homedir(), ".droid");
|
|
44
|
+
var CONFIG_FILE = join(CONFIG_DIR, "config.yaml");
|
|
45
|
+
var DEFAULT_AUTO_UPDATE = {
|
|
46
|
+
app: false,
|
|
47
|
+
// Opt-in: user must enable
|
|
48
|
+
tools: true
|
|
49
|
+
// Opt-out: enabled by default (tools only update when app updates)
|
|
50
|
+
};
|
|
51
|
+
var DEFAULT_CONFIG = {
|
|
52
|
+
platform: "claude-code" /* ClaudeCode */,
|
|
53
|
+
user_mention: "@user",
|
|
54
|
+
output_preference: "terminal" /* Terminal */,
|
|
55
|
+
git_username: "",
|
|
56
|
+
platforms: {}
|
|
57
|
+
};
|
|
58
|
+
function migrateConfig(config) {
|
|
59
|
+
if ("ai_tool" in config && !("platform" in config)) {
|
|
60
|
+
const legacyConfig = config;
|
|
61
|
+
return {
|
|
62
|
+
platform: legacyConfig.ai_tool,
|
|
63
|
+
user_mention: legacyConfig.user_mention ?? DEFAULT_CONFIG.user_mention,
|
|
64
|
+
output_preference: legacyConfig.output_preference ?? DEFAULT_CONFIG.output_preference,
|
|
65
|
+
git_username: legacyConfig.git_username ?? DEFAULT_CONFIG.git_username,
|
|
66
|
+
platforms: {
|
|
67
|
+
[legacyConfig.ai_tool]: {
|
|
68
|
+
tools: legacyConfig.skills ?? {}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
...DEFAULT_CONFIG,
|
|
75
|
+
...config,
|
|
76
|
+
platforms: config.platforms ?? {}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function ensureConfigDir() {
|
|
80
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
81
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function configExists() {
|
|
85
|
+
return existsSync(CONFIG_FILE);
|
|
86
|
+
}
|
|
87
|
+
function loadConfig() {
|
|
88
|
+
ensureConfigDir();
|
|
89
|
+
if (!existsSync(CONFIG_FILE)) {
|
|
90
|
+
return { ...DEFAULT_CONFIG };
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
const content = readFileSync(CONFIG_FILE, "utf-8");
|
|
94
|
+
const rawConfig = YAML.parse(content);
|
|
95
|
+
const needsMigration = "ai_tool" in rawConfig && !("platform" in rawConfig);
|
|
96
|
+
const config = migrateConfig(rawConfig);
|
|
97
|
+
if (needsMigration) {
|
|
98
|
+
saveConfig(config);
|
|
99
|
+
}
|
|
100
|
+
return config;
|
|
101
|
+
} catch (error) {
|
|
102
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
103
|
+
console.error(`Error reading config: ${message}`);
|
|
104
|
+
return { ...DEFAULT_CONFIG };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function saveConfig(config) {
|
|
108
|
+
ensureConfigDir();
|
|
109
|
+
const content = YAML.stringify(config, { indent: 2 });
|
|
110
|
+
writeFileSync(CONFIG_FILE, content, "utf-8");
|
|
111
|
+
}
|
|
112
|
+
function getConfigValue(key) {
|
|
113
|
+
const config = loadConfig();
|
|
114
|
+
const keys = key.split(".");
|
|
115
|
+
let value = config;
|
|
116
|
+
for (const k of keys) {
|
|
117
|
+
if (value === void 0 || value === null || typeof value !== "object") {
|
|
118
|
+
return void 0;
|
|
119
|
+
}
|
|
120
|
+
value = value[k];
|
|
121
|
+
}
|
|
122
|
+
return value;
|
|
123
|
+
}
|
|
124
|
+
function setConfigValue(key, value) {
|
|
125
|
+
const config = loadConfig();
|
|
126
|
+
const keys = key.split(".");
|
|
127
|
+
let current = config;
|
|
128
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
129
|
+
if (current[keys[i]] === void 0) {
|
|
130
|
+
current[keys[i]] = {};
|
|
131
|
+
}
|
|
132
|
+
current = current[keys[i]];
|
|
133
|
+
}
|
|
134
|
+
current[keys[keys.length - 1]] = value;
|
|
135
|
+
saveConfig(config);
|
|
136
|
+
}
|
|
137
|
+
function getConfigPath() {
|
|
138
|
+
return CONFIG_FILE;
|
|
139
|
+
}
|
|
140
|
+
function getConfigDir() {
|
|
141
|
+
return CONFIG_DIR;
|
|
142
|
+
}
|
|
143
|
+
function getSkillOverridesPath(skillName) {
|
|
144
|
+
return join(CONFIG_DIR, "skills", skillName, "overrides.yaml");
|
|
145
|
+
}
|
|
146
|
+
function loadSkillOverrides(skillName) {
|
|
147
|
+
const overridesPath = getSkillOverridesPath(skillName);
|
|
148
|
+
if (!existsSync(overridesPath)) {
|
|
149
|
+
return {};
|
|
150
|
+
}
|
|
151
|
+
try {
|
|
152
|
+
const content = readFileSync(overridesPath, "utf-8");
|
|
153
|
+
return YAML.parse(content) || {};
|
|
154
|
+
} catch {
|
|
155
|
+
return {};
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function saveSkillOverrides(skillName, overrides) {
|
|
159
|
+
const overridesPath = getSkillOverridesPath(skillName);
|
|
160
|
+
const skillDir = join(CONFIG_DIR, "skills", skillName);
|
|
161
|
+
if (!existsSync(skillDir)) {
|
|
162
|
+
mkdirSync(skillDir, { recursive: true });
|
|
163
|
+
}
|
|
164
|
+
const content = YAML.stringify(overrides, { indent: 2 });
|
|
165
|
+
writeFileSync(overridesPath, content, "utf-8");
|
|
166
|
+
}
|
|
167
|
+
function getAutoUpdateConfig() {
|
|
168
|
+
const config = loadConfig();
|
|
169
|
+
return {
|
|
170
|
+
...DEFAULT_AUTO_UPDATE,
|
|
171
|
+
...config.auto_update
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
function setAutoUpdateConfig(updates) {
|
|
175
|
+
const config = loadConfig();
|
|
176
|
+
config.auto_update = {
|
|
177
|
+
...DEFAULT_AUTO_UPDATE,
|
|
178
|
+
...config.auto_update,
|
|
179
|
+
...updates
|
|
180
|
+
};
|
|
181
|
+
saveConfig(config);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// src/lib/skills.ts
|
|
185
|
+
import { existsSync as existsSync4, readdirSync as readdirSync3, readFileSync as readFileSync5, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3, rmSync } from "fs";
|
|
186
|
+
import { join as join6, dirname as dirname4 } from "path";
|
|
187
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
188
|
+
import YAML4 from "yaml";
|
|
189
|
+
|
|
190
|
+
// src/lib/agents.ts
|
|
191
|
+
import { existsSync as existsSync3, readdirSync as readdirSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync2, unlinkSync, mkdirSync as mkdirSync2 } from "fs";
|
|
192
|
+
import { join as join5, dirname as dirname3 } from "path";
|
|
193
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
194
|
+
import YAML3 from "yaml";
|
|
195
|
+
|
|
196
|
+
// src/lib/platforms.ts
|
|
197
|
+
import { join as join2 } from "path";
|
|
198
|
+
import { homedir as homedir2 } from "os";
|
|
199
|
+
var PLATFORM_PATHS = {
|
|
200
|
+
["claude-code" /* ClaudeCode */]: {
|
|
201
|
+
skills: join2(homedir2(), ".claude", "skills"),
|
|
202
|
+
commands: join2(homedir2(), ".claude", "commands"),
|
|
203
|
+
agents: join2(homedir2(), ".claude", "agents"),
|
|
204
|
+
config: join2(homedir2(), ".claude", "CLAUDE.md")
|
|
205
|
+
},
|
|
206
|
+
["opencode" /* OpenCode */]: {
|
|
207
|
+
skills: join2(homedir2(), ".config", "opencode", "skills"),
|
|
208
|
+
commands: join2(homedir2(), ".config", "opencode", "command"),
|
|
209
|
+
agents: join2(homedir2(), ".config", "opencode", "agent"),
|
|
210
|
+
config: join2(homedir2(), ".config", "opencode", "AGENTS.md")
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
function getSkillsPath(platform) {
|
|
214
|
+
return PLATFORM_PATHS[platform].skills;
|
|
215
|
+
}
|
|
216
|
+
function getCommandsPath(platform) {
|
|
217
|
+
return PLATFORM_PATHS[platform].commands;
|
|
218
|
+
}
|
|
219
|
+
function getAgentsPath(platform) {
|
|
220
|
+
return PLATFORM_PATHS[platform].agents;
|
|
221
|
+
}
|
|
222
|
+
function getConfigPath2(platform) {
|
|
223
|
+
return PLATFORM_PATHS[platform].config;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// src/lib/tools.ts
|
|
227
|
+
import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync3 } from "fs";
|
|
228
|
+
import { join as join4, dirname as dirname2 } from "path";
|
|
229
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
230
|
+
import YAML2 from "yaml";
|
|
231
|
+
|
|
232
|
+
// src/lib/version.ts
|
|
233
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
234
|
+
import { fileURLToPath } from "url";
|
|
235
|
+
import { dirname, join as join3 } from "path";
|
|
236
|
+
import { execSync } from "child_process";
|
|
237
|
+
import chalk from "chalk";
|
|
238
|
+
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
239
|
+
var packageJsonPath = join3(__dirname, "../../package.json");
|
|
240
|
+
function getVersion() {
|
|
241
|
+
try {
|
|
242
|
+
const pkg = JSON.parse(readFileSync2(packageJsonPath, "utf-8"));
|
|
243
|
+
return pkg.version;
|
|
244
|
+
} catch {
|
|
245
|
+
return "0.0.0";
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
function compareSemver(a, b) {
|
|
249
|
+
const partsA = a.split(".").map(Number);
|
|
250
|
+
const partsB = b.split(".").map(Number);
|
|
251
|
+
for (let i = 0; i < 3; i++) {
|
|
252
|
+
const numA = partsA[i] || 0;
|
|
253
|
+
const numB = partsB[i] || 0;
|
|
254
|
+
if (numA > numB) return 1;
|
|
255
|
+
if (numA < numB) return -1;
|
|
256
|
+
}
|
|
257
|
+
return 0;
|
|
258
|
+
}
|
|
259
|
+
function getUpdateInfo() {
|
|
260
|
+
const currentVersion = getVersion();
|
|
261
|
+
try {
|
|
262
|
+
const latestVersion = execSync("npm view @orderful/droid version 2>/dev/null", {
|
|
263
|
+
encoding: "utf-8",
|
|
264
|
+
timeout: 3e3
|
|
265
|
+
}).trim();
|
|
266
|
+
return {
|
|
267
|
+
hasUpdate: latestVersion ? compareSemver(latestVersion, currentVersion) > 0 : false,
|
|
268
|
+
currentVersion,
|
|
269
|
+
latestVersion: latestVersion || null
|
|
270
|
+
};
|
|
271
|
+
} catch {
|
|
272
|
+
return {
|
|
273
|
+
hasUpdate: false,
|
|
274
|
+
currentVersion,
|
|
275
|
+
latestVersion: null
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
function runUpdate() {
|
|
280
|
+
try {
|
|
281
|
+
execSync("npm install -g @orderful/droid@latest", {
|
|
282
|
+
encoding: "utf-8",
|
|
283
|
+
stdio: "pipe",
|
|
284
|
+
timeout: 6e4
|
|
285
|
+
});
|
|
286
|
+
return { success: true, message: "Update complete!" };
|
|
287
|
+
} catch (error) {
|
|
288
|
+
return { success: false, message: `Update failed: ${error}` };
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
async function checkForUpdates() {
|
|
292
|
+
try {
|
|
293
|
+
const currentVersion = getVersion();
|
|
294
|
+
const latestVersion = execSync("npm view @orderful/droid version 2>/dev/null", {
|
|
295
|
+
encoding: "utf-8",
|
|
296
|
+
timeout: 3e3
|
|
297
|
+
}).trim();
|
|
298
|
+
if (latestVersion && compareSemver(latestVersion, currentVersion) > 0) {
|
|
299
|
+
console.log(
|
|
300
|
+
chalk.yellow(
|
|
301
|
+
`
|
|
302
|
+
\u26A0\uFE0F A new version of droid is available (${currentVersion} \u2192 ${latestVersion})`
|
|
303
|
+
)
|
|
304
|
+
);
|
|
305
|
+
console.log(chalk.yellow(` Run ${chalk.bold("droid update")} to upgrade
|
|
306
|
+
`));
|
|
307
|
+
}
|
|
308
|
+
} catch {
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// src/lib/tools.ts
|
|
313
|
+
var __dirname2 = dirname2(fileURLToPath2(import.meta.url));
|
|
314
|
+
var BUNDLED_TOOLS_DIR = join4(__dirname2, "../tools");
|
|
315
|
+
function loadToolManifest(toolDir) {
|
|
316
|
+
const manifestPath = join4(toolDir, "TOOL.yaml");
|
|
317
|
+
if (!existsSync2(manifestPath)) {
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
try {
|
|
321
|
+
const content = readFileSync3(manifestPath, "utf-8");
|
|
322
|
+
const parsed = YAML2.parse(content);
|
|
323
|
+
const includes = {
|
|
324
|
+
skills: parsed.includes?.skills || [],
|
|
325
|
+
commands: parsed.includes?.commands || [],
|
|
326
|
+
agents: parsed.includes?.agents || []
|
|
327
|
+
};
|
|
328
|
+
return {
|
|
329
|
+
...parsed,
|
|
330
|
+
includes
|
|
331
|
+
};
|
|
332
|
+
} catch {
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// src/lib/agents.ts
|
|
338
|
+
var __dirname3 = dirname3(fileURLToPath3(import.meta.url));
|
|
339
|
+
var BUNDLED_TOOLS_DIR2 = join5(__dirname3, "../tools");
|
|
340
|
+
function getAgentsInstallPath(platform) {
|
|
341
|
+
return getAgentsPath(platform);
|
|
342
|
+
}
|
|
343
|
+
function parseAgentFrontmatter(content) {
|
|
344
|
+
const trimmed = content.trimStart();
|
|
345
|
+
if (!trimmed.startsWith("---")) {
|
|
346
|
+
return null;
|
|
347
|
+
}
|
|
348
|
+
const endMatch = trimmed.slice(3).indexOf("---");
|
|
349
|
+
if (endMatch === -1) {
|
|
350
|
+
return null;
|
|
351
|
+
}
|
|
352
|
+
const frontmatterContent = trimmed.slice(3, 3 + endMatch);
|
|
353
|
+
try {
|
|
354
|
+
return YAML3.parse(frontmatterContent);
|
|
355
|
+
} catch {
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
function loadAgentManifest(agentPath) {
|
|
360
|
+
if (!existsSync3(agentPath)) {
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
363
|
+
const content = readFileSync4(agentPath, "utf-8");
|
|
364
|
+
const frontmatter = parseAgentFrontmatter(content);
|
|
365
|
+
if (!frontmatter || !frontmatter.name) {
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
const toolDir = dirname3(dirname3(agentPath));
|
|
369
|
+
const toolManifest = loadToolManifest(toolDir);
|
|
370
|
+
return {
|
|
371
|
+
name: frontmatter.name,
|
|
372
|
+
description: frontmatter.description || "",
|
|
373
|
+
version: toolManifest?.version || "0.0.0",
|
|
374
|
+
status: toolManifest?.status,
|
|
375
|
+
mode: frontmatter.mode,
|
|
376
|
+
model: frontmatter.model,
|
|
377
|
+
color: frontmatter.color,
|
|
378
|
+
tools: frontmatter.tools
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
function getInstalledAgentsDir() {
|
|
382
|
+
const config = loadConfig();
|
|
383
|
+
return getAgentsInstallPath(config.platform);
|
|
384
|
+
}
|
|
385
|
+
function isAgentInstalled(agentName) {
|
|
386
|
+
const config = loadConfig();
|
|
387
|
+
const agentsDir = getAgentsInstallPath(config.platform);
|
|
388
|
+
const agentPath = join5(agentsDir, `${agentName}.md`);
|
|
389
|
+
return existsSync3(agentPath);
|
|
390
|
+
}
|
|
391
|
+
function generateClaudeCodeAgent(manifest, agentContent) {
|
|
392
|
+
const lines = [
|
|
393
|
+
"---",
|
|
394
|
+
`name: ${manifest.name}`,
|
|
395
|
+
`description: ${manifest.description}`
|
|
396
|
+
];
|
|
397
|
+
if (manifest.tools && manifest.tools.length > 0) {
|
|
398
|
+
lines.push(`tools: ${manifest.tools.join(", ")}`);
|
|
399
|
+
}
|
|
400
|
+
if (manifest.color) {
|
|
401
|
+
lines.push(`color: ${manifest.color}`);
|
|
402
|
+
}
|
|
403
|
+
lines.push("---", "", agentContent.trim(), "");
|
|
404
|
+
return lines.join("\n");
|
|
405
|
+
}
|
|
406
|
+
function generateOpenCodeAgent(manifest, agentContent) {
|
|
407
|
+
const lines = [
|
|
408
|
+
"---",
|
|
409
|
+
`description: ${manifest.description}`,
|
|
410
|
+
`mode: ${manifest.mode || "subagent"}`
|
|
411
|
+
];
|
|
412
|
+
if (manifest.tools && manifest.tools.length > 0) {
|
|
413
|
+
lines.push("tools:");
|
|
414
|
+
for (const tool of manifest.tools) {
|
|
415
|
+
const toolName = tool.toLowerCase();
|
|
416
|
+
lines.push(` ${toolName}: true`);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
lines.push("---", "", agentContent.trim(), "");
|
|
420
|
+
return lines.join("\n");
|
|
421
|
+
}
|
|
422
|
+
function installAgentFromPath(agentPath, agentName) {
|
|
423
|
+
const config = loadConfig();
|
|
424
|
+
const manifest = loadAgentManifest(agentPath);
|
|
425
|
+
if (!manifest) {
|
|
426
|
+
return { success: false, message: `Agent manifest not found: ${agentName}` };
|
|
427
|
+
}
|
|
428
|
+
try {
|
|
429
|
+
const rawContent = readFileSync4(agentPath, "utf-8");
|
|
430
|
+
const frontmatterMatch = rawContent.match(/^---\n[\s\S]*?\n---\n?/);
|
|
431
|
+
const agentContent = frontmatterMatch ? rawContent.slice(frontmatterMatch[0].length) : rawContent;
|
|
432
|
+
const installedContent = config.platform === "claude-code" /* ClaudeCode */ ? generateClaudeCodeAgent(manifest, agentContent) : generateOpenCodeAgent(manifest, agentContent);
|
|
433
|
+
const agentsDir = getAgentsInstallPath(config.platform);
|
|
434
|
+
if (!existsSync3(agentsDir)) {
|
|
435
|
+
mkdirSync2(agentsDir, { recursive: true });
|
|
436
|
+
}
|
|
437
|
+
const outputPath = join5(agentsDir, `${agentName}.md`);
|
|
438
|
+
writeFileSync2(outputPath, installedContent);
|
|
439
|
+
const targetDir = config.platform === "claude-code" /* ClaudeCode */ ? "~/.claude/agents/" : "~/.config/opencode/agent/";
|
|
440
|
+
return { success: true, message: `Installed ${agentName} to ${targetDir}` };
|
|
441
|
+
} catch (error) {
|
|
442
|
+
return { success: false, message: `Failed to install agent: ${error}` };
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
function uninstallAgent(agentName) {
|
|
446
|
+
const config = loadConfig();
|
|
447
|
+
const agentsDir = getAgentsInstallPath(config.platform);
|
|
448
|
+
const agentPath = join5(agentsDir, `${agentName}.md`);
|
|
449
|
+
if (!existsSync3(agentPath)) {
|
|
450
|
+
return { success: false, message: `Agent not installed: ${agentName}` };
|
|
451
|
+
}
|
|
452
|
+
try {
|
|
453
|
+
unlinkSync(agentPath);
|
|
454
|
+
return { success: true, message: `Uninstalled ${agentName}` };
|
|
455
|
+
} catch (error) {
|
|
456
|
+
return { success: false, message: `Failed to uninstall agent: ${error}` };
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// src/lib/skills.ts
|
|
461
|
+
var DROID_SKILLS_START = "<!-- droid-skills-start -->";
|
|
462
|
+
var DROID_SKILLS_END = "<!-- droid-skills-end -->";
|
|
463
|
+
var __dirname4 = dirname4(fileURLToPath4(import.meta.url));
|
|
464
|
+
var BUNDLED_SKILLS_DIR = join6(__dirname4, "../tools");
|
|
465
|
+
function getBundledSkillsDir() {
|
|
466
|
+
return BUNDLED_SKILLS_DIR;
|
|
467
|
+
}
|
|
468
|
+
function getSkillsInstallPath(platform) {
|
|
469
|
+
return getSkillsPath(platform);
|
|
470
|
+
}
|
|
471
|
+
function getCommandsInstallPath(platform) {
|
|
472
|
+
return getCommandsPath(platform);
|
|
473
|
+
}
|
|
474
|
+
function getPlatformConfigPath(platform) {
|
|
475
|
+
return getConfigPath2(platform);
|
|
476
|
+
}
|
|
477
|
+
function updatePlatformConfigSkills(platform, installedSkills) {
|
|
478
|
+
const configPath = getPlatformConfigPath(platform);
|
|
479
|
+
let content = "";
|
|
480
|
+
if (existsSync4(configPath)) {
|
|
481
|
+
content = readFileSync5(configPath, "utf-8");
|
|
482
|
+
}
|
|
483
|
+
const skillLines = installedSkills.map((name) => {
|
|
484
|
+
const relativePath = `skills/${name}/SKILL.md`;
|
|
485
|
+
return `- [${name}](${relativePath})`;
|
|
486
|
+
});
|
|
487
|
+
const skillsSection = installedSkills.length > 0 ? `${DROID_SKILLS_START}
|
|
488
|
+
## Droid Skills
|
|
489
|
+
|
|
490
|
+
${skillLines.join("\n")}
|
|
491
|
+
${DROID_SKILLS_END}` : "";
|
|
492
|
+
const startIdx = content.indexOf(DROID_SKILLS_START);
|
|
493
|
+
const endIdx = content.indexOf(DROID_SKILLS_END);
|
|
494
|
+
if (startIdx !== -1 && endIdx !== -1) {
|
|
495
|
+
content = content.slice(0, startIdx) + skillsSection + content.slice(endIdx + DROID_SKILLS_END.length);
|
|
496
|
+
} else if (skillsSection) {
|
|
497
|
+
content = content.trim() + "\n\n" + skillsSection + "\n";
|
|
498
|
+
}
|
|
499
|
+
const configDir = dirname4(configPath);
|
|
500
|
+
if (!existsSync4(configDir)) {
|
|
501
|
+
mkdirSync3(configDir, { recursive: true });
|
|
502
|
+
}
|
|
503
|
+
writeFileSync3(configPath, content, "utf-8");
|
|
504
|
+
}
|
|
505
|
+
function parseSkillFrontmatter(content) {
|
|
506
|
+
const trimmed = content.trimStart();
|
|
507
|
+
if (!trimmed.startsWith("---")) {
|
|
508
|
+
return null;
|
|
509
|
+
}
|
|
510
|
+
const endMatch = trimmed.slice(3).indexOf("---");
|
|
511
|
+
if (endMatch === -1) {
|
|
512
|
+
return null;
|
|
513
|
+
}
|
|
514
|
+
const frontmatterContent = trimmed.slice(3, 3 + endMatch);
|
|
515
|
+
try {
|
|
516
|
+
return YAML4.parse(frontmatterContent);
|
|
517
|
+
} catch {
|
|
518
|
+
return null;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
function loadSkillManifest(skillDir) {
|
|
522
|
+
const skillMdPath = join6(skillDir, "SKILL.md");
|
|
523
|
+
if (!existsSync4(skillMdPath)) {
|
|
524
|
+
return null;
|
|
525
|
+
}
|
|
526
|
+
const content = readFileSync5(skillMdPath, "utf-8");
|
|
527
|
+
const frontmatter = parseSkillFrontmatter(content);
|
|
528
|
+
if (!frontmatter || !frontmatter.name) {
|
|
529
|
+
return null;
|
|
530
|
+
}
|
|
531
|
+
const toolDir = dirname4(dirname4(skillDir));
|
|
532
|
+
const toolManifest = loadToolManifest(toolDir);
|
|
533
|
+
return {
|
|
534
|
+
name: frontmatter.name,
|
|
535
|
+
description: frontmatter.description || "",
|
|
536
|
+
version: toolManifest?.version || "0.0.0",
|
|
537
|
+
status: toolManifest?.status,
|
|
538
|
+
dependencies: toolManifest?.dependencies,
|
|
539
|
+
config_schema: toolManifest?.config_schema
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
function findSkillPath(skillName) {
|
|
543
|
+
if (!existsSync4(BUNDLED_SKILLS_DIR)) {
|
|
544
|
+
return null;
|
|
545
|
+
}
|
|
546
|
+
const toolDirs = readdirSync3(BUNDLED_SKILLS_DIR, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
547
|
+
for (const toolName of toolDirs) {
|
|
548
|
+
const skillsDir = join6(BUNDLED_SKILLS_DIR, toolName, "skills");
|
|
549
|
+
if (!existsSync4(skillsDir)) continue;
|
|
550
|
+
const skillDir = join6(skillsDir, skillName);
|
|
551
|
+
if (existsSync4(skillDir) && existsSync4(join6(skillDir, "SKILL.md"))) {
|
|
552
|
+
return {
|
|
553
|
+
toolDir: join6(BUNDLED_SKILLS_DIR, toolName),
|
|
554
|
+
skillDir
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return null;
|
|
559
|
+
}
|
|
560
|
+
function getBundledSkills() {
|
|
561
|
+
if (!existsSync4(BUNDLED_SKILLS_DIR)) {
|
|
562
|
+
return [];
|
|
563
|
+
}
|
|
564
|
+
const toolDirs = readdirSync3(BUNDLED_SKILLS_DIR, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
565
|
+
const skills = [];
|
|
566
|
+
for (const toolName of toolDirs) {
|
|
567
|
+
const skillsDir = join6(BUNDLED_SKILLS_DIR, toolName, "skills");
|
|
568
|
+
if (!existsSync4(skillsDir)) continue;
|
|
569
|
+
const skillSubdirs = readdirSync3(skillsDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
570
|
+
for (const skillName of skillSubdirs) {
|
|
571
|
+
const manifest = loadSkillManifest(join6(skillsDir, skillName));
|
|
572
|
+
if (manifest) {
|
|
573
|
+
skills.push(manifest);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
return skills;
|
|
578
|
+
}
|
|
579
|
+
function isSkillInstalled(skillName) {
|
|
580
|
+
const config = loadConfig();
|
|
581
|
+
const tools = getPlatformTools(config);
|
|
582
|
+
return skillName in tools;
|
|
583
|
+
}
|
|
584
|
+
function getInstalledSkill(skillName) {
|
|
585
|
+
const config = loadConfig();
|
|
586
|
+
const tools = getPlatformTools(config);
|
|
587
|
+
return tools[skillName] || null;
|
|
588
|
+
}
|
|
589
|
+
function getSkillUpdateStatus(skillName) {
|
|
590
|
+
const installed = getInstalledSkill(skillName);
|
|
591
|
+
const skillPath = findSkillPath(skillName);
|
|
592
|
+
const manifest = skillPath ? loadSkillManifest(skillPath.skillDir) : null;
|
|
593
|
+
if (!installed || !manifest) {
|
|
594
|
+
return {
|
|
595
|
+
hasUpdate: false,
|
|
596
|
+
installedVersion: installed?.version || null,
|
|
597
|
+
bundledVersion: manifest?.version || null
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
return {
|
|
601
|
+
hasUpdate: manifest.version !== installed.version,
|
|
602
|
+
installedVersion: installed.version,
|
|
603
|
+
bundledVersion: manifest.version
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
function getSkillsWithUpdates() {
|
|
607
|
+
const config = loadConfig();
|
|
608
|
+
const tools = getPlatformTools(config);
|
|
609
|
+
const updates = [];
|
|
610
|
+
for (const skillName of Object.keys(tools)) {
|
|
611
|
+
const status = getSkillUpdateStatus(skillName);
|
|
612
|
+
if (status.hasUpdate && status.installedVersion && status.bundledVersion) {
|
|
613
|
+
updates.push({
|
|
614
|
+
name: skillName,
|
|
615
|
+
installedVersion: status.installedVersion,
|
|
616
|
+
bundledVersion: status.bundledVersion
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
return updates;
|
|
621
|
+
}
|
|
622
|
+
function updateSkill(skillName) {
|
|
623
|
+
const status = getSkillUpdateStatus(skillName);
|
|
624
|
+
if (!status.installedVersion) {
|
|
625
|
+
return { success: false, message: `Skill '${skillName}' is not installed` };
|
|
626
|
+
}
|
|
627
|
+
if (!status.bundledVersion) {
|
|
628
|
+
return { success: false, message: `Skill '${skillName}' not found in bundled skills` };
|
|
629
|
+
}
|
|
630
|
+
if (!status.hasUpdate) {
|
|
631
|
+
return { success: false, message: `Skill '${skillName}' is already at latest version (${status.installedVersion})` };
|
|
632
|
+
}
|
|
633
|
+
const result = installSkill(skillName);
|
|
634
|
+
if (result.success) {
|
|
635
|
+
return {
|
|
636
|
+
success: true,
|
|
637
|
+
message: `Updated ${skillName} from ${status.installedVersion} to ${status.bundledVersion}`
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
return result;
|
|
641
|
+
}
|
|
642
|
+
function updateAllSkills() {
|
|
643
|
+
const config = loadConfig();
|
|
644
|
+
const tools = getPlatformTools(config);
|
|
645
|
+
const result = {
|
|
646
|
+
updated: [],
|
|
647
|
+
failed: [],
|
|
648
|
+
upToDate: 0
|
|
649
|
+
};
|
|
650
|
+
for (const skillName of Object.keys(tools)) {
|
|
651
|
+
const status = getSkillUpdateStatus(skillName);
|
|
652
|
+
if (!status.hasUpdate) {
|
|
653
|
+
result.upToDate++;
|
|
654
|
+
continue;
|
|
655
|
+
}
|
|
656
|
+
const updateResult = updateSkill(skillName);
|
|
657
|
+
if (updateResult.success) {
|
|
658
|
+
result.updated.push({
|
|
659
|
+
name: skillName,
|
|
660
|
+
from: status.installedVersion,
|
|
661
|
+
to: status.bundledVersion
|
|
662
|
+
});
|
|
663
|
+
} else {
|
|
664
|
+
result.failed.push({
|
|
665
|
+
name: skillName,
|
|
666
|
+
error: updateResult.message
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
return result;
|
|
671
|
+
}
|
|
672
|
+
function installSkill(skillName) {
|
|
673
|
+
const config = loadConfig();
|
|
674
|
+
const skillPath = findSkillPath(skillName);
|
|
675
|
+
if (!skillPath) {
|
|
676
|
+
return { success: false, message: `Skill '${skillName}' not found` };
|
|
677
|
+
}
|
|
678
|
+
const { toolDir, skillDir } = skillPath;
|
|
679
|
+
const manifest = loadSkillManifest(skillDir);
|
|
680
|
+
if (!manifest) {
|
|
681
|
+
return { success: false, message: `Invalid skill manifest for '${skillName}'` };
|
|
682
|
+
}
|
|
683
|
+
if (manifest.dependencies) {
|
|
684
|
+
for (const dep of manifest.dependencies) {
|
|
685
|
+
if (!isSkillInstalled(dep)) {
|
|
686
|
+
return {
|
|
687
|
+
success: false,
|
|
688
|
+
message: `Missing dependency: '${dep}'. Install it first with \`droid install ${dep}\``
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
const skillsPath = getSkillsInstallPath(config.platform);
|
|
694
|
+
const targetSkillDir = join6(skillsPath, skillName);
|
|
695
|
+
const commandsPath = getCommandsInstallPath(config.platform);
|
|
696
|
+
const tools = getPlatformTools(config);
|
|
697
|
+
const commandsSource = join6(toolDir, "commands");
|
|
698
|
+
const agentsSource = join6(toolDir, "agents");
|
|
699
|
+
if (!tools[skillName]) {
|
|
700
|
+
if (existsSync4(commandsSource)) {
|
|
701
|
+
const commandFiles = readdirSync3(commandsSource).filter((f) => f.endsWith(".md") && f.toLowerCase() !== "readme.md");
|
|
702
|
+
for (const file of commandFiles) {
|
|
703
|
+
const targetCommandPath = join6(commandsPath, file);
|
|
704
|
+
if (existsSync4(targetCommandPath)) {
|
|
705
|
+
const commandName = file.replace(".md", "");
|
|
706
|
+
return {
|
|
707
|
+
success: false,
|
|
708
|
+
message: `Cannot install: command /${commandName} already exists at ${targetCommandPath}`
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
if (existsSync4(agentsSource)) {
|
|
714
|
+
const agentDirs = readdirSync3(agentsSource, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
715
|
+
for (const agentName of agentDirs) {
|
|
716
|
+
if (isAgentInstalled(agentName)) {
|
|
717
|
+
return {
|
|
718
|
+
success: false,
|
|
719
|
+
message: `Cannot install: agent '${agentName}' already exists at ${getInstalledAgentsDir()}`
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
if (!existsSync4(skillsPath)) {
|
|
726
|
+
mkdirSync3(skillsPath, { recursive: true });
|
|
727
|
+
}
|
|
728
|
+
const skillMdSource = join6(skillDir, "SKILL.md");
|
|
729
|
+
if (existsSync4(skillMdSource)) {
|
|
730
|
+
if (!existsSync4(targetSkillDir)) {
|
|
731
|
+
mkdirSync3(targetSkillDir, { recursive: true });
|
|
732
|
+
}
|
|
733
|
+
const skillMdTarget = join6(targetSkillDir, "SKILL.md");
|
|
734
|
+
const content = readFileSync5(skillMdSource, "utf-8");
|
|
735
|
+
writeFileSync3(skillMdTarget, content);
|
|
736
|
+
}
|
|
737
|
+
const referencesSource = join6(skillDir, "references");
|
|
738
|
+
if (existsSync4(referencesSource)) {
|
|
739
|
+
const targetReferencesDir = join6(targetSkillDir, "references");
|
|
740
|
+
if (!existsSync4(targetReferencesDir)) {
|
|
741
|
+
mkdirSync3(targetReferencesDir, { recursive: true });
|
|
742
|
+
}
|
|
743
|
+
const referenceFiles = readdirSync3(referencesSource).filter((f) => f.endsWith(".md"));
|
|
744
|
+
for (const file of referenceFiles) {
|
|
745
|
+
const sourcePath = join6(referencesSource, file);
|
|
746
|
+
const targetPath = join6(targetReferencesDir, file);
|
|
747
|
+
const content = readFileSync5(sourcePath, "utf-8");
|
|
748
|
+
writeFileSync3(targetPath, content);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
if (existsSync4(commandsSource)) {
|
|
752
|
+
if (!existsSync4(commandsPath)) {
|
|
753
|
+
mkdirSync3(commandsPath, { recursive: true });
|
|
754
|
+
}
|
|
755
|
+
const commandFiles = readdirSync3(commandsSource).filter((f) => f.endsWith(".md") && f.toLowerCase() !== "readme.md");
|
|
756
|
+
for (const file of commandFiles) {
|
|
757
|
+
const sourcePath = join6(commandsSource, file);
|
|
758
|
+
const targetPath = join6(commandsPath, file);
|
|
759
|
+
const content = readFileSync5(sourcePath, "utf-8");
|
|
760
|
+
writeFileSync3(targetPath, content);
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
const installedAgents = [];
|
|
764
|
+
if (existsSync4(agentsSource)) {
|
|
765
|
+
const agentDirs = readdirSync3(agentsSource, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
766
|
+
for (const agentName of agentDirs) {
|
|
767
|
+
const agentDir = join6(agentsSource, agentName);
|
|
768
|
+
const result = installAgentFromPath(agentDir, agentName);
|
|
769
|
+
if (result.success) {
|
|
770
|
+
installedAgents.push(agentName);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
const updatedTools = {
|
|
775
|
+
...tools,
|
|
776
|
+
[skillName]: {
|
|
777
|
+
version: manifest.version,
|
|
778
|
+
installed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
779
|
+
...installedAgents.length > 0 && { bundled_agents: installedAgents }
|
|
780
|
+
}
|
|
781
|
+
};
|
|
782
|
+
setPlatformTools(config, updatedTools);
|
|
783
|
+
saveConfig(config);
|
|
784
|
+
const installedSkillNames = Object.keys(updatedTools);
|
|
785
|
+
updatePlatformConfigSkills(config.platform, installedSkillNames);
|
|
786
|
+
return { success: true, message: `Installed ${skillName} v${manifest.version}` };
|
|
787
|
+
}
|
|
788
|
+
function uninstallSkill(skillName) {
|
|
789
|
+
const config = loadConfig();
|
|
790
|
+
const tools = getPlatformTools(config);
|
|
791
|
+
if (!isSkillInstalled(skillName)) {
|
|
792
|
+
return { success: false, message: `Skill '${skillName}' is not installed` };
|
|
793
|
+
}
|
|
794
|
+
const skillsPath = getSkillsInstallPath(config.platform);
|
|
795
|
+
const skillDir = join6(skillsPath, skillName);
|
|
796
|
+
if (existsSync4(skillDir)) {
|
|
797
|
+
rmSync(skillDir, { recursive: true });
|
|
798
|
+
}
|
|
799
|
+
const skillPath = findSkillPath(skillName);
|
|
800
|
+
const commandsPath = getCommandsInstallPath(config.platform);
|
|
801
|
+
const commandsSource = skillPath ? join6(skillPath.toolDir, "commands") : null;
|
|
802
|
+
if (commandsSource && existsSync4(commandsSource)) {
|
|
803
|
+
const commandFiles = readdirSync3(commandsSource).filter((f) => f.endsWith(".md") && f.toLowerCase() !== "readme.md");
|
|
804
|
+
for (const file of commandFiles) {
|
|
805
|
+
const commandPath = join6(commandsPath, file);
|
|
806
|
+
if (existsSync4(commandPath)) {
|
|
807
|
+
rmSync(commandPath);
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
const installedSkillInfo = tools[skillName];
|
|
812
|
+
if (installedSkillInfo?.bundled_agents) {
|
|
813
|
+
for (const agentName of installedSkillInfo.bundled_agents) {
|
|
814
|
+
uninstallAgent(agentName);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
const { [skillName]: removed, ...remainingTools } = tools;
|
|
818
|
+
setPlatformTools(config, remainingTools);
|
|
819
|
+
saveConfig(config);
|
|
820
|
+
const installedSkillNames = Object.keys(remainingTools);
|
|
821
|
+
updatePlatformConfigSkills(config.platform, installedSkillNames);
|
|
822
|
+
return { success: true, message: `Uninstalled ${skillName}` };
|
|
823
|
+
}
|
|
824
|
+
function getSkillStatusDisplay(status) {
|
|
825
|
+
switch (status) {
|
|
826
|
+
case "alpha" /* Alpha */:
|
|
827
|
+
return "[alpha]";
|
|
828
|
+
case "beta" /* Beta */:
|
|
829
|
+
return "[beta]";
|
|
830
|
+
case "stable" /* Stable */:
|
|
831
|
+
default:
|
|
832
|
+
return "";
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
function isCommandInstalled(commandName, skillName) {
|
|
836
|
+
if (isSkillInstalled(skillName)) {
|
|
837
|
+
return true;
|
|
838
|
+
}
|
|
839
|
+
const config = loadConfig();
|
|
840
|
+
const commandsPath = getCommandsInstallPath(config.platform);
|
|
841
|
+
const cmdPart = commandName.startsWith(skillName + " ") ? commandName.slice(skillName.length + 1) : commandName;
|
|
842
|
+
const filename = cmdPart.replace(/\s+/g, "-") + ".md";
|
|
843
|
+
return existsSync4(join6(commandsPath, filename));
|
|
844
|
+
}
|
|
845
|
+
function installCommand(commandName, skillName) {
|
|
846
|
+
const config = loadConfig();
|
|
847
|
+
const skillPath = findSkillPath(skillName);
|
|
848
|
+
if (!skillPath) {
|
|
849
|
+
return { success: false, message: `Skill '${skillName}' not found` };
|
|
850
|
+
}
|
|
851
|
+
const commandsDir = join6(skillPath.toolDir, "commands");
|
|
852
|
+
if (!existsSync4(commandsDir)) {
|
|
853
|
+
return { success: false, message: `No commands found for skill '${skillName}'` };
|
|
854
|
+
}
|
|
855
|
+
const cmdPart = commandName.startsWith(skillName + " ") ? commandName.slice(skillName.length + 1) : commandName;
|
|
856
|
+
const files = readdirSync3(commandsDir).filter((f) => f.endsWith(".md") && f.toLowerCase() !== "readme.md");
|
|
857
|
+
const sourceFile = files.find((f) => {
|
|
858
|
+
const base = f.replace(".md", "");
|
|
859
|
+
return base === cmdPart || base === cmdPart.replace(/\s+/g, "-");
|
|
860
|
+
});
|
|
861
|
+
if (!sourceFile) {
|
|
862
|
+
return { success: false, message: `Command file not found for: ${commandName}` };
|
|
863
|
+
}
|
|
864
|
+
const commandsPath = getCommandsInstallPath(config.platform);
|
|
865
|
+
if (!existsSync4(commandsPath)) {
|
|
866
|
+
mkdirSync3(commandsPath, { recursive: true });
|
|
867
|
+
}
|
|
868
|
+
const actualSourcePath = join6(commandsDir, sourceFile);
|
|
869
|
+
const targetPath = join6(commandsPath, sourceFile);
|
|
870
|
+
try {
|
|
871
|
+
const content = readFileSync5(actualSourcePath, "utf-8");
|
|
872
|
+
writeFileSync3(targetPath, content);
|
|
873
|
+
return { success: true, message: `Installed /${commandName}` };
|
|
874
|
+
} catch (error) {
|
|
875
|
+
return { success: false, message: `Failed to install command: ${error}` };
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
function uninstallCommand(commandName, skillName) {
|
|
879
|
+
const config = loadConfig();
|
|
880
|
+
if (isSkillInstalled(skillName)) {
|
|
881
|
+
return {
|
|
882
|
+
success: false,
|
|
883
|
+
message: `Command belongs to installed skill '${skillName}'. Uninstall the skill to remove this command.`
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
const commandsPath = getCommandsInstallPath(config.platform);
|
|
887
|
+
const cmdPart = commandName.startsWith(skillName + " ") ? commandName.slice(skillName.length + 1) : commandName;
|
|
888
|
+
const possibleFilenames = [
|
|
889
|
+
cmdPart + ".md",
|
|
890
|
+
cmdPart.replace(/\s+/g, "-") + ".md"
|
|
891
|
+
];
|
|
892
|
+
for (const filename of possibleFilenames) {
|
|
893
|
+
const commandPath = join6(commandsPath, filename);
|
|
894
|
+
if (existsSync4(commandPath)) {
|
|
895
|
+
try {
|
|
896
|
+
rmSync(commandPath);
|
|
897
|
+
return { success: true, message: `Uninstalled /${commandName}` };
|
|
898
|
+
} catch (error) {
|
|
899
|
+
return { success: false, message: `Failed to uninstall command: ${error}` };
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
return { success: false, message: `Command not installed: ${commandName}` };
|
|
904
|
+
}
|
|
905
|
+
export {
|
|
906
|
+
AIToolValue as AITool,
|
|
907
|
+
BuiltInOutput,
|
|
908
|
+
ConfigOptionType,
|
|
909
|
+
Platform,
|
|
910
|
+
SkillStatus,
|
|
911
|
+
checkForUpdates,
|
|
912
|
+
compareSemver,
|
|
913
|
+
configExists,
|
|
914
|
+
ensureConfigDir,
|
|
915
|
+
findSkillPath,
|
|
916
|
+
getAITag,
|
|
917
|
+
getAutoUpdateConfig,
|
|
918
|
+
getBundledSkills,
|
|
919
|
+
getBundledSkillsDir,
|
|
920
|
+
getCommandsInstallPath,
|
|
921
|
+
getConfigDir,
|
|
922
|
+
getConfigPath,
|
|
923
|
+
getConfigValue,
|
|
924
|
+
getInstalledSkill,
|
|
925
|
+
getPlatformConfigPath,
|
|
926
|
+
getPlatformTools,
|
|
927
|
+
getSkillOverridesPath,
|
|
928
|
+
getSkillStatusDisplay,
|
|
929
|
+
getSkillUpdateStatus,
|
|
930
|
+
getSkillsInstallPath,
|
|
931
|
+
getSkillsWithUpdates,
|
|
932
|
+
getUpdateInfo,
|
|
933
|
+
getVersion,
|
|
934
|
+
installCommand,
|
|
935
|
+
installSkill,
|
|
936
|
+
isCommandInstalled,
|
|
937
|
+
isSkillInstalled,
|
|
938
|
+
loadConfig,
|
|
939
|
+
loadSkillManifest,
|
|
940
|
+
loadSkillOverrides,
|
|
941
|
+
runUpdate,
|
|
942
|
+
saveConfig,
|
|
943
|
+
saveSkillOverrides,
|
|
944
|
+
setAutoUpdateConfig,
|
|
945
|
+
setConfigValue,
|
|
946
|
+
setPlatformTools,
|
|
947
|
+
uninstallCommand,
|
|
948
|
+
uninstallSkill,
|
|
949
|
+
updateAllSkills,
|
|
950
|
+
updatePlatformConfigSkills,
|
|
951
|
+
updateSkill
|
|
952
|
+
};
|