claude-comms 1.0.1 â 1.0.3
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 +76 -0
- package/README.md +64 -23
- package/bin/claude-setup.js +118 -38
- package/package.json +67 -19
- 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 +1092 -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 +875 -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,317 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive Prompts for @claude-code/setup-installer
|
|
3
|
+
*
|
|
4
|
+
* Handles user interaction through prompts for:
|
|
5
|
+
* - Installation confirmation
|
|
6
|
+
* - Directory selection
|
|
7
|
+
* - Overwrite warnings
|
|
8
|
+
* - Configuration options
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const prompts = require('prompts');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const fs = require('fs').promises;
|
|
14
|
+
const chalk = require('chalk');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Main prompt orchestrator for installation flow
|
|
18
|
+
* @param {Object} options - Parsed CLI options
|
|
19
|
+
* @returns {Promise<Object>} User responses and validated settings
|
|
20
|
+
*/
|
|
21
|
+
async function runInstallationPrompts(options) {
|
|
22
|
+
const responses = {};
|
|
23
|
+
|
|
24
|
+
console.log(chalk.cyan('đ Claude Code Setup Installer'));
|
|
25
|
+
console.log(chalk.gray('Setting up multi-agent orchestration in your project\n'));
|
|
26
|
+
|
|
27
|
+
// Skip prompts if force mode
|
|
28
|
+
if (options.force) {
|
|
29
|
+
return {
|
|
30
|
+
confirmed: true,
|
|
31
|
+
targetDir: options.targetDir,
|
|
32
|
+
overwriteStrategy: 'overwrite',
|
|
33
|
+
configUrl: options.configUrl || 'http://localhost:4000',
|
|
34
|
+
pythonCheck: options.pythonCheck
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Confirm installation location
|
|
39
|
+
const dirConfirmation = await confirmTargetDirectory(options.targetDir);
|
|
40
|
+
if (!dirConfirmation.confirmed) {
|
|
41
|
+
return { confirmed: false, cancelled: true };
|
|
42
|
+
}
|
|
43
|
+
responses.targetDir = dirConfirmation.targetDir;
|
|
44
|
+
|
|
45
|
+
// Check for existing files
|
|
46
|
+
const existingFiles = await checkExistingFiles(responses.targetDir);
|
|
47
|
+
if (existingFiles.hasConflicts) {
|
|
48
|
+
const overwriteResponse = await handleExistingFiles(existingFiles);
|
|
49
|
+
if (!overwriteResponse.confirmed) {
|
|
50
|
+
return { confirmed: false, cancelled: true };
|
|
51
|
+
}
|
|
52
|
+
responses.overwriteStrategy = overwriteResponse.strategy;
|
|
53
|
+
} else {
|
|
54
|
+
responses.overwriteStrategy = 'none';
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Configuration options
|
|
58
|
+
const configResponse = await promptConfigurationOptions(options);
|
|
59
|
+
responses.configUrl = configResponse.configUrl;
|
|
60
|
+
responses.pythonCheck = configResponse.pythonCheck;
|
|
61
|
+
|
|
62
|
+
// Final confirmation
|
|
63
|
+
const finalConfirmation = await promptFinalConfirmation(responses);
|
|
64
|
+
if (!finalConfirmation) {
|
|
65
|
+
return { confirmed: false, cancelled: true };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
confirmed: true,
|
|
70
|
+
...responses
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Confirm target directory for installation
|
|
76
|
+
* @param {string} defaultDir - Default directory path
|
|
77
|
+
* @returns {Promise<Object>} Directory confirmation result
|
|
78
|
+
*/
|
|
79
|
+
async function confirmTargetDirectory(defaultDir) {
|
|
80
|
+
try {
|
|
81
|
+
await fs.access(defaultDir);
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.log(chalk.yellow(`â ď¸ Directory ${defaultDir} does not exist.`));
|
|
84
|
+
|
|
85
|
+
const createResponse = await prompts({
|
|
86
|
+
type: 'confirm',
|
|
87
|
+
name: 'create',
|
|
88
|
+
message: 'Would you like to create it?',
|
|
89
|
+
initial: true
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
if (!createResponse.create) {
|
|
93
|
+
return { confirmed: false };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const dirResponse = await prompts({
|
|
98
|
+
type: 'text',
|
|
99
|
+
name: 'targetDir',
|
|
100
|
+
message: 'Installation directory:',
|
|
101
|
+
initial: defaultDir,
|
|
102
|
+
validate: (value) => {
|
|
103
|
+
if (!value.trim()) return 'Directory path cannot be empty';
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
if (!dirResponse.targetDir) {
|
|
109
|
+
return { confirmed: false };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
confirmed: true,
|
|
114
|
+
targetDir: path.resolve(dirResponse.targetDir)
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Check for existing files that would conflict
|
|
120
|
+
* @param {string} targetDir - Target installation directory
|
|
121
|
+
* @returns {Promise<Object>} Conflict detection result
|
|
122
|
+
*/
|
|
123
|
+
async function checkExistingFiles(targetDir) {
|
|
124
|
+
const conflictFiles = [];
|
|
125
|
+
const checkFiles = [
|
|
126
|
+
'.claude',
|
|
127
|
+
'CLAUDE.md',
|
|
128
|
+
'.claude/settings.json',
|
|
129
|
+
'.claude/hooks',
|
|
130
|
+
'.claude/agents'
|
|
131
|
+
];
|
|
132
|
+
|
|
133
|
+
for (const file of checkFiles) {
|
|
134
|
+
const filePath = path.join(targetDir, file);
|
|
135
|
+
try {
|
|
136
|
+
await fs.access(filePath);
|
|
137
|
+
conflictFiles.push(file);
|
|
138
|
+
} catch (error) {
|
|
139
|
+
// File doesn't exist, no conflict
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
hasConflicts: conflictFiles.length > 0,
|
|
145
|
+
conflictFiles
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Handle existing files through user prompts
|
|
151
|
+
* @param {Object} existingFiles - Existing file detection result
|
|
152
|
+
* @returns {Promise<Object>} User decision on handling conflicts
|
|
153
|
+
*/
|
|
154
|
+
async function handleExistingFiles(existingFiles) {
|
|
155
|
+
console.log(chalk.yellow('\nâ ď¸ Found existing Claude setup files:'));
|
|
156
|
+
existingFiles.conflictFiles.forEach(file => {
|
|
157
|
+
console.log(chalk.gray(` ⢠${file}`));
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
const strategy = await prompts({
|
|
161
|
+
type: 'select',
|
|
162
|
+
name: 'strategy',
|
|
163
|
+
message: 'How would you like to handle existing files?',
|
|
164
|
+
choices: [
|
|
165
|
+
{
|
|
166
|
+
title: 'Backup and replace',
|
|
167
|
+
description: 'Create .backup files and install fresh setup',
|
|
168
|
+
value: 'backup'
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
title: 'Skip existing files',
|
|
172
|
+
description: 'Only install missing files, keep existing ones',
|
|
173
|
+
value: 'skip'
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
title: 'Overwrite all',
|
|
177
|
+
description: 'Replace all existing files (no backup)',
|
|
178
|
+
value: 'overwrite'
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
title: 'Cancel installation',
|
|
182
|
+
description: 'Exit without making changes',
|
|
183
|
+
value: 'cancel'
|
|
184
|
+
}
|
|
185
|
+
]
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
if (!strategy.strategy || strategy.strategy === 'cancel') {
|
|
189
|
+
return { confirmed: false };
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
confirmed: true,
|
|
194
|
+
strategy: strategy.strategy
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Prompt for configuration options
|
|
200
|
+
* @param {Object} options - CLI options
|
|
201
|
+
* @returns {Promise<Object>} Configuration responses
|
|
202
|
+
*/
|
|
203
|
+
async function promptConfigurationOptions(options) {
|
|
204
|
+
console.log(chalk.blue('\nâď¸ Configuration Options'));
|
|
205
|
+
|
|
206
|
+
const configUrl = await prompts({
|
|
207
|
+
type: 'text',
|
|
208
|
+
name: 'url',
|
|
209
|
+
message: 'Observability server URL (optional):',
|
|
210
|
+
initial: options.configUrl || 'http://localhost:4000',
|
|
211
|
+
validate: (value) => {
|
|
212
|
+
if (!value.trim()) return true; // Optional field
|
|
213
|
+
try {
|
|
214
|
+
new URL(value);
|
|
215
|
+
return true;
|
|
216
|
+
} catch (error) {
|
|
217
|
+
return 'Please enter a valid URL';
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
const pythonCheck = await prompts({
|
|
223
|
+
type: 'confirm',
|
|
224
|
+
name: 'check',
|
|
225
|
+
message: 'Check for Python and uv dependencies?',
|
|
226
|
+
initial: options.pythonCheck !== false
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
return {
|
|
230
|
+
configUrl: configUrl.url || 'http://localhost:4000',
|
|
231
|
+
pythonCheck: pythonCheck.check
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Final confirmation before installation
|
|
237
|
+
* @param {Object} responses - Collected user responses
|
|
238
|
+
* @returns {Promise<boolean>} Final confirmation
|
|
239
|
+
*/
|
|
240
|
+
async function promptFinalConfirmation(responses) {
|
|
241
|
+
console.log(chalk.green('\nđ Installation Summary:'));
|
|
242
|
+
console.log(chalk.gray(` Directory: ${responses.targetDir}`));
|
|
243
|
+
console.log(chalk.gray(` Overwrite strategy: ${responses.overwriteStrategy}`));
|
|
244
|
+
console.log(chalk.gray(` Config URL: ${responses.configUrl}`));
|
|
245
|
+
console.log(chalk.gray(` Python check: ${responses.pythonCheck ? 'Yes' : 'No'}`));
|
|
246
|
+
|
|
247
|
+
const confirmation = await prompts({
|
|
248
|
+
type: 'confirm',
|
|
249
|
+
name: 'proceed',
|
|
250
|
+
message: 'Proceed with installation?',
|
|
251
|
+
initial: true
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
return confirmation.proceed;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Handle user interruption (Ctrl+C)
|
|
259
|
+
*/
|
|
260
|
+
function setupInterruptHandler() {
|
|
261
|
+
process.on('SIGINT', () => {
|
|
262
|
+
console.log(chalk.yellow('\n\nâ ď¸ Installation cancelled by user'));
|
|
263
|
+
process.exit(0);
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Prompt for specific installation scenarios
|
|
269
|
+
*/
|
|
270
|
+
const scenarios = {
|
|
271
|
+
/**
|
|
272
|
+
* Prompt for force mode confirmation when destructive
|
|
273
|
+
*/
|
|
274
|
+
async confirmForceMode(conflictFiles) {
|
|
275
|
+
console.log(chalk.red('\nâ ď¸ Force mode will overwrite:'));
|
|
276
|
+
conflictFiles.forEach(file => {
|
|
277
|
+
console.log(chalk.gray(` ⢠${file}`));
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
return await prompts({
|
|
281
|
+
type: 'confirm',
|
|
282
|
+
name: 'proceed',
|
|
283
|
+
message: 'Continue with force installation?',
|
|
284
|
+
initial: false
|
|
285
|
+
});
|
|
286
|
+
},
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Prompt for Python installation if missing
|
|
290
|
+
*/
|
|
291
|
+
async promptPythonInstall() {
|
|
292
|
+
console.log(chalk.yellow('\nâ ď¸ Python or uv not found'));
|
|
293
|
+
console.log(chalk.gray('The Claude hooks require Python and uv to function properly.'));
|
|
294
|
+
|
|
295
|
+
return await prompts({
|
|
296
|
+
type: 'select',
|
|
297
|
+
name: 'action',
|
|
298
|
+
message: 'How would you like to proceed?',
|
|
299
|
+
choices: [
|
|
300
|
+
{ title: 'Continue anyway', value: 'continue' },
|
|
301
|
+
{ title: 'Open installation guide', value: 'guide' },
|
|
302
|
+
{ title: 'Cancel installation', value: 'cancel' }
|
|
303
|
+
]
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
module.exports = {
|
|
309
|
+
runInstallationPrompts,
|
|
310
|
+
confirmTargetDirectory,
|
|
311
|
+
checkExistingFiles,
|
|
312
|
+
handleExistingFiles,
|
|
313
|
+
promptConfigurationOptions,
|
|
314
|
+
promptFinalConfirmation,
|
|
315
|
+
setupInterruptHandler,
|
|
316
|
+
scenarios
|
|
317
|
+
};
|