multi-agents-cli 1.0.53 → 1.0.54

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.
@@ -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 = {
@@ -176,6 +176,55 @@ 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 allowed = (policyScope && policyScope.agentOverrides && policyScope.agentOverrides[agentKey] && policyScope.agentOverrides[agentKey].allowed) || (policyScope && policyScope.allowed) || [];
191
+ const blocked = (policyScope && policyScope.blocked) || [];
192
+
193
+ const changedFiles = execSync('git diff --name-only main...HEAD', { cwd: worktreePath, stdio: 'pipe' })
194
+ .toString().trim().split('\n').filter(Boolean);
195
+
196
+ const matchesGlob = (file, pat) => {
197
+ if (pat.endsWith('/**')) return file.startsWith(pat.slice(0, -3));
198
+ if (pat.includes('*')) {
199
+ const re = pat.replace(/[.+^${}()|[\]\\]/g, '\\$&')
200
+ .replace(/\*\*/g, 'DOUBLESTAR')
201
+ .replace(/\*/g, '[^/]*')
202
+ .replace(/DOUBLESTAR/g, '.*');
203
+ return new RegExp('^' + re + '$').test(file);
204
+ }
205
+ return file === pat;
206
+ };
207
+
208
+ const violations = changedFiles.filter(file => {
209
+ const isAllowed = allowed.some(pat => matchesGlob(file, pat));
210
+ const isBlocked = blocked.some(pat => matchesGlob(file, pat));
211
+ return !isAllowed || isBlocked;
212
+ });
213
+
214
+ if (violations.length > 0) {
215
+ console.log('\n' + red(' ✗ Scope violation - merge blocked.'));
216
+ console.log(dim(' The following files are outside the allowed scope for ' + scopeMeta.agent + ' (' + scopeMeta.scope + '):\n'));
217
+ violations.forEach(f => console.log(' ' + red('✗') + ' ' + f));
218
+ console.log('\n' + dim(' Fix the violations, then re-run npm run complete.\n'));
219
+ rl.close();
220
+ return;
221
+ }
222
+
223
+ console.log(' ' + green('✓') + ' Scope validation passed (' + changedFiles.length + ' files checked)');
224
+ } else {
225
+ console.log(' ' + dim('ℹ scope.json or scope-policy.json not found - skipping validation'));
226
+ }
227
+
179
228
  // ── Check TASK.md status ──────────────────────────────────────────────────────
180
229
 
181
230
  const taskMdPath = path.join(worktreePath, 'TASK.md');
package/init.js CHANGED
@@ -1201,6 +1201,35 @@ const main = async () => {
1201
1201
  );
1202
1202
  console.log(` ${green('✓')} .scaffold/.config.json written`);
1203
1203
 
1204
+ // ── Write scope-policy.json ──────────────────────────────────────────────────
1205
+
1206
+ const scopePolicy = {
1207
+ client: {
1208
+ allowed: ['client/**'],
1209
+ blocked: ['backend/**', 'shared/**', 'CONTRACTS.md', 'BUILD_STATE.md', 'TASKS_HISTORY.md'],
1210
+ },
1211
+ backend: {
1212
+ allowed: ['backend/**'],
1213
+ blocked: ['client/**', 'shared/**', 'CONTRACTS.md', 'BUILD_STATE.md', 'TASKS_HISTORY.md'],
1214
+ agentOverrides: {
1215
+ INIT: {
1216
+ allowed: ['backend/**', 'shared/wiring.config.json', 'CONTRACTS.md'],
1217
+ },
1218
+ },
1219
+ },
1220
+ shared: {
1221
+ allowed: ['CLOUD_STATE.md', 'CLOUD.md', 'CLOUD_TEARDOWN.md', '.github/**', 'docker-compose*.yml', 'Dockerfile', '**/.env.example'],
1222
+ blocked: ['client/**', 'backend/**', 'CONTRACTS.md', 'BUILD_STATE.md', 'TASKS_HISTORY.md'],
1223
+ },
1224
+ };
1225
+
1226
+ fs.writeFileSync(
1227
+ path.join(RUNTIME_DIR, 'scope-policy.json'),
1228
+ JSON.stringify(scopePolicy, null, 2),
1229
+ 'utf8'
1230
+ );
1231
+ console.log(` ${green('✓')} .scaffold/scope-policy.json written`);
1232
+
1204
1233
  // ── Generate BUILD_STATE.md ──────────────────────────────────────────────────
1205
1234
 
1206
1235
  const backendDisplay = backendType === 'integrated'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "multi-agents-cli",
3
- "version": "1.0.53",
3
+ "version": "1.0.54",
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",