spirewise 1.8.0 → 1.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 (3) hide show
  1. package/bin/cli.js +32 -41
  2. package/install.sh +6 -6
  3. package/package.json +1 -1
package/bin/cli.js CHANGED
@@ -211,27 +211,19 @@ function removeFromAgent(agentKey, agent, scope, skills, onItem) {
211
211
  return removed;
212
212
  }
213
213
 
214
- // Vertical wizard stepper. Each step is a rounded number square (#01, #02, #03)
215
- // with a vertical connector line dropping from the centre of each square to the
216
- // next a left-rail "stepper" rendered above every wizard screen.
214
+ // Clean single-line horizontal stepper (like a React UI-library Steps component):
215
+ // completed steps show a check, the active step is a filled, highlighted circle,
216
+ // upcoming steps are dim outline circles joined by thin connectors.
217
+ const STEP_FILLED = ['', '❶', '❷', '❸', '❹', '❺', '❻'];
218
+ const STEP_OUTLINE = ['', '①', '②', '③', '④', '⑤', '⑥'];
217
219
  function stepper(current, steps) {
218
- const out = [];
219
- const PAD = ' ';
220
- for (let i = 0; i < steps.length; i++) {
220
+ const parts = steps.map((label, i) => {
221
221
  const n = i + 1;
222
- const num = '#' + String(n).padStart(2, '0'); // #01, #02, #03
223
- const state = n < current ? 'done' : n === current ? 'active' : 'pending';
224
- const color = state === 'done' ? RAW.green : state === 'active' ? RAW.cyan : RAW.dim;
225
- const label = state === 'active' ? paint(RAW.bold, steps[i])
226
- : state === 'done' ? paint(RAW.dim, steps[i] + ' ')
227
- : paint(RAW.dim, steps[i]);
228
- // rounded square (≈10–15% corner radius via ╭╮╰╯) holding the step number
229
- out.push(PAD + paint(color, '╭─────╮'));
230
- out.push(PAD + paint(color, '│ ' + num + ' │') + ' ' + label);
231
- out.push(PAD + paint(color, '╰─────╯'));
232
- if (n < steps.length) out.push(PAD + ' ' + paint(RAW.dim, '│')); // centred connector
233
- }
234
- return out;
222
+ if (n < current) return `${paint(RAW.green, '')} ${paint(RAW.dim, label)}`; // done
223
+ if (n === current) return `${paint(RAW.cyan, STEP_FILLED[n])} ${paint(RAW.bold, label)}`; // active
224
+ return paint(RAW.dim, `${STEP_OUTLINE[n]} ${label}`); // upcoming
225
+ });
226
+ return [' ' + parts.join(paint(RAW.dim, ' ── '))];
235
227
  }
236
228
 
237
229
  // Single, in-place updating status line (collapses the install/remove progress
@@ -411,7 +403,6 @@ async function main() {
411
403
 
412
404
  const o = parseArgs(argv);
413
405
  const tty = process.stdin.isTTY;
414
- const verb = action === 'remove' ? 'remove' : 'install';
415
406
  const Ving = action === 'remove' ? 'Removing' : 'Installing';
416
407
  banner();
417
408
 
@@ -425,9 +416,9 @@ async function main() {
425
416
  });
426
417
  } else if (tty) {
427
418
  skills = await interactiveSelect({
428
- title: `Select skills to ${verb}`,
429
- step: 1, steps: ['Select skills', 'Select agents', 'Select scope'],
430
- subtitle: action === 'remove' ? 'These will be deleted from the chosen agents' : 'Copy templates to install into your agents',
419
+ title: `Skills`,
420
+ step: 1, steps: ['Skills', 'Tools', 'Where'],
421
+ subtitle: action === 'remove' ? 'Pick the skills to remove.' : 'Pick the skills you want.',
431
422
  items: available.map((s) => ({ value: s, label: s, hint: skillHint(s) })),
432
423
  multi: true, preselected: [],
433
424
  });
@@ -441,9 +432,9 @@ async function main() {
441
432
  for (const k of agentKeys) if (!AGENTS[k]) die(`Unknown agent '${k}'. Run "spirewise agents".`);
442
433
  } else if (tty) {
443
434
  agentKeys = await interactiveSelect({
444
- title: `Select agents`,
445
- step: 2, steps: ['Select skills', 'Select agents', 'Select scope'],
446
- subtitle: action === 'remove' ? 'Skills are removed from each agent’s folder' : 'Each agent gets the skills in its own folder + format',
435
+ title: `Tools`,
436
+ step: 2, steps: ['Skills', 'Tools', 'Where'],
437
+ subtitle: action === 'remove' ? 'Pick which tools to remove them from.' : 'Pick which tools to add them to.',
447
438
  items: Object.entries(AGENTS).map(([k, a]) => ({ value: k, label: a.label, hint: `(${k}) · ${a.format}` })),
448
439
  multi: true, preselected: [],
449
440
  });
@@ -455,13 +446,13 @@ async function main() {
455
446
  let scope = o.scope;
456
447
  if (!scope && tty) {
457
448
  scope = await interactiveSelect({
458
- title: 'Select scope',
459
- step: 3, steps: ['Select skills', 'Select agents', 'Select scope'],
460
- subtitle: action === 'remove' ? 'Where to remove the skills from?' : 'Where should the skills live?',
449
+ title: 'Where',
450
+ step: 3, steps: ['Skills', 'Tools', 'Where'],
451
+ subtitle: action === 'remove' ? 'Where to remove them from?' : 'Where should they go?',
461
452
  items: [
462
- { value: 'project', label: 'Workspace', hint: 'this folder only — the current project' },
463
- { value: 'global', label: 'Global', hint: 'your home folders — applies to all projects' },
464
- { value: 'both', label: 'Both', hint: 'workspace + global' },
453
+ { value: 'project', label: 'This project', hint: 'just this folder' },
454
+ { value: 'global', label: 'Everywhere', hint: 'all your projects' },
455
+ { value: 'both', label: 'Both', hint: 'this project + everywhere' },
465
456
  ],
466
457
  multi: false, preselected: [],
467
458
  });
@@ -472,33 +463,33 @@ async function main() {
472
463
 
473
464
  // ACTION
474
465
  console.log('');
475
- info(`${Ving} ${paint(RAW.bold, String(skills.length))} skill(s) ${action === 'remove' ? 'from' : 'into'} ${paint(RAW.bold, String(agentKeys.length))} agent(s) · scope ${paint(RAW.bold, scope === 'project' ? 'workspace' : scope)}`);
466
+
467
+ const pl = (n, w) => `${n} ${w}${n === 1 ? '' : 's'}`;
468
+ const where = { project: 'this project', global: 'everywhere', both: 'this project + everywhere' }[scope];
476
469
 
477
470
  let count = 0;
478
471
  const totalOps = scopes.length * agentKeys.length * skills.length;
479
472
  let seen = 0;
480
- const progress = (agent, skill, removed) => {
473
+ const progress = (agent, skill) => {
481
474
  seen++;
482
- const pct = totalOps ? Math.round((seen / totalOps) * 100) : 100;
483
- live(`${paint(RAW.cyan, '⟳')} ${Ving}… ${paint(RAW.bold, String(seen))}/${totalOps} (${pct}%) ${c.dim}${agent.label} · ${skill}${c.reset}`);
475
+ live(`${paint(RAW.cyan, '⟳')} ${Ving}… ${paint(RAW.bold, `${seen}/${totalOps}`)} ${c.dim}${agent.label}${c.reset}`);
484
476
  };
485
477
  for (const sc of scopes) for (const k of agentKeys) {
486
478
  if (action === 'remove') count += removeFromAgent(k, AGENTS[k], sc, skills, progress);
487
479
  else { installToAgent(k, AGENTS[k], sc, skills, progress); count += skills.length; }
488
480
  }
489
481
  // Collapse the whole done process into one final line.
490
- const scopeLabel = scopes.map((s) => (s === 'project' ? 'workspace' : s)).join(' + ');
491
482
  if (action === 'remove') {
492
- liveEnd(`${count === 0 ? paint(RAW.yellow, '·') : paint(RAW.green, '✓')} Removed ${paint(RAW.bold, String(count))} item(s) from ${paint(RAW.bold, String(agentKeys.length))} agent(s) ${c.dim}· ${scopeLabel}${c.reset}`);
483
+ liveEnd(`${count === 0 ? paint(RAW.yellow, '·') : paint(RAW.green, '✓')} Removed ${paint(RAW.bold, pl(count, 'skill'))} from ${pl(agentKeys.length, 'tool')} ${c.dim}(${where})${c.reset}`);
493
484
  } else {
494
- liveEnd(`${paint(RAW.green, '✓')} Installed ${paint(RAW.bold, String(skills.length))} skill(s) × ${paint(RAW.bold, String(agentKeys.length))} agent(s) ${c.dim}· ${count} file(s) · ${scopeLabel}${c.reset}`);
485
+ liveEnd(`${paint(RAW.green, '✓')} Added ${paint(RAW.bold, pl(skills.length, 'skill'))} to ${pl(agentKeys.length, 'tool')} ${c.dim}(${where})${c.reset}`);
495
486
  }
496
487
 
497
488
  if (action === 'remove') {
498
- if (count === 0) liveEnd(paint(RAW.dim, ' nothing matched — already clean'));
489
+ if (count === 0) liveEnd(paint(RAW.dim, ' nothing to remove — already clean'));
499
490
  } else {
500
491
  console.log('');
501
- info(`next: open your agent and say ${paint(RAW.bold, '"write our F6S profile copy"')}`);
492
+ info(`Done. Open your tool and ask it to use a skill.`);
502
493
  }
503
494
  console.log('');
504
495
  }
package/install.sh CHANGED
@@ -43,7 +43,7 @@ info() { printf '%s %s\n' "$(color '1;34' '==>')" "$1"; }
43
43
  ok() { printf '%s %s\n' "$(color '1;32' ' ok')" "$1"; }
44
44
  warn() { printf '%s %s\n' "$(color '1;33' ' !')" "$1" >&2; }
45
45
  die() { printf '%s %s\n' "$(color '1;31' 'err')" "$1" >&2; exit 1; }
46
- step() { printf '%s %s %s\n' "$(color '1;36' ' >')" "$(color '1;36' "[ #$(printf '%02d' "$1") ]")" "$2"; }
46
+ step() { printf '%s %s\n' "$(color '1;36' " $1.")" "$(color '1' "$2")"; }
47
47
  substep() { :; } # per-item output collapses into the single final summary line
48
48
 
49
49
  banner() {
@@ -255,7 +255,7 @@ fi
255
255
  banner
256
256
 
257
257
  # Step 1: skills (default all).
258
- step 1 "Scanning available skills"
258
+ step 1 "Skills"
259
259
  if [[ ${#SELECTED[@]} -eq 0 ]]; then
260
260
  SELECTED=("${AVAILABLE[@]}")
261
261
  else
@@ -269,11 +269,11 @@ fi
269
269
  substep "${#SELECTED[@]} skill(s): ${SELECTED[*]}"
270
270
 
271
271
  # Step 2: agents
272
- step 2 "Selecting target agents"
272
+ step 2 "Tools"
273
273
  if [[ -n "$AGENT_FILTER" ]]; then substep "agents: $AGENT_FILTER"; else substep "agents: all supported"; fi
274
274
 
275
275
  # Step 3: scope — prompt if not given.
276
- step 3 "Choosing scope"
276
+ step 3 "Where"
277
277
  if [[ -z "$SCOPE" ]]; then
278
278
  if [[ -t 0 ]]; then
279
279
  [[ "$MODE" == "remove" ]] && info "Where should the skills be removed from?" || info "Where should the skills be installed?"
@@ -308,8 +308,8 @@ done
308
308
 
309
309
  printf '\n'
310
310
  if [[ "$MODE" == "remove" ]]; then
311
- ok "Removed $REMOVED item(s)."
311
+ ok "Removed $REMOVED."
312
312
  else
313
- ok "Installed ${#SELECTED[@]} skill(s). Next: open your agent and say \"write our F6S profile copy\"."
313
+ ok "Added ${#SELECTED[@]}. Open your tool and ask it to use a skill."
314
314
  fi
315
315
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spirewise",
3
- "version": "1.8.0",
3
+ "version": "1.9.0",
4
4
  "description": "Installable Agent Skills for GitHub Copilot, Claude Code, and Cursor — copywriting (F6S & LinkedIn) and NVIDIA Inception tooling.",
5
5
  "bin": {
6
6
  "spirewise": "bin/cli.js"