multi-agents-cli 1.0.95 → 1.0.97
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/core/workflow/agent.js +105 -0
- package/package.json +1 -1
package/core/workflow/agent.js
CHANGED
|
@@ -836,6 +836,52 @@ const main = async () => {
|
|
|
836
836
|
|
|
837
837
|
// Soft gate - backend selected but missing prerequisites
|
|
838
838
|
if (project === 'backend') {
|
|
839
|
+
// Architectural change warning — no backend/ folder + integrated backend config
|
|
840
|
+
const backendFolderExists = fs.existsSync(path.join(ROOT, 'backend'));
|
|
841
|
+
const isIntegrated = config.backend?.type === 'integrated';
|
|
842
|
+
|
|
843
|
+
if (!backendFolderExists) {
|
|
844
|
+
separator();
|
|
845
|
+
console.log(`\n ${yellow('⚠ No backend/ folder detected')}
|
|
846
|
+
`);
|
|
847
|
+
if (isIntegrated) {
|
|
848
|
+
console.log(` This project currently uses ${bold('integrated backend')} (${dim(config.frontend?.type || 'client framework')}).`);
|
|
849
|
+
console.log(` Adding a separate backend will change your project architecture:
|
|
850
|
+
`);
|
|
851
|
+
} else {
|
|
852
|
+
console.log(` A ${bold('backend/')} directory does not exist yet.`);
|
|
853
|
+
console.log(` Proceeding will create it and establish a separate backend:
|
|
854
|
+
`);
|
|
855
|
+
}
|
|
856
|
+
console.log(` ${dim('→')} A new ${bold('backend/')} directory will be created`);
|
|
857
|
+
console.log(` ${dim('→')} Client API calls will need redirecting to the new backend`);
|
|
858
|
+
console.log(` ${dim('→')} CONTRACTS.md will need updating`);
|
|
859
|
+
if (isIntegrated) {
|
|
860
|
+
console.log(` ${dim('→')} Project config will update to ${bold('separate')} backend type
|
|
861
|
+
`);
|
|
862
|
+
}
|
|
863
|
+
console.log('');
|
|
864
|
+
|
|
865
|
+
const archIdx = await arrowSelect('How would you like to proceed?', [
|
|
866
|
+
{ label: `${green('→')} Proceed — I want to add a separate backend` },
|
|
867
|
+
{ label: `${yellow('←')} Go back — keep current setup ${dim('← recommended')}` },
|
|
868
|
+
], rl);
|
|
869
|
+
|
|
870
|
+
if (archIdx === 1) continue flowLoop;
|
|
871
|
+
|
|
872
|
+
// Update config to separate if was integrated
|
|
873
|
+
if (isIntegrated) {
|
|
874
|
+
try {
|
|
875
|
+
const cfgPath = path.join(ROOT, '.scaffold', '.config.json');
|
|
876
|
+
const cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf8'));
|
|
877
|
+
cfg.backend.type = 'separate';
|
|
878
|
+
fs.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2), 'utf8');
|
|
879
|
+
console.log(` ${green('✓')} Project config updated to separate backend
|
|
880
|
+
`);
|
|
881
|
+
} catch {}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
|
|
839
885
|
const clientCompleted = buildEntries.filter(e => e.scope === 'client' && e.status === 'COMPLETED');
|
|
840
886
|
const clientLogicDone = clientCompleted.some(e => e.agent === 'LOGIC');
|
|
841
887
|
const missing = [];
|
|
@@ -948,6 +994,34 @@ const main = async () => {
|
|
|
948
994
|
agent = agentOptions[agentIdx];
|
|
949
995
|
contractsNote = '';
|
|
950
996
|
|
|
997
|
+
// ── Check for OTHER active agents in same scope ───────────────────────────
|
|
998
|
+
const otherActiveInScope = Object.entries(tracking?.[project] || {})
|
|
999
|
+
.filter(([a, data]) => a !== agent && data?.status === 'ACTIVE');
|
|
1000
|
+
|
|
1001
|
+
if (otherActiveInScope.length > 0) {
|
|
1002
|
+
separator();
|
|
1003
|
+
console.log(`\n ${yellow('⚠ Active agent detected in ' + project + ' scope')}
|
|
1004
|
+
`);
|
|
1005
|
+
for (const [a, data] of otherActiveInScope) {
|
|
1006
|
+
console.log(` ${dim('→')} ${bold(a)} is currently ${yellow('ACTIVE')}`);
|
|
1007
|
+
console.log(` Branch : ${dim(data.branch)}`);
|
|
1008
|
+
console.log(` Launched: ${dim(data.launchedAt ? new Date(data.launchedAt).toLocaleString() : 'unknown')}
|
|
1009
|
+
`);
|
|
1010
|
+
}
|
|
1011
|
+
console.log(` ${yellow('Launching')} ${bold(agent)} ${yellow('alongside an active agent in the same scope means:')}`);
|
|
1012
|
+
console.log(` ${dim('→')} Both agents may write to overlapping files`);
|
|
1013
|
+
console.log(` ${dim('→')} Scope violations may occur at merge time`);
|
|
1014
|
+
console.log(` ${dim('→')} CONTRACTS.md may receive conflicting entries
|
|
1015
|
+
`);
|
|
1016
|
+
|
|
1017
|
+
const warningIdx = await arrowSelect('How would you like to proceed?', [
|
|
1018
|
+
{ label: `${yellow('→')} Proceed anyway ${dim('— I understand the risks')}` },
|
|
1019
|
+
{ label: `${green('←')} Go back — pick a different agent ${dim('← recommended')}` },
|
|
1020
|
+
], rl);
|
|
1021
|
+
|
|
1022
|
+
if (warningIdx === 1) continue agentLoop;
|
|
1023
|
+
}
|
|
1024
|
+
|
|
951
1025
|
// Agent already active - decisional block
|
|
952
1026
|
const { active, slot: activeSlot } = guards.checkAgentActive(tracking, project, agent);
|
|
953
1027
|
if (active) {
|
|
@@ -1095,6 +1169,32 @@ const main = async () => {
|
|
|
1095
1169
|
} // end else (argAgent bypass)
|
|
1096
1170
|
} // end if (project !== 'cloud')
|
|
1097
1171
|
|
|
1172
|
+
// ── First-run project context question (UI agent only, no completed agents) ──
|
|
1173
|
+
let projectContext = '';
|
|
1174
|
+
const isFirstRun = project === 'client' && agent === 'UI' && buildEntries.filter(e => e.status === 'COMPLETED').length === 0;
|
|
1175
|
+
|
|
1176
|
+
if (isFirstRun) {
|
|
1177
|
+
separator();
|
|
1178
|
+
console.log(`\n ${bold('Before we begin...')}
|
|
1179
|
+
`);
|
|
1180
|
+
|
|
1181
|
+
if (prompts && process.stdin.isTTY) {
|
|
1182
|
+
const ctxRes = await prompts({
|
|
1183
|
+
type: 'text',
|
|
1184
|
+
name: 'value',
|
|
1185
|
+
message: '* What are you building?',
|
|
1186
|
+
initial: 'e.g. A stock market prediction app with AI insights and portfolio tracking',
|
|
1187
|
+
}, { onCancel: () => process.exit(0) });
|
|
1188
|
+
const rawCtx = (ctxRes.value || '').trim();
|
|
1189
|
+
const isPlaceholderCtx = rawCtx.startsWith('e.g. ');
|
|
1190
|
+
projectContext = isPlaceholderCtx ? '' : rawCtx;
|
|
1191
|
+
} else {
|
|
1192
|
+
console.log(dim(' (optional — helps the agent make better decisions)'));
|
|
1193
|
+
const input = await ask(`\n${bold('* What are you building?')}: `);
|
|
1194
|
+
projectContext = input.trim();
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1098
1198
|
// ── Task description ──────────────────────────────────────────────────────────
|
|
1099
1199
|
|
|
1100
1200
|
separator();
|
|
@@ -1142,6 +1242,11 @@ const main = async () => {
|
|
|
1142
1242
|
let skipped = [];
|
|
1143
1243
|
contextSection = '';
|
|
1144
1244
|
|
|
1245
|
+
// Inject project context if provided on first UI run
|
|
1246
|
+
if (projectContext) {
|
|
1247
|
+
contextSection += `\n---\n\n## Project Context\n\n${projectContext}\n\nUse this as the primary directive for what you are building. All component names, page structure, and UI decisions should align with this project description.\n`;
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1145
1250
|
if (AGENT_QUESTIONS[agent] && userSeedingContracts) {
|
|
1146
1251
|
let gathering = true;
|
|
1147
1252
|
while (gathering) {
|
package/package.json
CHANGED