@paulduvall/claude-dev-toolkit 0.0.1-alpha.1 → 0.0.1-alpha.10

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 (141) hide show
  1. package/README.md +75 -17
  2. package/bin/claude-commands +250 -64
  3. package/commands/active/xarchitecture.md +393 -0
  4. package/commands/active/xconfig.md +127 -0
  5. package/commands/active/xdebug.md +130 -0
  6. package/commands/active/xdocs.md +178 -0
  7. package/commands/active/xgit.md +149 -0
  8. package/commands/active/xpipeline.md +152 -0
  9. package/commands/active/xquality.md +96 -0
  10. package/commands/active/xrefactor.md +198 -0
  11. package/commands/active/xrelease.md +142 -0
  12. package/commands/active/xsecurity.md +92 -0
  13. package/commands/active/xspec.md +174 -0
  14. package/commands/active/xtdd.md +151 -0
  15. package/commands/active/xtest.md +89 -0
  16. package/commands/experiments/xact.md +742 -0
  17. package/commands/experiments/xanalytics.md +113 -0
  18. package/commands/experiments/xanalyze.md +70 -0
  19. package/commands/experiments/xapi.md +161 -0
  20. package/commands/experiments/xatomic.md +112 -0
  21. package/commands/experiments/xaws.md +85 -0
  22. package/commands/experiments/xcicd.md +337 -0
  23. package/commands/experiments/xcommit.md +122 -0
  24. package/commands/experiments/xcompliance.md +182 -0
  25. package/commands/experiments/xconstraints.md +89 -0
  26. package/commands/experiments/xcoverage.md +90 -0
  27. package/commands/experiments/xdb.md +102 -0
  28. package/commands/experiments/xdesign.md +121 -0
  29. package/commands/experiments/xevaluate.md +111 -0
  30. package/commands/experiments/xfootnote.md +12 -0
  31. package/commands/experiments/xgenerate.md +117 -0
  32. package/commands/experiments/xgovernance.md +149 -0
  33. package/commands/experiments/xgreen.md +66 -0
  34. package/commands/experiments/xiac.md +118 -0
  35. package/commands/experiments/xincident.md +137 -0
  36. package/commands/experiments/xinfra.md +115 -0
  37. package/commands/experiments/xknowledge.md +115 -0
  38. package/commands/experiments/xmaturity.md +120 -0
  39. package/commands/experiments/xmetrics.md +118 -0
  40. package/commands/experiments/xmonitoring.md +128 -0
  41. package/commands/experiments/xnew.md +898 -0
  42. package/commands/experiments/xobservable.md +114 -0
  43. package/commands/experiments/xoidc.md +165 -0
  44. package/commands/experiments/xoptimize.md +115 -0
  45. package/commands/experiments/xperformance.md +112 -0
  46. package/commands/experiments/xplanning.md +131 -0
  47. package/commands/experiments/xpolicy.md +115 -0
  48. package/commands/experiments/xproduct.md +98 -0
  49. package/commands/experiments/xreadiness.md +75 -0
  50. package/commands/experiments/xred.md +55 -0
  51. package/commands/experiments/xrisk.md +128 -0
  52. package/commands/experiments/xrules.md +124 -0
  53. package/commands/experiments/xsandbox.md +120 -0
  54. package/commands/experiments/xscan.md +102 -0
  55. package/commands/experiments/xsetup.md +123 -0
  56. package/commands/experiments/xtemplate.md +116 -0
  57. package/commands/experiments/xtrace.md +212 -0
  58. package/commands/experiments/xux.md +171 -0
  59. package/commands/experiments/xvalidate.md +104 -0
  60. package/commands/experiments/xworkflow.md +113 -0
  61. package/hooks/README.md +231 -0
  62. package/hooks/file-logger.sh +98 -0
  63. package/hooks/lib/argument-parser.sh +422 -0
  64. package/hooks/lib/config-constants.sh +230 -0
  65. package/hooks/lib/context-manager.sh +549 -0
  66. package/hooks/lib/error-handler.sh +412 -0
  67. package/hooks/lib/execution-engine.sh +627 -0
  68. package/hooks/lib/file-utils.sh +375 -0
  69. package/hooks/lib/subagent-discovery.sh +465 -0
  70. package/hooks/lib/subagent-validator.sh +597 -0
  71. package/hooks/on-error-debug.sh +221 -0
  72. package/hooks/pre-commit-quality.sh +204 -0
  73. package/hooks/pre-write-security.sh +107 -0
  74. package/hooks/prevent-credential-exposure.sh +265 -0
  75. package/hooks/subagent-trigger-simple.sh +193 -0
  76. package/hooks/subagent-trigger.sh +253 -0
  77. package/lib/backup-restore-command.js +140 -0
  78. package/lib/base/base-command.js +252 -0
  79. package/lib/base/command-result.js +184 -0
  80. package/lib/config/constants.js +255 -0
  81. package/lib/config.js +228 -3
  82. package/lib/configure-command.js +428 -0
  83. package/lib/dependency-validator.js +64 -5
  84. package/lib/hook-installer-core.js +2 -2
  85. package/lib/installation-instruction-generator-backup.js +579 -0
  86. package/lib/installation-instruction-generator.js +213 -495
  87. package/lib/installer.js +134 -56
  88. package/lib/oidc-command.js +354 -0
  89. package/lib/result.js +138 -0
  90. package/lib/services/backup-list-service.js +226 -0
  91. package/lib/services/backup-service.js +230 -0
  92. package/lib/services/command-installer-service.js +217 -0
  93. package/lib/services/logger-service.js +201 -0
  94. package/lib/services/package-manager-service.js +319 -0
  95. package/lib/services/platform-instruction-service.js +294 -0
  96. package/lib/services/recovery-instruction-service.js +348 -0
  97. package/lib/services/restore-service.js +221 -0
  98. package/lib/setup-command.js +309 -0
  99. package/lib/subagent-formatter.js +278 -0
  100. package/lib/subagents-core.js +237 -0
  101. package/lib/subagents.js +508 -0
  102. package/lib/types.d.ts +183 -0
  103. package/lib/utils/claude-path-config.js +184 -0
  104. package/lib/utils/file-system-utils.js +152 -0
  105. package/lib/utils.js +8 -4
  106. package/lib/verify-command.js +430 -0
  107. package/package.json +17 -4
  108. package/scripts/postinstall.js +28 -10
  109. package/subagents/api-guardian.md +29 -0
  110. package/subagents/audit-trail-verifier.md +24 -0
  111. package/subagents/change-scoper.md +23 -0
  112. package/subagents/ci-pipeline-curator.md +24 -0
  113. package/subagents/code-review-assistant.md +258 -0
  114. package/subagents/continuous-release-orchestrator.md +29 -0
  115. package/subagents/contract-tester.md +24 -0
  116. package/subagents/data-steward.md +29 -0
  117. package/subagents/debug-context.md +197 -0
  118. package/subagents/debug-specialist.md +138 -0
  119. package/subagents/dependency-steward.md +24 -0
  120. package/subagents/deployment-strategist.md +29 -0
  121. package/subagents/documentation-curator.md +29 -0
  122. package/subagents/environment-guardian.md +29 -0
  123. package/subagents/license-compliance-guardian.md +29 -0
  124. package/subagents/observability-engineer.md +25 -0
  125. package/subagents/performance-guardian.md +29 -0
  126. package/subagents/product-owner-proxy.md +28 -0
  127. package/subagents/requirements-reviewer.md +26 -0
  128. package/subagents/rollback-first-responder.md +24 -0
  129. package/subagents/sbom-provenance.md +25 -0
  130. package/subagents/security-auditor.md +29 -0
  131. package/subagents/style-enforcer.md +23 -0
  132. package/subagents/test-writer.md +24 -0
  133. package/subagents/trunk-guardian.md +29 -0
  134. package/subagents/workflow-coordinator.md +26 -0
  135. package/templates/README.md +100 -0
  136. package/templates/basic-settings.json +30 -0
  137. package/templates/comprehensive-settings.json +206 -0
  138. package/templates/hybrid-hook-config.yaml +133 -0
  139. package/templates/security-focused-settings.json +62 -0
  140. package/templates/subagent-hooks.yaml +188 -0
  141. package/tsconfig.json +37 -0
@@ -0,0 +1,278 @@
1
+ /**
2
+ * Subagent Output Formatter
3
+ * Handles all console output formatting for subagent operations
4
+ * Separates display logic from business logic
5
+ */
6
+
7
+ /**
8
+ * Emoji and message constants for consistent formatting
9
+ */
10
+ const DISPLAY_CONSTANTS = {
11
+ EMOJIS: {
12
+ ROBOT: '🤖',
13
+ SUCCESS: '✅',
14
+ ERROR: '❌',
15
+ FOLDER: '📁',
16
+ ROCKET: '🚀',
17
+ PARTY: '🎉',
18
+ CHART: '📊'
19
+ },
20
+ MESSAGES: {
21
+ NO_SUBAGENTS: 'No subagents directory found in package or no subagent files available',
22
+ NO_SUBAGENTS_INSTALL: 'No subagents directory found in package or no subagent files to install',
23
+ INSTALL_FAILED: 'Failed to install',
24
+ INSTALL_SUCCESS: 'Successfully installed',
25
+ CREATE_DIR_FAILED: 'Failed to create directory'
26
+ }
27
+ };
28
+
29
+ /**
30
+ * Formatter for subagent listing operations
31
+ */
32
+ class SubagentListFormatter {
33
+ /**
34
+ * Format the header for subagent listing
35
+ */
36
+ static formatHeader() {
37
+ return `${DISPLAY_CONSTANTS.EMOJIS.ROBOT} Available Subagents:\n`;
38
+ }
39
+
40
+ /**
41
+ * Format the no subagents found message
42
+ */
43
+ static formatNoSubagents() {
44
+ return `${DISPLAY_CONSTANTS.EMOJIS.ERROR} ${DISPLAY_CONSTANTS.MESSAGES.NO_SUBAGENTS}`;
45
+ }
46
+
47
+ /**
48
+ * Format a single subagent item
49
+ * @param {string} name - Subagent name
50
+ * @param {number} index - Index in the list
51
+ */
52
+ static formatSubagentItem(name, index) {
53
+ return ` ${index + 1}. ${name}`;
54
+ }
55
+
56
+ /**
57
+ * Format the summary footer
58
+ * @param {number} count - Number of subagents
59
+ */
60
+ static formatSummary(count) {
61
+ return `\n${DISPLAY_CONSTANTS.EMOJIS.CHART} ${count} subagents available`;
62
+ }
63
+
64
+ /**
65
+ * Format complete subagent list
66
+ * @param {string[]} subagents - Array of subagent names
67
+ */
68
+ static formatList(subagents) {
69
+ if (subagents.length === 0) {
70
+ return [
71
+ this.formatHeader(),
72
+ this.formatNoSubagents()
73
+ ];
74
+ }
75
+
76
+ const lines = [this.formatHeader()];
77
+
78
+ subagents.forEach((name, index) => {
79
+ lines.push(this.formatSubagentItem(name, index));
80
+ });
81
+
82
+ lines.push(this.formatSummary(subagents.length));
83
+
84
+ return lines;
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Formatter for subagent installation operations
90
+ */
91
+ class SubagentInstallFormatter {
92
+ /**
93
+ * Format installation header
94
+ */
95
+ static formatHeader() {
96
+ return `${DISPLAY_CONSTANTS.EMOJIS.ROCKET} Installing AI Subagents...\n`;
97
+ }
98
+
99
+ /**
100
+ * Format no subagents to install message
101
+ */
102
+ static formatNoSubagents() {
103
+ return `${DISPLAY_CONSTANTS.EMOJIS.ERROR} ${DISPLAY_CONSTANTS.MESSAGES.NO_SUBAGENTS_INSTALL}`;
104
+ }
105
+
106
+ /**
107
+ * Format directory creation message
108
+ * @param {string} path - Directory path that was created
109
+ */
110
+ static formatDirectoryCreated(path) {
111
+ return `${DISPLAY_CONSTANTS.EMOJIS.FOLDER} Created directory: ${path}`;
112
+ }
113
+
114
+ /**
115
+ * Format successful installation of a single file
116
+ * @param {string} filename - Name of the installed file
117
+ */
118
+ static formatInstallSuccess(filename) {
119
+ return ` ${DISPLAY_CONSTANTS.EMOJIS.SUCCESS} ${filename}`;
120
+ }
121
+
122
+ /**
123
+ * Format failed installation of a single file
124
+ * @param {string} filename - Name of the file that failed to install
125
+ * @param {string} error - Error message
126
+ */
127
+ static formatInstallError(filename, error) {
128
+ return ` ${DISPLAY_CONSTANTS.EMOJIS.ERROR} ${DISPLAY_CONSTANTS.MESSAGES.INSTALL_FAILED} ${filename}: ${error}`;
129
+ }
130
+
131
+ /**
132
+ * Format installation summary
133
+ * @param {Object} summary - Installation summary object
134
+ * @param {number} summary.installed - Number of successfully installed files
135
+ * @param {number} summary.failed - Number of failed installations
136
+ * @param {string} summary.path - Installation path
137
+ */
138
+ static formatSummary(summary) {
139
+ const lines = [
140
+ `\n${DISPLAY_CONSTANTS.EMOJIS.PARTY} Installation Summary:`,
141
+ ` ${DISPLAY_CONSTANTS.MESSAGES.INSTALL_SUCCESS}: ${summary.installed} subagents`
142
+ ];
143
+
144
+ if (summary.failed > 0) {
145
+ lines.push(` ${DISPLAY_CONSTANTS.MESSAGES.INSTALL_FAILED}: ${summary.failed} subagents`);
146
+ }
147
+
148
+ lines.push(` Installation path: ${summary.path}`);
149
+
150
+ return lines;
151
+ }
152
+
153
+ /**
154
+ * Format directory creation error
155
+ * @param {string} error - Error message
156
+ */
157
+ static formatDirectoryError(error) {
158
+ return `${DISPLAY_CONSTANTS.EMOJIS.ERROR} ${DISPLAY_CONSTANTS.MESSAGES.CREATE_DIR_FAILED}: ${error}`;
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Formatter for help text
164
+ */
165
+ class SubagentHelpFormatter {
166
+ /**
167
+ * Format complete help text
168
+ * @param {number} subagentCount - Number of available subagents
169
+ */
170
+ static formatHelp(subagentCount) {
171
+ return [
172
+ `${DISPLAY_CONSTANTS.EMOJIS.ROBOT} Claude Commands - Subagents Management\n`,
173
+ 'Usage:',
174
+ ' claude-commands subagents [options]\n',
175
+ 'Options:',
176
+ ' -l, --list List available AI subagents from package',
177
+ ' -i, --install Install all subagents to Claude Code (~/.claude/subagents/)',
178
+ ' -h, --help Show this help message\n',
179
+ 'Examples:',
180
+ ' claude-commands subagents --list # Show available subagents',
181
+ ' claude-commands subagents --install # Install all subagents',
182
+ ' claude-commands subagents --help # Show this help\n',
183
+ 'Description:',
184
+ ' Manage AI subagents for Claude Code. Subagents are specialized AI',
185
+ ' assistants that help with specific development tasks like security',
186
+ ' auditing, code review, documentation, and more.\n',
187
+ `Package Status: ${subagentCount} subagents available`
188
+ ];
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Main formatter class that orchestrates all formatting operations
194
+ */
195
+ class SubagentFormatter {
196
+ /**
197
+ * Display formatted subagent list
198
+ * @param {string[]} subagents - Array of subagent names
199
+ */
200
+ static displayList(subagents) {
201
+ const lines = SubagentListFormatter.formatList(subagents);
202
+ console.log(lines.join('\n'));
203
+ }
204
+
205
+ /**
206
+ * Display installation progress and results
207
+ * @param {Object} params - Installation parameters
208
+ * @param {string[]} params.subagents - Subagents to install
209
+ * @param {function} params.onProgress - Progress callback (filename, success, error)
210
+ * @param {function} params.onDirectoryCreated - Directory creation callback (path)
211
+ * @param {Object} params.summary - Final summary
212
+ */
213
+ static displayInstallation({ subagents, onProgress, onDirectoryCreated, summary }) {
214
+ console.log(SubagentInstallFormatter.formatHeader());
215
+
216
+ if (subagents.length === 0) {
217
+ console.log(SubagentInstallFormatter.formatNoSubagents());
218
+ return;
219
+ }
220
+
221
+ // Directory creation feedback
222
+ if (onDirectoryCreated) {
223
+ onDirectoryCreated((path) => {
224
+ console.log(SubagentInstallFormatter.formatDirectoryCreated(path));
225
+ });
226
+ }
227
+
228
+ // Progress feedback
229
+ if (onProgress) {
230
+ onProgress((filename, success, error) => {
231
+ if (success) {
232
+ console.log(SubagentInstallFormatter.formatInstallSuccess(filename));
233
+ } else {
234
+ console.log(SubagentInstallFormatter.formatInstallError(filename, error));
235
+ }
236
+ });
237
+ }
238
+
239
+ // Final summary
240
+ if (summary) {
241
+ const summaryLines = SubagentInstallFormatter.formatSummary(summary);
242
+ console.log(summaryLines.join('\n'));
243
+ }
244
+ }
245
+
246
+ /**
247
+ * Display help text
248
+ * @param {number} subagentCount - Number of available subagents
249
+ */
250
+ static displayHelp(subagentCount) {
251
+ const helpLines = SubagentHelpFormatter.formatHelp(subagentCount);
252
+ console.log(helpLines.join('\n'));
253
+ }
254
+
255
+ /**
256
+ * Display error message
257
+ * @param {string} error - Error message
258
+ */
259
+ static displayError(error) {
260
+ console.error(`${DISPLAY_CONSTANTS.EMOJIS.ERROR} ${error}`);
261
+ }
262
+
263
+ /**
264
+ * Display directory creation error
265
+ * @param {string} error - Error message
266
+ */
267
+ static displayDirectoryError(error) {
268
+ console.error(SubagentInstallFormatter.formatDirectoryError(error));
269
+ }
270
+ }
271
+
272
+ module.exports = {
273
+ SubagentFormatter,
274
+ SubagentListFormatter,
275
+ SubagentInstallFormatter,
276
+ SubagentHelpFormatter,
277
+ DISPLAY_CONSTANTS
278
+ };
@@ -0,0 +1,237 @@
1
+ /**
2
+ * Subagents Core Business Logic
3
+ * Pure business logic without console output side effects
4
+ * Uses Result pattern for error handling
5
+ */
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+ const os = require('os');
10
+ const { Result } = require('./result');
11
+
12
+ // Business logic constants
13
+ const CORE_CONSTANTS = {
14
+ FILE_EXTENSION: '.md',
15
+ CLAUDE_DIR: '.claude',
16
+ SUBAGENTS_DIR: 'subagents'
17
+ };
18
+
19
+ /**
20
+ * Pure business logic for subagent operations
21
+ * All methods return Result objects instead of boolean/throwing
22
+ */
23
+ class SubagentsCoreService {
24
+ constructor() {
25
+ this.packageRoot = path.join(__dirname, '..');
26
+ this.subagentsDir = path.join(this.packageRoot, CORE_CONSTANTS.SUBAGENTS_DIR);
27
+ this.claudeDir = path.join(os.homedir(), CORE_CONSTANTS.CLAUDE_DIR);
28
+ this.claudeSubagentsDir = path.join(this.claudeDir, CORE_CONSTANTS.SUBAGENTS_DIR);
29
+ }
30
+
31
+ /**
32
+ * Get list of available subagent files
33
+ * @returns {Result<string[]>} Array of subagent filenames or error
34
+ */
35
+ getAvailableSubagents() {
36
+ return Result.try(() => {
37
+ if (!fs.existsSync(this.subagentsDir)) {
38
+ return [];
39
+ }
40
+
41
+ return fs.readdirSync(this.subagentsDir)
42
+ .filter(f => f.endsWith(CORE_CONSTANTS.FILE_EXTENSION))
43
+ .sort();
44
+ });
45
+ }
46
+
47
+ /**
48
+ * Get subagent names without file extensions
49
+ * @returns {Result<string[]>} Array of subagent names or error
50
+ */
51
+ getSubagentNames() {
52
+ return this.getAvailableSubagents()
53
+ .map(files => files.map(f => f.replace(CORE_CONSTANTS.FILE_EXTENSION, '')));
54
+ }
55
+
56
+ /**
57
+ * Check if Claude directory structure exists
58
+ * @returns {Result<{claudeDir: boolean, subagentsDir: boolean}>} Directory existence status
59
+ */
60
+ checkDirectoryStructure() {
61
+ return Result.try(() => ({
62
+ claudeDir: fs.existsSync(this.claudeDir),
63
+ subagentsDir: fs.existsSync(this.claudeSubagentsDir)
64
+ }));
65
+ }
66
+
67
+ /**
68
+ * Ensure Claude directory structure exists
69
+ * @returns {Result<{created: boolean, path: string}>} Creation result
70
+ */
71
+ ensureClaudeDirectory() {
72
+ return Result.try(() => {
73
+ let created = false;
74
+
75
+ if (!fs.existsSync(this.claudeDir)) {
76
+ fs.mkdirSync(this.claudeDir, { recursive: true });
77
+ }
78
+
79
+ if (!fs.existsSync(this.claudeSubagentsDir)) {
80
+ fs.mkdirSync(this.claudeSubagentsDir, { recursive: true });
81
+ created = true;
82
+ }
83
+
84
+ return {
85
+ created,
86
+ path: this.claudeSubagentsDir
87
+ };
88
+ });
89
+ }
90
+
91
+ /**
92
+ * Install a single subagent file
93
+ * @param {string} filename - Subagent filename
94
+ * @returns {Result<{filename: string, installed: boolean}>} Installation result
95
+ */
96
+ installSingleSubagent(filename) {
97
+ return Result.try(() => {
98
+ const sourcePath = path.join(this.subagentsDir, filename);
99
+ const destPath = path.join(this.claudeSubagentsDir, filename);
100
+
101
+ fs.copyFileSync(sourcePath, destPath);
102
+
103
+ return {
104
+ filename,
105
+ installed: true
106
+ };
107
+ });
108
+ }
109
+
110
+ /**
111
+ * Install all available subagents
112
+ * @returns {Result<{installed: string[], failed: Array<{filename: string, error: string}>, summary: Object}>}
113
+ */
114
+ installAllSubagents() {
115
+ // Get available subagents
116
+ const subagentsResult = this.getAvailableSubagents();
117
+ if (subagentsResult.isError) {
118
+ return subagentsResult;
119
+ }
120
+
121
+ const subagentFiles = subagentsResult.value;
122
+ if (subagentFiles.length === 0) {
123
+ return Result.err(new Error('No subagent files found to install'));
124
+ }
125
+
126
+ // Ensure directory exists
127
+ const dirResult = this.ensureClaudeDirectory();
128
+ if (dirResult.isError) {
129
+ return dirResult;
130
+ }
131
+
132
+ // Install each subagent
133
+ const installed = [];
134
+ const failed = [];
135
+
136
+ for (const filename of subagentFiles) {
137
+ const installResult = this.installSingleSubagent(filename);
138
+
139
+ if (installResult.isOk) {
140
+ installed.push(filename);
141
+ } else {
142
+ failed.push({
143
+ filename,
144
+ error: installResult.error.message
145
+ });
146
+ }
147
+ }
148
+
149
+ const summary = {
150
+ installed: installed.length,
151
+ failed: failed.length,
152
+ path: this.claudeSubagentsDir,
153
+ directoryCreated: dirResult.value.created
154
+ };
155
+
156
+ return Result.ok({
157
+ installed,
158
+ failed,
159
+ summary
160
+ });
161
+ }
162
+
163
+ /**
164
+ * Validate subagent installation
165
+ * @returns {Result<{valid: boolean, installedCount: number, issues: string[]}>}
166
+ */
167
+ validateInstallation() {
168
+ return Result.try(() => {
169
+ const issues = [];
170
+ let installedCount = 0;
171
+
172
+ // Check if directory exists
173
+ if (!fs.existsSync(this.claudeSubagentsDir)) {
174
+ issues.push('Subagents directory does not exist');
175
+ return { valid: false, installedCount: 0, issues };
176
+ }
177
+
178
+ // Count installed files
179
+ const installedFiles = fs.readdirSync(this.claudeSubagentsDir)
180
+ .filter(f => f.endsWith(CORE_CONSTANTS.FILE_EXTENSION));
181
+
182
+ installedCount = installedFiles.length;
183
+
184
+ // Get available files for comparison
185
+ const availableResult = this.getAvailableSubagents();
186
+ if (availableResult.isOk) {
187
+ const availableFiles = availableResult.value;
188
+ const missingFiles = availableFiles.filter(f => !installedFiles.includes(f));
189
+
190
+ if (missingFiles.length > 0) {
191
+ issues.push(`Missing files: ${missingFiles.join(', ')}`);
192
+ }
193
+ }
194
+
195
+ return {
196
+ valid: issues.length === 0,
197
+ installedCount,
198
+ issues
199
+ };
200
+ });
201
+ }
202
+
203
+ /**
204
+ * Get installation status information
205
+ * @returns {Result<Object>} Status information
206
+ */
207
+ getInstallationStatus() {
208
+ return Result.try(() => {
209
+ const available = this.getAvailableSubagents().unwrapOr([]);
210
+ const directoryStatus = this.checkDirectoryStructure().unwrapOr({
211
+ claudeDir: false,
212
+ subagentsDir: false
213
+ });
214
+
215
+ let installed = [];
216
+ if (directoryStatus.subagentsDir) {
217
+ installed = fs.readdirSync(this.claudeSubagentsDir)
218
+ .filter(f => f.endsWith(CORE_CONSTANTS.FILE_EXTENSION));
219
+ }
220
+
221
+ return {
222
+ available: available.length,
223
+ installed: installed.length,
224
+ directories: directoryStatus,
225
+ paths: {
226
+ packageSubagents: this.subagentsDir,
227
+ claudeSubagents: this.claudeSubagentsDir
228
+ }
229
+ };
230
+ });
231
+ }
232
+ }
233
+
234
+ module.exports = {
235
+ SubagentsCoreService,
236
+ CORE_CONSTANTS
237
+ };