claude-comms 1.0.1 → 1.0.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/CHANGELOG.md +53 -0
- package/README.md +64 -23
- package/bin/claude-setup.js +118 -38
- package/package.json +65 -18
- package/src/cli/index.js +30 -0
- package/src/cli/interfaces.js +386 -0
- package/src/cli/parser.js +158 -0
- package/src/cli/prompts.js +317 -0
- package/src/cli/runner.js +436 -0
- package/src/fetcher/github.js +676 -0
- package/src/index.js +221 -0
- package/src/installer/dependency-check.js +19 -0
- package/src/installer/file-writer.js +648 -0
- package/src/orchestrator/installer.js +849 -0
- package/src/orchestrator/main.js +267 -0
- package/src/orchestrator/mocks/index.js +388 -0
- package/src/utils/config.js +430 -0
- package/src/utils/constants.js +397 -0
- package/src/utils/errors.js +361 -0
- package/src/utils/index.js +46 -0
- package/src/utils/logger.js +177 -0
- package/src/utils/platform.js +362 -0
- package/src/utils/retry.js +358 -0
- package/templates/settings.local.json +1 -0
- package/.claude/hooks/comms/messages_UmaMatrix.json +0 -10
- package/.claude/hooks/comms/messages_VictorSpiral.json +0 -10
- package/.claude/hooks/comms/messages_WendyQuantum.json +0 -10
- package/.claude/hooks/comms/messages_XavierPrism.json +0 -10
- package/templates/get_unread_messages.py +0 -54
- package/templates/send_message.py +0 -75
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface Contracts for @claude-code/setup-installer
|
|
3
|
+
*
|
|
4
|
+
* Defines the contracts and interfaces for future integration with:
|
|
5
|
+
* - GitHub API operations (WP03)
|
|
6
|
+
* - File system operations (WP04)
|
|
7
|
+
* - Installation orchestration (WP06)
|
|
8
|
+
*
|
|
9
|
+
* These interfaces serve as the integration points between CLI and core modules.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* GitHub Fetcher Interface
|
|
14
|
+
* Will be implemented in WP03 - GitHub API Integration
|
|
15
|
+
*/
|
|
16
|
+
class GitHubFetcherInterface {
|
|
17
|
+
/**
|
|
18
|
+
* Fetch directory structure from GitHub repository
|
|
19
|
+
* @param {Object} options - Fetch options
|
|
20
|
+
* @param {string} options.owner - Repository owner
|
|
21
|
+
* @param {string} options.repo - Repository name
|
|
22
|
+
* @param {string} options.path - Directory path to fetch
|
|
23
|
+
* @param {string} options.ref - Git reference (branch/tag/commit)
|
|
24
|
+
* @returns {Promise<DirectoryStructure>} Directory structure with files
|
|
25
|
+
*/
|
|
26
|
+
async fetchDirectory(_options) {
|
|
27
|
+
throw new Error('GitHubFetcher.fetchDirectory not implemented');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Fetch single file content from GitHub
|
|
32
|
+
* @param {Object} options - Fetch options
|
|
33
|
+
* @param {string} options.owner - Repository owner
|
|
34
|
+
* @param {string} options.repo - Repository name
|
|
35
|
+
* @param {string} options.path - File path
|
|
36
|
+
* @param {string} options.ref - Git reference
|
|
37
|
+
* @returns {Promise<FileContent>} File content and metadata
|
|
38
|
+
*/
|
|
39
|
+
async fetchFile(_options) {
|
|
40
|
+
throw new Error('GitHubFetcher.fetchFile not implemented');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Validate GitHub API connectivity and rate limits
|
|
45
|
+
* @returns {Promise<APIStatus>} API status and rate limit info
|
|
46
|
+
*/
|
|
47
|
+
async validateConnection() {
|
|
48
|
+
throw new Error('GitHubFetcher.validateConnection not implemented');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* File Writer Interface
|
|
54
|
+
* Will be implemented in WP04 - File Writer Module
|
|
55
|
+
*/
|
|
56
|
+
class FileWriterInterface {
|
|
57
|
+
/**
|
|
58
|
+
* Write files to target directory with conflict resolution
|
|
59
|
+
* @param {Array<FileSpec>} files - Files to write
|
|
60
|
+
* @param {Object} options - Write options
|
|
61
|
+
* @param {string} options.targetDir - Target directory
|
|
62
|
+
* @param {string} options.strategy - Conflict resolution strategy
|
|
63
|
+
* @param {boolean} options.createBackup - Whether to create backups
|
|
64
|
+
* @param {boolean} options.preservePermissions - Preserve file permissions
|
|
65
|
+
* @returns {Promise<WriteResult>} Write operation results
|
|
66
|
+
*/
|
|
67
|
+
async writeFiles(_files, _options) {
|
|
68
|
+
throw new Error('FileWriter.writeFiles not implemented');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Check for existing files that would conflict
|
|
73
|
+
* @param {Array<string>} filePaths - File paths to check
|
|
74
|
+
* @param {string} targetDir - Target directory
|
|
75
|
+
* @returns {Promise<ConflictReport>} Conflict detection report
|
|
76
|
+
*/
|
|
77
|
+
async checkConflicts(_filePaths, _targetDir) {
|
|
78
|
+
throw new Error('FileWriter.checkConflicts not implemented');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Create backup of existing files
|
|
83
|
+
* @param {Array<string>} filePaths - Files to backup
|
|
84
|
+
* @param {string} targetDir - Target directory
|
|
85
|
+
* @returns {Promise<BackupResult>} Backup operation results
|
|
86
|
+
*/
|
|
87
|
+
async createBackups(_filePaths, _targetDir) {
|
|
88
|
+
throw new Error('FileWriter.createBackups not implemented');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Rollback file operations on failure
|
|
93
|
+
* @param {WriteResult} writeResult - Previous write operation result
|
|
94
|
+
* @returns {Promise<void>} Rollback completion
|
|
95
|
+
*/
|
|
96
|
+
async rollback(_writeResult) {
|
|
97
|
+
throw new Error('FileWriter.rollback not implemented');
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Dependency Checker Interface
|
|
103
|
+
* Will be implemented in WP04 - File Writer Module
|
|
104
|
+
*/
|
|
105
|
+
class DependencyCheckerInterface {
|
|
106
|
+
/**
|
|
107
|
+
* Check for Python installation and version
|
|
108
|
+
* @returns {Promise<PythonStatus>} Python installation status
|
|
109
|
+
*/
|
|
110
|
+
async checkPython() {
|
|
111
|
+
throw new Error('DependencyChecker.checkPython not implemented');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Check for uv (Python package manager) installation
|
|
116
|
+
* @returns {Promise<UvStatus>} uv installation status
|
|
117
|
+
*/
|
|
118
|
+
async checkUv() {
|
|
119
|
+
throw new Error('DependencyChecker.checkUv not implemented');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Check Node.js version compatibility
|
|
124
|
+
* @returns {Promise<NodeStatus>} Node.js status
|
|
125
|
+
*/
|
|
126
|
+
async checkNode() {
|
|
127
|
+
throw new Error('DependencyChecker.checkNode not implemented');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Validate all required dependencies
|
|
132
|
+
* @returns {Promise<DependencyReport>} Complete dependency report
|
|
133
|
+
*/
|
|
134
|
+
async validateAll() {
|
|
135
|
+
throw new Error('DependencyChecker.validateAll not implemented');
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Installation Orchestrator Interface
|
|
141
|
+
* Will be implemented in WP06 - Installation Orchestrator
|
|
142
|
+
*/
|
|
143
|
+
class InstallationOrchestratorInterface {
|
|
144
|
+
/**
|
|
145
|
+
* Run complete installation flow
|
|
146
|
+
* @param {InstallationConfig} config - Installation configuration
|
|
147
|
+
* @returns {Promise<InstallationResult>} Installation results
|
|
148
|
+
*/
|
|
149
|
+
async install(_config) {
|
|
150
|
+
throw new Error('InstallationOrchestrator.install not implemented');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Validate installation integrity
|
|
155
|
+
* @param {string} targetDir - Installation directory
|
|
156
|
+
* @returns {Promise<ValidationResult>} Validation results
|
|
157
|
+
*/
|
|
158
|
+
async validate(_targetDir) {
|
|
159
|
+
throw new Error('InstallationOrchestrator.validate not implemented');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Generate configuration files
|
|
164
|
+
* @param {Object} options - Configuration options
|
|
165
|
+
* @returns {Promise<Array<FileSpec>>} Generated configuration files
|
|
166
|
+
*/
|
|
167
|
+
async generateConfigs(_options) {
|
|
168
|
+
throw new Error('InstallationOrchestrator.generateConfigs not implemented');
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// ============================================================================
|
|
173
|
+
// TYPE DEFINITIONS (for documentation and future TypeScript support)
|
|
174
|
+
// ============================================================================
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* @typedef {Object} DirectoryStructure
|
|
178
|
+
* @property {Array<FileSpec>} files - Array of files in directory
|
|
179
|
+
* @property {Array<string>} directories - Subdirectories found
|
|
180
|
+
* @property {Object} metadata - Repository metadata
|
|
181
|
+
* @property {string} metadata.sha - Commit SHA
|
|
182
|
+
* @property {string} metadata.url - API URL used
|
|
183
|
+
*/
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* @typedef {Object} FileSpec
|
|
187
|
+
* @property {string} path - Relative file path
|
|
188
|
+
* @property {string} content - File content (string or base64)
|
|
189
|
+
* @property {number} mode - File permissions (octal)
|
|
190
|
+
* @property {number} size - File size in bytes
|
|
191
|
+
* @property {string} encoding - Content encoding ('utf-8' or 'base64')
|
|
192
|
+
* @property {string} sha - File SHA hash
|
|
193
|
+
*/
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* @typedef {Object} FileContent
|
|
197
|
+
* @property {string} content - File content
|
|
198
|
+
* @property {string} encoding - Content encoding
|
|
199
|
+
* @property {number} size - File size
|
|
200
|
+
* @property {string} sha - File SHA
|
|
201
|
+
* @property {Object} metadata - File metadata
|
|
202
|
+
*/
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* @typedef {Object} WriteResult
|
|
206
|
+
* @property {Array<string>} written - Successfully written files
|
|
207
|
+
* @property {Array<string>} skipped - Skipped files
|
|
208
|
+
* @property {Array<string>} backed_up - Files that were backed up
|
|
209
|
+
* @property {Array<Object>} errors - Write errors encountered
|
|
210
|
+
* @property {Array<string>} rollback_info - Information for potential rollback
|
|
211
|
+
*/
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* @typedef {Object} ConflictReport
|
|
215
|
+
* @property {boolean} hasConflicts - Whether conflicts were found
|
|
216
|
+
* @property {Array<string>} conflictFiles - Files that would conflict
|
|
217
|
+
* @property {Array<Object>} details - Detailed conflict information
|
|
218
|
+
*/
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* @typedef {Object} InstallationConfig
|
|
222
|
+
* @property {string} targetDir - Target installation directory
|
|
223
|
+
* @property {string} repository - GitHub repository
|
|
224
|
+
* @property {string} ref - Git reference (branch/tag/commit)
|
|
225
|
+
* @property {string} strategy - Conflict resolution strategy
|
|
226
|
+
* @property {boolean} pythonCheck - Whether to check Python dependencies
|
|
227
|
+
* @property {boolean} createBackup - Whether to create backups
|
|
228
|
+
* @property {string} configUrl - Observability server URL
|
|
229
|
+
* @property {boolean} dryRun - Whether to run in dry-run mode
|
|
230
|
+
*/
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* @typedef {Object} InstallationResult
|
|
234
|
+
* @property {boolean} success - Whether installation succeeded
|
|
235
|
+
* @property {WriteResult} writeResult - File write results
|
|
236
|
+
* @property {Array<string>} configFiles - Generated configuration files
|
|
237
|
+
* @property {DependencyReport} dependencies - Dependency check results
|
|
238
|
+
* @property {string} installationId - Unique installation ID
|
|
239
|
+
* @property {number} duration - Installation duration in ms
|
|
240
|
+
*/
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* @typedef {Object} PythonStatus
|
|
244
|
+
* @property {boolean} installed - Whether Python is installed
|
|
245
|
+
* @property {string} version - Python version string
|
|
246
|
+
* @property {string} executable - Path to Python executable
|
|
247
|
+
* @property {boolean} compatible - Whether version is compatible
|
|
248
|
+
*/
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* @typedef {Object} DependencyReport
|
|
252
|
+
* @property {PythonStatus} python - Python status
|
|
253
|
+
* @property {Object} uv - uv status
|
|
254
|
+
* @property {Object} node - Node.js status
|
|
255
|
+
* @property {boolean} allSatisfied - Whether all dependencies are satisfied
|
|
256
|
+
* @property {Array<string>} missing - Missing dependencies
|
|
257
|
+
* @property {Array<string>} warnings - Dependency warnings
|
|
258
|
+
*/
|
|
259
|
+
|
|
260
|
+
// ============================================================================
|
|
261
|
+
// MOCK IMPLEMENTATIONS (for testing CLI during early development)
|
|
262
|
+
// ============================================================================
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Mock GitHub Fetcher for CLI testing
|
|
266
|
+
*/
|
|
267
|
+
class MockGitHubFetcher extends GitHubFetcherInterface {
|
|
268
|
+
async fetchDirectory(_options) {
|
|
269
|
+
// Simulate network delay
|
|
270
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
271
|
+
|
|
272
|
+
return {
|
|
273
|
+
files: [
|
|
274
|
+
{
|
|
275
|
+
path: '.claude/settings.json',
|
|
276
|
+
content: JSON.stringify({ version: '1.0.0' }, null, 2),
|
|
277
|
+
mode: 0o644,
|
|
278
|
+
size: 50,
|
|
279
|
+
encoding: 'utf-8',
|
|
280
|
+
sha: 'mock-sha-1'
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
path: 'CLAUDE.md',
|
|
284
|
+
content: '# Claude Setup\n\nProject configured for Claude.',
|
|
285
|
+
mode: 0o644,
|
|
286
|
+
size: 45,
|
|
287
|
+
encoding: 'utf-8',
|
|
288
|
+
sha: 'mock-sha-2'
|
|
289
|
+
}
|
|
290
|
+
],
|
|
291
|
+
directories: ['.claude', '.claude/hooks', '.claude/agents'],
|
|
292
|
+
metadata: {
|
|
293
|
+
sha: 'mock-commit-sha',
|
|
294
|
+
url: 'mock-api-url'
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
async validateConnection() {
|
|
300
|
+
return {
|
|
301
|
+
connected: true,
|
|
302
|
+
rateLimit: { remaining: 5000, reset: Date.now() + 3600000 }
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Mock File Writer for CLI testing
|
|
309
|
+
*/
|
|
310
|
+
class MockFileWriter extends FileWriterInterface {
|
|
311
|
+
async writeFiles(files, _options) {
|
|
312
|
+
// Simulate file operations
|
|
313
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
314
|
+
|
|
315
|
+
return {
|
|
316
|
+
written: files.map(f => f.path),
|
|
317
|
+
skipped: [],
|
|
318
|
+
backed_up: [],
|
|
319
|
+
errors: [],
|
|
320
|
+
rollback_info: []
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
async checkConflicts(_filePaths, _targetDir) {
|
|
325
|
+
return {
|
|
326
|
+
hasConflicts: false,
|
|
327
|
+
conflictFiles: [],
|
|
328
|
+
details: []
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Integration factory for creating service instances
|
|
335
|
+
* This will be replaced with real implementations as they become available
|
|
336
|
+
*/
|
|
337
|
+
class ServiceFactory {
|
|
338
|
+
static createGitHubFetcher(useMock = true) {
|
|
339
|
+
if (useMock) {
|
|
340
|
+
return new MockGitHubFetcher();
|
|
341
|
+
}
|
|
342
|
+
// Will return real implementation when available
|
|
343
|
+
throw new Error('Real GitHubFetcher not yet implemented');
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
static createFileWriter(useMock = true) {
|
|
347
|
+
if (useMock) {
|
|
348
|
+
return new MockFileWriter();
|
|
349
|
+
}
|
|
350
|
+
// Will return real implementation when available
|
|
351
|
+
throw new Error('Real FileWriter not yet implemented');
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
static createDependencyChecker(useMock = true) {
|
|
355
|
+
if (useMock) {
|
|
356
|
+
return {
|
|
357
|
+
async validateAll() {
|
|
358
|
+
return {
|
|
359
|
+
python: { installed: true, version: '3.9.0', compatible: true },
|
|
360
|
+
uv: { installed: true, version: '0.1.0' },
|
|
361
|
+
node: { installed: true, version: '18.0.0', compatible: true },
|
|
362
|
+
allSatisfied: true,
|
|
363
|
+
missing: [],
|
|
364
|
+
warnings: []
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
throw new Error('Real DependencyChecker not yet implemented');
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
module.exports = {
|
|
374
|
+
// Interface classes
|
|
375
|
+
GitHubFetcherInterface,
|
|
376
|
+
FileWriterInterface,
|
|
377
|
+
DependencyCheckerInterface,
|
|
378
|
+
InstallationOrchestratorInterface,
|
|
379
|
+
|
|
380
|
+
// Mock implementations
|
|
381
|
+
MockGitHubFetcher,
|
|
382
|
+
MockFileWriter,
|
|
383
|
+
|
|
384
|
+
// Service factory
|
|
385
|
+
ServiceFactory
|
|
386
|
+
};
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Argument Parser for @claude-code/setup-installer
|
|
3
|
+
*
|
|
4
|
+
* Uses commander.js to define and parse command-line arguments
|
|
5
|
+
* Supports:
|
|
6
|
+
* - --force: Skip confirmation prompts and overwrite existing files
|
|
7
|
+
* - --verbose: Enable detailed logging
|
|
8
|
+
* - --target-dir: Specify installation directory
|
|
9
|
+
* - --tag: Install specific version tag
|
|
10
|
+
* - --no-python-check: Skip Python/uv dependency checks
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const { Command } = require('commander');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Create and configure the CLI parser
|
|
18
|
+
* @returns {Command} Configured commander instance
|
|
19
|
+
*/
|
|
20
|
+
function createParser() {
|
|
21
|
+
const program = new Command();
|
|
22
|
+
|
|
23
|
+
program
|
|
24
|
+
.name('claude-setup')
|
|
25
|
+
.description('NPX installer for Claude multi-agent orchestration setup')
|
|
26
|
+
.version('1.0.0', '-v, --version', 'Display version number')
|
|
27
|
+
.helpOption('-h, --help', 'Display help for command');
|
|
28
|
+
|
|
29
|
+
// Primary options
|
|
30
|
+
program
|
|
31
|
+
.option('--force', 'Skip confirmation prompts and overwrite existing files', false)
|
|
32
|
+
.option('--verbose', 'Enable detailed logging output', false)
|
|
33
|
+
.option('--target-dir <path>', 'Target directory for installation (default: current directory)', process.cwd())
|
|
34
|
+
.option('--tag <version>', 'Install specific version tag from GitHub (default: main branch)', 'main')
|
|
35
|
+
.option('--no-python-check', 'Skip Python and uv dependency validation', false);
|
|
36
|
+
|
|
37
|
+
// Advanced options
|
|
38
|
+
program
|
|
39
|
+
.option('--dry-run', 'Show what would be installed without making changes', false)
|
|
40
|
+
.option('--backup', 'Create backup of existing files before overwriting', false)
|
|
41
|
+
.option('--config-url <url>', 'Custom observability server URL for settings.local.json');
|
|
42
|
+
|
|
43
|
+
return program;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Parse command line arguments and validate options
|
|
48
|
+
* @param {string[]} argv - Command line arguments (defaults to process.argv)
|
|
49
|
+
* @returns {ParsedOptions} Parsed and validated options
|
|
50
|
+
*/
|
|
51
|
+
function parseArguments(argv = process.argv) {
|
|
52
|
+
const program = createParser();
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
program.parse(argv);
|
|
56
|
+
const options = program.opts();
|
|
57
|
+
|
|
58
|
+
// Validate and normalize options
|
|
59
|
+
const parsedOptions = validateOptions(options);
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
success: true,
|
|
63
|
+
options: parsedOptions,
|
|
64
|
+
command: program
|
|
65
|
+
};
|
|
66
|
+
} catch (error) {
|
|
67
|
+
return {
|
|
68
|
+
success: false,
|
|
69
|
+
error: error.message,
|
|
70
|
+
command: program
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Validate and normalize parsed options
|
|
77
|
+
* @param {Object} options - Raw options from commander
|
|
78
|
+
* @returns {ValidatedOptions} Validated options object
|
|
79
|
+
*/
|
|
80
|
+
function validateOptions(options) {
|
|
81
|
+
const validated = { ...options };
|
|
82
|
+
|
|
83
|
+
// Normalize target directory
|
|
84
|
+
if (validated.targetDir) {
|
|
85
|
+
validated.targetDir = path.resolve(validated.targetDir);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Validate tag format (basic validation)
|
|
89
|
+
if (validated.tag && validated.tag !== 'main') {
|
|
90
|
+
if (!/^v?\d+\.\d+\.\d+$/.test(validated.tag) && !/^[a-f0-9]{40}$/.test(validated.tag)) {
|
|
91
|
+
throw new Error(`Invalid tag format: ${validated.tag}. Use semantic version (v1.0.0) or commit hash`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Validate config URL if provided
|
|
96
|
+
if (validated.configUrl) {
|
|
97
|
+
try {
|
|
98
|
+
new URL(validated.configUrl);
|
|
99
|
+
} catch (error) {
|
|
100
|
+
throw new Error(`Invalid config URL: ${validated.configUrl}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Set derived flags
|
|
105
|
+
validated.interactive = !validated.force;
|
|
106
|
+
validated.pythonCheck = !validated.noPythonCheck;
|
|
107
|
+
|
|
108
|
+
return validated;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Display help information
|
|
113
|
+
* @param {Command} program - Commander instance
|
|
114
|
+
*/
|
|
115
|
+
function displayHelp(program) {
|
|
116
|
+
program.outputHelp();
|
|
117
|
+
|
|
118
|
+
console.log('\nExamples:');
|
|
119
|
+
console.log(' npx @claude-code/setup-installer');
|
|
120
|
+
console.log(' npx @claude-code/setup-installer --target-dir ./my-project');
|
|
121
|
+
console.log(' npx @claude-code/setup-installer --force --tag v1.2.0');
|
|
122
|
+
console.log(' npx @claude-code/setup-installer --dry-run --verbose');
|
|
123
|
+
console.log(' npx @claude-code/setup-installer --config-url http://localhost:4000');
|
|
124
|
+
|
|
125
|
+
console.log('\nFor more information, visit: https://github.com/alexsavage/claude-code-hooks-multi-agent-observability');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Interface definitions for TypeScript-style documentation
|
|
130
|
+
*/
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* @typedef {Object} ParsedOptions
|
|
134
|
+
* @property {boolean} force - Skip confirmation prompts
|
|
135
|
+
* @property {boolean} verbose - Enable detailed logging
|
|
136
|
+
* @property {string} targetDir - Target installation directory
|
|
137
|
+
* @property {string} tag - Git tag or branch to install
|
|
138
|
+
* @property {boolean} pythonCheck - Whether to check Python dependencies
|
|
139
|
+
* @property {boolean} dryRun - Show changes without executing
|
|
140
|
+
* @property {boolean} backup - Create backup of existing files
|
|
141
|
+
* @property {string} [configUrl] - Custom config URL
|
|
142
|
+
* @property {boolean} interactive - Derived: opposite of force
|
|
143
|
+
*/
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* @typedef {Object} ParseResult
|
|
147
|
+
* @property {boolean} success - Whether parsing succeeded
|
|
148
|
+
* @property {ParsedOptions} [options] - Parsed options (if successful)
|
|
149
|
+
* @property {string} [error] - Error message (if failed)
|
|
150
|
+
* @property {Command} command - Commander instance
|
|
151
|
+
*/
|
|
152
|
+
|
|
153
|
+
module.exports = {
|
|
154
|
+
createParser,
|
|
155
|
+
parseArguments,
|
|
156
|
+
validateOptions,
|
|
157
|
+
displayHelp
|
|
158
|
+
};
|