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.
- package/init.js +130 -28
- 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
|
|
662
|
-
const
|
|
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
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
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
|
|
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
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
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
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
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