multi-agents-cli 1.0.31 → 1.0.32

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 +130 -28
  2. package/package.json +1 -1
package/init.js CHANGED
@@ -658,38 +658,140 @@ 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 rl3 = readline.createInterface({ input: process.stdin, output: process.stdout });
699
+ const ask3 = (q) => new Promise((resolve) => rl3.question(q, (a) => { rl3.close(); resolve(a.trim()); }));
700
+ const pick = await ask3(` ${bold('Select')} ${dim(`(1-${active.length + 1})`)}: `);
701
+
702
+ const idx = parseInt(pick) - 1;
703
+ if (idx === active.length) return false; // Back
704
+ if (idx < 0 || idx >= active.length) return false;
705
+
706
+ const { scope, agent, data } = active[idx];
707
+ const deps = (DEPENDENCIES[scope] || {})[agent] || [];
708
+ const affectedAgents = [{ scope, agent, data }];
709
+
710
+ // Find dependent agents that are also active
711
+ for (const dep of deps) {
712
+ const depData = (tracking[scope] || {})[dep];
713
+ if (depData && depData.branch) {
714
+ affectedAgents.push({ scope, agent: dep, data: depData });
715
+ }
716
+ }
717
+
718
+ // Show warning with exact names
719
+ separator();
720
+ console.log(`\n${yellow(` ⚠ Restarting ${agent} will delete:`)}`);
721
+ for (const { agent: a, data: d } of affectedAgents) {
722
+ console.log(`\n ${bold(a)}`);
723
+ console.log(` - Branch (${d.branch})`);
724
+ console.log(` - Remote branch (origin/${d.branch})`);
725
+ if (d.worktreePath) {
726
+ const wtName = path.relative(ROOT, d.worktreePath);
727
+ console.log(` - Worktree (${wtName})`);
728
+ }
729
+ }
730
+
731
+ if (deps.length > 0) {
732
+ console.log(`\n ${yellow('Dependent processes will also be wiped.')}`);
733
+ }
734
+
735
+ console.log(`\n ${red('This cannot be undone.')}\n`);
736
+
737
+ const rl4 = readline.createInterface({ input: process.stdin, output: process.stdout });
738
+ const ask4 = (q) => new Promise((resolve) => rl4.question(q, (a) => { rl4.close(); resolve(a.trim()); }));
739
+ const confirm = await ask4(` Continue? (y/N): `);
740
+
741
+ if (confirm.toLowerCase() !== 'y') {
742
+ console.log(dim('\n Cancelled.\n'));
743
+ return false;
744
+ }
745
+
746
+ // Perform wipe
747
+ for (const { agent: a, data: d, scope: s } of affectedAgents) {
748
+ try { execSync(`git worktree remove "${d.worktreePath}" --force`, { cwd: ROOT, stdio: 'pipe' }); } catch {}
749
+ try { execSync(`git branch -D ${d.branch}`, { cwd: ROOT, stdio: 'pipe' }); } catch {}
750
+ try { execSync(`git push origin --delete ${d.branch}`, { cwd: ROOT, stdio: 'pipe' }); } catch {}
751
+ // Clear tracking
752
+ if (tracking[s] && tracking[s][a]) {
753
+ tracking[s][a] = { branch: null, timestamp: null, launchedAt: null, status: null, missingCount: 0, worktreePath: null };
754
+ }
755
+ console.log(` ${green('✓')} ${a} wiped`);
756
+ }
757
+
758
+ fs.writeFileSync(trackingPath, JSON.stringify(tracking, null, 2), 'utf8');
759
+ console.log(`\n ${green('✓')} Restart complete.\n`);
760
+ return true;
761
+ };
762
+
763
+ if (prompts && process.stdin.isTTY) {
764
+ let lockLoop = true;
765
+ while (lockLoop) {
766
+ separator();
767
+ console.log(`\n${yellow(' This project has already been initialized.')}`);
768
+ console.log(dim(` Initialized on: ${ts}\n`));
769
+
770
+ const res = await prompts({
771
+ type: 'select',
772
+ name: 'value',
773
+ message: 'What would you like to do?',
774
+ choices: [
775
+ { title: 'Resume', description: 'Pick up where you left off', value: '1' },
776
+ { title: 'Restart process', description: 'Wipe and restart a specific process', value: '2' },
777
+ { title: 'Cancel', value: '3' },
778
+ ],
779
+ }, { onCancel: () => process.exit(0) });
780
+
781
+ if (res.value === '1') {
782
+ const child = spawn('node', [path.join(ROOT, '.workflow', 'agent.js')], { stdio: 'inherit', cwd: ROOT });
783
+ child.on('exit', (code) => process.exit(code));
784
+ return;
785
+ } else if (res.value === '2') {
786
+ const didRestart = await showRestartProcess();
787
+ if (!didRestart) continue; // Back — show menu again
788
+ lockLoop = false;
789
+ return;
790
+ } else {
791
+ console.log(dim('\n Cancelled.\n'));
792
+ process.exit(0);
793
+ }
794
+ }
693
795
  }
694
796
  }
695
797
 
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.32",
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",