@epicai/legion 1.0.0 → 1.0.1

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.
Files changed (2) hide show
  1. package/dist/bin/setup.js +50 -145
  2. package/package.json +1 -1
package/dist/bin/setup.js CHANGED
@@ -104,50 +104,6 @@ function loadCredentials() {
104
104
  }
105
105
  return creds;
106
106
  }
107
- // ─── Category display names ─────────────────────────────────
108
- const CATEGORY_LABELS = {
109
- 'ai': 'AI / ML',
110
- 'cloud': 'Cloud Infrastructure',
111
- 'collaboration': 'Collaboration',
112
- 'commerce': 'Commerce & eCommerce',
113
- 'communication': 'Communication',
114
- 'compliance': 'Compliance & GRC',
115
- 'construction': 'Construction',
116
- 'crm': 'CRM & Sales',
117
- 'customer-support': 'Customer Support',
118
- 'cybersecurity': 'Cybersecurity',
119
- 'data': 'Data & Analytics',
120
- 'design': 'Design & Creative',
121
- 'devops': 'DevOps & CI/CD',
122
- 'education': 'Education',
123
- 'energy': 'Energy',
124
- 'engineering': 'Engineering & Aerospace',
125
- 'erp': 'ERP',
126
- 'finance': 'Finance & Payments',
127
- 'government': 'Government',
128
- 'healthcare': 'Healthcare',
129
- 'hospitality': 'Hospitality & Food',
130
- 'hr': 'HR & People',
131
- 'identity': 'Identity & Access',
132
- 'insurance': 'Insurance',
133
- 'iot': 'IoT & Devices',
134
- 'legal': 'Legal',
135
- 'logistics': 'Logistics & Shipping',
136
- 'manufacturing': 'Manufacturing',
137
- 'marketing': 'Marketing',
138
- 'media': 'Media & Entertainment',
139
- 'misc': 'Other',
140
- 'observability': 'Observability & Monitoring',
141
- 'productivity': 'Productivity',
142
- 'real-estate': 'Real Estate & Property',
143
- 'science': 'Science & Research',
144
- 'social': 'Social Media',
145
- 'telecom': 'Telecom',
146
- 'travel': 'Travel & Transportation',
147
- };
148
- function formatCategory(cat) {
149
- return CATEGORY_LABELS[cat] || cat.charAt(0).toUpperCase() + cat.slice(1).replace(/-/g, ' ');
150
- }
151
107
  function expandHome(p) {
152
108
  return p.startsWith('~') ? join(homedir(), p.slice(1)) : p;
153
109
  }
@@ -1049,117 +1005,66 @@ async function runSetupWizard() {
1049
1005
  p.log.warning('Doppler CLI not found — install from https://docs.doppler.com/docs/install-cli');
1050
1006
  }
1051
1007
  }
1052
- // Step 4: Adapter selection tree structure (group → category → adapters)
1053
- // Build category map
1054
- const categories = new Map();
1008
+ // Step 4: Auto-wire adapters from credentials
1009
+ const selectedAdapterIds = [];
1010
+ const existingCreds = loadCredentials();
1011
+ // Match adapters whose required env keys are already present
1012
+ const autoMatched = [];
1055
1013
  for (const adapter of allAdapters) {
1056
- const cat = adapter.category || 'other';
1057
- if (!categories.has(cat))
1058
- categories.set(cat, []);
1059
- categories.get(cat).push(adapter);
1014
+ const restKey = adapter.rest?.envKey;
1015
+ const mcpKeys = adapter.mcp?.envKeys || [];
1016
+ const allKeys = [...(restKey ? [restKey] : []), ...mcpKeys];
1017
+ if (allKeys.length > 0 && allKeys.every(k => !!existingCreds[k])) {
1018
+ autoMatched.push(adapter);
1019
+ }
1060
1020
  }
1061
- // Top-level groups that map to subcategories
1062
- const GROUPS = {
1063
- 'security': {
1064
- label: 'Security & Identity',
1065
- cats: ['cybersecurity', 'identity', 'compliance'],
1066
- },
1067
- 'devops': {
1068
- label: 'DevOps & Infrastructure',
1069
- cats: ['devops', 'cloud', 'observability', 'engineering'],
1070
- },
1071
- 'business': {
1072
- label: 'Business & Finance',
1073
- cats: ['finance', 'crm', 'commerce', 'marketing', 'customer-support', 'hr', 'productivity', 'erp'],
1074
- },
1075
- 'comms': {
1076
- label: 'Communication & Collaboration',
1077
- cats: ['communication', 'collaboration'],
1078
- },
1079
- 'data-ai': {
1080
- label: 'Data & AI',
1081
- cats: ['data', 'ai', 'science'],
1082
- },
1083
- 'industry': {
1084
- label: 'Industry',
1085
- cats: ['healthcare', 'hospitality', 'construction', 'manufacturing', 'real-estate', 'travel', 'education', 'insurance', 'legal', 'energy', 'automotive', 'telecom', 'logistics', 'government', 'iot'],
1086
- },
1087
- 'media': {
1088
- label: 'Media & Social',
1089
- cats: ['media', 'social', 'design'],
1090
- },
1091
- 'other': {
1092
- label: 'Other',
1093
- cats: ['misc', 'other'],
1094
- },
1095
- };
1096
- // Count adapters per group
1097
- function countGroup(cats) {
1098
- let total = 0;
1099
- for (const cat of cats)
1100
- total += (categories.get(cat) || []).length;
1101
- return total;
1021
+ if (autoMatched.length > 0) {
1022
+ p.note(autoMatched.map(a => `${pc.green('✓')} ${a.name || a.id}`).join('\n'), `${autoMatched.length} adapter${autoMatched.length !== 1 ? 's' : ''} matched from your credentials`);
1023
+ selectedAdapterIds.push(...autoMatched.map(a => a.id));
1102
1024
  }
1103
- // Collect any categories not in a group
1104
- const allGroupedCats = new Set(Object.values(GROUPS).flatMap(g => g.cats));
1105
- const ungrouped = Array.from(categories.keys()).filter(c => !allGroupedCats.has(c));
1106
- if (ungrouped.length > 0) {
1107
- GROUPS['other'].cats.push(...ungrouped);
1025
+ else {
1026
+ p.log.info('No adapters matched from credentials — use ' + pc.cyan('npx @epicai/legion add <name>') + ' to connect adapters.');
1108
1027
  }
1109
- const groupOptions = Object.entries(GROUPS)
1110
- .filter(([_, g]) => countGroup(g.cats) > 0)
1111
- .map(([key, g]) => ({
1112
- value: key,
1113
- label: `${g.label} (${countGroup(g.cats)})`,
1114
- }));
1115
- const selectedGroups = await p.multiselect({
1116
- message: 'What do you work with? (Space to select, Enter to confirm)',
1117
- options: groupOptions,
1118
- required: false,
1028
+ // Optional: search for additional adapters
1029
+ const addMore = await p.confirm({
1030
+ message: 'Search for additional adapters to configure?',
1031
+ initialValue: false,
1119
1032
  });
1120
- if (p.isCancel(selectedGroups)) {
1121
- p.cancel('Setup cancelled.');
1122
- process.exit(0);
1123
- }
1124
- const selectedAdapterIds = [];
1125
- for (const groupKey of selectedGroups) {
1126
- const group = GROUPS[groupKey];
1127
- if (!group)
1128
- continue;
1129
- // Show subcategories within this group
1130
- const subCatOptions = group.cats
1131
- .filter(cat => (categories.get(cat) || []).length > 0)
1132
- .map(cat => ({
1133
- value: cat,
1134
- label: `${formatCategory(cat)} (${(categories.get(cat) || []).length})`,
1135
- }));
1136
- if (subCatOptions.length === 0)
1137
- continue;
1138
- const selectedSubCats = await p.multiselect({
1139
- message: `${group.label} — select categories (Space to select, Enter to confirm)`,
1140
- options: subCatOptions,
1141
- required: false,
1142
- });
1143
- if (p.isCancel(selectedSubCats))
1144
- continue;
1145
- if (selectedSubCats.length > 0) {
1146
- // Show adapters from selected subcategories
1147
- const available = [];
1148
- for (const cat of selectedSubCats) {
1149
- for (const a of categories.get(cat) || []) {
1150
- available.push({ value: a.id, label: a.name || a.id, hint: a.description?.slice(0, 60) });
1151
- }
1033
+ if (!p.isCancel(addMore) && addMore) {
1034
+ let searching = true;
1035
+ while (searching) {
1036
+ const searchTerm = await p.text({
1037
+ message: 'Search adapters (name or keyword)',
1038
+ placeholder: 'e.g. grafana, paypal, github',
1039
+ });
1040
+ if (p.isCancel(searchTerm) || !searchTerm)
1041
+ break;
1042
+ const term = searchTerm.toLowerCase();
1043
+ const matches = allAdapters.filter(a => !selectedAdapterIds.includes(a.id) && (a.id.includes(term) ||
1044
+ (a.name || '').toLowerCase().includes(term) ||
1045
+ (a.description || '').toLowerCase().includes(term) ||
1046
+ (a.category || '').includes(term)));
1047
+ if (matches.length === 0) {
1048
+ p.log.warning(`No adapters found for "${searchTerm}"`);
1152
1049
  }
1153
- if (available.length > 0) {
1154
- const selected = await p.multiselect({
1155
- message: `Select adapters (${available.length} available)`,
1156
- options: available.slice(0, 50),
1050
+ else {
1051
+ const options = matches.slice(0, 50).map(a => ({
1052
+ value: a.id,
1053
+ label: a.name || a.id,
1054
+ hint: a.description?.slice(0, 60),
1055
+ }));
1056
+ const picked = await p.multiselect({
1057
+ message: `${matches.length} match${matches.length !== 1 ? 'es' : ''} — select to add`,
1058
+ options,
1157
1059
  required: false,
1158
1060
  });
1159
- if (!p.isCancel(selected)) {
1160
- selectedAdapterIds.push(...selected);
1061
+ if (!p.isCancel(picked)) {
1062
+ selectedAdapterIds.push(...picked);
1161
1063
  }
1162
1064
  }
1065
+ const cont = await p.confirm({ message: 'Search for more?', initialValue: false });
1066
+ if (p.isCancel(cont) || !cont)
1067
+ searching = false;
1163
1068
  }
1164
1069
  }
1165
1070
  // Step 5: Credentials
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epicai/legion",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Epic AI® Legion — 35,020 tools. One self-hosted MCP server. Intelligent Virtual Assistant (IVA) integration layer for AI agents.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",