multi-agents-cli 1.0.6 → 1.0.8

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 +79 -55
  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,19 @@ 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
+ const idx = await arrowSelect(prompt, items.map(i => ({ label: typeof i === 'string' ? i : i.label })), rl);
479
+ return items[idx];
447
480
  };
448
481
 
449
482
  const selectOptional = async (prompt, items) => {
450
483
  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
- }
484
+ const choices = [
485
+ ...items.map(i => ({ label: typeof i === 'string' ? i : i.label })),
486
+ { label: dim('Skip (agent will propose when needed)') },
487
+ ];
488
+ const idx = await arrowSelect(prompt, choices, rl);
489
+ if (idx === items.length) return null;
490
+ return typeof items[idx] === 'string' ? items[idx] : items[idx].value;
462
491
  };
463
492
 
464
493
  const separator = () => console.log(`\n${dim('─'.repeat(60))}`);
@@ -564,7 +593,7 @@ const main = async () => {
564
593
  separator();
565
594
 
566
595
  console.log(`\n${bold('Let\'s configure your project.')}`);
567
- console.log(dim(' Required fields must be selected. Optional fields can be skipped (press 0 or Enter).\n'));
596
+ console.log(dim(' Use arrow keys to select. Optional fields can be skipped.\n'));
568
597
  console.log(dim(' Skipped fields will be resolved by the agent when first needed.\n'));
569
598
 
570
599
  // ── Project name ────────────────────────────────────────────────────────────
@@ -600,11 +629,11 @@ const main = async () => {
600
629
  let backendOrm = null;
601
630
  let backendAuth = null;
602
631
  let backendType = null;
632
+ let backendFwObj = null;
603
633
 
604
634
  if (clientFw.integratedBackend) {
605
635
  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';
636
+ useIntegratedBackend = await arrowConfirm(`Use integrated backend (${clientFw.value} API routes/SSR) instead of a separate backend?`, rl);
608
637
 
609
638
  if (useIntegratedBackend) {
610
639
  backendType = 'integrated';
@@ -615,22 +644,12 @@ const main = async () => {
615
644
  if (!useIntegratedBackend) {
616
645
  console.log(dim(' You can skip the backend framework and decide later.\n'));
617
646
 
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
- }
647
+ const backendChoices = [
648
+ ...BACKEND_FRAMEWORKS.map(f => ({ label: f.label || f.value })),
649
+ { label: dim('Skip (decide later)') },
650
+ ];
651
+ const backendIdx = await arrowSelect('Backend framework:', backendChoices, rl);
652
+ backendFwObj = backendIdx === BACKEND_FRAMEWORKS.length ? null : BACKEND_FRAMEWORKS[backendIdx];
634
653
 
635
654
  backendFw = backendFwObj ? backendFwObj.value : null;
636
655
  backendLang = backendFwObj ? backendFwObj.language : null;
@@ -675,8 +694,7 @@ const main = async () => {
675
694
  if (ideChoice.cmd && !ideChoice.detected) {
676
695
  console.log(yellow(` ⚠ ${ideChoice.name} was not detected on PATH. It may not open automatically.`));
677
696
  }
678
- const confirmIde = await ask(` ${bold('Confirm this selection?')} ${dim('(y/n)')}: `);
679
- if (confirmIde.toLowerCase() !== 'y') {
697
+ if (!await arrowConfirm('Confirm this selection?', rl)) {
680
698
  console.log(dim(' Re-selecting...\n'));
681
699
  continue;
682
700
  }
@@ -698,8 +716,7 @@ const main = async () => {
698
716
  }
699
717
 
700
718
  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;
719
+ if (await arrowConfirm('Continue with this IDE anyway?', rl)) break;
703
720
  console.log(dim(' Re-selecting...\n'));
704
721
  }
705
722
 
@@ -724,9 +741,13 @@ const main = async () => {
724
741
 
725
742
  console.log('');
726
743
  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)')}: `);
744
+ const confirmIdx = await arrowSelect('Confirm and write to config files?', [
745
+ { label: `${green('✓')} Confirm — write config and set up project` },
746
+ { label: `${yellow('↺')} Restart — redo configuration` },
747
+ { label: `${red('✗')} Abort` },
748
+ ], rl);
728
749
 
729
- if (confirm.toLowerCase() === 'e') {
750
+ if (confirmIdx === 1) {
730
751
  console.log(yellow('\n Restarting configuration...\n'));
731
752
  rl.close();
732
753
  const { spawn } = require('child_process');
@@ -735,7 +756,7 @@ const main = async () => {
735
756
  return;
736
757
  }
737
758
 
738
- if (confirm.toLowerCase() !== 'y') {
759
+ if (confirmIdx === 2) {
739
760
  console.log(yellow('\n Aborted. No files were changed.\n'));
740
761
  rl.close();
741
762
  return;
@@ -1125,11 +1146,11 @@ fi
1125
1146
  // Wrap in loop to support back navigation
1126
1147
  let trajectory = null;
1127
1148
  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
- }
1149
+ const trajIdx = await arrowSelect('How do you want to build?', [
1150
+ { label: bold('Multi-Agent Driven Orchestration') },
1151
+ { label: bold('Shared Orchestration') },
1152
+ ], rl);
1153
+ trajectory = String(trajIdx + 1);
1133
1154
 
1134
1155
  const selected = TRAJECTORY_DETAILS[trajectory];
1135
1156
  separator();
@@ -1137,9 +1158,12 @@ fi
1137
1158
  renderTrajectoryLines(selected.full);
1138
1159
  console.log('');
1139
1160
 
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
1161
+ const confirmIdx = await arrowSelect('Confirm?', [
1162
+ { label: `${green('')} Confirm` },
1163
+ { label: `${yellow('←')} Back pick differently` },
1164
+ ], rl);
1165
+ if (confirmIdx === 0) break trajectoryLoop;
1166
+ trajectory = null;
1143
1167
  separator();
1144
1168
  console.log(`\n ${bold('How do you want to build?')}\n`);
1145
1169
  console.log(` ${dim('1.')} ${bold('Multi-Agent Driven Orchestration')}`);
@@ -1168,8 +1192,8 @@ fi
1168
1192
  } catch { /* best-effort */ }
1169
1193
 
1170
1194
  if (selected.next === 'launch') {
1171
- const launchInput = await ask(` ${bold('Ready to launch your first task?')} ${dim('(y/n)')}: `);
1172
- if (launchInput.toLowerCase() === 'y') {
1195
+ const launchConfirm = await arrowConfirm('Ready to launch your first task?', rl);
1196
+ if (launchConfirm) {
1173
1197
  rl.close();
1174
1198
  console.log('');
1175
1199
  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.6",
3
+ "version": "1.0.8",
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",