@oro.ad/nuxt-claude-devtools 1.2.0 → 1.3.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/README.md +105 -13
- package/dist/client/200.html +1 -1
- package/dist/client/404.html +1 -1
- package/dist/client/_nuxt/B8uzckkK.js +1 -0
- package/dist/client/_nuxt/{CPQSDiF7.js → BAb1fJOF.js} +4 -4
- package/dist/client/_nuxt/BB1-kxmm.js +1 -0
- package/dist/client/_nuxt/BMZIbUUD.js +1 -0
- package/dist/client/_nuxt/BSF2Vz9o.js +1 -0
- package/dist/client/_nuxt/BSVkH7b6.js +1 -0
- package/dist/client/_nuxt/{08Mb3FOO.js → BYp73eMl.js} +1 -1
- package/dist/client/_nuxt/B_BoWmnX.js +1 -0
- package/dist/client/_nuxt/BcZxFXBD.js +1 -0
- package/dist/client/_nuxt/BflmC3YB.js +1 -0
- package/dist/client/_nuxt/BnXQTjo-.js +1 -0
- package/dist/client/_nuxt/C--9REmc.js +1 -0
- package/dist/client/_nuxt/CDQtmRaX.js +1 -0
- package/dist/client/_nuxt/CHeJJZL9.js +1 -0
- package/dist/client/_nuxt/{CSlPuO5s.js → COus5Ssl.js} +1 -1
- package/dist/client/_nuxt/{o1jjB-UO.js → CPA0s6N9.js} +1 -1
- package/dist/client/_nuxt/CRkq21kc.js +1 -0
- package/dist/client/_nuxt/Cgba93Y9.js +1 -0
- package/dist/client/_nuxt/D2l4TRxW.js +1 -0
- package/dist/client/_nuxt/DC_XB519.js +1 -0
- package/dist/client/_nuxt/DEys9N1G.js +1 -0
- package/dist/client/_nuxt/{b4Upel01.js → DGQ4s7ae.js} +1 -1
- package/dist/client/_nuxt/DH8Ugy8E.js +1 -0
- package/dist/client/_nuxt/DSt96JPY.js +4 -0
- package/dist/client/_nuxt/DbJLoP3G.js +1 -0
- package/dist/client/_nuxt/DeGmaFBY.js +1 -0
- package/dist/client/_nuxt/DgfRwrFR.js +1 -0
- package/dist/client/_nuxt/{CLKqRoht.js → DolUcBed.js} +1 -1
- package/dist/client/_nuxt/M6QPYocW.js +1 -0
- package/dist/client/_nuxt/QumocfwJ.js +1 -0
- package/dist/client/_nuxt/TQi6eIO6.js +1 -0
- package/dist/client/_nuxt/V4UvAcd3.js +1 -0
- package/dist/client/_nuxt/builds/latest.json +1 -1
- package/dist/client/_nuxt/builds/meta/2be12f06-336a-4fdd-b982-2f6c682c14a6.json +1 -0
- package/dist/client/_nuxt/d8BPa19J.js +1 -0
- package/dist/client/_nuxt/entry.BMxUr06A.css +1 -0
- package/dist/client/_nuxt/qbS8UemQ.js +1 -0
- package/dist/client/_nuxt/wDw60tEC.js +10 -0
- package/dist/client/_nuxt/xEjB6ozD.js +1 -0
- package/dist/client/agents/index.html +1 -1
- package/dist/client/commands/index.html +1 -1
- package/dist/client/docs/index.html +1 -1
- package/dist/client/index.html +1 -1
- package/dist/client/mcp/index.html +1 -1
- package/dist/client/plugins/index.html +1 -0
- package/dist/client/settings/index.html +1 -0
- package/dist/client/skills/index.html +1 -1
- package/dist/module.d.mts +12 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +27 -5
- package/dist/runtime/constants.d.ts +29 -0
- package/dist/runtime/constants.js +5 -0
- package/dist/runtime/overlay/components/ChatOverlay.d.vue.ts +7 -0
- package/dist/runtime/overlay/components/ChatOverlay.vue +893 -0
- package/dist/runtime/overlay/components/ChatOverlay.vue.d.ts +7 -0
- package/dist/runtime/overlay/components/MarkdownContent.d.vue.ts +6 -0
- package/dist/runtime/overlay/components/MarkdownContent.vue +31 -0
- package/dist/runtime/overlay/components/MarkdownContent.vue.d.ts +6 -0
- package/dist/runtime/overlay/components/ToolCallBlock.d.vue.ts +8 -0
- package/dist/runtime/overlay/components/ToolCallBlock.vue +77 -0
- package/dist/runtime/overlay/components/ToolCallBlock.vue.d.ts +8 -0
- package/dist/runtime/overlay/plugin.client.d.ts +6 -0
- package/dist/runtime/overlay/plugin.client.js +29 -0
- package/dist/runtime/server/agents-manager.d.ts +17 -4
- package/dist/runtime/server/agents-manager.js +38 -109
- package/dist/runtime/server/base-resource-manager.d.ts +90 -0
- package/dist/runtime/server/base-resource-manager.js +201 -0
- package/dist/runtime/server/claude-session.d.ts +11 -1
- package/dist/runtime/server/claude-session.js +246 -27
- package/dist/runtime/server/commands-manager.d.ts +12 -4
- package/dist/runtime/server/commands-manager.js +25 -100
- package/dist/runtime/server/constants.d.ts +94 -0
- package/dist/runtime/server/constants.js +18 -0
- package/dist/runtime/server/docs-manager.d.ts +7 -0
- package/dist/runtime/server/docs-manager.js +112 -3
- package/dist/runtime/server/history-manager.d.ts +1 -0
- package/dist/runtime/server/history-manager.js +25 -3
- package/dist/runtime/server/plugins/socket.io.js +5 -3
- package/dist/runtime/server/plugins-manager.d.ts +84 -0
- package/dist/runtime/server/plugins-manager.js +338 -0
- package/dist/runtime/server/settings-manager.d.ts +17 -0
- package/dist/runtime/server/settings-manager.js +70 -0
- package/dist/runtime/server/share-manager.d.ts +24 -0
- package/dist/runtime/server/share-manager.js +96 -0
- package/dist/runtime/server/skills-manager.d.ts +18 -4
- package/dist/runtime/server/skills-manager.js +32 -159
- package/dist/runtime/shared/composables/useClaudeChat.d.ts +35 -0
- package/dist/runtime/shared/composables/useClaudeChat.js +264 -0
- package/dist/runtime/shared/composables/useShare.d.ts +42 -0
- package/dist/runtime/shared/composables/useShare.js +192 -0
- package/dist/runtime/shared/composables/useVoiceInput.d.ts +8 -0
- package/dist/runtime/shared/composables/useVoiceInput.js +77 -0
- package/dist/runtime/shared/constants.d.ts +28 -0
- package/dist/runtime/shared/constants.js +6 -0
- package/dist/runtime/shared/index.d.ts +9 -0
- package/dist/runtime/shared/index.js +5 -0
- package/dist/runtime/shared/types.d.ts +48 -0
- package/dist/runtime/shared/types.js +0 -0
- package/dist/runtime/types.d.ts +2 -0
- package/dist/types.d.mts +1 -1
- package/package.json +5 -3
- package/dist/client/_nuxt/BMi2eT6G.js +0 -1
- package/dist/client/_nuxt/BiBLVxWh.js +0 -1
- package/dist/client/_nuxt/BnRGpZsC.js +0 -8
- package/dist/client/_nuxt/C2GhPw5d.js +0 -7
- package/dist/client/_nuxt/D8683igF.js +0 -7
- package/dist/client/_nuxt/DBIw6BGF.js +0 -1
- package/dist/client/_nuxt/DCgjfr8H.js +0 -9
- package/dist/client/_nuxt/bl5iU4Kz.js +0 -1
- package/dist/client/_nuxt/builds/meta/35284331-5e85-46e0-9058-988fea05336c.json +0 -1
- package/dist/client/_nuxt/entry.BhHeZ_Nj.css +0 -1
- package/dist/client/_nuxt/nKfsBgPE.js +0 -4
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { createLogger } from "../logger.js";
|
|
5
|
+
import {
|
|
6
|
+
AGENTS_SUBDIR,
|
|
7
|
+
CLAUDE_DIR,
|
|
8
|
+
CLAUDE_SETTINGS_FILE,
|
|
9
|
+
CLAUDE_SETTINGS_LOCAL_FILE,
|
|
10
|
+
COMMANDS_SUBDIR,
|
|
11
|
+
DEFAULT_PLUGINS_CACHE_PATH,
|
|
12
|
+
PLUGIN_MANIFEST_DIR,
|
|
13
|
+
PLUGIN_MANIFEST_FILE,
|
|
14
|
+
SKILL_FILE,
|
|
15
|
+
SKILLS_SUBDIR
|
|
16
|
+
} from "./constants.js";
|
|
17
|
+
const log = createLogger("plugins", { timestamp: true });
|
|
18
|
+
export class PluginsManager {
|
|
19
|
+
projectPath;
|
|
20
|
+
pluginsCachePath;
|
|
21
|
+
userClaudeDir;
|
|
22
|
+
constructor(projectPath, customCachePath) {
|
|
23
|
+
this.projectPath = projectPath;
|
|
24
|
+
this.userClaudeDir = join(homedir(), CLAUDE_DIR);
|
|
25
|
+
if (customCachePath) {
|
|
26
|
+
this.pluginsCachePath = customCachePath;
|
|
27
|
+
} else {
|
|
28
|
+
this.pluginsCachePath = join(homedir(), DEFAULT_PLUGINS_CACHE_PATH);
|
|
29
|
+
}
|
|
30
|
+
log("PluginsManager initialized", {
|
|
31
|
+
projectPath,
|
|
32
|
+
pluginsCachePath: this.pluginsCachePath,
|
|
33
|
+
userClaudeDir: this.userClaudeDir
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
// ============ Settings Reading ============
|
|
37
|
+
readSettingsFile(path) {
|
|
38
|
+
try {
|
|
39
|
+
if (!existsSync(path)) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
const content = readFileSync(path, "utf-8");
|
|
43
|
+
return JSON.parse(content);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
log("Failed to read settings file", { path, error });
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
getUserSettings() {
|
|
50
|
+
const path = join(this.userClaudeDir, CLAUDE_SETTINGS_FILE);
|
|
51
|
+
return this.readSettingsFile(path);
|
|
52
|
+
}
|
|
53
|
+
getProjectSettings() {
|
|
54
|
+
const path = join(this.projectPath, CLAUDE_DIR, CLAUDE_SETTINGS_FILE);
|
|
55
|
+
return this.readSettingsFile(path);
|
|
56
|
+
}
|
|
57
|
+
getLocalSettings() {
|
|
58
|
+
const path = join(this.projectPath, CLAUDE_DIR, CLAUDE_SETTINGS_LOCAL_FILE);
|
|
59
|
+
return this.readSettingsFile(path);
|
|
60
|
+
}
|
|
61
|
+
// ============ Plugin Discovery ============
|
|
62
|
+
parsePluginId(pluginId) {
|
|
63
|
+
const atIndex = pluginId.lastIndexOf("@");
|
|
64
|
+
if (atIndex === -1 || atIndex === 0) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
name: pluginId.slice(0, atIndex),
|
|
69
|
+
marketplace: pluginId.slice(atIndex + 1)
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
findPluginInCache(pluginName, marketplace) {
|
|
73
|
+
const possibleBasePaths = [
|
|
74
|
+
join(this.pluginsCachePath, marketplace, pluginName),
|
|
75
|
+
join(this.pluginsCachePath, `${pluginName}@${marketplace}`),
|
|
76
|
+
join(this.pluginsCachePath, pluginName)
|
|
77
|
+
];
|
|
78
|
+
for (const basePath of possibleBasePaths) {
|
|
79
|
+
if (!existsSync(basePath) || !statSync(basePath).isDirectory()) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const directManifest = join(basePath, PLUGIN_MANIFEST_DIR, PLUGIN_MANIFEST_FILE);
|
|
83
|
+
if (existsSync(directManifest)) {
|
|
84
|
+
return basePath;
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
const entries = readdirSync(basePath, { withFileTypes: true });
|
|
88
|
+
for (const entry of entries) {
|
|
89
|
+
if (entry.isDirectory() && !entry.name.startsWith(".")) {
|
|
90
|
+
const versionPath = join(basePath, entry.name);
|
|
91
|
+
const versionManifest = join(versionPath, PLUGIN_MANIFEST_DIR, PLUGIN_MANIFEST_FILE);
|
|
92
|
+
if (existsSync(versionManifest)) {
|
|
93
|
+
return versionPath;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
} catch {
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
readPluginManifest(pluginPath) {
|
|
103
|
+
const manifestPath = join(pluginPath, PLUGIN_MANIFEST_DIR, PLUGIN_MANIFEST_FILE);
|
|
104
|
+
try {
|
|
105
|
+
if (!existsSync(manifestPath)) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
const content = readFileSync(manifestPath, "utf-8");
|
|
109
|
+
return JSON.parse(content);
|
|
110
|
+
} catch (error) {
|
|
111
|
+
log("Failed to read plugin manifest", { manifestPath, error });
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// ============ Public API: Plugins ============
|
|
116
|
+
normalizePluginList(list, filterEnabled) {
|
|
117
|
+
if (!list) return [];
|
|
118
|
+
if (Array.isArray(list)) return list;
|
|
119
|
+
return Object.entries(list).filter(([_, enabled]) => filterEnabled === void 0 || enabled === filterEnabled).map(([id]) => id);
|
|
120
|
+
}
|
|
121
|
+
getInstalledPlugins() {
|
|
122
|
+
const plugins = [];
|
|
123
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
124
|
+
const addPlugins = (enabledList, disabledList, scope) => {
|
|
125
|
+
for (const pluginId of this.normalizePluginList(enabledList, true)) {
|
|
126
|
+
if (seenIds.has(pluginId)) continue;
|
|
127
|
+
seenIds.add(pluginId);
|
|
128
|
+
const parsed = this.parsePluginId(pluginId);
|
|
129
|
+
if (!parsed) {
|
|
130
|
+
log("Invalid plugin ID format", { pluginId });
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
const cachePath = this.findPluginInCache(parsed.name, parsed.marketplace);
|
|
134
|
+
const manifest = cachePath ? this.readPluginManifest(cachePath) : void 0;
|
|
135
|
+
plugins.push({
|
|
136
|
+
id: pluginId,
|
|
137
|
+
name: parsed.name,
|
|
138
|
+
marketplace: parsed.marketplace,
|
|
139
|
+
scope,
|
|
140
|
+
enabled: true,
|
|
141
|
+
manifest: manifest || void 0,
|
|
142
|
+
cachePath: cachePath || void 0
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
for (const pluginId of this.normalizePluginList(disabledList)) {
|
|
146
|
+
if (seenIds.has(pluginId)) continue;
|
|
147
|
+
seenIds.add(pluginId);
|
|
148
|
+
const parsed = this.parsePluginId(pluginId);
|
|
149
|
+
if (!parsed) continue;
|
|
150
|
+
const cachePath = this.findPluginInCache(parsed.name, parsed.marketplace);
|
|
151
|
+
const manifest = cachePath ? this.readPluginManifest(cachePath) : void 0;
|
|
152
|
+
plugins.push({
|
|
153
|
+
id: pluginId,
|
|
154
|
+
name: parsed.name,
|
|
155
|
+
marketplace: parsed.marketplace,
|
|
156
|
+
scope,
|
|
157
|
+
enabled: false,
|
|
158
|
+
manifest: manifest || void 0,
|
|
159
|
+
cachePath: cachePath || void 0
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
const userSettings = this.getUserSettings();
|
|
164
|
+
const projectSettings = this.getProjectSettings();
|
|
165
|
+
const localSettings = this.getLocalSettings();
|
|
166
|
+
addPlugins(userSettings?.enabledPlugins, userSettings?.disabledPlugins, "user");
|
|
167
|
+
addPlugins(projectSettings?.enabledPlugins, projectSettings?.disabledPlugins, "project");
|
|
168
|
+
addPlugins(localSettings?.enabledPlugins, localSettings?.disabledPlugins, "local");
|
|
169
|
+
return plugins;
|
|
170
|
+
}
|
|
171
|
+
// ============ Public API: Marketplaces ============
|
|
172
|
+
getMarketplaces() {
|
|
173
|
+
const marketplaces = [];
|
|
174
|
+
const seenNames = /* @__PURE__ */ new Set();
|
|
175
|
+
marketplaces.push({
|
|
176
|
+
name: "claude-plugins-official",
|
|
177
|
+
source: "anthropic/claude-plugins",
|
|
178
|
+
autoUpdate: true
|
|
179
|
+
});
|
|
180
|
+
seenNames.add("claude-plugins-official");
|
|
181
|
+
const addMarketplaces = (settings) => {
|
|
182
|
+
for (const mp of settings?.extraKnownMarketplaces || []) {
|
|
183
|
+
if (seenNames.has(mp.name)) continue;
|
|
184
|
+
seenNames.add(mp.name);
|
|
185
|
+
marketplaces.push({
|
|
186
|
+
name: mp.name,
|
|
187
|
+
source: mp.source,
|
|
188
|
+
autoUpdate: mp.autoUpdate
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
addMarketplaces(this.getUserSettings());
|
|
193
|
+
addMarketplaces(this.getProjectSettings());
|
|
194
|
+
addMarketplaces(this.getLocalSettings());
|
|
195
|
+
return marketplaces;
|
|
196
|
+
}
|
|
197
|
+
// ============ Public API: Plugin Resources ============
|
|
198
|
+
parseFrontmatter(content) {
|
|
199
|
+
const frontmatter = {};
|
|
200
|
+
let body = content;
|
|
201
|
+
if (content.startsWith("---")) {
|
|
202
|
+
const endIndex = content.indexOf("---", 3);
|
|
203
|
+
if (endIndex !== -1) {
|
|
204
|
+
const yamlContent = content.slice(3, endIndex).trim();
|
|
205
|
+
body = content.slice(endIndex + 3).trim();
|
|
206
|
+
for (const line of yamlContent.split("\n")) {
|
|
207
|
+
const colonIndex = line.indexOf(":");
|
|
208
|
+
if (colonIndex !== -1) {
|
|
209
|
+
const key = line.slice(0, colonIndex).trim();
|
|
210
|
+
const value = line.slice(colonIndex + 1).trim();
|
|
211
|
+
frontmatter[key] = value;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return { frontmatter, body };
|
|
217
|
+
}
|
|
218
|
+
getPluginSkills(pluginPath, pluginName) {
|
|
219
|
+
const skills = [];
|
|
220
|
+
const skillsDir = join(pluginPath, SKILLS_SUBDIR);
|
|
221
|
+
if (!existsSync(skillsDir)) {
|
|
222
|
+
return skills;
|
|
223
|
+
}
|
|
224
|
+
try {
|
|
225
|
+
const entries = readdirSync(skillsDir, { withFileTypes: true });
|
|
226
|
+
for (const entry of entries) {
|
|
227
|
+
if (!entry.isDirectory()) continue;
|
|
228
|
+
const skillFile = join(skillsDir, entry.name, SKILL_FILE);
|
|
229
|
+
if (!existsSync(skillFile)) continue;
|
|
230
|
+
try {
|
|
231
|
+
const content = readFileSync(skillFile, "utf-8");
|
|
232
|
+
const { frontmatter, body } = this.parseFrontmatter(content);
|
|
233
|
+
skills.push({
|
|
234
|
+
name: frontmatter.name || entry.name,
|
|
235
|
+
description: frontmatter.description || "",
|
|
236
|
+
content: body,
|
|
237
|
+
pluginName,
|
|
238
|
+
fullName: `${pluginName}:${frontmatter.name || entry.name}`
|
|
239
|
+
});
|
|
240
|
+
} catch (error) {
|
|
241
|
+
log("Failed to read plugin skill", { skillFile, error });
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
} catch (error) {
|
|
245
|
+
log("Failed to read plugin skills directory", { skillsDir, error });
|
|
246
|
+
}
|
|
247
|
+
return skills;
|
|
248
|
+
}
|
|
249
|
+
getPluginCommands(pluginPath, pluginName) {
|
|
250
|
+
const commands = [];
|
|
251
|
+
const commandsDir = join(pluginPath, COMMANDS_SUBDIR);
|
|
252
|
+
if (!existsSync(commandsDir)) {
|
|
253
|
+
return commands;
|
|
254
|
+
}
|
|
255
|
+
try {
|
|
256
|
+
const entries = readdirSync(commandsDir, { withFileTypes: true });
|
|
257
|
+
for (const entry of entries) {
|
|
258
|
+
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
259
|
+
const commandFile = join(commandsDir, entry.name);
|
|
260
|
+
const commandName = entry.name.replace(/\.md$/, "");
|
|
261
|
+
try {
|
|
262
|
+
const content = readFileSync(commandFile, "utf-8");
|
|
263
|
+
const { frontmatter, body } = this.parseFrontmatter(content);
|
|
264
|
+
commands.push({
|
|
265
|
+
name: commandName,
|
|
266
|
+
description: frontmatter.description,
|
|
267
|
+
content: body,
|
|
268
|
+
pluginName,
|
|
269
|
+
fullName: `${pluginName}:${commandName}`
|
|
270
|
+
});
|
|
271
|
+
} catch (error) {
|
|
272
|
+
log("Failed to read plugin command", { commandFile, error });
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
} catch (error) {
|
|
276
|
+
log("Failed to read plugin commands directory", { commandsDir, error });
|
|
277
|
+
}
|
|
278
|
+
return commands;
|
|
279
|
+
}
|
|
280
|
+
getPluginAgents(pluginPath, pluginName) {
|
|
281
|
+
const agents = [];
|
|
282
|
+
const agentsDir = join(pluginPath, AGENTS_SUBDIR);
|
|
283
|
+
if (!existsSync(agentsDir)) {
|
|
284
|
+
return agents;
|
|
285
|
+
}
|
|
286
|
+
try {
|
|
287
|
+
const entries = readdirSync(agentsDir, { withFileTypes: true });
|
|
288
|
+
for (const entry of entries) {
|
|
289
|
+
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
290
|
+
const agentFile = join(agentsDir, entry.name);
|
|
291
|
+
const agentName = entry.name.replace(/\.md$/, "");
|
|
292
|
+
try {
|
|
293
|
+
const content = readFileSync(agentFile, "utf-8");
|
|
294
|
+
const { frontmatter, body } = this.parseFrontmatter(content);
|
|
295
|
+
agents.push({
|
|
296
|
+
name: frontmatter.name || agentName,
|
|
297
|
+
description: frontmatter.description || "",
|
|
298
|
+
prompt: body,
|
|
299
|
+
pluginName
|
|
300
|
+
});
|
|
301
|
+
} catch (error) {
|
|
302
|
+
log("Failed to read plugin agent", { agentFile, error });
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
} catch (error) {
|
|
306
|
+
log("Failed to read plugin agents directory", { agentsDir, error });
|
|
307
|
+
}
|
|
308
|
+
return agents;
|
|
309
|
+
}
|
|
310
|
+
// ============ Aggregate Methods ============
|
|
311
|
+
getAllPluginSkills() {
|
|
312
|
+
const skills = [];
|
|
313
|
+
const plugins = this.getInstalledPlugins();
|
|
314
|
+
for (const plugin of plugins) {
|
|
315
|
+
if (!plugin.enabled || !plugin.cachePath) continue;
|
|
316
|
+
skills.push(...this.getPluginSkills(plugin.cachePath, plugin.name));
|
|
317
|
+
}
|
|
318
|
+
return skills;
|
|
319
|
+
}
|
|
320
|
+
getAllPluginCommands() {
|
|
321
|
+
const commands = [];
|
|
322
|
+
const plugins = this.getInstalledPlugins();
|
|
323
|
+
for (const plugin of plugins) {
|
|
324
|
+
if (!plugin.enabled || !plugin.cachePath) continue;
|
|
325
|
+
commands.push(...this.getPluginCommands(plugin.cachePath, plugin.name));
|
|
326
|
+
}
|
|
327
|
+
return commands;
|
|
328
|
+
}
|
|
329
|
+
getAllPluginAgents() {
|
|
330
|
+
const agents = [];
|
|
331
|
+
const plugins = this.getInstalledPlugins();
|
|
332
|
+
for (const plugin of plugins) {
|
|
333
|
+
if (!plugin.enabled || !plugin.cachePath) continue;
|
|
334
|
+
agents.push(...this.getPluginAgents(plugin.cachePath, plugin.name));
|
|
335
|
+
}
|
|
336
|
+
return agents;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface DevToolsSettings {
|
|
2
|
+
criticalFiles: {
|
|
3
|
+
autoConfirm: boolean;
|
|
4
|
+
};
|
|
5
|
+
}
|
|
6
|
+
export declare class SettingsManager {
|
|
7
|
+
private settingsPath;
|
|
8
|
+
private settings;
|
|
9
|
+
constructor(rootDir: string);
|
|
10
|
+
private loadSettings;
|
|
11
|
+
private mergeWithDefaults;
|
|
12
|
+
private saveSettings;
|
|
13
|
+
getSettings(): DevToolsSettings;
|
|
14
|
+
updateSettings(updates: Partial<DevToolsSettings>): DevToolsSettings;
|
|
15
|
+
isAutoConfirmEnabled(): boolean;
|
|
16
|
+
setAutoConfirm(value: boolean): void;
|
|
17
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { createLogger } from "../logger.js";
|
|
4
|
+
import { DEVTOOLS_DATA_DIR, SETTINGS_FILE } from "./constants.js";
|
|
5
|
+
const log = createLogger("settings", { timestamp: true });
|
|
6
|
+
const DEFAULT_SETTINGS = {
|
|
7
|
+
criticalFiles: {
|
|
8
|
+
autoConfirm: false
|
|
9
|
+
// By default, require user confirmation
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
export class SettingsManager {
|
|
13
|
+
settingsPath;
|
|
14
|
+
settings;
|
|
15
|
+
constructor(rootDir) {
|
|
16
|
+
this.settingsPath = join(rootDir, DEVTOOLS_DATA_DIR, SETTINGS_FILE);
|
|
17
|
+
this.settings = this.loadSettings();
|
|
18
|
+
}
|
|
19
|
+
loadSettings() {
|
|
20
|
+
try {
|
|
21
|
+
if (existsSync(this.settingsPath)) {
|
|
22
|
+
const data = readFileSync(this.settingsPath, "utf-8");
|
|
23
|
+
const parsed = JSON.parse(data);
|
|
24
|
+
return this.mergeWithDefaults(parsed);
|
|
25
|
+
}
|
|
26
|
+
} catch (error) {
|
|
27
|
+
log("Failed to load settings, using defaults", { error });
|
|
28
|
+
}
|
|
29
|
+
return { ...DEFAULT_SETTINGS };
|
|
30
|
+
}
|
|
31
|
+
mergeWithDefaults(partial) {
|
|
32
|
+
return {
|
|
33
|
+
criticalFiles: {
|
|
34
|
+
...DEFAULT_SETTINGS.criticalFiles,
|
|
35
|
+
...partial.criticalFiles
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
saveSettings() {
|
|
40
|
+
try {
|
|
41
|
+
const dir = dirname(this.settingsPath);
|
|
42
|
+
if (!existsSync(dir)) {
|
|
43
|
+
mkdirSync(dir, { recursive: true });
|
|
44
|
+
}
|
|
45
|
+
writeFileSync(this.settingsPath, JSON.stringify(this.settings, null, 2));
|
|
46
|
+
log("Settings saved");
|
|
47
|
+
} catch (error) {
|
|
48
|
+
log("Failed to save settings", { error });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
getSettings() {
|
|
52
|
+
return { ...this.settings };
|
|
53
|
+
}
|
|
54
|
+
updateSettings(updates) {
|
|
55
|
+
this.settings = this.mergeWithDefaults({
|
|
56
|
+
...this.settings,
|
|
57
|
+
...updates
|
|
58
|
+
});
|
|
59
|
+
this.saveSettings();
|
|
60
|
+
return this.getSettings();
|
|
61
|
+
}
|
|
62
|
+
// Convenience methods
|
|
63
|
+
isAutoConfirmEnabled() {
|
|
64
|
+
return this.settings.criticalFiles.autoConfirm;
|
|
65
|
+
}
|
|
66
|
+
setAutoConfirm(value) {
|
|
67
|
+
this.settings.criticalFiles.autoConfirm = value;
|
|
68
|
+
this.saveSettings();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface ShareUser {
|
|
2
|
+
id: string;
|
|
3
|
+
nickname: string;
|
|
4
|
+
joinedAt: string;
|
|
5
|
+
lastSeen: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ShareStore {
|
|
8
|
+
version: 1;
|
|
9
|
+
users: ShareUser[];
|
|
10
|
+
}
|
|
11
|
+
export declare class ShareManager {
|
|
12
|
+
private storePath;
|
|
13
|
+
constructor(projectPath: string);
|
|
14
|
+
private loadStore;
|
|
15
|
+
private saveStore;
|
|
16
|
+
getUsers(): ShareUser[];
|
|
17
|
+
getUser(id: string): ShareUser | null;
|
|
18
|
+
getUserByNickname(nickname: string): ShareUser | null;
|
|
19
|
+
registerUser(id: string, nickname: string): ShareUser;
|
|
20
|
+
updateLastSeen(id: string): void;
|
|
21
|
+
isNicknameAvailable(nickname: string, excludeId?: string): boolean;
|
|
22
|
+
isActive(): boolean;
|
|
23
|
+
static generateUserId(): string;
|
|
24
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { createLogger } from "../logger.js";
|
|
4
|
+
import { DEVTOOLS_DATA_DIR, SHARE_FILE } from "./constants.js";
|
|
5
|
+
const log = createLogger("share", { timestamp: true });
|
|
6
|
+
export class ShareManager {
|
|
7
|
+
storePath;
|
|
8
|
+
constructor(projectPath) {
|
|
9
|
+
this.storePath = join(projectPath, DEVTOOLS_DATA_DIR, SHARE_FILE);
|
|
10
|
+
}
|
|
11
|
+
loadStore() {
|
|
12
|
+
try {
|
|
13
|
+
if (existsSync(this.storePath)) {
|
|
14
|
+
const data = readFileSync(this.storePath, "utf-8");
|
|
15
|
+
return JSON.parse(data);
|
|
16
|
+
}
|
|
17
|
+
} catch (error) {
|
|
18
|
+
log("Failed to load share store", { error });
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
version: 1,
|
|
22
|
+
users: []
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
saveStore(store) {
|
|
26
|
+
const dir = dirname(this.storePath);
|
|
27
|
+
if (!existsSync(dir)) {
|
|
28
|
+
mkdirSync(dir, { recursive: true });
|
|
29
|
+
}
|
|
30
|
+
writeFileSync(this.storePath, JSON.stringify(store, null, 2));
|
|
31
|
+
log("Saved share store");
|
|
32
|
+
}
|
|
33
|
+
// Get all users
|
|
34
|
+
getUsers() {
|
|
35
|
+
return this.loadStore().users;
|
|
36
|
+
}
|
|
37
|
+
// Get user by ID
|
|
38
|
+
getUser(id) {
|
|
39
|
+
const store = this.loadStore();
|
|
40
|
+
return store.users.find((u) => u.id === id) || null;
|
|
41
|
+
}
|
|
42
|
+
// Get user by nickname
|
|
43
|
+
getUserByNickname(nickname) {
|
|
44
|
+
const store = this.loadStore();
|
|
45
|
+
return store.users.find((u) => u.nickname.toLowerCase() === nickname.toLowerCase()) || null;
|
|
46
|
+
}
|
|
47
|
+
// Register or update user
|
|
48
|
+
registerUser(id, nickname) {
|
|
49
|
+
const store = this.loadStore();
|
|
50
|
+
const existingIndex = store.users.findIndex((u) => u.id === id);
|
|
51
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
52
|
+
if (existingIndex >= 0) {
|
|
53
|
+
store.users[existingIndex].nickname = nickname;
|
|
54
|
+
store.users[existingIndex].lastSeen = now;
|
|
55
|
+
this.saveStore(store);
|
|
56
|
+
log("Updated user", { id, nickname });
|
|
57
|
+
return store.users[existingIndex];
|
|
58
|
+
}
|
|
59
|
+
const user = {
|
|
60
|
+
id,
|
|
61
|
+
nickname,
|
|
62
|
+
joinedAt: now,
|
|
63
|
+
lastSeen: now
|
|
64
|
+
};
|
|
65
|
+
store.users.push(user);
|
|
66
|
+
this.saveStore(store);
|
|
67
|
+
log("Registered new user", { id, nickname });
|
|
68
|
+
return user;
|
|
69
|
+
}
|
|
70
|
+
// Update last seen
|
|
71
|
+
updateLastSeen(id) {
|
|
72
|
+
const store = this.loadStore();
|
|
73
|
+
const user = store.users.find((u) => u.id === id);
|
|
74
|
+
if (user) {
|
|
75
|
+
user.lastSeen = (/* @__PURE__ */ new Date()).toISOString();
|
|
76
|
+
this.saveStore(store);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Check if nickname is available
|
|
80
|
+
isNicknameAvailable(nickname, excludeId) {
|
|
81
|
+
const store = this.loadStore();
|
|
82
|
+
const existing = store.users.find(
|
|
83
|
+
(u) => u.nickname.toLowerCase() === nickname.toLowerCase() && u.id !== excludeId
|
|
84
|
+
);
|
|
85
|
+
return !existing;
|
|
86
|
+
}
|
|
87
|
+
// Check if sharing is active (has registered users)
|
|
88
|
+
isActive() {
|
|
89
|
+
const store = this.loadStore();
|
|
90
|
+
return store.users.length > 0;
|
|
91
|
+
}
|
|
92
|
+
// Generate user ID
|
|
93
|
+
static generateUserId() {
|
|
94
|
+
return Math.random().toString(36).substring(2, 10);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { MarkdownResourceManager } from './base-resource-manager.js';
|
|
1
2
|
export interface Skill {
|
|
2
3
|
name: string;
|
|
3
4
|
description: string;
|
|
@@ -11,12 +12,24 @@ export interface Skill {
|
|
|
11
12
|
context?: 'fork';
|
|
12
13
|
agent?: string;
|
|
13
14
|
updatedAt: string;
|
|
15
|
+
/** Source of the skill: 'project' for local .claude/, or plugin name */
|
|
16
|
+
source?: string;
|
|
14
17
|
}
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
interface SkillFrontmatter {
|
|
19
|
+
'name'?: string;
|
|
20
|
+
'description'?: string;
|
|
21
|
+
'argument-hint'?: string;
|
|
22
|
+
'disable-model-invocation'?: boolean;
|
|
23
|
+
'user-invocable'?: boolean;
|
|
24
|
+
'allowed-tools'?: string;
|
|
25
|
+
'model'?: string;
|
|
26
|
+
'context'?: string;
|
|
27
|
+
'agent'?: string;
|
|
28
|
+
}
|
|
29
|
+
export declare class SkillsManager extends MarkdownResourceManager<Skill, SkillFrontmatter> {
|
|
17
30
|
constructor(projectPath: string);
|
|
18
|
-
|
|
19
|
-
|
|
31
|
+
protected buildFrontmatter(skill: Partial<Skill>): string;
|
|
32
|
+
protected toResource(name: string, frontmatter: SkillFrontmatter, body: string, rawContent: string, updatedAt: string): Skill;
|
|
20
33
|
getSkills(): Skill[];
|
|
21
34
|
getSkill(name: string): Skill | null;
|
|
22
35
|
getSkillNames(): string[];
|
|
@@ -34,3 +47,4 @@ export declare class SkillsManager {
|
|
|
34
47
|
}): Skill;
|
|
35
48
|
deleteSkill(name: string): boolean;
|
|
36
49
|
}
|
|
50
|
+
export {};
|