vme-mcp-server 0.1.10 → 0.1.13

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/README.md CHANGED
@@ -18,18 +18,37 @@ npm install -g vme-mcp-server
18
18
 
19
19
  ### 2. Configure VME API Access
20
20
 
21
+ **Option A: Command Line Arguments (Recommended)**
22
+
23
+ ```bash
24
+ vme-mcp-server --endpoint https://your-vme-instance.com/api --token your-bearer-token
25
+ # Or use short forms:
26
+ vme-mcp-server -e https://your-vme-instance.com/api -t your-bearer-token
27
+ ```
28
+
29
+ **Option B: Environment Variables**
30
+
31
+ ```bash
32
+ export VME_ENDPOINT=https://your-vme-instance.com/api
33
+ export VME_TOKEN=your-bearer-token-here
34
+ ```
35
+
36
+ **Option C: Configuration File**
37
+
21
38
  Create a `.env` file:
22
39
  ```env
23
- VME_API_BASE_URL=https://your-vme-instance.com/api
24
- VME_API_TOKEN=your-bearer-token-here
40
+ VME_ENDPOINT=https://your-vme-instance.com/api
41
+ VME_TOKEN=your-bearer-token-here
25
42
  ```
26
43
 
44
+ **Priority Order**: Command line arguments → Environment variables → .env files
45
+
27
46
  ### 3. Add to Claude Code
28
47
 
29
48
  **Option A: Using Claude Code CLI (Recommended)**
30
49
 
31
50
  ```bash
32
- claude mcp add vme-server -- vme-mcp-server
51
+ claude mcp add vme-server -- vme-mcp-server --endpoint https://your-vme-instance.com/api --token your-bearer-token
33
52
  ```
34
53
 
35
54
  **Option B: Manual Configuration**
@@ -40,12 +59,23 @@ Add to your Claude Code configuration file:
40
59
  {
41
60
  "mcpServers": {
42
61
  "vme-server": {
43
- "command": "npx",
44
- "args": ["tsx", "src/server.ts"],
45
- "cwd": "/path/to/vme-mcp-server",
62
+ "command": "vme-mcp-server",
63
+ "args": ["--endpoint", "https://your-vme-instance.com/api", "--token", "your-bearer-token"]
64
+ }
65
+ }
66
+ }
67
+ ```
68
+
69
+ **Option C: Using Environment Variables**
70
+
71
+ ```json
72
+ {
73
+ "mcpServers": {
74
+ "vme-server": {
75
+ "command": "vme-mcp-server",
46
76
  "env": {
47
- "VME_API_BASE_URL": "https://your-vme-instance.com/api",
48
- "VME_API_TOKEN": "your-bearer-token"
77
+ "VME_ENDPOINT": "https://your-vme-instance.com/api",
78
+ "VME_TOKEN": "your-bearer-token"
49
79
  }
50
80
  }
51
81
  }
package/dist/README.md CHANGED
@@ -10,20 +10,39 @@ npm install -g vme-mcp-server
10
10
 
11
11
  ## Quick Start
12
12
 
13
- ### 1. Configure Environment
13
+ ### 1. Configure VME API Access
14
+
15
+ **Option A: Command Line Arguments (Recommended)**
16
+
17
+ ```bash
18
+ vme-mcp-server --endpoint https://your-hpe-vme-instance.com/api --token your-bearer-token
19
+ # Or use short forms:
20
+ vme-mcp-server -e https://your-hpe-vme-instance.com/api -t your-bearer-token
21
+ ```
22
+
23
+ **Option B: Environment Variables**
24
+
25
+ ```bash
26
+ export VME_ENDPOINT=https://your-hpe-vme-instance.com/api
27
+ export VME_TOKEN=your-bearer-token
28
+ ```
29
+
30
+ **Option C: Configuration File**
14
31
 
15
32
  Create a `.env` file:
16
33
 
17
34
  ```bash
18
35
  # HPE VM Essentials Configuration
19
- VME_API_BASE_URL=https://your-hpe-vme-instance.com/api
20
- VME_API_TOKEN=your-bearer-token
36
+ VME_ENDPOINT=https://your-hpe-vme-instance.com/api
37
+ VME_TOKEN=your-bearer-token
21
38
 
22
39
  # Privacy Controls (Optional)
23
40
  ENABLE_AI_TRAINING_DATA=false
24
41
  AI_TRAINING_DATA_RETENTION_DAYS=30
25
42
  ```
26
43
 
44
+ **Priority Order**: Command line arguments → Environment variables → .env files
45
+
27
46
  ### 2. Add to Claude Desktop
28
47
 
29
48
  Add to your Claude Desktop configuration file:
@@ -31,6 +50,37 @@ Add to your Claude Desktop configuration file:
31
50
  **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
32
51
  **Windows**: `%APPDATA%/Claude/claude_desktop_config.json`
33
52
 
53
+ **Option A: With Command Line Arguments**
54
+
55
+ ```json
56
+ {
57
+ "mcpServers": {
58
+ "vme": {
59
+ "command": "vme-mcp-server",
60
+ "args": ["--endpoint", "https://your-hpe-vme-instance.com/api", "--token", "your-bearer-token"]
61
+ }
62
+ }
63
+ }
64
+ ```
65
+
66
+ **Option B: With Environment Variables**
67
+
68
+ ```json
69
+ {
70
+ "mcpServers": {
71
+ "vme": {
72
+ "command": "vme-mcp-server",
73
+ "env": {
74
+ "VME_ENDPOINT": "https://your-hpe-vme-instance.com/api",
75
+ "VME_TOKEN": "your-bearer-token"
76
+ }
77
+ }
78
+ }
79
+ }
80
+ ```
81
+
82
+ **Option C: Using .env File**
83
+
34
84
  ```json
35
85
  {
36
86
  "mcpServers": {
@@ -101,9 +151,15 @@ The server automatically searches for `.env` files in multiple locations:
101
151
 
102
152
  ### Recommended Configuration Methods
103
153
 
104
- **Method 1: Direct Environment Variables (Best for Global Install)**
154
+ **Method 1: Command Line Arguments (Recommended)**
155
+
156
+ ```bash
157
+ vme-mcp-server --endpoint https://your-hpe-vme-instance.com/api --token your-bearer-token
158
+ ```
159
+
160
+ **Method 2: Direct Environment Variables**
105
161
 
106
- Add to your Claude Desktop config (`~/.config/claude-desktop/config.json`):
162
+ Add to your Claude Desktop config:
107
163
 
108
164
  ```json
109
165
  {
@@ -111,15 +167,15 @@ Add to your Claude Desktop config (`~/.config/claude-desktop/config.json`):
111
167
  "vme-mcp-server": {
112
168
  "command": "vme-mcp-server",
113
169
  "env": {
114
- "VME_API_BASE_URL": "https://your-hpe-vme-instance.com/api",
115
- "VME_API_TOKEN": "your-bearer-token"
170
+ "VME_ENDPOINT": "https://your-hpe-vme-instance.com/api",
171
+ "VME_TOKEN": "your-bearer-token"
116
172
  }
117
173
  }
118
174
  }
119
175
  }
120
176
  ```
121
177
 
122
- **Method 2: .env File (Good for Local Development)**
178
+ **Method 3: .env File (Good for Local Development)**
123
179
 
124
180
  Create `.env` file in any of the supported locations above.
125
181
 
@@ -127,8 +183,8 @@ Create `.env` file in any of the supported locations above.
127
183
 
128
184
  | Variable | Description | Example |
129
185
  |----------|-------------|---------|
130
- | `VME_API_BASE_URL` | HPE VM Essentials API endpoint | `https://vme.company.com/api` |
131
- | `VME_API_TOKEN` | Bearer token for authentication | `your-bearer-token` |
186
+ | `VME_ENDPOINT` | HPE VM Essentials API endpoint | `https://vme.company.com/api` |
187
+ | `VME_TOKEN` | Bearer token for authentication | `your-bearer-token` |
132
188
 
133
189
  ### Optional Environment Variables
134
190
 
@@ -148,8 +204,8 @@ Create `.env` file in any of the supported locations above.
148
204
  - Verify MCP configuration syntax in `claude_desktop_config.json`
149
205
 
150
206
  **"API connection failed"**
151
- - Verify `VME_API_BASE_URL` is correct and accessible
152
- - Check that `VME_API_TOKEN` has sufficient permissions
207
+ - Verify `VME_ENDPOINT` is correct and accessible
208
+ - Check that `VME_TOKEN` has sufficient permissions
153
209
  - Ensure network connectivity to HPE VM Essentials infrastructure
154
210
 
155
211
  **"VM creation failed"**
@@ -176,6 +232,6 @@ Built with TypeScript and the Model Context Protocol for seamless Claude integra
176
232
 
177
233
  ## Version
178
234
 
179
- Current version: 0.1.10
235
+ Current version: 0.1.11
180
236
 
181
237
  For development documentation and contribution guidelines, see the project repository.
@@ -1,23 +1,35 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getResources = exports.resolveInput = exports.getClusterNodes = exports.api = void 0;
7
- const axios_1 = __importDefault(require("axios"));
8
- // Setup axios instance for VME API
9
- exports.api = axios_1.default.create({
10
- baseURL: process.env.VME_API_BASE_URL,
11
- headers: {
12
- Authorization: `Bearer ${process.env.VME_API_TOKEN}`,
13
- "Content-Type": "application/json"
1
+ import axios from "axios";
2
+ // Lazy axios instance creation to ensure environment variables are loaded
3
+ let _api = null;
4
+ function createApiInstance() {
5
+ if (!_api) {
6
+ console.log('VME API Configuration:');
7
+ console.log(' Base URL:', process.env.VME_API_BASE_URL);
8
+ console.log(' Token:', process.env.VME_API_TOKEN ? '***configured***' : 'NOT SET');
9
+ if (!process.env.VME_API_BASE_URL || !process.env.VME_API_TOKEN) {
10
+ throw new Error('VME API credentials not configured. Please check your .env file.');
11
+ }
12
+ _api = axios.create({
13
+ baseURL: process.env.VME_API_BASE_URL,
14
+ headers: {
15
+ Authorization: `Bearer ${process.env.VME_API_TOKEN}`,
16
+ "Content-Type": "application/json"
17
+ }
18
+ });
14
19
  }
15
- });
20
+ return _api;
21
+ }
22
+ export const api = {
23
+ get: (url) => createApiInstance().get(url),
24
+ post: (url, data) => createApiInstance().post(url, data),
25
+ put: (url, data) => createApiInstance().put(url, data),
26
+ delete: (url) => createApiInstance().delete(url)
27
+ };
16
28
  // Helper function to get available cluster nodes (hypervisor hosts, not VMs)
17
- async function getClusterNodes() {
29
+ export async function getClusterNodes() {
18
30
  try {
19
31
  // Get actual cluster hypervisor nodes from /clusters endpoint
20
- const clusters = await exports.api.get("/clusters");
32
+ const clusters = await api.get("/clusters");
21
33
  let allNodes = [];
22
34
  if (clusters.data.clusters) {
23
35
  for (const cluster of clusters.data.clusters) {
@@ -41,14 +53,13 @@ async function getClusterNodes() {
41
53
  console.warn('Using fallback hypervisor nodes [1, 2, 3] - could not detect cluster hosts');
42
54
  return [1, 2, 3];
43
55
  }
44
- exports.getClusterNodes = getClusterNodes;
45
56
  // Resolve user input parameters to VME API resource IDs
46
- async function resolveInput({ group, cloud, template, size }) {
57
+ export async function resolveInput({ group, cloud, template, size }) {
47
58
  const [groups, zones, instanceTypes, servicePlans] = await Promise.all([
48
- exports.api.get("/groups"),
49
- exports.api.get("/zones"),
50
- exports.api.get("/instance-types"),
51
- exports.api.get("/service-plans")
59
+ api.get("/groups"),
60
+ api.get("/zones"),
61
+ api.get("/instance-types"),
62
+ api.get("/service-plans")
52
63
  ]);
53
64
  // Find group (case-insensitive)
54
65
  const foundGroup = groups.data.groups.find((g) => g.name.toLowerCase() === group.toLowerCase());
@@ -61,7 +72,7 @@ async function resolveInput({ group, cloud, template, size }) {
61
72
  let selectedImage;
62
73
  const templateLower = template.toLowerCase();
63
74
  // Get available images to find the right one
64
- const images = await exports.api.get("/virtual-images");
75
+ const images = await api.get("/virtual-images");
65
76
  if (templateLower.includes('ubuntu')) {
66
77
  // Find Ubuntu images using osType.category and prefer latest version
67
78
  const ubuntuImages = images.data.virtualImages.filter((img) => img.osType && img.osType.category === 'ubuntu').sort((a, b) => {
@@ -156,18 +167,17 @@ async function resolveInput({ group, cloud, template, size }) {
156
167
  availableZones: zones.data.zones.map((z) => z.name)
157
168
  };
158
169
  }
159
- exports.resolveInput = resolveInput;
160
170
  // Unified resource discovery function
161
- async function getResources(type, intent, role) {
171
+ export async function getResources(type, intent, role) {
162
172
  try {
163
173
  // Fetch all resource types in parallel for comprehensive discovery
164
174
  const [groups, zones, instanceTypes, servicePlans, virtualImages, clusters] = await Promise.all([
165
- exports.api.get("/groups"),
166
- exports.api.get("/zones"),
167
- exports.api.get("/instance-types"),
168
- exports.api.get("/service-plans"),
169
- exports.api.get("/virtual-images"),
170
- exports.api.get("/clusters")
175
+ api.get("/groups"),
176
+ api.get("/zones"),
177
+ api.get("/instance-types"),
178
+ api.get("/service-plans"),
179
+ api.get("/virtual-images"),
180
+ api.get("/clusters")
171
181
  ]);
172
182
  const allResources = {
173
183
  groups: groups.data.groups || [],
@@ -261,4 +271,3 @@ async function getResources(type, intent, role) {
261
271
  };
262
272
  }
263
273
  }
264
- exports.getResources = getResources;
@@ -1,9 +1,6 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.capabilityCache = exports.SmartCapabilityCache = void 0;
4
- const api_utils_js_1 = require("./api-utils.js");
1
+ import { api } from "./api-utils.js";
5
2
  // Smart capability cache with field-level TTL
6
- class SmartCapabilityCache {
3
+ export class SmartCapabilityCache {
7
4
  constructor() {
8
5
  this.cache = new Map();
9
6
  // TTL configuration based on VME resource change patterns
@@ -34,7 +31,7 @@ class SmartCapabilityCache {
34
31
  // Fetch fresh data from VME API
35
32
  const endpoint = this.getEndpointForField(fieldName);
36
33
  try {
37
- const response = await api_utils_js_1.api.get(endpoint);
34
+ const response = await api.get(endpoint);
38
35
  // Store in cache with appropriate TTL
39
36
  const cacheEntry = {
40
37
  data: response.data,
@@ -126,6 +123,5 @@ class SmartCapabilityCache {
126
123
  return endpointMap[fieldName] || `/${fieldName}`;
127
124
  }
128
125
  }
129
- exports.SmartCapabilityCache = SmartCapabilityCache;
130
126
  // Global cache instance
131
- exports.capabilityCache = new SmartCapabilityCache();
127
+ export const capabilityCache = new SmartCapabilityCache();
@@ -1,9 +1,6 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.capabilityDiscovery = exports.CapabilityDiscoveryEngine = void 0;
4
- const capability_cache_js_1 = require("./capability-cache.js");
1
+ import { capabilityCache } from "./capability-cache.js";
5
2
  // Capability discovery engine
6
- class CapabilityDiscoveryEngine {
3
+ export class CapabilityDiscoveryEngine {
7
4
  /**
8
5
  * Discover capabilities for specified domains
9
6
  */
@@ -108,10 +105,10 @@ class CapabilityDiscoveryEngine {
108
105
  // Private discovery methods for each domain
109
106
  async discoverComputeCapabilities(forceRefresh = false) {
110
107
  const [clusters, servicePlans, instanceTypes, virtualImages] = await Promise.all([
111
- capability_cache_js_1.capabilityCache.getField("clusters", forceRefresh),
112
- capability_cache_js_1.capabilityCache.getField("service_plans", forceRefresh),
113
- capability_cache_js_1.capabilityCache.getField("instance_types", forceRefresh),
114
- capability_cache_js_1.capabilityCache.getField("virtual_images", forceRefresh),
108
+ capabilityCache.getField("clusters", forceRefresh),
109
+ capabilityCache.getField("service_plans", forceRefresh),
110
+ capabilityCache.getField("instance_types", forceRefresh),
111
+ capabilityCache.getField("virtual_images", forceRefresh),
115
112
  ]);
116
113
  // Derive hypervisors from cluster data
117
114
  const hypervisors = new Set();
@@ -172,8 +169,8 @@ class CapabilityDiscoveryEngine {
172
169
  }
173
170
  async discoverNetworkingCapabilities(forceRefresh = false) {
174
171
  const [zones, networks] = await Promise.all([
175
- capability_cache_js_1.capabilityCache.getField("zones", forceRefresh),
176
- capability_cache_js_1.capabilityCache.getField("networks", forceRefresh).catch(() => null), // Optional
172
+ capabilityCache.getField("zones", forceRefresh),
173
+ capabilityCache.getField("networks", forceRefresh).catch(() => null), // Optional
177
174
  ]);
178
175
  const zoneList = zones?.zones?.map((zone) => ({
179
176
  id: zone.id,
@@ -189,7 +186,7 @@ class CapabilityDiscoveryEngine {
189
186
  }
190
187
  async discoverStorageCapabilities(forceRefresh = false) {
191
188
  // Get real data from VME API
192
- const servicePlans = await capability_cache_js_1.capabilityCache.getField("service_plans", forceRefresh);
189
+ const servicePlans = await capabilityCache.getField("service_plans", forceRefresh);
193
190
  // Derive storage capabilities from actual service plans and other data
194
191
  const storageTypes = new Set();
195
192
  let maxVolumeSize = "1TB"; // Default
@@ -214,7 +211,7 @@ class CapabilityDiscoveryEngine {
214
211
  };
215
212
  }
216
213
  async discoverPlatformCapabilities(forceRefresh = false) {
217
- const groups = await capability_cache_js_1.capabilityCache.getField("groups", forceRefresh);
214
+ const groups = await capabilityCache.getField("groups", forceRefresh);
218
215
  const groupList = groups?.groups?.map((group) => ({
219
216
  id: group.id,
220
217
  name: group.name,
@@ -227,7 +224,7 @@ class CapabilityDiscoveryEngine {
227
224
  };
228
225
  }
229
226
  getCacheStatusSummary() {
230
- const statuses = capability_cache_js_1.capabilityCache.getCacheStatus();
227
+ const statuses = capabilityCache.getCacheStatus();
231
228
  return statuses.map(status => ({
232
229
  field: status.field_name,
233
230
  fresh: status.is_fresh,
@@ -235,6 +232,5 @@ class CapabilityDiscoveryEngine {
235
232
  }));
236
233
  }
237
234
  }
238
- exports.CapabilityDiscoveryEngine = CapabilityDiscoveryEngine;
239
235
  // Global discovery engine instance
240
- exports.capabilityDiscovery = new CapabilityDiscoveryEngine();
236
+ export const capabilityDiscovery = new CapabilityDiscoveryEngine();
@@ -1,9 +1,6 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseVMIntent = void 0;
4
- const vm_parsing_js_1 = require("./vm-parsing.js");
1
+ import { parseVMNames } from "./vm-parsing.js";
5
2
  // Intent recognition system for natural language processing
6
- function parseVMIntent(naturalLanguageInput) {
3
+ export function parseVMIntent(naturalLanguageInput) {
7
4
  const input = naturalLanguageInput.toLowerCase().trim();
8
5
  const result = {
9
6
  action: 'unknown',
@@ -71,7 +68,7 @@ function parseVMIntent(naturalLanguageInput) {
71
68
  const match = input.match(pattern);
72
69
  if (match) {
73
70
  const nameInput = match[1] || match[2];
74
- result.entities.vmNames = (0, vm_parsing_js_1.parseVMNames)(nameInput);
71
+ result.entities.vmNames = parseVMNames(nameInput);
75
72
  break;
76
73
  }
77
74
  }
@@ -156,4 +153,3 @@ function parseVMIntent(naturalLanguageInput) {
156
153
  }
157
154
  return result;
158
155
  }
159
- exports.parseVMIntent = parseVMIntent;
@@ -1,9 +1,6 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.nameResolver = exports.NameResolver = void 0;
4
- const capability_discovery_js_1 = require("./capability-discovery.js");
1
+ import { capabilityDiscovery } from "./capability-discovery.js";
5
2
  // Generic name->ID resolver using capability discovery data
6
- class NameResolver {
3
+ export class NameResolver {
7
4
  constructor() {
8
5
  this.capabilitiesCache = null;
9
6
  this.cacheTimestamp = 0;
@@ -12,7 +9,7 @@ class NameResolver {
12
9
  async getCapabilities() {
13
10
  const now = Date.now();
14
11
  if (!this.capabilitiesCache || (now - this.cacheTimestamp) > this.CACHE_TTL) {
15
- this.capabilitiesCache = await capability_discovery_js_1.capabilityDiscovery.discoverCapabilities(['all']);
12
+ this.capabilitiesCache = await capabilityDiscovery.discoverCapabilities(['all']);
16
13
  this.cacheTimestamp = now;
17
14
  }
18
15
  return this.capabilitiesCache;
@@ -169,6 +166,5 @@ class NameResolver {
169
166
  return results;
170
167
  }
171
168
  }
172
- exports.NameResolver = NameResolver;
173
169
  // Global resolver instance
174
- exports.nameResolver = new NameResolver();
170
+ export const nameResolver = new NameResolver();
@@ -1,27 +1,23 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.logInteraction = exports.generateSessionId = void 0;
4
- const fs_1 = require("fs");
5
- const path_1 = require("path");
1
+ import { writeFileSync, existsSync, mkdirSync } from "fs";
2
+ import { join } from "path";
6
3
  // AI Training Data Collection Configuration
7
4
  const AI_TRAINING_ENABLED = process.env.ENABLE_AI_TRAINING_DATA === 'true';
8
5
  const AI_TRAINING_FIELDS = (process.env.AI_TRAINING_DATA_FIELDS || 'user_input,parsed_output,success_metrics').split(',');
9
6
  const AI_TRAINING_RETENTION_DAYS = parseInt(process.env.AI_TRAINING_DATA_RETENTION_DAYS || '30');
10
7
  // Generate session ID for interaction tracking
11
- function generateSessionId() {
8
+ export function generateSessionId() {
12
9
  return `session-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
13
10
  }
14
- exports.generateSessionId = generateSessionId;
15
11
  // Privacy-aware interaction logging
16
- function logInteraction(interaction) {
12
+ export function logInteraction(interaction) {
17
13
  if (!AI_TRAINING_ENABLED) {
18
14
  return; // Respect user privacy choice
19
15
  }
20
16
  try {
21
17
  // Ensure logs directory exists
22
- const logsDir = (0, path_1.join)(process.cwd(), 'ai-training-logs');
23
- if (!(0, fs_1.existsSync)(logsDir)) {
24
- (0, fs_1.mkdirSync)(logsDir, { recursive: true });
18
+ const logsDir = join(process.cwd(), 'ai-training-logs');
19
+ if (!existsSync(logsDir)) {
20
+ mkdirSync(logsDir, { recursive: true });
25
21
  }
26
22
  // Filter fields based on user preferences
27
23
  const filteredInteraction = {
@@ -47,13 +43,12 @@ function logInteraction(interaction) {
47
43
  filteredInteraction.timing = interaction.timing;
48
44
  }
49
45
  // Append to daily log file (JSONL format)
50
- const logFile = (0, path_1.join)(logsDir, `interactions-${new Date().toISOString().split('T')[0]}.jsonl`);
46
+ const logFile = join(logsDir, `interactions-${new Date().toISOString().split('T')[0]}.jsonl`);
51
47
  const logEntry = JSON.stringify(filteredInteraction) + '\n';
52
- (0, fs_1.writeFileSync)(logFile, logEntry, { flag: 'a' });
48
+ writeFileSync(logFile, logEntry, { flag: 'a' });
53
49
  }
54
50
  catch (error) {
55
51
  // Fail silently to not disrupt user experience
56
52
  console.warn('AI training data logging failed:', error);
57
53
  }
58
54
  }
59
- exports.logInteraction = logInteraction;
@@ -1,8 +1,5 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.calculateNodeAssignments = exports.parseVMNames = void 0;
4
1
  // Helper function to parse VM name patterns
5
- function parseVMNames(nameInput, count) {
2
+ export function parseVMNames(nameInput, count) {
6
3
  // Handle letter range patterns like "ws-a->ws-x" or "ws-a -> ws-x"
7
4
  const letterRangeMatch = nameInput.match(/^(.+?)([a-z])\s*->\s*(.+?)([a-z])$/i);
8
5
  if (letterRangeMatch) {
@@ -62,9 +59,8 @@ function parseVMNames(nameInput, count) {
62
59
  // Single VM
63
60
  return [nameInput];
64
61
  }
65
- exports.parseVMNames = parseVMNames;
66
62
  // Determine node assignment strategy for VMs
67
- function calculateNodeAssignments(vmNames, nodes, distribution) {
63
+ export function calculateNodeAssignments(vmNames, nodes, distribution) {
68
64
  let nodeAssignments = [];
69
65
  if (distribution === 'spread' || (vmNames.length > 1 && !distribution)) {
70
66
  // Distribute VMs across all available nodes
@@ -87,4 +83,3 @@ function calculateNodeAssignments(vmNames, nodes, distribution) {
87
83
  }
88
84
  return nodeAssignments;
89
85
  }
90
- exports.calculateNodeAssignments = calculateNodeAssignments;