multi-agents-cli 1.0.31 → 1.0.33

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 +144 -28
  2. package/package.json +1 -1
package/init.js CHANGED
@@ -658,38 +658,154 @@ const main = async () => {
658
658
 
659
659
  if (fs.existsSync(LOCK_FILE)) {
660
660
  const ts = fs.readFileSync(LOCK_FILE, 'utf8').trim();
661
- const rl2 = readline.createInterface({ input: process.stdin, output: process.stdout });
662
- const ask2 = (q) => new Promise((resolve) => rl2.question(q, (a) => resolve(a.trim())));
661
+ const trackingPath = path.join(RUNTIME_DIR, '.tracking.json');
662
+ const tracking = fs.existsSync(trackingPath) ? JSON.parse(fs.readFileSync(trackingPath, 'utf8')) : {};
663
+
664
+ // Dependency map — primary agents whose restart cascades to dependents
665
+ const DEPENDENCIES = {
666
+ client: { UI: ['LOGIC', 'FORMS', 'ROUTING', 'TESTING', 'ACCESSIBILITY'] },
667
+ backend: { DB: ['API', 'AUTH', 'LOGIC', 'EVENTS', 'JOBS', 'TESTING'] },
668
+ shared: {},
669
+ };
663
670
 
664
- console.log(`\n${yellow(' This project has already been initialized.')}`);
665
- console.log(dim(` Initialized on: ${ts}\n`));
666
- console.log(` ${dim('1.')} Continue — run ${cyan('npm run agent')}`);
667
- console.log(` ${dim('2.')} Reset — delete config and re-run initialization`);
668
- console.log(` ${dim('3.')} Exit\n`);
671
+ const getActiveAgents = (scope) => {
672
+ const agents = tracking[scope] || {};
673
+ return Object.entries(agents).filter(([, v]) => v && v.branch);
674
+ };
669
675
 
670
- const choice = await ask2(` ${bold('Select')} ${dim('(1-3)')}: `);
676
+ const showRestartProcess = async () => {
677
+ // Build list of active processes across all scopes
678
+ const active = [];
679
+ for (const scope of ['client', 'backend', 'shared']) {
680
+ for (const [agent, data] of getActiveAgents(scope)) {
681
+ active.push({ scope, agent, data });
682
+ }
683
+ }
671
684
 
672
- if (choice === '1') {
673
- console.log('');
674
- rl2.close();
675
- const child = spawn('node', [path.join(ROOT, '.workflow', 'agent.js')], {
676
- stdio: 'inherit',
677
- cwd: ROOT,
685
+ if (active.length === 0) {
686
+ console.log(yellow('\n No active processes found.\n'));
687
+ return false;
688
+ }
689
+
690
+ separator();
691
+ console.log(`\n${bold(' Which process do you want to restart?')}\n`);
692
+ active.forEach(({ scope, agent, data }, i) => {
693
+ const status = data.status || 'ACTIVE';
694
+ console.log(` ${dim(`${i + 1}.`)} ${bold(agent)} ${dim(`(${scope})`)} - ${dim(status)}`);
678
695
  });
679
- child.on('exit', (code) => process.exit(code));
680
- return;
681
- } else if (choice === '2') {
682
- console.log(yellow('\n Resetting configuration...\n'));
683
- fs.unlinkSync(LOCK_FILE);
684
- const configPath = path.join(RUNTIME_DIR, '.config.json');
685
- if (fs.existsSync(configPath)) fs.unlinkSync(configPath);
686
- rl2.close();
687
- console.log(green(' Reset complete. Re-running initialization...\n'));
688
- // Fall through to run init again
689
- } else {
690
- console.log(dim('\n Exited.\n'));
691
- rl2.close();
692
- return;
696
+ console.log(` ${dim(`${active.length + 1}.`)} ${dim('Back')}\n`);
697
+
698
+ const pickRes = await prompts({
699
+ type: 'select',
700
+ name: 'value',
701
+ message: 'Which process do you want to restart?',
702
+ choices: [
703
+ ...active.map(({ scope, agent, data }) => ({
704
+ title: `${agent} (${scope}) - ${data.status || 'ACTIVE'}`,
705
+ value: agent,
706
+ })),
707
+ { title: 'Back', value: '__back__' },
708
+ ],
709
+ }, { onCancel: () => process.exit(0) });
710
+
711
+ if (!pickRes.value || pickRes.value === '__back__') return false;
712
+ const idx = active.findIndex(a => a.agent === pickRes.value);
713
+ if (idx < 0) return false;
714
+ const { scope, agent, data } = active[idx];
715
+ const deps = (DEPENDENCIES[scope] || {})[agent] || [];
716
+ const affectedAgents = [{ scope, agent, data }];
717
+
718
+ // Find dependent agents that are also active
719
+ for (const dep of deps) {
720
+ const depData = (tracking[scope] || {})[dep];
721
+ if (depData && depData.branch) {
722
+ affectedAgents.push({ scope, agent: dep, data: depData });
723
+ }
724
+ }
725
+
726
+ // Show warning with exact names
727
+ separator();
728
+ console.log(`\n${yellow(` ⚠ Restarting ${agent} will delete:`)}`);
729
+ for (const { agent: a, data: d } of affectedAgents) {
730
+ console.log(`\n ${bold(a)}`);
731
+ console.log(` - Branch (${d.branch})`);
732
+ console.log(` - Remote branch (origin/${d.branch})`);
733
+ if (d.worktreePath) {
734
+ const wtName = path.relative(ROOT, d.worktreePath);
735
+ console.log(` - Worktree (${wtName})`);
736
+ }
737
+ }
738
+
739
+ if (deps.length > 0) {
740
+ console.log(`\n ${yellow('Dependent processes will also be wiped.')}`);
741
+ }
742
+
743
+ console.log(`\n ${red('This cannot be undone.')}\n`);
744
+
745
+ const confirmRes = await prompts({
746
+ type: 'select',
747
+ name: 'value',
748
+ message: 'This cannot be undone. Continue?',
749
+ choices: [
750
+ { title: 'Yes - wipe and restart', value: 'y' },
751
+ { title: 'Cancel', value: 'n' },
752
+ ],
753
+ }, { onCancel: () => process.exit(0) });
754
+
755
+ if (confirmRes.value !== 'y') {
756
+ console.log(dim('\n Cancelled.\n'));
757
+ return false;
758
+ }
759
+
760
+ // Perform wipe
761
+ for (const { agent: a, data: d, scope: s } of affectedAgents) {
762
+ try { execSync(`git worktree remove "${d.worktreePath}" --force`, { cwd: ROOT, stdio: 'pipe' }); } catch {}
763
+ try { execSync(`git branch -D ${d.branch}`, { cwd: ROOT, stdio: 'pipe' }); } catch {}
764
+ try { execSync(`git push origin --delete ${d.branch}`, { cwd: ROOT, stdio: 'pipe' }); } catch {}
765
+ // Clear tracking
766
+ if (tracking[s] && tracking[s][a]) {
767
+ tracking[s][a] = { branch: null, timestamp: null, launchedAt: null, status: null, missingCount: 0, worktreePath: null };
768
+ }
769
+ console.log(` ${green('✓')} ${a} wiped`);
770
+ }
771
+
772
+ fs.writeFileSync(trackingPath, JSON.stringify(tracking, null, 2), 'utf8');
773
+ console.log(`\n ${green('✓')} Restart complete.\n`);
774
+ return true;
775
+ };
776
+
777
+ if (prompts && process.stdin.isTTY) {
778
+ let lockLoop = true;
779
+ while (lockLoop) {
780
+ separator();
781
+ console.log(`\n${yellow(' This project has already been initialized.')}`);
782
+ console.log(dim(` Initialized on: ${ts}\n`));
783
+
784
+ const res = await prompts({
785
+ type: 'select',
786
+ name: 'value',
787
+ message: 'What would you like to do?',
788
+ choices: [
789
+ { title: 'Resume', description: 'Pick up where you left off', value: '1' },
790
+ { title: 'Restart process', description: 'Wipe and restart a specific process', value: '2' },
791
+ { title: 'Cancel', value: '3' },
792
+ ],
793
+ }, { onCancel: () => process.exit(0) });
794
+
795
+ if (res.value === '1') {
796
+ const child = spawn('node', [path.join(ROOT, '.workflow', 'agent.js')], { stdio: 'inherit', cwd: ROOT });
797
+ child.on('exit', (code) => process.exit(code));
798
+ return;
799
+ } else if (res.value === '2') {
800
+ const didRestart = await showRestartProcess();
801
+ if (!didRestart) continue; // Back — show menu again
802
+ lockLoop = false;
803
+ return;
804
+ } else {
805
+ console.log(dim('\n Cancelled.\n'));
806
+ process.exit(0);
807
+ }
808
+ }
693
809
  }
694
810
  }
695
811
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "multi-agents-cli",
3
- "version": "1.0.31",
3
+ "version": "1.0.33",
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",