multi-agents-cli 1.1.71 → 1.1.73

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/lib/ui.js CHANGED
@@ -121,7 +121,7 @@ const stepHeader = (stepIndex, totalSteps) => {
121
121
  // ── Step selection helpers ────────────────────────────────────────────────────
122
122
 
123
123
  const { BACK, RESTART } = require('./steps');
124
- const { validateCombination, checkFrameworkExists, fuzzyMatchFramework } = require('./validate');
124
+ const { validateCombination, resolveFramework } = require('./validate');
125
125
  const { BLOCKS } = require('./data-config');
126
126
 
127
127
  const NONE_LABEL = '→ None of these - I\'ll specify my own';
@@ -133,47 +133,64 @@ const handleFreeText = async (prompt, items, stepMachine, stepIndex, context, is
133
133
  const typed = (_res.value || '').trim();
134
134
  if (!typed) return isOptional ? null : handleFreeText(prompt, items, stepMachine, stepIndex, context, isOptional, block);
135
135
 
136
- // Fuzzy match first - before registry check
137
- const matches = fuzzyMatchFramework(typed, block);
138
- if (matches.length > 0) {
139
- const didYouMeanOpts = [
140
- ...matches.map(m => `→ ${m.label || m}`),
136
+ console.log(dim(' Verifying...'));
137
+ const resolved = await resolveFramework(typed, block);
138
+
139
+ if (resolved.status === 'fuzzy') {
140
+ const opts = [
141
+ ...resolved.matches.map(m => `→ ${m.label || m}`),
141
142
  `→ Type a different value`,
142
143
  ];
143
- const choice = await arrowSelect(`"${typed}" couldn't be verified. Did you mean:`, didYouMeanOpts.map(o => ({ label: o })));
144
- if (choice < matches.length) return matches[choice]; // returns full framework object
144
+ const choice = await arrowSelect(`"${typed}" couldn't be verified. Did you mean:`, opts.map(o => ({ label: o })));
145
+ if (choice < resolved.matches.length) return resolved.matches[choice];
145
146
  return handleFreeText(prompt, items, stepMachine, stepIndex, context, isOptional, block);
146
147
  }
147
148
 
148
- // Live registry check - only when no fuzzy match
149
- console.log(dim(' Verifying...'));
150
- const existence = await checkFrameworkExists(typed);
149
+ if (resolved.status === 'valid') return resolved.match;
151
150
 
152
- if (!existence.exists) {
153
- console.log('');
154
- const riskOpts = [
155
- `→ Proceed with "${typed}" - I accept the risks`,
156
- `→ Type a different value`,
157
- ];
158
- const choice = await arrowSelect(`"${typed}" couldn't be verified.`, riskOpts.map(o => ({ label: o })));
159
- if (choice === 1) return handleFreeText(prompt, items, stepMachine, stepIndex, context, isOptional, block);
160
- // Show risk consequence block
161
- console.log('');
162
- console.log(` ${yellow('⚠ Proceeding with an unverified framework may result in:')}`);
163
- console.log(dim(' · Agent spending excessive tokens resolving unknown setup'));
164
- console.log(dim(' · Incorrect scaffold structure for this framework'));
165
- console.log(dim(' · Missing contracts and integration points'));
166
- console.log(dim(' · Potential mid-flow failures requiring full restart'));
167
- console.log('');
168
- const confirm = await arrowSelect('Confirm you understand and want to continue?', [
169
- { label: `→ Yes - proceed with "${typed}"` },
170
- { label: `→ No - let me pick something else` },
151
+ if (resolved.status === 'partial_cross') {
152
+ console.log(`\n ${yellow('')} ${resolved.message}\n`);
153
+ const choice = await arrowSelect(`"${typed}" couldn't be verified.`, [
154
+ { label: `→ Type a different value` },
155
+ { label: `→ Choose from the ${block} list` },
156
+ ]);
157
+ if (choice === 1) return null;
158
+ return handleFreeText(prompt, items, stepMachine, stepIndex, context, isOptional, block);
159
+ }
160
+
161
+ if (resolved.status === 'cross_block') {
162
+ console.log(`
163
+ ${yellow('')} ${resolved.message}
164
+ `);
165
+ const choice = await arrowSelect('How would you like to proceed?', [
166
+ { label: `→ Continue - I understand the tradeoff` },
167
+ { label: `→ Type a different value` },
171
168
  ]);
172
- if (confirm === 1) return handleFreeText(prompt, items, stepMachine, stepIndex, context, isOptional, block);
169
+ if (choice === 1) return handleFreeText(prompt, items, stepMachine, stepIndex, context, isOptional, block);
173
170
  return typed;
174
171
  }
175
172
 
176
- // Valid + verified - check compatibility
173
+ // unverified - risk block
174
+ console.log('');
175
+ const riskOpts = [
176
+ `→ Proceed with "${typed}" - I accept the risks`,
177
+ `→ Type a different value`,
178
+ ];
179
+ const riskChoice = await arrowSelect(`"${typed}" couldn't be verified.`, riskOpts.map(o => ({ label: o })));
180
+ if (riskChoice === 1) return handleFreeText(prompt, items, stepMachine, stepIndex, context, isOptional, block);
181
+ console.log('');
182
+ console.log(` ${yellow('⚠ Proceeding with an unverified framework may result in:')}`);
183
+ console.log(dim(' · Agent spending excessive tokens resolving unknown setup'));
184
+ console.log(dim(' · Incorrect scaffold structure for this framework'));
185
+ console.log(dim(' · Missing contracts and integration points'));
186
+ console.log(dim(' · Potential mid-flow failures requiring full restart'));
187
+ console.log('');
188
+ const confirm = await arrowSelect('Confirm you understand and want to continue?', [
189
+ { label: `→ Yes - proceed with "${typed}"` },
190
+ { label: `→ No - let me pick something else` },
191
+ ]);
192
+ if (confirm === 1) return handleFreeText(prompt, items, stepMachine, stepIndex, context, isOptional, block);
193
+
177
194
  const check = validateCombination(typed, context);
178
195
  if (!check.valid) {
179
196
  console.log(`
package/lib/validate.js CHANGED
@@ -127,4 +127,47 @@ const validateCombination = (chosen, context = {}) => {
127
127
  return { valid: true, reason: null, alternatives: [] };
128
128
  };
129
129
 
130
- module.exports = { validateCombination, checkFrameworkExists, fuzzyMatchFramework };
130
+
131
+ // ── resolveFramework ──────────────────────────────────────────────────────────
132
+ // Full lookup order per block — returns { status, match, message }
133
+ // status: 'match' | 'cross_block' | 'partial_cross' | 'unverified' | 'valid'
134
+
135
+ const resolveFramework = async (typed, block = null) => {
136
+ const lower = typed.toLowerCase().replace(/[^a-z0-9]/g, '');
137
+
138
+ const primaryPool = block === BLOCKS.CLIENT ? CLIENT_FRAMEWORKS
139
+ : block === BLOCKS.BACKEND ? BACKEND_FRAMEWORKS
140
+ : ALL_FRAMEWORKS;
141
+ const secondaryPool = block === BLOCKS.CLIENT ? BACKEND_FRAMEWORKS
142
+ : block === BLOCKS.BACKEND ? CLIENT_FRAMEWORKS
143
+ : [];
144
+ const crossLabel = block === BLOCKS.CLIENT ? 'backend' : 'client';
145
+
146
+ // 1. Fuzzy match in primary pool
147
+ const primaryFuzzy = primaryPool.filter(f => {
148
+ const n = f.value.toLowerCase().replace(/[^a-z0-9]/g, '');
149
+ return n.includes(lower) || lower.includes(n) || (lower.length >= 3 && n.startsWith(lower.slice(0, 3)));
150
+ }).slice(0, 3);
151
+ if (primaryFuzzy.length > 0) return { status: 'fuzzy', matches: primaryFuzzy, message: null };
152
+
153
+ // 2. Exact match in primary pool
154
+ const primaryExact = primaryPool.find(f => f.value.toLowerCase() === typed.toLowerCase());
155
+ if (primaryExact) return { status: 'valid', match: primaryExact, message: null };
156
+
157
+ // 3. Partial match in secondary pool
158
+ const secondaryFuzzy = secondaryPool.filter(f => {
159
+ const n = f.value.toLowerCase().replace(/[^a-z0-9]/g, '');
160
+ return n.includes(lower) || lower.includes(n) || (lower.length >= 3 && n.startsWith(lower.slice(0, 3)));
161
+ });
162
+ if (secondaryFuzzy.length > 0) return { status: 'partial_cross', matches: secondaryFuzzy, message: `No such ${block} framework found. Did you mean a ${crossLabel} framework?` };
163
+
164
+ // 4. Exact match in secondary pool
165
+ const secondaryExact = secondaryPool.find(f => f.value.toLowerCase() === typed.toLowerCase());
166
+ if (secondaryExact) return { status: 'cross_block', match: secondaryExact, message: `"${typed}" is a ${crossLabel} framework, not a ${block} framework.` };
167
+
168
+ // 5. Registry check
169
+ const existence = await checkFrameworkExists(typed);
170
+ return { status: 'unverified', match: null, message: existence.exists ? `"${typed}" was found on ${existence.registry} but could not be confirmed as a ${block || ''} framework.` : `"${typed}" couldn't be verified on any registry.` };
171
+ };
172
+
173
+ module.exports = { validateCombination, checkFrameworkExists, fuzzyMatchFramework, resolveFramework };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "multi-agents-cli",
3
- "version": "1.1.71",
3
+ "version": "1.1.73",
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",