ma-agents 1.7.0 → 1.8.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.
- package/bin/cli.js +98 -28
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -120,60 +120,113 @@ async function installWizard(preselectedSkill, preselectedAgents, customPath, fo
|
|
|
120
120
|
const skills = listSkills();
|
|
121
121
|
const agents = listAgents();
|
|
122
122
|
|
|
123
|
+
let selectedSkillIds = preselectedSkill ? [preselectedSkill] : [];
|
|
124
|
+
let selectedAgentIds = preselectedAgents || [];
|
|
125
|
+
let installScope = 'project';
|
|
126
|
+
let installPath = customPath || '';
|
|
127
|
+
|
|
128
|
+
const existingStatus = getStatus([], '', 'project');
|
|
129
|
+
let isUpdate = false;
|
|
130
|
+
|
|
131
|
+
// Step 0: Check for existing installation ONLY in interactive mode (no preselected skill)
|
|
132
|
+
if (!preselectedSkill && !customPath && existingStatus.length > 0) {
|
|
133
|
+
console.log(chalk.cyan('\n Existing installation detected in project.'));
|
|
134
|
+
|
|
135
|
+
const { action } = await prompts({
|
|
136
|
+
type: 'select',
|
|
137
|
+
name: 'action',
|
|
138
|
+
message: 'What would you like to do?',
|
|
139
|
+
choices: [
|
|
140
|
+
{ title: 'Update (add/remove skills)', value: 'update' },
|
|
141
|
+
{ title: 'Clean reinstall (remove all first)', value: 'reinstall' },
|
|
142
|
+
{ title: 'Uninstall all skills', value: 'uninstall' },
|
|
143
|
+
{ title: 'Cancel', value: 'cancel' }
|
|
144
|
+
]
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
if (!action || action === 'cancel') process.exit(0);
|
|
148
|
+
|
|
149
|
+
if (action === 'uninstall') {
|
|
150
|
+
const { confirmed } = await prompts({
|
|
151
|
+
type: 'confirm',
|
|
152
|
+
name: 'confirmed',
|
|
153
|
+
message: 'This will remove all ma-agents skills from this project. Are you sure?',
|
|
154
|
+
initial: false
|
|
155
|
+
});
|
|
156
|
+
if (!confirmed) process.exit(0);
|
|
157
|
+
|
|
158
|
+
for (const entry of existingStatus) {
|
|
159
|
+
for (const skillId of Object.keys(entry.skills)) {
|
|
160
|
+
await uninstallSkill(skillId, [entry.agent.id], '', 'project');
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
console.log(chalk.bold.green('\n All skills successfully removed!\n'));
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (action === 'reinstall') {
|
|
168
|
+
for (const entry of existingStatus) {
|
|
169
|
+
for (const skillId of Object.keys(entry.skills)) {
|
|
170
|
+
await uninstallSkill(skillId, [entry.agent.id], '', 'project');
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
console.log(chalk.gray(' Clean slate prepared.'));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (action === 'update') {
|
|
177
|
+
isUpdate = true;
|
|
178
|
+
// Pre-populate selections from existing status
|
|
179
|
+
const existingSkillIds = new Set();
|
|
180
|
+
const existingAgentIds = new Set();
|
|
181
|
+
existingStatus.forEach(entry => {
|
|
182
|
+
existingAgentIds.add(entry.agent.id);
|
|
183
|
+
Object.keys(entry.skills).forEach(id => existingSkillIds.add(id));
|
|
184
|
+
});
|
|
185
|
+
selectedSkillIds = Array.from(existingSkillIds);
|
|
186
|
+
selectedAgentIds = Array.from(existingAgentIds);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
123
190
|
// Step 1: Select skills
|
|
124
|
-
|
|
125
|
-
if (preselectedSkill) {
|
|
126
|
-
selectedSkillIds = [preselectedSkill];
|
|
127
|
-
} else {
|
|
191
|
+
if (selectedSkillIds.length === 0 || isUpdate) {
|
|
128
192
|
const { skills: chosen } = await prompts({
|
|
129
193
|
type: 'multiselect',
|
|
130
194
|
name: 'skills',
|
|
131
|
-
message: '
|
|
195
|
+
message: 'Select the skills you want to have installed:',
|
|
132
196
|
choices: skills.map(s => ({
|
|
133
197
|
title: chalk.white(s.name) + chalk.gray(` v${s.version} - ${s.description}`),
|
|
134
198
|
value: s.id,
|
|
135
|
-
selected:
|
|
199
|
+
selected: selectedSkillIds.includes(s.id)
|
|
136
200
|
})),
|
|
137
201
|
instructions: chalk.gray(' Use space to select, enter to confirm'),
|
|
138
202
|
min: 1
|
|
139
203
|
});
|
|
140
204
|
|
|
141
|
-
if (!chosen
|
|
142
|
-
console.log(chalk.yellow('No skills selected. Exiting.'));
|
|
143
|
-
process.exit(0);
|
|
144
|
-
}
|
|
205
|
+
if (!chosen) process.exit(0);
|
|
145
206
|
selectedSkillIds = chosen;
|
|
146
207
|
}
|
|
147
208
|
|
|
148
209
|
// Step 2: Select agents
|
|
149
|
-
|
|
150
|
-
if (preselectedAgents && preselectedAgents.length > 0) {
|
|
151
|
-
selectedAgentIds = preselectedAgents;
|
|
152
|
-
} else {
|
|
210
|
+
if (selectedAgentIds.length === 0 || isUpdate) {
|
|
153
211
|
const { agents: chosen } = await prompts({
|
|
154
212
|
type: 'multiselect',
|
|
155
213
|
name: 'agents',
|
|
156
|
-
message: '
|
|
214
|
+
message: 'Select which coding agents to include:',
|
|
157
215
|
choices: agents.map(a => ({
|
|
158
216
|
title: chalk.white(a.name) + chalk.gray(` v${a.version} - ${a.description}`),
|
|
159
217
|
value: a.id,
|
|
160
|
-
selected:
|
|
218
|
+
selected: selectedAgentIds.includes(a.id)
|
|
161
219
|
})),
|
|
162
220
|
instructions: chalk.gray(' Use space to select, enter to confirm'),
|
|
163
221
|
min: 1
|
|
164
222
|
});
|
|
165
223
|
|
|
166
|
-
if (!chosen
|
|
167
|
-
console.log(chalk.yellow('No agents selected. Exiting.'));
|
|
168
|
-
process.exit(0);
|
|
169
|
-
}
|
|
224
|
+
if (!chosen) process.exit(0);
|
|
170
225
|
selectedAgentIds = chosen;
|
|
171
226
|
}
|
|
172
227
|
|
|
173
|
-
// Step 3:
|
|
174
|
-
|
|
175
|
-
let installScope = 'project';
|
|
176
|
-
if (!installPath) {
|
|
228
|
+
// Step 3: Scope (Skip if update, we already know it's project)
|
|
229
|
+
if (!isUpdate && !installPath) {
|
|
177
230
|
const { pathChoice } = await prompts({
|
|
178
231
|
type: 'select',
|
|
179
232
|
name: 'pathChoice',
|
|
@@ -209,16 +262,33 @@ async function installWizard(preselectedSkill, preselectedAgents, customPath, fo
|
|
|
209
262
|
const { confirmed } = await prompts({
|
|
210
263
|
type: 'confirm',
|
|
211
264
|
name: 'confirmed',
|
|
212
|
-
message: 'Proceed with installation?',
|
|
265
|
+
message: isUpdate ? 'Apply changes?' : 'Proceed with installation?',
|
|
213
266
|
initial: true
|
|
214
267
|
});
|
|
215
268
|
|
|
216
269
|
if (!confirmed) {
|
|
217
|
-
console.log(chalk.yellow('
|
|
270
|
+
console.log(chalk.yellow('Operation cancelled.'));
|
|
218
271
|
process.exit(0);
|
|
219
272
|
}
|
|
220
273
|
|
|
221
|
-
// Step 5:
|
|
274
|
+
// Step 5: Execution
|
|
275
|
+
if (isUpdate) {
|
|
276
|
+
// Identify removals
|
|
277
|
+
const currentlyInstalled = new Set();
|
|
278
|
+
existingStatus.forEach(entry => Object.keys(entry.skills).forEach(id => currentlyInstalled.add(id)));
|
|
279
|
+
|
|
280
|
+
const finalSkills = new Set(selectedSkillIds);
|
|
281
|
+
const toRemove = [...currentlyInstalled].filter(id => !finalSkills.has(id));
|
|
282
|
+
|
|
283
|
+
if (toRemove.length > 0) {
|
|
284
|
+
console.log(chalk.gray(`\n Cleaning up ${toRemove.length} removed skills...`));
|
|
285
|
+
for (const skillId of toRemove) {
|
|
286
|
+
await uninstallSkill(skillId, selectedAgentIds, installPath, 'project');
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Install requested skills
|
|
222
292
|
for (const skillId of selectedSkillIds) {
|
|
223
293
|
try {
|
|
224
294
|
await installSkill(skillId, selectedAgentIds, installPath, installScope, { force: !!forceFlag });
|
|
@@ -227,7 +297,7 @@ async function installWizard(preselectedSkill, preselectedAgents, customPath, fo
|
|
|
227
297
|
}
|
|
228
298
|
}
|
|
229
299
|
|
|
230
|
-
console.log(chalk.bold.green('\n
|
|
300
|
+
console.log(chalk.bold.green('\n Done!\n'));
|
|
231
301
|
}
|
|
232
302
|
|
|
233
303
|
// --- Command handlers ---
|