@paulduvall/claude-dev-toolkit 0.0.1-alpha.1 → 0.0.1-alpha.2
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/bin/claude-commands +20 -0
- package/lib/config.js +186 -3
- package/lib/result.js +138 -0
- package/lib/subagent-formatter.js +278 -0
- package/lib/subagents-core.js +237 -0
- package/lib/subagents.js +508 -0
- package/lib/types.d.ts +183 -0
- package/package.json +12 -3
- package/subagents/api-guardian.md +29 -0
- package/subagents/audit-trail-verifier.md +24 -0
- package/subagents/change-scoper.md +23 -0
- package/subagents/ci-pipeline-curator.md +24 -0
- package/subagents/code-review-assistant.md +258 -0
- package/subagents/continuous-release-orchestrator.md +29 -0
- package/subagents/contract-tester.md +24 -0
- package/subagents/data-steward.md +29 -0
- package/subagents/debug-context.md +197 -0
- package/subagents/debug-specialist.md +138 -0
- package/subagents/dependency-steward.md +24 -0
- package/subagents/deployment-strategist.md +29 -0
- package/subagents/documentation-curator.md +29 -0
- package/subagents/environment-guardian.md +29 -0
- package/subagents/license-compliance-guardian.md +29 -0
- package/subagents/observability-engineer.md +25 -0
- package/subagents/performance-guardian.md +29 -0
- package/subagents/product-owner-proxy.md +28 -0
- package/subagents/requirements-reviewer.md +26 -0
- package/subagents/rollback-first-responder.md +24 -0
- package/subagents/sbom-provenance.md +25 -0
- package/subagents/security-auditor.md +29 -0
- package/subagents/style-enforcer.md +23 -0
- package/subagents/test-writer.md +24 -0
- package/subagents/trunk-guardian.md +29 -0
- package/subagents/workflow-coordinator.md +26 -0
- package/tsconfig.json +37 -0
package/lib/subagents.js
ADDED
|
@@ -0,0 +1,508 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subagents Module - Async/Await Version (CommonJS)
|
|
3
|
+
* Backward compatible with enhanced async support
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs').promises;
|
|
7
|
+
const fsSync = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const os = require('os');
|
|
10
|
+
const { Result } = require('./result');
|
|
11
|
+
const { SubagentFormatter } = require('./subagent-formatter');
|
|
12
|
+
|
|
13
|
+
// Enhanced Result with async support
|
|
14
|
+
class AsyncResult extends Result {
|
|
15
|
+
static async tryAsync(fn) {
|
|
16
|
+
try {
|
|
17
|
+
const result = await fn();
|
|
18
|
+
return Result.ok(result);
|
|
19
|
+
} catch (error) {
|
|
20
|
+
return Result.err(error);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async mapAsync(fn) {
|
|
25
|
+
if (this.isError) return this;
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const result = await fn(this.value);
|
|
29
|
+
return Result.ok(result);
|
|
30
|
+
} catch (error) {
|
|
31
|
+
return Result.err(error);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async flatMapAsync(fn) {
|
|
36
|
+
if (this.isError) return this;
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
return await fn(this.value);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
return Result.err(error);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async matchAsync(okFn, errFn) {
|
|
46
|
+
if (this.isOk) {
|
|
47
|
+
return await okFn(this.value);
|
|
48
|
+
} else {
|
|
49
|
+
return await errFn(this.error);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Constants
|
|
55
|
+
const CONSTANTS = {
|
|
56
|
+
FILE_EXTENSION: '.md',
|
|
57
|
+
CLAUDE_DIR: '.claude',
|
|
58
|
+
SUBAGENTS_DIR: 'subagents'
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Async Core Service for subagent operations
|
|
63
|
+
*/
|
|
64
|
+
class AsyncSubagentsCoreService {
|
|
65
|
+
constructor() {
|
|
66
|
+
this.packageRoot = path.join(__dirname, '..');
|
|
67
|
+
this.subagentsDir = path.join(this.packageRoot, CONSTANTS.SUBAGENTS_DIR);
|
|
68
|
+
this.claudeDir = path.join(os.homedir(), CONSTANTS.CLAUDE_DIR);
|
|
69
|
+
this.claudeSubagentsDir = path.join(this.claudeDir, CONSTANTS.SUBAGENTS_DIR);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Get list of available subagent files (async)
|
|
74
|
+
*/
|
|
75
|
+
async getAvailableSubagents() {
|
|
76
|
+
return await AsyncResult.tryAsync(async () => {
|
|
77
|
+
try {
|
|
78
|
+
await fs.access(this.subagentsDir);
|
|
79
|
+
} catch {
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const files = await fs.readdir(this.subagentsDir);
|
|
84
|
+
return files
|
|
85
|
+
.filter(f => f.endsWith(CONSTANTS.FILE_EXTENSION))
|
|
86
|
+
.sort();
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Get subagent names without file extensions (async)
|
|
92
|
+
*/
|
|
93
|
+
async getSubagentNames() {
|
|
94
|
+
const result = await this.getAvailableSubagents();
|
|
95
|
+
return result.map(files => files.map(f => f.replace(CONSTANTS.FILE_EXTENSION, '')));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Check if Claude directory structure exists (async)
|
|
100
|
+
*/
|
|
101
|
+
async checkDirectoryStructure() {
|
|
102
|
+
return await AsyncResult.tryAsync(async () => {
|
|
103
|
+
const checkPromises = [
|
|
104
|
+
fs.access(this.claudeDir).then(() => true).catch(() => false),
|
|
105
|
+
fs.access(this.claudeSubagentsDir).then(() => true).catch(() => false)
|
|
106
|
+
];
|
|
107
|
+
|
|
108
|
+
const [claudeDir, subagentsDir] = await Promise.all(checkPromises);
|
|
109
|
+
|
|
110
|
+
return { claudeDir, subagentsDir };
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Ensure Claude directory structure exists (async)
|
|
116
|
+
*/
|
|
117
|
+
async ensureClaudeDirectory() {
|
|
118
|
+
return await AsyncResult.tryAsync(async () => {
|
|
119
|
+
let created = false;
|
|
120
|
+
|
|
121
|
+
// Create base Claude directory
|
|
122
|
+
await fs.mkdir(this.claudeDir, { recursive: true });
|
|
123
|
+
|
|
124
|
+
// Check if subagents directory exists
|
|
125
|
+
try {
|
|
126
|
+
await fs.access(this.claudeSubagentsDir);
|
|
127
|
+
} catch {
|
|
128
|
+
// Create subagents directory if it doesn't exist
|
|
129
|
+
await fs.mkdir(this.claudeSubagentsDir, { recursive: true });
|
|
130
|
+
created = true;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
created,
|
|
135
|
+
path: this.claudeSubagentsDir
|
|
136
|
+
};
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Install a single subagent file (async)
|
|
142
|
+
*/
|
|
143
|
+
async installSingleSubagent(filename) {
|
|
144
|
+
return await AsyncResult.tryAsync(async () => {
|
|
145
|
+
const sourcePath = path.join(this.subagentsDir, filename);
|
|
146
|
+
const destPath = path.join(this.claudeSubagentsDir, filename);
|
|
147
|
+
|
|
148
|
+
await fs.copyFile(sourcePath, destPath);
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
filename,
|
|
152
|
+
installed: true
|
|
153
|
+
};
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Install all available subagents with parallel processing (async)
|
|
159
|
+
*/
|
|
160
|
+
async installAllSubagents() {
|
|
161
|
+
// Get available subagents
|
|
162
|
+
const subagentsResult = await this.getAvailableSubagents();
|
|
163
|
+
if (subagentsResult.isError) {
|
|
164
|
+
return subagentsResult;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const subagentFiles = subagentsResult.value;
|
|
168
|
+
if (subagentFiles.length === 0) {
|
|
169
|
+
return Result.err(new Error('No subagent files found to install'));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Ensure directory exists
|
|
173
|
+
const dirResult = await this.ensureClaudeDirectory();
|
|
174
|
+
if (dirResult.isError) {
|
|
175
|
+
return dirResult;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Install all subagents in parallel for better performance
|
|
179
|
+
const installPromises = subagentFiles.map(async (filename) => {
|
|
180
|
+
const result = await this.installSingleSubagent(filename);
|
|
181
|
+
return { filename, result };
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const results = await Promise.allSettled(installPromises);
|
|
185
|
+
|
|
186
|
+
const installed = [];
|
|
187
|
+
const failed = [];
|
|
188
|
+
|
|
189
|
+
results.forEach((promiseResult) => {
|
|
190
|
+
if (promiseResult.status === 'fulfilled') {
|
|
191
|
+
const { filename, result } = promiseResult.value;
|
|
192
|
+
if (result.isOk) {
|
|
193
|
+
installed.push(filename);
|
|
194
|
+
} else {
|
|
195
|
+
failed.push({
|
|
196
|
+
filename,
|
|
197
|
+
error: result.error.message
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
} else {
|
|
201
|
+
// This should rarely happen as we're catching errors in installSingleSubagent
|
|
202
|
+
failed.push({
|
|
203
|
+
filename: 'unknown',
|
|
204
|
+
error: promiseResult.reason.message || 'Unknown error'
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
const summary = {
|
|
210
|
+
installed: installed.length,
|
|
211
|
+
failed: failed.length,
|
|
212
|
+
path: this.claudeSubagentsDir,
|
|
213
|
+
directoryCreated: dirResult.value.created
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
return Result.ok({
|
|
217
|
+
installed,
|
|
218
|
+
failed,
|
|
219
|
+
summary
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Validate subagent installation (async)
|
|
225
|
+
*/
|
|
226
|
+
async validateInstallation() {
|
|
227
|
+
return await AsyncResult.tryAsync(async () => {
|
|
228
|
+
const issues = [];
|
|
229
|
+
let installedCount = 0;
|
|
230
|
+
|
|
231
|
+
// Check if directory exists
|
|
232
|
+
try {
|
|
233
|
+
await fs.access(this.claudeSubagentsDir);
|
|
234
|
+
} catch {
|
|
235
|
+
issues.push('Subagents directory does not exist');
|
|
236
|
+
return { valid: false, installedCount: 0, issues };
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Count installed files
|
|
240
|
+
const installedFiles = await fs.readdir(this.claudeSubagentsDir);
|
|
241
|
+
const mdFiles = installedFiles.filter(f => f.endsWith(CONSTANTS.FILE_EXTENSION));
|
|
242
|
+
installedCount = mdFiles.length;
|
|
243
|
+
|
|
244
|
+
// Get available files for comparison
|
|
245
|
+
const availableResult = await this.getAvailableSubagents();
|
|
246
|
+
if (availableResult.isOk) {
|
|
247
|
+
const availableFiles = availableResult.value;
|
|
248
|
+
const missingFiles = availableFiles.filter(f => !mdFiles.includes(f));
|
|
249
|
+
|
|
250
|
+
if (missingFiles.length > 0) {
|
|
251
|
+
issues.push(`Missing files: ${missingFiles.join(', ')}`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return {
|
|
256
|
+
valid: issues.length === 0,
|
|
257
|
+
installedCount,
|
|
258
|
+
issues
|
|
259
|
+
};
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Get installation status information (async)
|
|
265
|
+
*/
|
|
266
|
+
async getInstallationStatus() {
|
|
267
|
+
return await AsyncResult.tryAsync(async () => {
|
|
268
|
+
const [availableResult, directoryResult] = await Promise.all([
|
|
269
|
+
this.getAvailableSubagents(),
|
|
270
|
+
this.checkDirectoryStructure()
|
|
271
|
+
]);
|
|
272
|
+
|
|
273
|
+
const availableCount = availableResult.unwrapOr([]).length;
|
|
274
|
+
const dirStatus = directoryResult.unwrapOr({
|
|
275
|
+
claudeDir: false,
|
|
276
|
+
subagentsDir: false
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
let installedCount = 0;
|
|
280
|
+
if (dirStatus.subagentsDir) {
|
|
281
|
+
try {
|
|
282
|
+
const installed = await fs.readdir(this.claudeSubagentsDir);
|
|
283
|
+
installedCount = installed.filter(f => f.endsWith(CONSTANTS.FILE_EXTENSION)).length;
|
|
284
|
+
} catch {
|
|
285
|
+
installedCount = 0;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return {
|
|
290
|
+
available: availableCount,
|
|
291
|
+
installed: installedCount,
|
|
292
|
+
directories: dirStatus,
|
|
293
|
+
paths: {
|
|
294
|
+
packageSubagents: this.subagentsDir,
|
|
295
|
+
claudeSubagents: this.claudeSubagentsDir
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Async Subagents Manager with backward-compatible interface
|
|
304
|
+
*/
|
|
305
|
+
class AsyncSubagentsManager {
|
|
306
|
+
constructor() {
|
|
307
|
+
this.coreService = new AsyncSubagentsCoreService();
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Async versions of all methods
|
|
311
|
+
async listAvailableSubagentsAsync() {
|
|
312
|
+
const result = await this.coreService.getSubagentNames();
|
|
313
|
+
|
|
314
|
+
return await result.matchAsync(
|
|
315
|
+
async (names) => {
|
|
316
|
+
SubagentFormatter.displayList(names);
|
|
317
|
+
return true;
|
|
318
|
+
},
|
|
319
|
+
async (error) => {
|
|
320
|
+
SubagentFormatter.displayError(`Failed to list subagents: ${error.message}`);
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
async installSubagentsAsync() {
|
|
327
|
+
const result = await this.coreService.installAllSubagents();
|
|
328
|
+
|
|
329
|
+
return await result.matchAsync(
|
|
330
|
+
async (installationData) => {
|
|
331
|
+
SubagentFormatter.displayInstallation({
|
|
332
|
+
subagents: [...installationData.installed, ...installationData.failed.map(f => f.filename)],
|
|
333
|
+
onProgress: (callback) => {
|
|
334
|
+
installationData.installed.forEach(filename => {
|
|
335
|
+
callback(filename, true, null);
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
installationData.failed.forEach(failure => {
|
|
339
|
+
callback(failure.filename, false, failure.error);
|
|
340
|
+
});
|
|
341
|
+
},
|
|
342
|
+
onDirectoryCreated: (callback) => {
|
|
343
|
+
if (installationData.summary.directoryCreated) {
|
|
344
|
+
callback(installationData.summary.path);
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
summary: installationData.summary
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
return installationData.summary.installed > 0;
|
|
351
|
+
},
|
|
352
|
+
async (error) => {
|
|
353
|
+
SubagentFormatter.displayError(`Installation failed: ${error.message}`);
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
async showHelpAsync() {
|
|
360
|
+
const countResult = await this.coreService.getAvailableSubagents();
|
|
361
|
+
const count = countResult.unwrapOr([]).length;
|
|
362
|
+
|
|
363
|
+
SubagentFormatter.displayHelp(count);
|
|
364
|
+
return true;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
async handleCommandAsync(options) {
|
|
368
|
+
if (options.help) {
|
|
369
|
+
return await this.showHelpAsync();
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (options.list) {
|
|
373
|
+
return await this.listAvailableSubagentsAsync();
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (options.install) {
|
|
377
|
+
return await this.installSubagentsAsync();
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
return await this.showHelpAsync();
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Backward compatible sync versions (using fallback)
|
|
384
|
+
listAvailableSubagents() {
|
|
385
|
+
// For sync compatibility, we fall back to the sync version
|
|
386
|
+
// In a real scenario, you might want to use sync fs operations here
|
|
387
|
+
console.warn('Using async method synchronously. Consider using the async version.');
|
|
388
|
+
|
|
389
|
+
// Use the sync fallback from the original implementation
|
|
390
|
+
const { SubagentsCoreService } = require('./subagents-core');
|
|
391
|
+
const syncService = new SubagentsCoreService();
|
|
392
|
+
const result = syncService.getSubagentNames();
|
|
393
|
+
|
|
394
|
+
return result.match(
|
|
395
|
+
(names) => {
|
|
396
|
+
SubagentFormatter.displayList(names);
|
|
397
|
+
return true;
|
|
398
|
+
},
|
|
399
|
+
(error) => {
|
|
400
|
+
SubagentFormatter.displayError(`Failed to list subagents: ${error.message}`);
|
|
401
|
+
return false;
|
|
402
|
+
}
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
installSubagents() {
|
|
407
|
+
console.warn('Using async method synchronously. Consider using the async version.');
|
|
408
|
+
|
|
409
|
+
const { SubagentsCoreService } = require('./subagents-core');
|
|
410
|
+
const syncService = new SubagentsCoreService();
|
|
411
|
+
const result = syncService.installAllSubagents();
|
|
412
|
+
|
|
413
|
+
return result.match(
|
|
414
|
+
(installationData) => {
|
|
415
|
+
SubagentFormatter.displayInstallation({
|
|
416
|
+
subagents: [...installationData.installed, ...installationData.failed.map(f => f.filename)],
|
|
417
|
+
onProgress: (callback) => {
|
|
418
|
+
installationData.installed.forEach(filename => {
|
|
419
|
+
callback(filename, true, null);
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
installationData.failed.forEach(failure => {
|
|
423
|
+
callback(failure.filename, false, failure.error);
|
|
424
|
+
});
|
|
425
|
+
},
|
|
426
|
+
onDirectoryCreated: (callback) => {
|
|
427
|
+
if (installationData.summary.directoryCreated) {
|
|
428
|
+
callback(installationData.summary.path);
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
summary: installationData.summary
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
return installationData.summary.installed > 0;
|
|
435
|
+
},
|
|
436
|
+
(error) => {
|
|
437
|
+
SubagentFormatter.displayError(`Installation failed: ${error.message}`);
|
|
438
|
+
return false;
|
|
439
|
+
}
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
showHelp() {
|
|
444
|
+
const { SubagentsCoreService } = require('./subagents-core');
|
|
445
|
+
const syncService = new SubagentsCoreService();
|
|
446
|
+
const countResult = syncService.getAvailableSubagents();
|
|
447
|
+
const count = countResult.unwrapOr([]).length;
|
|
448
|
+
|
|
449
|
+
SubagentFormatter.displayHelp(count);
|
|
450
|
+
return true;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
handleCommand(options) {
|
|
454
|
+
if (options.help) {
|
|
455
|
+
return this.showHelp();
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (options.list) {
|
|
459
|
+
return this.listAvailableSubagents();
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
if (options.install) {
|
|
463
|
+
return this.installSubagents();
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
return this.showHelp();
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// Pure async business logic methods
|
|
470
|
+
async getStatusAsync() {
|
|
471
|
+
return await this.coreService.getInstallationStatus();
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
async validateInstallationAsync() {
|
|
475
|
+
return await this.coreService.validateInstallation();
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
async getAvailableSubagentsAsync() {
|
|
479
|
+
return await this.coreService.getSubagentNames();
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Create manager instance
|
|
484
|
+
const asyncSubagentsManager = new AsyncSubagentsManager();
|
|
485
|
+
|
|
486
|
+
module.exports = {
|
|
487
|
+
// Legacy compatibility - sync interface
|
|
488
|
+
handleCommand: (options) => asyncSubagentsManager.handleCommand(options),
|
|
489
|
+
listAvailableSubagents: () => asyncSubagentsManager.listAvailableSubagents(),
|
|
490
|
+
installSubagents: () => asyncSubagentsManager.installSubagents(),
|
|
491
|
+
showHelp: () => asyncSubagentsManager.showHelp(),
|
|
492
|
+
|
|
493
|
+
// New async interface (recommended)
|
|
494
|
+
handleCommandAsync: (options) => asyncSubagentsManager.handleCommandAsync(options),
|
|
495
|
+
listAvailableSubagentsAsync: () => asyncSubagentsManager.listAvailableSubagentsAsync(),
|
|
496
|
+
installSubagentsAsync: () => asyncSubagentsManager.installSubagentsAsync(),
|
|
497
|
+
showHelpAsync: () => asyncSubagentsManager.showHelpAsync(),
|
|
498
|
+
|
|
499
|
+
// Pure business logic (async)
|
|
500
|
+
getStatusAsync: () => asyncSubagentsManager.getStatusAsync(),
|
|
501
|
+
validateInstallationAsync: () => asyncSubagentsManager.validateInstallationAsync(),
|
|
502
|
+
getAvailableSubagentsAsync: () => asyncSubagentsManager.getAvailableSubagentsAsync(),
|
|
503
|
+
|
|
504
|
+
// Export classes for advanced usage
|
|
505
|
+
AsyncSubagentsManager,
|
|
506
|
+
AsyncSubagentsCoreService,
|
|
507
|
+
AsyncResult
|
|
508
|
+
};
|
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript Type Definitions for Subagents Module
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Result Pattern Types
|
|
6
|
+
export interface ResultOk<T> {
|
|
7
|
+
readonly value: T;
|
|
8
|
+
readonly isOk: true;
|
|
9
|
+
readonly isError: false;
|
|
10
|
+
map<U>(fn: (value: T) => U): Result<U>;
|
|
11
|
+
flatMap<U>(fn: (value: T) => Result<U>): Result<U>;
|
|
12
|
+
mapError(fn: (error: any) => any): Result<T>;
|
|
13
|
+
unwrap(): T;
|
|
14
|
+
unwrapOr(defaultValue: T): T;
|
|
15
|
+
match<U>(okFn: (value: T) => U, errFn: (error: any) => U): U;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ResultErr<E = Error> {
|
|
19
|
+
readonly error: E;
|
|
20
|
+
readonly isOk: false;
|
|
21
|
+
readonly isError: true;
|
|
22
|
+
map<U>(fn: (value: any) => U): Result<U>;
|
|
23
|
+
flatMap<U>(fn: (value: any) => Result<U>): Result<U>;
|
|
24
|
+
mapError(fn: (error: E) => any): Result<any>;
|
|
25
|
+
unwrap(): never;
|
|
26
|
+
unwrapOr<T>(defaultValue: T): T;
|
|
27
|
+
match<U>(okFn: (value: any) => U, errFn: (error: E) => U): U;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type Result<T, E = Error> = ResultOk<T> | ResultErr<E>;
|
|
31
|
+
|
|
32
|
+
// Core Business Logic Types
|
|
33
|
+
export interface SubagentFile {
|
|
34
|
+
filename: string;
|
|
35
|
+
name: string;
|
|
36
|
+
path: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface DirectoryStatus {
|
|
40
|
+
claudeDir: boolean;
|
|
41
|
+
subagentsDir: boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface DirectoryCreationResult {
|
|
45
|
+
created: boolean;
|
|
46
|
+
path: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface InstallationResult {
|
|
50
|
+
filename: string;
|
|
51
|
+
installed: boolean;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface InstallationFailure {
|
|
55
|
+
filename: string;
|
|
56
|
+
error: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface InstallationSummary {
|
|
60
|
+
installed: number;
|
|
61
|
+
failed: number;
|
|
62
|
+
path: string;
|
|
63
|
+
directoryCreated: boolean;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface InstallationData {
|
|
67
|
+
installed: string[];
|
|
68
|
+
failed: InstallationFailure[];
|
|
69
|
+
summary: InstallationSummary;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface ValidationResult {
|
|
73
|
+
valid: boolean;
|
|
74
|
+
installedCount: number;
|
|
75
|
+
issues: string[];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface InstallationStatus {
|
|
79
|
+
available: number;
|
|
80
|
+
installed: number;
|
|
81
|
+
directories: DirectoryStatus;
|
|
82
|
+
paths: {
|
|
83
|
+
packageSubagents: string;
|
|
84
|
+
claudeSubagents: string;
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Command Options Types
|
|
89
|
+
export interface SubagentCommandOptions {
|
|
90
|
+
help?: boolean;
|
|
91
|
+
list?: boolean;
|
|
92
|
+
install?: boolean;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Formatter Types
|
|
96
|
+
export interface FormatterCallbacks {
|
|
97
|
+
onProgress?: (callback: (filename: string, success: boolean, error: string | null) => void) => void;
|
|
98
|
+
onDirectoryCreated?: (callback: (path: string) => void) => void;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface DisplayInstallationParams extends FormatterCallbacks {
|
|
102
|
+
subagents: string[];
|
|
103
|
+
summary?: InstallationSummary;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Core Service Interface
|
|
107
|
+
export interface ISubagentsCoreService {
|
|
108
|
+
getAvailableSubagents(): Result<string[]>;
|
|
109
|
+
getSubagentNames(): Result<string[]>;
|
|
110
|
+
checkDirectoryStructure(): Result<DirectoryStatus>;
|
|
111
|
+
ensureClaudeDirectory(): Result<DirectoryCreationResult>;
|
|
112
|
+
installSingleSubagent(filename: string): Result<InstallationResult>;
|
|
113
|
+
installAllSubagents(): Result<InstallationData>;
|
|
114
|
+
validateInstallation(): Result<ValidationResult>;
|
|
115
|
+
getInstallationStatus(): Result<InstallationStatus>;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Manager Interface
|
|
119
|
+
export interface ISubagentsManager {
|
|
120
|
+
listAvailableSubagents(): boolean;
|
|
121
|
+
installSubagents(): boolean;
|
|
122
|
+
showHelp(): boolean;
|
|
123
|
+
handleCommand(options: SubagentCommandOptions): boolean;
|
|
124
|
+
getStatus(): Result<InstallationStatus>;
|
|
125
|
+
validateInstallation(): Result<ValidationResult>;
|
|
126
|
+
getAvailableSubagents(): Result<string[]>;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Formatter Interface
|
|
130
|
+
export interface ISubagentFormatter {
|
|
131
|
+
displayList(subagents: string[]): void;
|
|
132
|
+
displayInstallation(params: DisplayInstallationParams): void;
|
|
133
|
+
displayHelp(subagentCount: number): void;
|
|
134
|
+
displayError(error: string): void;
|
|
135
|
+
displayDirectoryError(error: string): void;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Constants
|
|
139
|
+
export interface DisplayConstants {
|
|
140
|
+
EMOJIS: {
|
|
141
|
+
ROBOT: string;
|
|
142
|
+
SUCCESS: string;
|
|
143
|
+
ERROR: string;
|
|
144
|
+
FOLDER: string;
|
|
145
|
+
ROCKET: string;
|
|
146
|
+
PARTY: string;
|
|
147
|
+
CHART: string;
|
|
148
|
+
};
|
|
149
|
+
MESSAGES: {
|
|
150
|
+
NO_SUBAGENTS: string;
|
|
151
|
+
NO_SUBAGENTS_INSTALL: string;
|
|
152
|
+
INSTALL_FAILED: string;
|
|
153
|
+
INSTALL_SUCCESS: string;
|
|
154
|
+
CREATE_DIR_FAILED: string;
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export interface CoreConstants {
|
|
159
|
+
FILE_EXTENSION: string;
|
|
160
|
+
CLAUDE_DIR: string;
|
|
161
|
+
SUBAGENTS_DIR: string;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Module Exports
|
|
165
|
+
export interface SubagentsModule {
|
|
166
|
+
handleCommand: (options: SubagentCommandOptions) => boolean;
|
|
167
|
+
listAvailableSubagents: () => boolean;
|
|
168
|
+
installSubagents: () => boolean;
|
|
169
|
+
showHelp: () => boolean;
|
|
170
|
+
getStatus: () => Result<InstallationStatus>;
|
|
171
|
+
validateInstallation: () => Result<ValidationResult>;
|
|
172
|
+
getAvailableSubagents: () => Result<string[]>;
|
|
173
|
+
SubagentsManager: new () => ISubagentsManager;
|
|
174
|
+
SubagentsCoreService: new () => ISubagentsCoreService;
|
|
175
|
+
SubagentFormatter: ISubagentFormatter;
|
|
176
|
+
Result: {
|
|
177
|
+
ok<T>(value: T): ResultOk<T>;
|
|
178
|
+
err<E>(error: E): ResultErr<E>;
|
|
179
|
+
try<T>(fn: () => T): Result<T>;
|
|
180
|
+
tryAsync<T>(fn: () => Promise<T>): Promise<Result<T>>;
|
|
181
|
+
all<T>(results: Result<T>[]): Result<T[]>;
|
|
182
|
+
};
|
|
183
|
+
}
|