multi-agents-cli 1.0.53 → 1.0.55
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 +10 -1
- package/core/workflow/complete.js +68 -0
- package/init.js +40 -0
- package/package.json +1 -1
package/core/workflow/agent.js
CHANGED
|
@@ -1183,6 +1183,15 @@ Mark each step complete. Only proceed to the task below when all are checked.
|
|
|
1183
1183
|
);
|
|
1184
1184
|
console.log(` ${green('✓')} .claude-scope written`);
|
|
1185
1185
|
|
|
1186
|
+
// ── Write scope.json ─────────────────────────────────────────────────────────
|
|
1187
|
+
|
|
1188
|
+
fs.writeFileSync(
|
|
1189
|
+
path.join(worktreePath, 'scope.json'),
|
|
1190
|
+
JSON.stringify({ agent, scope: project, branch: branchName, policy: project }, null, 2),
|
|
1191
|
+
'utf8'
|
|
1192
|
+
);
|
|
1193
|
+
console.log(` ${green('✓')} scope.json written`);
|
|
1194
|
+
|
|
1186
1195
|
// ── Generate IDE settings ─────────────────────────────────────────────────────
|
|
1187
1196
|
|
|
1188
1197
|
const excludedFolders = {
|
|
@@ -1391,7 +1400,7 @@ ${excludedUrls}
|
|
|
1391
1400
|
console.log(` ${bold('2.')} ${bold(yellow('Open a NEW session in Claude Code CLI or Claude Code Extension - and type go or start to initiate'))}`);
|
|
1392
1401
|
console.log(dim(' Do NOT reuse a previous session.\n'));
|
|
1393
1402
|
console.log(` ${bold('3.')} Start the session and let the agent run.\n`);
|
|
1394
|
-
console.log(
|
|
1403
|
+
console.log(` ${bold('4.')} When the agent is done, run: ${cyan('npm run complete')} to merge the task into main.\n`);
|
|
1395
1404
|
separator();
|
|
1396
1405
|
console.log('');
|
|
1397
1406
|
|
|
@@ -176,6 +176,58 @@ const main = async () => {
|
|
|
176
176
|
|
|
177
177
|
const { path: worktreePath, branch: branchName } = selectedWorktree;
|
|
178
178
|
|
|
179
|
+
// ── Scope validation (Trust + Verify) ────────────────────────────────────────
|
|
180
|
+
|
|
181
|
+
const scopeJsonPath = path.join(worktreePath, 'scope.json');
|
|
182
|
+
const scopePolicyPath = path.join(ROOT, '.scaffold', 'scope-policy.json');
|
|
183
|
+
|
|
184
|
+
if (fs.existsSync(scopeJsonPath) && fs.existsSync(scopePolicyPath)) {
|
|
185
|
+
const scopeMeta = JSON.parse(fs.readFileSync(scopeJsonPath, 'utf8'));
|
|
186
|
+
const scopePolicy = JSON.parse(fs.readFileSync(scopePolicyPath, 'utf8'));
|
|
187
|
+
|
|
188
|
+
const policyScope = scopePolicy[scopeMeta.policy];
|
|
189
|
+
const agentKey = scopeMeta.agent && scopeMeta.agent.toUpperCase();
|
|
190
|
+
const override = policyScope && policyScope.agentOverrides && policyScope.agentOverrides[agentKey];
|
|
191
|
+
const scaffoldedFlag = (config.scaffolded || {})[scopeMeta.scope];
|
|
192
|
+
const overrideActive = override && (!override.onlyBeforeScaffolded || !scaffoldedFlag);
|
|
193
|
+
const allowed = (overrideActive && override.allowed) || (policyScope && policyScope.allowed) || [];
|
|
194
|
+
const blocked = (policyScope && policyScope.blocked) || [];
|
|
195
|
+
|
|
196
|
+
const changedFiles = execSync('git diff --name-only main...HEAD', { cwd: worktreePath, stdio: 'pipe' })
|
|
197
|
+
.toString().trim().split('\n').filter(Boolean);
|
|
198
|
+
|
|
199
|
+
const matchesGlob = (file, pat) => {
|
|
200
|
+
if (pat.endsWith('/**')) return file.startsWith(pat.slice(0, -3));
|
|
201
|
+
if (pat.includes('*')) {
|
|
202
|
+
const re = pat.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
203
|
+
.replace(/\*\*/g, 'DOUBLESTAR')
|
|
204
|
+
.replace(/\*/g, '[^/]*')
|
|
205
|
+
.replace(/DOUBLESTAR/g, '.*');
|
|
206
|
+
return new RegExp('^' + re + '$').test(file);
|
|
207
|
+
}
|
|
208
|
+
return file === pat;
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const violations = changedFiles.filter(file => {
|
|
212
|
+
const isAllowed = allowed.some(pat => matchesGlob(file, pat));
|
|
213
|
+
const isBlocked = blocked.some(pat => matchesGlob(file, pat));
|
|
214
|
+
return !isAllowed || isBlocked;
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
if (violations.length > 0) {
|
|
218
|
+
console.log('\n' + red(' ✗ Scope violation - merge blocked.'));
|
|
219
|
+
console.log(dim(' The following files are outside the allowed scope for ' + scopeMeta.agent + ' (' + scopeMeta.scope + '):\n'));
|
|
220
|
+
violations.forEach(f => console.log(' ' + red('✗') + ' ' + f));
|
|
221
|
+
console.log('\n' + dim(' Fix the violations, then re-run npm run complete.\n'));
|
|
222
|
+
rl.close();
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
console.log(' ' + green('✓') + ' Scope validation passed (' + changedFiles.length + ' files checked)');
|
|
227
|
+
} else {
|
|
228
|
+
console.log(' ' + dim('ℹ scope.json or scope-policy.json not found - skipping validation'));
|
|
229
|
+
}
|
|
230
|
+
|
|
179
231
|
// ── Check TASK.md status ──────────────────────────────────────────────────────
|
|
180
232
|
|
|
181
233
|
const taskMdPath = path.join(worktreePath, 'TASK.md');
|
|
@@ -304,6 +356,22 @@ const main = async () => {
|
|
|
304
356
|
}
|
|
305
357
|
} catch { /* best-effort */ }
|
|
306
358
|
|
|
359
|
+
// ── Update scaffold flags ──────────────────────────────────────────────────
|
|
360
|
+
|
|
361
|
+
try {
|
|
362
|
+
const parts = branchName.split('/');
|
|
363
|
+
if (parts.length >= 4) {
|
|
364
|
+
const scope = parts[1];
|
|
365
|
+
const agent = parts[2].toUpperCase();
|
|
366
|
+
const cfgPath = path.join(ROOT, '.scaffold', '.config.json');
|
|
367
|
+
const cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf8'));
|
|
368
|
+
if (!cfg.scaffolded) cfg.scaffolded = { client: false, backend: false };
|
|
369
|
+
if (scope === 'client' && agent === 'UI') cfg.scaffolded.client = true;
|
|
370
|
+
if (scope === 'backend' && agent === 'INIT') cfg.scaffolded.backend = true;
|
|
371
|
+
fs.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2), 'utf8');
|
|
372
|
+
}
|
|
373
|
+
} catch { /* best-effort */ }
|
|
374
|
+
|
|
307
375
|
// ── Push to origin ────────────────────────────────────────────────────────────
|
|
308
376
|
|
|
309
377
|
try {
|
package/init.js
CHANGED
|
@@ -1192,6 +1192,10 @@ const main = async () => {
|
|
|
1192
1192
|
orm: backendOrm,
|
|
1193
1193
|
auth: backendAuth,
|
|
1194
1194
|
},
|
|
1195
|
+
scaffolded: {
|
|
1196
|
+
client: false,
|
|
1197
|
+
backend: false,
|
|
1198
|
+
},
|
|
1195
1199
|
};
|
|
1196
1200
|
|
|
1197
1201
|
fs.writeFileSync(
|
|
@@ -1201,6 +1205,42 @@ const main = async () => {
|
|
|
1201
1205
|
);
|
|
1202
1206
|
console.log(` ${green('✓')} .scaffold/.config.json written`);
|
|
1203
1207
|
|
|
1208
|
+
// ── Write scope-policy.json ──────────────────────────────────────────────────
|
|
1209
|
+
|
|
1210
|
+
const scopePolicy = {
|
|
1211
|
+
client: {
|
|
1212
|
+
allowed: ['client/**'],
|
|
1213
|
+
blocked: ['backend/**', 'shared/**', 'CONTRACTS.md', 'BUILD_STATE.md', 'TASKS_HISTORY.md'],
|
|
1214
|
+
agentOverrides: {
|
|
1215
|
+
UI: {
|
|
1216
|
+
allowed: ['client/**', 'shared/wiring.config.json'],
|
|
1217
|
+
onlyBeforeScaffolded: true,
|
|
1218
|
+
},
|
|
1219
|
+
},
|
|
1220
|
+
},
|
|
1221
|
+
backend: {
|
|
1222
|
+
allowed: ['backend/**'],
|
|
1223
|
+
blocked: ['client/**', 'shared/**', 'CONTRACTS.md', 'BUILD_STATE.md', 'TASKS_HISTORY.md'],
|
|
1224
|
+
agentOverrides: {
|
|
1225
|
+
INIT: {
|
|
1226
|
+
allowed: ['backend/**', 'shared/wiring.config.json', 'CONTRACTS.md'],
|
|
1227
|
+
onlyBeforeScaffolded: true,
|
|
1228
|
+
},
|
|
1229
|
+
},
|
|
1230
|
+
},
|
|
1231
|
+
shared: {
|
|
1232
|
+
allowed: ['CLOUD_STATE.md', 'CLOUD.md', 'CLOUD_TEARDOWN.md', '.github/**', 'docker-compose*.yml', 'Dockerfile', '**/.env.example'],
|
|
1233
|
+
blocked: ['client/**', 'backend/**', 'CONTRACTS.md', 'BUILD_STATE.md', 'TASKS_HISTORY.md'],
|
|
1234
|
+
},
|
|
1235
|
+
};
|
|
1236
|
+
|
|
1237
|
+
fs.writeFileSync(
|
|
1238
|
+
path.join(RUNTIME_DIR, 'scope-policy.json'),
|
|
1239
|
+
JSON.stringify(scopePolicy, null, 2),
|
|
1240
|
+
'utf8'
|
|
1241
|
+
);
|
|
1242
|
+
console.log(` ${green('✓')} .scaffold/scope-policy.json written`);
|
|
1243
|
+
|
|
1204
1244
|
// ── Generate BUILD_STATE.md ──────────────────────────────────────────────────
|
|
1205
1245
|
|
|
1206
1246
|
const backendDisplay = backendType === 'integrated'
|
package/package.json
CHANGED