@guanmu/ccprofile 0.1.14 → 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.
Files changed (2) hide show
  1. package/dist/index.js +108 -141
  2. 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 selectProfile(message) {
144
+ async function selectProfileOrNew() {
145
145
  const names = getProfileNames();
146
146
  if (names.length === 0) {
147
- p.log.warn("No profiles found.");
148
- return undefined;
149
- }
150
- const name = await p.select({
151
- message,
152
- options: names.map((n) => ({ value: n, label: n })),
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(name))
163
+ if (p.isCancel(selected))
155
164
  return undefined;
156
- return name;
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) {
@@ -341,17 +355,17 @@ async function listPlugins(profileName) {
341
355
  p.log.success(pl);
342
356
  }
343
357
  }
344
- async function searchPlugins(keyword) {
358
+ async function searchPlugins(keyword, currentProfile) {
345
359
  if (!keyword) {
346
360
  if (!canPrompt()) {
347
361
  missingArg("Search keyword is required.", "ccx search <keyword>");
348
- return;
362
+ return undefined;
349
363
  }
350
364
  keyword = (await p.text({
351
365
  message: "Search plugins:",
352
366
  }));
353
367
  if (p.isCancel(keyword))
354
- return;
368
+ return undefined;
355
369
  }
356
370
  const allPlugins = getAllPlugins();
357
371
  const lower = keyword.toLowerCase();
@@ -360,7 +374,24 @@ async function searchPlugins(keyword) {
360
374
  (pl.category || "").toLowerCase().includes(lower));
361
375
  if (results.length === 0) {
362
376
  p.log.warn(`No plugins matching "${keyword}".`);
363
- 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;
364
395
  }
365
396
  const grouped = new Map();
366
397
  for (const pl of results) {
@@ -379,6 +410,7 @@ async function searchPlugins(keyword) {
379
410
  }
380
411
  console.log();
381
412
  }
413
+ return undefined;
382
414
  }
383
415
  async function executeProfile(profileName) {
384
416
  const normalizedProfileName = normalizeProfileName(profileName);
@@ -409,103 +441,6 @@ async function executeProfile(profileName) {
409
441
  s.stop(`${installed} installed${failed > 0 ? `, ${failed} failed` : ""}`);
410
442
  p.log.success("Done.");
411
443
  }
412
- async function installWizard() {
413
- while (true) {
414
- const action = await p.select({
415
- message: "Install",
416
- options: [
417
- { value: "install", label: "Install profile plugins", hint: "Run a profile" },
418
- { value: "back", label: "Back" },
419
- { value: "exit", label: "Exit" },
420
- ],
421
- });
422
- if (p.isCancel(action) || action === "exit")
423
- return "exit";
424
- if (action === "back")
425
- return "back";
426
- const name = await selectProfile("Select profile to install:");
427
- if (name)
428
- await executeProfile(name);
429
- }
430
- }
431
- async function profilesWizard() {
432
- while (true) {
433
- const action = await p.select({
434
- message: "Profiles",
435
- options: [
436
- { value: "create", label: "Create profile", hint: "Create a new empty profile" },
437
- { value: "list", label: "List profiles", hint: "Show all profiles" },
438
- { value: "delete", label: "Delete profile", hint: "Remove a profile" },
439
- { value: "back", label: "Back" },
440
- { value: "exit", label: "Exit" },
441
- ],
442
- });
443
- if (p.isCancel(action) || action === "exit")
444
- return "exit";
445
- if (action === "back")
446
- return "back";
447
- switch (action) {
448
- case "create":
449
- await addProfile();
450
- break;
451
- case "list":
452
- await listProfiles();
453
- break;
454
- case "delete":
455
- await removeProfile();
456
- break;
457
- }
458
- }
459
- }
460
- async function pluginsWizard() {
461
- while (true) {
462
- const action = await p.select({
463
- message: "Plugins",
464
- options: [
465
- { value: "add", label: "Add plugin to profile", hint: "Choose a profile, then a plugin" },
466
- { value: "remove", label: "Remove plugin from profile", hint: "Choose a profile, then a plugin" },
467
- { value: "list", label: "List profile plugins", hint: "Show plugins in a profile" },
468
- { value: "back", label: "Back" },
469
- { value: "exit", label: "Exit" },
470
- ],
471
- });
472
- if (p.isCancel(action) || action === "exit")
473
- return "exit";
474
- if (action === "back")
475
- return "back";
476
- const name = await selectProfile("Select profile:");
477
- if (!name)
478
- continue;
479
- switch (action) {
480
- case "add":
481
- await addPlugin(name);
482
- break;
483
- case "remove":
484
- await removePlugin(name);
485
- break;
486
- case "list":
487
- await listPlugins(name);
488
- break;
489
- }
490
- }
491
- }
492
- async function marketplaceWizard() {
493
- while (true) {
494
- const action = await p.select({
495
- message: "Marketplace",
496
- options: [
497
- { value: "search", label: "Search plugins", hint: "Search installed marketplaces" },
498
- { value: "back", label: "Back" },
499
- { value: "exit", label: "Exit" },
500
- ],
501
- });
502
- if (p.isCancel(action) || action === "exit")
503
- return "exit";
504
- if (action === "back")
505
- return "back";
506
- await searchPlugins();
507
- }
508
- }
509
444
  function printBanner() {
510
445
  const require = createRequire(import.meta.url);
511
446
  const pkg = require("../package.json");
@@ -518,40 +453,72 @@ async function interactiveMode() {
518
453
  return;
519
454
  }
520
455
  printBanner();
521
- let shouldExit = false;
522
- while (!shouldExit) {
523
- const area = await p.select({
524
- message: "Choose area:",
525
- options: [
526
- { value: "install", label: "Install", hint: "Run a profile" },
527
- { value: "profiles", label: "Profiles", hint: "Create, list, or delete profiles" },
528
- { value: "plugins", label: "Plugins", hint: "Manage plugins inside profiles" },
529
- { value: "marketplace", label: "Marketplace", hint: "Search available plugins" },
530
- { value: "help", label: "Help", hint: "Show command usage" },
531
- { value: "exit", label: "Exit" },
532
- ],
533
- });
534
- if (p.isCancel(area) || area === "exit")
456
+ let currentProfile;
457
+ // Profile selection loop
458
+ while (true) {
459
+ currentProfile = await selectProfileOrNew();
460
+ if (!currentProfile)
535
461
  break;
536
- let result = "back";
537
- switch (area) {
538
- case "install":
539
- result = await installWizard();
540
- break;
541
- case "profiles":
542
- result = await profilesWizard();
543
- break;
544
- case "plugins":
545
- result = await pluginsWizard();
546
- break;
547
- case "marketplace":
548
- result = await marketplaceWizard();
549
- break;
550
- case "help":
551
- printHelp();
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;
552
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
+ }
553
521
  }
554
- shouldExit = result === "exit";
555
522
  }
556
523
  p.outro("Done.");
557
524
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@guanmu/ccprofile",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
4
  "description": "Agent Profile Manager for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {