pruff-skills 0.8.0 → 0.9.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.
Files changed (2) hide show
  1. package/dist/cli.mjs +97 -41
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -4258,6 +4258,8 @@ const CYAN$1 = "\x1B[36m";
4258
4258
  const GREEN = "\x1B[32m";
4259
4259
  const MAGENTA = "\x1B[35m";
4260
4260
  const BLUE$1 = "\x1B[38;2;110;139;255m";
4261
+ const CHECKED = "◼";
4262
+ const UNCHECKED = "◻";
4261
4263
  const CATALOG_SOURCE = process.env.PRUFF_SKILLS_CATALOG || "Pruff-Tech/pruff-skills";
4262
4264
  async function fetchCatalogIndex(source) {
4263
4265
  const rel = ".well-known/agent-skills/index.json";
@@ -4350,10 +4352,11 @@ function rowBadge(skill) {
4350
4352
  if (parts.length === 0) return "";
4351
4353
  return ` ${DIM$3}[${RESET$3}${parts.join(`${DIM$3} · ${RESET$3}`)}${DIM$3}]${RESET$3}`;
4352
4354
  }
4353
- async function runSearchPrompt(kind, initialQuery = "") {
4355
+ async function runSearchPrompt(kind, alreadyPicked = /* @__PURE__ */ new Set(), initialQuery = "") {
4354
4356
  let results = [];
4355
4357
  let selectedIndex = 0;
4356
4358
  let query = initialQuery;
4359
+ const picked = new Set(alreadyPicked);
4357
4360
  let loading = false;
4358
4361
  let lastRenderedLines = 0;
4359
4362
  const noun = kind === "agent" ? "subagents" : kind === "rule" ? "rules" : "skills";
@@ -4381,15 +4384,17 @@ async function runSearchPrompt(kind, initialQuery = "") {
4381
4384
  const skill = visible[i];
4382
4385
  const isSelected = idx === selectedIndex;
4383
4386
  const arrow = isSelected ? `${BOLD$3}>${RESET$3}` : " ";
4387
+ const box = picked.has(skill.name) ? `${GREEN}${CHECKED}${RESET$3}` : `${DIM$3}${UNCHECKED}${RESET$3}`;
4384
4388
  const name = isSelected ? `${BOLD$3}${skill.name}${RESET$3}` : `${TEXT$2}${skill.name}${RESET$3}`;
4385
4389
  const loadingIndicator = loading && idx === 0 ? ` ${DIM$3}...${RESET$3}` : "";
4386
- lines.push(` ${arrow} ${name}${rowBadge(skill)}${loadingIndicator}`);
4390
+ lines.push(` ${arrow} ${box} ${name}${rowBadge(skill)}${loadingIndicator}`);
4387
4391
  }
4388
4392
  const remaining = results.length - (from + visible.length);
4389
4393
  if (remaining > 0) lines.push(` ${DIM$3}↓ ${remaining} more${RESET$3}`);
4390
4394
  }
4391
4395
  lines.push("");
4392
- lines.push(`${DIM$3}up/down navigate | enter select | esc back${RESET$3}`);
4396
+ const count = picked.size > 0 ? ` ${GREEN}(${picked.size} selected)${RESET$3}` : "";
4397
+ lines.push(`${DIM$3}up/down navigate | space toggle | enter done${count}${DIM$3} | esc back${RESET$3}`);
4393
4398
  for (const line of lines) process.stdout.write(line + "\n");
4394
4399
  lastRenderedLines = lines.length;
4395
4400
  }
@@ -4428,8 +4433,19 @@ async function runSearchPrompt(kind, initialQuery = "") {
4428
4433
  return;
4429
4434
  }
4430
4435
  if (key.name === "return") {
4436
+ const row = results[selectedIndex];
4437
+ if (picked.size === 0 && row) picked.add(row.name);
4431
4438
  cleanup();
4432
- resolve(results[selectedIndex] || null);
4439
+ resolve(picked);
4440
+ return;
4441
+ }
4442
+ if (key.name === "space") {
4443
+ const row = results[selectedIndex];
4444
+ if (row) {
4445
+ if (picked.has(row.name)) picked.delete(row.name);
4446
+ else picked.add(row.name);
4447
+ render();
4448
+ }
4433
4449
  return;
4434
4450
  }
4435
4451
  if (key.name === "up") {
@@ -4490,59 +4506,99 @@ ${DIM$3} 2) npx pruff-skills add <skill>${RESET$3}`;
4490
4506
  return;
4491
4507
  }
4492
4508
  const all = await searchSkillsAPI("");
4493
- const skillCount = all.filter((s) => s.kind === "skill").length;
4494
- const agentCount = all.filter((s) => s.kind === "agent").length;
4495
- const ruleCount = all.filter((s) => s.kind === "rule").length;
4496
- let selected = "back";
4497
- while (selected === "back") {
4509
+ const countOf = (kind) => all.filter((s) => s.kind === kind).length;
4510
+ const KINDS = [
4511
+ {
4512
+ value: "skill",
4513
+ label: "Skills",
4514
+ count: countOf("skill")
4515
+ },
4516
+ {
4517
+ value: "agent",
4518
+ label: "Subagents",
4519
+ count: countOf("agent")
4520
+ },
4521
+ {
4522
+ value: "rule",
4523
+ label: "Rules",
4524
+ count: countOf("rule")
4525
+ }
4526
+ ];
4527
+ const pickedByKind = new Map(KINDS.map((k) => [k.value, /* @__PURE__ */ new Set()]));
4528
+ const totalPicked = () => [...pickedByKind.values()].reduce((n, set) => n + set.size, 0);
4529
+ const cancelled = () => {
4530
+ console.log(`${DIM$3}Search cancelled${RESET$3}`);
4531
+ console.log();
4532
+ };
4533
+ for (;;) {
4534
+ const total = totalPicked();
4535
+ const options = KINDS.map((k) => {
4536
+ const picked = pickedByKind.get(k.value).size;
4537
+ return {
4538
+ value: k.value,
4539
+ label: k.label,
4540
+ hint: picked > 0 ? `${k.count} · ${picked} selected` : `${k.count} available`
4541
+ };
4542
+ });
4543
+ if (total > 0) options.push({
4544
+ value: "review",
4545
+ label: "Review & install",
4546
+ hint: `${total} selected`
4547
+ });
4498
4548
  const kindChoice = await ve({
4499
4549
  message: "What are you looking for?",
4500
- options: [
4501
- {
4502
- value: "skill",
4503
- label: "Skills",
4504
- hint: `${skillCount} available`
4505
- },
4506
- {
4507
- value: "agent",
4508
- label: "Subagents",
4509
- hint: `${agentCount} available`
4510
- },
4511
- {
4512
- value: "rule",
4513
- label: "Rules",
4514
- hint: `${ruleCount} available`
4515
- }
4516
- ]
4550
+ options
4517
4551
  });
4518
4552
  if (pD(kindChoice)) {
4519
- console.log(`${DIM$3}Search cancelled${RESET$3}`);
4520
- console.log();
4553
+ cancelled();
4521
4554
  return;
4522
4555
  }
4556
+ if (kindChoice === "review") {
4557
+ console.log();
4558
+ for (const kind of KINDS) {
4559
+ const names = [...pickedByKind.get(kind.value)];
4560
+ if (names.length === 0) continue;
4561
+ console.log(`${TEXT$2}${kind.label}${RESET$3} ${DIM$3}(${names.length})${RESET$3}`);
4562
+ for (const name of names) {
4563
+ const note = all.find((s) => s.kind === kind.value && s.name === name)?.installed ? ` ${DIM$3}— already installed, will reinstall${RESET$3}` : "";
4564
+ console.log(` ${DIM$3}·${RESET$3} ${name}${note}`);
4565
+ }
4566
+ }
4567
+ console.log();
4568
+ const confirmed = await ye({ message: `Install ${total} item${total === 1 ? "" : "s"}?` });
4569
+ if (pD(confirmed)) {
4570
+ cancelled();
4571
+ return;
4572
+ }
4573
+ if (!confirmed) continue;
4574
+ break;
4575
+ }
4523
4576
  console.log();
4524
- selected = await runSearchPrompt(kindChoice);
4525
- }
4526
- if (!selected) {
4527
- console.log(`${DIM$3}Search cancelled${RESET$3}`);
4528
- console.log();
4529
- return;
4577
+ const result = await runSearchPrompt(kindChoice, pickedByKind.get(kindChoice));
4578
+ if (result === null) {
4579
+ cancelled();
4580
+ return;
4581
+ }
4582
+ if (result !== "back") pickedByKind.set(kindChoice, result);
4530
4583
  }
4531
- const skillName = selected.name;
4584
+ const skills = [...pickedByKind.get("skill")];
4585
+ const agents = [...pickedByKind.get("agent")];
4586
+ const rules = [...pickedByKind.get("rule")];
4587
+ String(skills.length + agents.length + rules.length);
4532
4588
  console.log();
4533
- if (selected.kind === "agent") await addAgents([skillName], {});
4534
- else if (selected.kind === "rule") await addRules([skillName], {});
4535
- else {
4536
- const pkg = selected.source || selected.slug;
4537
- console.log(`${TEXT$2}Installing ${BOLD$3}${skillName}${RESET$3} from ${DIM$3}${pkg}${RESET$3}...`);
4589
+ if (skills.length > 0) {
4590
+ const pkg = CATALOG_SOURCE;
4591
+ console.log(`${TEXT$2}Installing ${BOLD$3}${skills.join(", ")}${RESET$3} from ${DIM$3}${pkg}${RESET$3}...`);
4538
4592
  console.log();
4539
4593
  const { source, options } = parseAddOptions([
4540
4594
  pkg,
4541
4595
  "--skill",
4542
- skillName
4596
+ ...skills
4543
4597
  ]);
4544
4598
  await runAdd(source, options);
4545
4599
  }
4600
+ if (agents.length > 0) await addAgents(agents, {});
4601
+ if (rules.length > 0) await addRules(rules, {});
4546
4602
  console.log();
4547
4603
  console.log(`${DIM$3}Installed.${RESET$3} ${TEXT$2}npx pruff-skills list${RESET$3} ${DIM$3}shows what's installed.${RESET$3}`);
4548
4604
  console.log();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pruff-skills",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "The official Pruff agent skills CLI",
5
5
  "type": "module",
6
6
  "bin": {