@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.
Files changed (115) hide show
  1. package/README.md +105 -13
  2. package/dist/client/200.html +1 -1
  3. package/dist/client/404.html +1 -1
  4. package/dist/client/_nuxt/B8uzckkK.js +1 -0
  5. package/dist/client/_nuxt/{CPQSDiF7.js → BAb1fJOF.js} +4 -4
  6. package/dist/client/_nuxt/BB1-kxmm.js +1 -0
  7. package/dist/client/_nuxt/BMZIbUUD.js +1 -0
  8. package/dist/client/_nuxt/BSF2Vz9o.js +1 -0
  9. package/dist/client/_nuxt/BSVkH7b6.js +1 -0
  10. package/dist/client/_nuxt/{08Mb3FOO.js → BYp73eMl.js} +1 -1
  11. package/dist/client/_nuxt/B_BoWmnX.js +1 -0
  12. package/dist/client/_nuxt/BcZxFXBD.js +1 -0
  13. package/dist/client/_nuxt/BflmC3YB.js +1 -0
  14. package/dist/client/_nuxt/BnXQTjo-.js +1 -0
  15. package/dist/client/_nuxt/C--9REmc.js +1 -0
  16. package/dist/client/_nuxt/CDQtmRaX.js +1 -0
  17. package/dist/client/_nuxt/CHeJJZL9.js +1 -0
  18. package/dist/client/_nuxt/{CSlPuO5s.js → COus5Ssl.js} +1 -1
  19. package/dist/client/_nuxt/{o1jjB-UO.js → CPA0s6N9.js} +1 -1
  20. package/dist/client/_nuxt/CRkq21kc.js +1 -0
  21. package/dist/client/_nuxt/Cgba93Y9.js +1 -0
  22. package/dist/client/_nuxt/D2l4TRxW.js +1 -0
  23. package/dist/client/_nuxt/DC_XB519.js +1 -0
  24. package/dist/client/_nuxt/DEys9N1G.js +1 -0
  25. package/dist/client/_nuxt/{b4Upel01.js → DGQ4s7ae.js} +1 -1
  26. package/dist/client/_nuxt/DH8Ugy8E.js +1 -0
  27. package/dist/client/_nuxt/DSt96JPY.js +4 -0
  28. package/dist/client/_nuxt/DbJLoP3G.js +1 -0
  29. package/dist/client/_nuxt/DeGmaFBY.js +1 -0
  30. package/dist/client/_nuxt/DgfRwrFR.js +1 -0
  31. package/dist/client/_nuxt/{CLKqRoht.js → DolUcBed.js} +1 -1
  32. package/dist/client/_nuxt/M6QPYocW.js +1 -0
  33. package/dist/client/_nuxt/QumocfwJ.js +1 -0
  34. package/dist/client/_nuxt/TQi6eIO6.js +1 -0
  35. package/dist/client/_nuxt/V4UvAcd3.js +1 -0
  36. package/dist/client/_nuxt/builds/latest.json +1 -1
  37. package/dist/client/_nuxt/builds/meta/2be12f06-336a-4fdd-b982-2f6c682c14a6.json +1 -0
  38. package/dist/client/_nuxt/d8BPa19J.js +1 -0
  39. package/dist/client/_nuxt/entry.BMxUr06A.css +1 -0
  40. package/dist/client/_nuxt/qbS8UemQ.js +1 -0
  41. package/dist/client/_nuxt/wDw60tEC.js +10 -0
  42. package/dist/client/_nuxt/xEjB6ozD.js +1 -0
  43. package/dist/client/agents/index.html +1 -1
  44. package/dist/client/commands/index.html +1 -1
  45. package/dist/client/docs/index.html +1 -1
  46. package/dist/client/index.html +1 -1
  47. package/dist/client/mcp/index.html +1 -1
  48. package/dist/client/plugins/index.html +1 -0
  49. package/dist/client/settings/index.html +1 -0
  50. package/dist/client/skills/index.html +1 -1
  51. package/dist/module.d.mts +12 -1
  52. package/dist/module.json +1 -1
  53. package/dist/module.mjs +27 -5
  54. package/dist/runtime/constants.d.ts +29 -0
  55. package/dist/runtime/constants.js +5 -0
  56. package/dist/runtime/overlay/components/ChatOverlay.d.vue.ts +7 -0
  57. package/dist/runtime/overlay/components/ChatOverlay.vue +893 -0
  58. package/dist/runtime/overlay/components/ChatOverlay.vue.d.ts +7 -0
  59. package/dist/runtime/overlay/components/MarkdownContent.d.vue.ts +6 -0
  60. package/dist/runtime/overlay/components/MarkdownContent.vue +31 -0
  61. package/dist/runtime/overlay/components/MarkdownContent.vue.d.ts +6 -0
  62. package/dist/runtime/overlay/components/ToolCallBlock.d.vue.ts +8 -0
  63. package/dist/runtime/overlay/components/ToolCallBlock.vue +77 -0
  64. package/dist/runtime/overlay/components/ToolCallBlock.vue.d.ts +8 -0
  65. package/dist/runtime/overlay/plugin.client.d.ts +6 -0
  66. package/dist/runtime/overlay/plugin.client.js +29 -0
  67. package/dist/runtime/server/agents-manager.d.ts +17 -4
  68. package/dist/runtime/server/agents-manager.js +38 -109
  69. package/dist/runtime/server/base-resource-manager.d.ts +90 -0
  70. package/dist/runtime/server/base-resource-manager.js +201 -0
  71. package/dist/runtime/server/claude-session.d.ts +11 -1
  72. package/dist/runtime/server/claude-session.js +246 -27
  73. package/dist/runtime/server/commands-manager.d.ts +12 -4
  74. package/dist/runtime/server/commands-manager.js +25 -100
  75. package/dist/runtime/server/constants.d.ts +94 -0
  76. package/dist/runtime/server/constants.js +18 -0
  77. package/dist/runtime/server/docs-manager.d.ts +7 -0
  78. package/dist/runtime/server/docs-manager.js +112 -3
  79. package/dist/runtime/server/history-manager.d.ts +1 -0
  80. package/dist/runtime/server/history-manager.js +25 -3
  81. package/dist/runtime/server/plugins/socket.io.js +5 -3
  82. package/dist/runtime/server/plugins-manager.d.ts +84 -0
  83. package/dist/runtime/server/plugins-manager.js +338 -0
  84. package/dist/runtime/server/settings-manager.d.ts +17 -0
  85. package/dist/runtime/server/settings-manager.js +70 -0
  86. package/dist/runtime/server/share-manager.d.ts +24 -0
  87. package/dist/runtime/server/share-manager.js +96 -0
  88. package/dist/runtime/server/skills-manager.d.ts +18 -4
  89. package/dist/runtime/server/skills-manager.js +32 -159
  90. package/dist/runtime/shared/composables/useClaudeChat.d.ts +35 -0
  91. package/dist/runtime/shared/composables/useClaudeChat.js +264 -0
  92. package/dist/runtime/shared/composables/useShare.d.ts +42 -0
  93. package/dist/runtime/shared/composables/useShare.js +192 -0
  94. package/dist/runtime/shared/composables/useVoiceInput.d.ts +8 -0
  95. package/dist/runtime/shared/composables/useVoiceInput.js +77 -0
  96. package/dist/runtime/shared/constants.d.ts +28 -0
  97. package/dist/runtime/shared/constants.js +6 -0
  98. package/dist/runtime/shared/index.d.ts +9 -0
  99. package/dist/runtime/shared/index.js +5 -0
  100. package/dist/runtime/shared/types.d.ts +48 -0
  101. package/dist/runtime/shared/types.js +0 -0
  102. package/dist/runtime/types.d.ts +2 -0
  103. package/dist/types.d.mts +1 -1
  104. package/package.json +5 -3
  105. package/dist/client/_nuxt/BMi2eT6G.js +0 -1
  106. package/dist/client/_nuxt/BiBLVxWh.js +0 -1
  107. package/dist/client/_nuxt/BnRGpZsC.js +0 -8
  108. package/dist/client/_nuxt/C2GhPw5d.js +0 -7
  109. package/dist/client/_nuxt/D8683igF.js +0 -7
  110. package/dist/client/_nuxt/DBIw6BGF.js +0 -1
  111. package/dist/client/_nuxt/DCgjfr8H.js +0 -9
  112. package/dist/client/_nuxt/bl5iU4Kz.js +0 -1
  113. package/dist/client/_nuxt/builds/meta/35284331-5e85-46e0-9058-988fea05336c.json +0 -1
  114. package/dist/client/_nuxt/entry.BhHeZ_Nj.css +0 -1
  115. 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
- export declare class SkillsManager {
16
- private skillsDir;
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
- private parseFrontmatter;
19
- private buildFrontmatter;
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 {};