@guanmu/ccprofile 0.1.13 → 0.1.15
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/dist/index.js +128 -155
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -141,19 +141,33 @@ function missingArg(message, usage) {
|
|
|
141
141
|
console.error(`Usage: ${usage}`);
|
|
142
142
|
process.exitCode = 1;
|
|
143
143
|
}
|
|
144
|
-
async function
|
|
144
|
+
async function selectProfileOrNew() {
|
|
145
145
|
const names = getProfileNames();
|
|
146
146
|
if (names.length === 0) {
|
|
147
|
-
p.
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
147
|
+
const create = await p.confirm({
|
|
148
|
+
message: "No profiles found. Create one?",
|
|
149
|
+
initialValue: true,
|
|
150
|
+
});
|
|
151
|
+
if (p.isCancel(create) || !create)
|
|
152
|
+
return undefined;
|
|
153
|
+
await addProfile();
|
|
154
|
+
return getProfileNames()[0];
|
|
155
|
+
}
|
|
156
|
+
const selected = await p.select({
|
|
157
|
+
message: "Select profile:",
|
|
158
|
+
options: [
|
|
159
|
+
...names.map((n) => ({ value: n, label: n })),
|
|
160
|
+
{ value: "__create__", label: "Create new profile...", hint: "Add a new profile" },
|
|
161
|
+
],
|
|
153
162
|
});
|
|
154
|
-
if (p.isCancel(
|
|
163
|
+
if (p.isCancel(selected))
|
|
155
164
|
return undefined;
|
|
156
|
-
|
|
165
|
+
if (selected === "__create__") {
|
|
166
|
+
await addProfile();
|
|
167
|
+
const updated = getProfileNames();
|
|
168
|
+
return updated[updated.length - 1];
|
|
169
|
+
}
|
|
170
|
+
return selected;
|
|
157
171
|
}
|
|
158
172
|
// ── Commands ──────────────────────────────────────────────
|
|
159
173
|
async function addProfile(name) {
|
|
@@ -239,10 +253,28 @@ async function addPlugin(profileName, plugin) {
|
|
|
239
253
|
p.log.warn("All available plugins already added.");
|
|
240
254
|
return;
|
|
241
255
|
}
|
|
256
|
+
let filtered = available;
|
|
257
|
+
if (available.length > 10) {
|
|
258
|
+
const query = (await p.text({
|
|
259
|
+
message: `Search plugins (leave empty to list all):`,
|
|
260
|
+
}));
|
|
261
|
+
if (p.isCancel(query))
|
|
262
|
+
return;
|
|
263
|
+
const q = query.trim().toLowerCase();
|
|
264
|
+
if (q) {
|
|
265
|
+
filtered = available.filter((pl) => pl.name.toLowerCase().includes(q) ||
|
|
266
|
+
pl.description.toLowerCase().includes(q) ||
|
|
267
|
+
(pl.category && pl.category.toLowerCase().includes(q)));
|
|
268
|
+
if (filtered.length === 0) {
|
|
269
|
+
p.log.warn(`No plugins matching "${query.trim()}".`);
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
242
274
|
const selected = await p.select({
|
|
243
275
|
message: `Add plugin to "${profileName}":`,
|
|
244
276
|
options: [
|
|
245
|
-
...
|
|
277
|
+
...filtered.map((pl) => ({
|
|
246
278
|
value: pl.name,
|
|
247
279
|
label: pl.name,
|
|
248
280
|
hint: pl.description.slice(0, 60),
|
|
@@ -323,17 +355,17 @@ async function listPlugins(profileName) {
|
|
|
323
355
|
p.log.success(pl);
|
|
324
356
|
}
|
|
325
357
|
}
|
|
326
|
-
async function searchPlugins(keyword) {
|
|
358
|
+
async function searchPlugins(keyword, currentProfile) {
|
|
327
359
|
if (!keyword) {
|
|
328
360
|
if (!canPrompt()) {
|
|
329
361
|
missingArg("Search keyword is required.", "ccx search <keyword>");
|
|
330
|
-
return;
|
|
362
|
+
return undefined;
|
|
331
363
|
}
|
|
332
364
|
keyword = (await p.text({
|
|
333
365
|
message: "Search plugins:",
|
|
334
366
|
}));
|
|
335
367
|
if (p.isCancel(keyword))
|
|
336
|
-
return;
|
|
368
|
+
return undefined;
|
|
337
369
|
}
|
|
338
370
|
const allPlugins = getAllPlugins();
|
|
339
371
|
const lower = keyword.toLowerCase();
|
|
@@ -342,7 +374,24 @@ async function searchPlugins(keyword) {
|
|
|
342
374
|
(pl.category || "").toLowerCase().includes(lower));
|
|
343
375
|
if (results.length === 0) {
|
|
344
376
|
p.log.warn(`No plugins matching "${keyword}".`);
|
|
345
|
-
return;
|
|
377
|
+
return undefined;
|
|
378
|
+
}
|
|
379
|
+
if (currentProfile) {
|
|
380
|
+
const data = readProfile(currentProfile);
|
|
381
|
+
const selected = await p.select({
|
|
382
|
+
message: `Search results for "${keyword}":`,
|
|
383
|
+
options: [
|
|
384
|
+
...results.map((pl) => ({
|
|
385
|
+
value: pl.name,
|
|
386
|
+
label: pl.name,
|
|
387
|
+
hint: pl.description.slice(0, 60) + (data.plugins.includes(pl.name) ? " ✓" : ""),
|
|
388
|
+
})),
|
|
389
|
+
{ value: "__back__", label: "Back", hint: "Return to menu" },
|
|
390
|
+
],
|
|
391
|
+
});
|
|
392
|
+
if (p.isCancel(selected) || selected === "__back__")
|
|
393
|
+
return undefined;
|
|
394
|
+
return selected;
|
|
346
395
|
}
|
|
347
396
|
const grouped = new Map();
|
|
348
397
|
for (const pl of results) {
|
|
@@ -361,6 +410,7 @@ async function searchPlugins(keyword) {
|
|
|
361
410
|
}
|
|
362
411
|
console.log();
|
|
363
412
|
}
|
|
413
|
+
return undefined;
|
|
364
414
|
}
|
|
365
415
|
async function executeProfile(profileName) {
|
|
366
416
|
const normalizedProfileName = normalizeProfileName(profileName);
|
|
@@ -391,119 +441,10 @@ async function executeProfile(profileName) {
|
|
|
391
441
|
s.stop(`${installed} installed${failed > 0 ? `, ${failed} failed` : ""}`);
|
|
392
442
|
p.log.success("Done.");
|
|
393
443
|
}
|
|
394
|
-
async function installWizard() {
|
|
395
|
-
while (true) {
|
|
396
|
-
const action = await p.select({
|
|
397
|
-
message: "Install",
|
|
398
|
-
options: [
|
|
399
|
-
{ value: "install", label: "Install profile plugins", hint: "Run a profile" },
|
|
400
|
-
{ value: "back", label: "Back" },
|
|
401
|
-
{ value: "exit", label: "Exit" },
|
|
402
|
-
],
|
|
403
|
-
});
|
|
404
|
-
if (p.isCancel(action) || action === "exit")
|
|
405
|
-
return "exit";
|
|
406
|
-
if (action === "back")
|
|
407
|
-
return "back";
|
|
408
|
-
const name = await selectProfile("Select profile to install:");
|
|
409
|
-
if (name)
|
|
410
|
-
await executeProfile(name);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
async function profilesWizard() {
|
|
414
|
-
while (true) {
|
|
415
|
-
const action = await p.select({
|
|
416
|
-
message: "Profiles",
|
|
417
|
-
options: [
|
|
418
|
-
{ value: "create", label: "Create profile", hint: "Create a new empty profile" },
|
|
419
|
-
{ value: "list", label: "List profiles", hint: "Show all profiles" },
|
|
420
|
-
{ value: "delete", label: "Delete profile", hint: "Remove a profile" },
|
|
421
|
-
{ value: "back", label: "Back" },
|
|
422
|
-
{ value: "exit", label: "Exit" },
|
|
423
|
-
],
|
|
424
|
-
});
|
|
425
|
-
if (p.isCancel(action) || action === "exit")
|
|
426
|
-
return "exit";
|
|
427
|
-
if (action === "back")
|
|
428
|
-
return "back";
|
|
429
|
-
switch (action) {
|
|
430
|
-
case "create":
|
|
431
|
-
await addProfile();
|
|
432
|
-
break;
|
|
433
|
-
case "list":
|
|
434
|
-
await listProfiles();
|
|
435
|
-
break;
|
|
436
|
-
case "delete":
|
|
437
|
-
await removeProfile();
|
|
438
|
-
break;
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
async function pluginsWizard() {
|
|
443
|
-
while (true) {
|
|
444
|
-
const action = await p.select({
|
|
445
|
-
message: "Plugins",
|
|
446
|
-
options: [
|
|
447
|
-
{ value: "add", label: "Add plugin to profile", hint: "Choose a profile, then a plugin" },
|
|
448
|
-
{ value: "remove", label: "Remove plugin from profile", hint: "Choose a profile, then a plugin" },
|
|
449
|
-
{ value: "list", label: "List profile plugins", hint: "Show plugins in a profile" },
|
|
450
|
-
{ value: "back", label: "Back" },
|
|
451
|
-
{ value: "exit", label: "Exit" },
|
|
452
|
-
],
|
|
453
|
-
});
|
|
454
|
-
if (p.isCancel(action) || action === "exit")
|
|
455
|
-
return "exit";
|
|
456
|
-
if (action === "back")
|
|
457
|
-
return "back";
|
|
458
|
-
const name = await selectProfile("Select profile:");
|
|
459
|
-
if (!name)
|
|
460
|
-
continue;
|
|
461
|
-
switch (action) {
|
|
462
|
-
case "add":
|
|
463
|
-
await addPlugin(name);
|
|
464
|
-
break;
|
|
465
|
-
case "remove":
|
|
466
|
-
await removePlugin(name);
|
|
467
|
-
break;
|
|
468
|
-
case "list":
|
|
469
|
-
await listPlugins(name);
|
|
470
|
-
break;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
async function marketplaceWizard() {
|
|
475
|
-
while (true) {
|
|
476
|
-
const action = await p.select({
|
|
477
|
-
message: "Marketplace",
|
|
478
|
-
options: [
|
|
479
|
-
{ value: "search", label: "Search plugins", hint: "Search installed marketplaces" },
|
|
480
|
-
{ value: "back", label: "Back" },
|
|
481
|
-
{ value: "exit", label: "Exit" },
|
|
482
|
-
],
|
|
483
|
-
});
|
|
484
|
-
if (p.isCancel(action) || action === "exit")
|
|
485
|
-
return "exit";
|
|
486
|
-
if (action === "back")
|
|
487
|
-
return "back";
|
|
488
|
-
await searchPlugins();
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
const CCX_LOGO = [
|
|
492
|
-
" ██████╗██████╗",
|
|
493
|
-
" ██╔════╝██╔══██╗",
|
|
494
|
-
" ██║ ██████╔╝",
|
|
495
|
-
" ██║ ██╔══██╗",
|
|
496
|
-
" ╚██████╗██║ ██║",
|
|
497
|
-
" ╚═════╝╚═╝ ╚═╝",
|
|
498
|
-
];
|
|
499
444
|
function printBanner() {
|
|
500
445
|
const require = createRequire(import.meta.url);
|
|
501
446
|
const pkg = require("../package.json");
|
|
502
|
-
|
|
503
|
-
CCX_LOGO.forEach((line) => console.log(pc.bold(pc.magenta(line))));
|
|
504
|
-
console.log();
|
|
505
|
-
console.log(pc.dim(" ") + pc.italic(pc.white("Agent Profile Manager")) + pc.dim(" ") + pc.gray(`v${pkg.version}`));
|
|
506
|
-
console.log();
|
|
447
|
+
p.note(pc.bold("ccx") + pc.dim(" — Agent Profile Manager ") + pc.gray(`v${pkg.version}`));
|
|
507
448
|
}
|
|
508
449
|
async function interactiveMode() {
|
|
509
450
|
if (!canPrompt()) {
|
|
@@ -512,40 +453,72 @@ async function interactiveMode() {
|
|
|
512
453
|
return;
|
|
513
454
|
}
|
|
514
455
|
printBanner();
|
|
515
|
-
let
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
{ value: "install", label: "Install", hint: "Run a profile" },
|
|
521
|
-
{ value: "profiles", label: "Profiles", hint: "Create, list, or delete profiles" },
|
|
522
|
-
{ value: "plugins", label: "Plugins", hint: "Manage plugins inside profiles" },
|
|
523
|
-
{ value: "marketplace", label: "Marketplace", hint: "Search available plugins" },
|
|
524
|
-
{ value: "help", label: "Help", hint: "Show command usage" },
|
|
525
|
-
{ value: "exit", label: "Exit" },
|
|
526
|
-
],
|
|
527
|
-
});
|
|
528
|
-
if (p.isCancel(area) || area === "exit")
|
|
456
|
+
let currentProfile;
|
|
457
|
+
// Profile selection loop
|
|
458
|
+
while (true) {
|
|
459
|
+
currentProfile = await selectProfileOrNew();
|
|
460
|
+
if (!currentProfile)
|
|
529
461
|
break;
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
462
|
+
// Action loop — all operations on current profile
|
|
463
|
+
let stayInProfile = true;
|
|
464
|
+
while (stayInProfile && currentProfile) {
|
|
465
|
+
const data = readProfile(currentProfile);
|
|
466
|
+
const action = await p.select({
|
|
467
|
+
message: pc.bold(pc.cyan(`[${currentProfile}]`)) + ` ${data.plugins.length} plugin(s)`,
|
|
468
|
+
options: [
|
|
469
|
+
{ value: "install", label: "Install", hint: "Apply to current project" },
|
|
470
|
+
{ value: "add", label: "Add plugin", hint: "Search and add a plugin" },
|
|
471
|
+
{ value: "remove", label: "Remove plugin", hint: "Remove a plugin" },
|
|
472
|
+
{ value: "list", label: "List plugins", hint: "Show all plugins" },
|
|
473
|
+
{ value: "search", label: "Search marketplace", hint: "Find new plugins" },
|
|
474
|
+
{ value: "switch", label: "Switch profile", hint: "Choose a different profile" },
|
|
475
|
+
{ value: "delete", label: "Delete profile", hint: "Remove this profile" },
|
|
476
|
+
{ value: "exit", label: "Exit" },
|
|
477
|
+
],
|
|
478
|
+
});
|
|
479
|
+
if (p.isCancel(action) || action === "exit") {
|
|
480
|
+
currentProfile = undefined;
|
|
481
|
+
stayInProfile = false;
|
|
546
482
|
break;
|
|
483
|
+
}
|
|
484
|
+
switch (action) {
|
|
485
|
+
case "install":
|
|
486
|
+
await executeProfile(currentProfile);
|
|
487
|
+
break;
|
|
488
|
+
case "add":
|
|
489
|
+
await addPlugin(currentProfile);
|
|
490
|
+
break;
|
|
491
|
+
case "remove":
|
|
492
|
+
await removePlugin(currentProfile);
|
|
493
|
+
break;
|
|
494
|
+
case "list":
|
|
495
|
+
await listPlugins(currentProfile);
|
|
496
|
+
break;
|
|
497
|
+
case "search": {
|
|
498
|
+
const found = await searchPlugins(undefined, currentProfile);
|
|
499
|
+
if (found) {
|
|
500
|
+
const d = readProfile(currentProfile);
|
|
501
|
+
if (d.plugins.includes(found)) {
|
|
502
|
+
p.log.warn(`"${found}" already in profile "${currentProfile}".`);
|
|
503
|
+
}
|
|
504
|
+
else {
|
|
505
|
+
d.plugins.push(found);
|
|
506
|
+
writeProfile(currentProfile, d);
|
|
507
|
+
p.log.success(`Added "${found}" to profile "${currentProfile}".`);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
512
|
+
case "switch":
|
|
513
|
+
stayInProfile = false;
|
|
514
|
+
break;
|
|
515
|
+
case "delete":
|
|
516
|
+
await removeProfile(currentProfile);
|
|
517
|
+
currentProfile = undefined;
|
|
518
|
+
stayInProfile = false;
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
547
521
|
}
|
|
548
|
-
shouldExit = result === "exit";
|
|
549
522
|
}
|
|
550
523
|
p.outro("Done.");
|
|
551
524
|
}
|