multi-agents-cli 1.0.5 → 1.0.7

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/init.js +80 -54
  2. package/package.json +4 -1
package/init.js CHANGED
@@ -11,6 +11,45 @@
11
11
  const readline = require('readline');
12
12
  const fs = require('fs');
13
13
  const path = require('path');
14
+
15
+ // ── Prompts (arrow-key navigation) ───────────────────────────────────────────
16
+
17
+ let prompts;
18
+ try { prompts = require('prompts'); } catch { prompts = null; }
19
+
20
+ const arrowSelect = async (message, choices, rl) => {
21
+ if (prompts && process.stdin.isTTY) {
22
+ const res = await prompts({
23
+ type: 'select',
24
+ name: 'value',
25
+ message,
26
+ choices: choices.map((c, i) => ({ title: typeof c === 'string' ? c : c.label, value: i })),
27
+ }, { onCancel: () => process.exit(0) });
28
+ return res.value ?? 0;
29
+ }
30
+ choices.forEach((c, i) => console.log(` ${dim(`${i + 1}.`)} ${typeof c === 'string' ? c : c.label}`));
31
+ return new Promise(resolve => {
32
+ rl.question(`\n Select (1-${choices.length}): `, ans => {
33
+ const n = parseInt(ans) - 1;
34
+ resolve(!isNaN(n) && n >= 0 && n < choices.length ? n : 0);
35
+ });
36
+ });
37
+ };
38
+
39
+ const arrowConfirm = async (message, rl) => {
40
+ if (prompts && process.stdin.isTTY) {
41
+ const res = await prompts({
42
+ type: 'confirm',
43
+ name: 'value',
44
+ message,
45
+ initial: true,
46
+ }, { onCancel: () => process.exit(0) });
47
+ return res.value ?? true;
48
+ }
49
+ return new Promise(resolve => {
50
+ rl.question(`${message} (y/n): `, ans => resolve(ans.toLowerCase() !== 'n'));
51
+ });
52
+ };
14
53
  const os = require('os');
15
54
  const { execSync, spawn } = require('child_process');
16
55
 
@@ -436,29 +475,21 @@ const showList = (items, showSkip = false) => {
436
475
  };
437
476
 
438
477
  const selectRequired = async (prompt, items) => {
439
- while (true) {
440
- console.log(`\n${bold(prompt)}`);
441
- showList(items);
442
- const input = await ask(`\n ${bold('Select')} ${dim(`(1-${items.length})`)}: `);
443
- const index = parseInt(input) - 1;
444
- if (!isNaN(index) && index >= 0 && index < items.length) return items[index];
445
- console.log(yellow(` Please enter a number between 1 and ${items.length}.`));
446
- }
478
+ console.log(`\n${bold(prompt)}`);
479
+ const idx = await arrowSelect(prompt, items.map(i => ({ label: typeof i === 'string' ? i : i.label })), rl);
480
+ return items[idx];
447
481
  };
448
482
 
449
483
  const selectOptional = async (prompt, items) => {
450
484
  if (!items || items.length === 0) return null;
451
- while (true) {
452
- console.log(`\n${bold(prompt)}`);
453
- showList(items, true);
454
- const input = await ask(`\n ${bold('Select')} ${dim(`(0-${items.length})`)}: `);
455
- if (input === '0' || input === '') return null;
456
- const index = parseInt(input) - 1;
457
- if (!isNaN(index) && index >= 0 && index < items.length) {
458
- return typeof items[index] === 'string' ? items[index] : items[index].value;
459
- }
460
- console.log(yellow(` Invalid selection. Please enter a number between 0 and ${items.length}.`));
461
- }
485
+ console.log(`\n${bold(prompt)}`);
486
+ const choices = [
487
+ ...items.map(i => ({ label: typeof i === 'string' ? i : i.label })),
488
+ { label: dim('Skip (agent will propose when needed)') },
489
+ ];
490
+ const idx = await arrowSelect(prompt, choices, rl);
491
+ if (idx === items.length) return null;
492
+ return typeof items[idx] === 'string' ? items[idx] : items[idx].value;
462
493
  };
463
494
 
464
495
  const separator = () => console.log(`\n${dim('─'.repeat(60))}`);
@@ -600,11 +631,11 @@ const main = async () => {
600
631
  let backendOrm = null;
601
632
  let backendAuth = null;
602
633
  let backendType = null;
634
+ let backendFwObj = null;
603
635
 
604
636
  if (clientFw.integratedBackend) {
605
637
  console.log(dim(` ${clientFw.value} supports server-side rendering and API routes.\n`));
606
- const integratedAnswer = await ask(` ${bold('Use integrated backend')} ${dim(`(${clientFw.value} API routes/SSR)`)} ${dim('instead of a separate backend? (y/n)')}: `);
607
- useIntegratedBackend = integratedAnswer.toLowerCase() === 'y';
638
+ useIntegratedBackend = await arrowConfirm(`Use integrated backend (${clientFw.value} API routes/SSR) instead of a separate backend?`, rl);
608
639
 
609
640
  if (useIntegratedBackend) {
610
641
  backendType = 'integrated';
@@ -615,22 +646,12 @@ const main = async () => {
615
646
  if (!useIntegratedBackend) {
616
647
  console.log(dim(' You can skip the backend framework and decide later.\n'));
617
648
 
618
- let backendFwObj = undefined;
619
- while (backendFwObj === undefined) {
620
- console.log(`\n${bold('Backend framework:')}`);
621
- showList(BACKEND_FRAMEWORKS, true);
622
- const input = await ask(`\n ${bold('Select')} ${dim(`(0-${BACKEND_FRAMEWORKS.length})`)}: `);
623
- if (input === '0' || input === '') {
624
- backendFwObj = null;
625
- } else {
626
- const index = parseInt(input) - 1;
627
- if (isNaN(index) || index < 0 || index >= BACKEND_FRAMEWORKS.length) {
628
- console.log(yellow(` Please enter a number between 0 and ${BACKEND_FRAMEWORKS.length}.`));
629
- } else {
630
- backendFwObj = BACKEND_FRAMEWORKS[index];
631
- }
632
- }
633
- }
649
+ const backendChoices = [
650
+ ...BACKEND_FRAMEWORKS.map(f => ({ label: f.label || f.value })),
651
+ { label: dim('Skip (decide later)') },
652
+ ];
653
+ const backendIdx = await arrowSelect('Backend framework:', backendChoices, rl);
654
+ backendFwObj = backendIdx === BACKEND_FRAMEWORKS.length ? null : BACKEND_FRAMEWORKS[backendIdx];
634
655
 
635
656
  backendFw = backendFwObj ? backendFwObj.value : null;
636
657
  backendLang = backendFwObj ? backendFwObj.language : null;
@@ -675,8 +696,7 @@ const main = async () => {
675
696
  if (ideChoice.cmd && !ideChoice.detected) {
676
697
  console.log(yellow(` ⚠ ${ideChoice.name} was not detected on PATH. It may not open automatically.`));
677
698
  }
678
- const confirmIde = await ask(` ${bold('Confirm this selection?')} ${dim('(y/n)')}: `);
679
- if (confirmIde.toLowerCase() !== 'y') {
699
+ if (!await arrowConfirm('Confirm this selection?', rl)) {
680
700
  console.log(dim(' Re-selecting...\n'));
681
701
  continue;
682
702
  }
@@ -698,8 +718,7 @@ const main = async () => {
698
718
  }
699
719
 
700
720
  console.log(` ${yellow('!')} Could not verify ${ideChoice.name}. The CLI may not be installed or accessible.`);
701
- const proceedAnyway = await ask(` ${bold('Continue with this IDE anyway?')} ${dim('(y/n)')}: `);
702
- if (proceedAnyway.toLowerCase() === 'y') break;
721
+ if (await arrowConfirm('Continue with this IDE anyway?', rl)) break;
703
722
  console.log(dim(' Re-selecting...\n'));
704
723
  }
705
724
 
@@ -724,9 +743,13 @@ const main = async () => {
724
743
 
725
744
  console.log('');
726
745
  console.log(dim(' y = confirm | n = abort | e = edit (start over)\n'));
727
- const confirm = await ask(`${bold('Confirm and write to config files?')} ${dim('(y/n/e)')}: `);
746
+ const confirmIdx = await arrowSelect('Confirm and write to config files?', [
747
+ { label: `${green('✓')} Confirm — write config and set up project` },
748
+ { label: `${yellow('↺')} Restart — redo configuration` },
749
+ { label: `${red('✗')} Abort` },
750
+ ], rl);
728
751
 
729
- if (confirm.toLowerCase() === 'e') {
752
+ if (confirmIdx === 1) {
730
753
  console.log(yellow('\n Restarting configuration...\n'));
731
754
  rl.close();
732
755
  const { spawn } = require('child_process');
@@ -735,7 +758,7 @@ const main = async () => {
735
758
  return;
736
759
  }
737
760
 
738
- if (confirm.toLowerCase() !== 'y') {
761
+ if (confirmIdx === 2) {
739
762
  console.log(yellow('\n Aborted. No files were changed.\n'));
740
763
  rl.close();
741
764
  return;
@@ -1125,11 +1148,11 @@ fi
1125
1148
  // Wrap in loop to support back navigation
1126
1149
  let trajectory = null;
1127
1150
  trajectoryLoop: while (true) {
1128
- while (!trajectory) {
1129
- const input = await ask(` ${bold('Select (1-2)')}: `);
1130
- if (['1', '2'].includes(input)) trajectory = input;
1131
- else console.log(yellow(' Please enter 1 or 2.'));
1132
- }
1151
+ const trajIdx = await arrowSelect('How do you want to build?', [
1152
+ { label: bold('Multi-Agent Driven Orchestration') },
1153
+ { label: bold('Shared Orchestration') },
1154
+ ], rl);
1155
+ trajectory = String(trajIdx + 1);
1133
1156
 
1134
1157
  const selected = TRAJECTORY_DETAILS[trajectory];
1135
1158
  separator();
@@ -1137,9 +1160,12 @@ fi
1137
1160
  renderTrajectoryLines(selected.full);
1138
1161
  console.log('');
1139
1162
 
1140
- const confirm = await ask(` ${bold('Confirm?')} ${dim('(y / b = back)')}: `);
1141
- if (confirm.toLowerCase() === 'y') break trajectoryLoop;
1142
- trajectory = null; // reset and re-show menu
1163
+ const confirmIdx = await arrowSelect('Confirm?', [
1164
+ { label: `${green('')} Confirm` },
1165
+ { label: `${yellow('←')} Back pick differently` },
1166
+ ], rl);
1167
+ if (confirmIdx === 0) break trajectoryLoop;
1168
+ trajectory = null;
1143
1169
  separator();
1144
1170
  console.log(`\n ${bold('How do you want to build?')}\n`);
1145
1171
  console.log(` ${dim('1.')} ${bold('Multi-Agent Driven Orchestration')}`);
@@ -1168,8 +1194,8 @@ fi
1168
1194
  } catch { /* best-effort */ }
1169
1195
 
1170
1196
  if (selected.next === 'launch') {
1171
- const launchInput = await ask(` ${bold('Ready to launch your first task?')} ${dim('(y/n)')}: `);
1172
- if (launchInput.toLowerCase() === 'y') {
1197
+ const launchConfirm = await arrowConfirm('Ready to launch your first task?', rl);
1198
+ if (launchConfirm) {
1173
1199
  rl.close();
1174
1200
  console.log('');
1175
1201
  const child = spawn('node', [path.join(ROOT, '.workflow', 'launch.js')], {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "multi-agents-cli",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Multi-agent workflow orchestration for Claude Code — isolated git worktrees, structured state tracking, autonomous task chaining",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -16,6 +16,9 @@
16
16
  "bin": {
17
17
  "multi-agents": "init.js"
18
18
  },
19
+ "dependencies": {
20
+ "prompts": "^2.4.2"
21
+ },
19
22
  "files": [
20
23
  "init.js",
21
24
  "README.md",