maiass 5.7.31

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.
@@ -0,0 +1,184 @@
1
+ // API Token validation utility for debug mode
2
+ import path from 'path';
3
+ import fs from 'fs';
4
+ import os from 'os';
5
+ import dotenv from 'dotenv';
6
+ import colors from './colors.js';
7
+ import { getConfigPaths } from './config.js';
8
+ import { SYMBOLS } from './symbols.js';
9
+
10
+ /**
11
+ * List of API tokens to validate
12
+ */
13
+ const API_TOKENS = [
14
+ {
15
+ name: 'MAIASS_AI_TOKEN',
16
+ description: 'MAIASS AI API Token',
17
+ minLength: 10,
18
+ pattern: /^[a-zA-Z0-9_-]+$/
19
+ },
20
+ {
21
+ name: 'MAIASS_API_KEY',
22
+ description: 'MAIASS API Key',
23
+ minLength: 20,
24
+ pattern: /^sk-[a-zA-Z0-9]+$/
25
+ }
26
+ ];
27
+
28
+ /**
29
+ * Validate if a token value appears to be valid
30
+ * @param {string} token - The token value
31
+ * @param {Object} tokenConfig - Token configuration
32
+ * @returns {Object} Validation result
33
+ */
34
+ function validateTokenValue(token, tokenConfig) {
35
+ if (!token || token.trim() === '') {
36
+ return { valid: false, reason: 'empty' };
37
+ }
38
+
39
+ const trimmedToken = token.trim();
40
+
41
+ if (trimmedToken.length < tokenConfig.minLength) {
42
+ return { valid: false, reason: 'too_short' };
43
+ }
44
+
45
+ if (tokenConfig.pattern && !tokenConfig.pattern.test(trimmedToken)) {
46
+ return { valid: false, reason: 'invalid_format' };
47
+ }
48
+
49
+ return { valid: true, reason: 'valid' };
50
+ }
51
+
52
+ /**
53
+ * Load environment variables from a specific file without affecting global env
54
+ * @param {string} filePath - Path to the environment file
55
+ * @returns {Object} Environment variables from the file
56
+ */
57
+ function loadEnvFile(filePath) {
58
+ if (!fs.existsSync(filePath)) {
59
+ return null;
60
+ }
61
+
62
+ try {
63
+ const result = dotenv.config({ path: filePath, processEnv: {} });
64
+ return result.parsed || {};
65
+ } catch (error) {
66
+ return null;
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Get the status symbol and color for validation result
72
+ * @param {Object} validation - Validation result
73
+ * @returns {Object} Symbol and color info
74
+ */
75
+ function getValidationDisplay(validation) {
76
+ if (!validation) {
77
+ return { symbol: colors.Gray(SYMBOLS.MINUS), status: 'not found', color: colors.Gray };
78
+ }
79
+
80
+ switch (validation.reason) {
81
+ case 'valid':
82
+ return { symbol: colors.Green(SYMBOLS.CHECK), status: 'valid', color: colors.Green };
83
+ case 'empty':
84
+ return { symbol: colors.Yellow(SYMBOLS.WARNING), status: 'empty', color: colors.Yellow };
85
+ case 'too_short':
86
+ return { symbol: colors.Red(SYMBOLS.CROSS), status: 'too short', color: colors.Red };
87
+ case 'invalid_format':
88
+ return { symbol: colors.Red(SYMBOLS.CROSS), status: 'invalid format', color: colors.Red };
89
+ default:
90
+ return { symbol: colors.Red(SYMBOLS.CROSS), status: 'invalid', color: colors.Red };
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Display API token validation results for debug mode
96
+ * Only displays when MAIASS_DEBUG is enabled
97
+ */
98
+ export function displayTokenValidation() {
99
+ // Only run in debug mode
100
+ if (process.env.MAIASS_DEBUG !== 'true') {
101
+ return;
102
+ }
103
+
104
+ console.log(colors.Blue('\n[DEBUG] API Token Validation:'));
105
+
106
+ const paths = getConfigPaths();
107
+
108
+ // Define environment files in priority order (same as config.js)
109
+ const envFiles = [
110
+ {
111
+ path: path.join(paths.data, 'secure.env'),
112
+ name: 'secure.env (OS secure)',
113
+ priority: 1
114
+ },
115
+ {
116
+ path: path.join(paths.config, 'config.env'),
117
+ name: 'config.env (OS config)',
118
+ priority: 2
119
+ },
120
+ {
121
+ path: path.join(paths.home, '.maiass.env'),
122
+ name: '.maiass.env (user home)',
123
+ priority: 3
124
+ },
125
+ {
126
+ path: path.resolve(process.cwd(), '.env.maiass'),
127
+ name: '.env.maiass (project)',
128
+ priority: 4
129
+ }
130
+ ];
131
+
132
+ // Check each environment file
133
+ envFiles.forEach(envFile => {
134
+ console.log(colors.Blue(`\n[DEBUG] Checking ${envFile.name}:`));
135
+ console.log(colors.Gray(`[DEBUG] Path: ${envFile.path}`));
136
+
137
+ const envVars = loadEnvFile(envFile.path);
138
+
139
+ if (!envVars) {
140
+ console.log(colors.Gray(`[DEBUG] ${SYMBOLS.MINUS} File not found or unreadable`));
141
+ return;
142
+ }
143
+
144
+ console.log(colors.Green(`[DEBUG] ${SYMBOLS.CHECK} File loaded successfully`));
145
+
146
+ // Check each API token
147
+ API_TOKENS.forEach(tokenConfig => {
148
+ const tokenValue = envVars[tokenConfig.name];
149
+ const validation = tokenValue ? validateTokenValue(tokenValue, tokenConfig) : null;
150
+ const display = getValidationDisplay(validation);
151
+
152
+ console.log(`[DEBUG] ${display.symbol} ${tokenConfig.description} (${tokenConfig.name}): ${display.color(display.status)}`);
153
+
154
+ if (validation && validation.valid) {
155
+ // Show partial token for confirmation (first 8 chars + ...)
156
+ const maskedToken = tokenValue.substring(0, 8) + '...';
157
+ console.log(colors.Gray(`[DEBUG] Preview: ${maskedToken}`));
158
+ }
159
+ });
160
+ });
161
+
162
+ // Show final token resolution (what's actually in process.env after all files loaded)
163
+ console.log(colors.Blue('\n[DEBUG] Final Token Resolution (after all files loaded):'));
164
+ API_TOKENS.forEach(tokenConfig => {
165
+ const tokenValue = process.env[tokenConfig.name];
166
+ const validation = tokenValue ? validateTokenValue(tokenValue, tokenConfig) : null;
167
+ const display = getValidationDisplay(validation);
168
+
169
+ console.log(`[DEBUG] ${display.symbol} ${tokenConfig.description} (${tokenConfig.name}): ${display.color(display.status)}`);
170
+
171
+ if (validation && validation.valid) {
172
+ const maskedToken = tokenValue.substring(0, 8) + '...';
173
+ console.log(colors.Gray(`[DEBUG] Active: ${maskedToken}`));
174
+ }
175
+ });
176
+
177
+ console.log(colors.Blue('[DEBUG] Token validation complete.\n'));
178
+ }
179
+
180
+ export default {
181
+ displayTokenValidation,
182
+ validateTokenValue,
183
+ API_TOKENS
184
+ };
@@ -0,0 +1,256 @@
1
+ import { log, logger } from './logger.js';
2
+ import colors from './colors.js';
3
+ import { SYMBOLS } from './symbols.js';
4
+ import {
5
+ getCurrentVersion,
6
+ detectVersionFiles,
7
+ bumpVersion,
8
+ updateVersionFiles,
9
+ createVersionTag,
10
+ validateVersion,
11
+ parseVersion
12
+ } from './version-manager.js';
13
+ import { getSingleCharInput, getMultiLineInput } from './input-utils.js';
14
+
15
+ /**
16
+ * Display current version information
17
+ * @param {Object} versionInfo - Version information from getCurrentVersion
18
+ */
19
+ function displayVersionInfo(versionInfo) {
20
+ logger.header(SYMBOLS.INFO, 'Version Information');
21
+
22
+ if (versionInfo.current) {
23
+ console.log(` ${colors.BWhite('Current Version:')} ${colors.BGreen(versionInfo.current)}`);
24
+ console.log(` ${colors.BWhite('Source:')} ${colors.White(versionInfo.source)}`);
25
+ } else {
26
+ console.log(` ${colors.BYellow('No version detected')}`);
27
+ }
28
+
29
+ if (versionInfo.tagVersion && versionInfo.tagVersion !== versionInfo.current) {
30
+ console.log(` ${colors.BWhite('Latest Git Tag:')} ${colors.White(versionInfo.tagVersion)}`);
31
+ }
32
+
33
+ console.log();
34
+
35
+ if (versionInfo.files.length > 0) {
36
+ log.info(SYMBOLS.INFO, 'Version Files Found:');
37
+ console.log();
38
+
39
+ versionInfo.files.forEach((file, index) => {
40
+ const icon = file.filename === 'package.json' ? '📦' :
41
+ file.type === 'php' ? '🐘' :
42
+ file.type === 'text' ? '📄' : '📋';
43
+
44
+ console.log(` ${index + 1}. ${icon} ${colors.BWhite(file.filename)}`);
45
+ console.log(` ${colors.Gray('Version:')} ${colors.White(file.currentVersion)}`);
46
+ console.log(` ${colors.Gray('Type:')} ${colors.White(file.type)}`);
47
+ console.log(` ${colors.Gray('Path:')} ${colors.Gray(file.path)}`);
48
+ console.log();
49
+ });
50
+ } else {
51
+ log.warning(SYMBOLS.WARNING, 'No version files detected');
52
+ console.log();
53
+ console.log(colors.Gray(' Supported files: package.json, composer.json, VERSION, version.txt'));
54
+ console.log(colors.Gray(' WordPress: style.css, plugin.php, functions.php'));
55
+ console.log();
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Display version bump preview
61
+ * @param {string} currentVersion - Current version
62
+ * @param {string} newVersion - New version
63
+ * @param {string} bumpType - Type of bump
64
+ * @param {Array} files - Files that will be updated
65
+ */
66
+ function displayBumpPreview(currentVersion, newVersion, bumpType, files) {
67
+ log.info(SYMBOLS.INFO, 'Version Bump Preview:');
68
+ console.log();
69
+
70
+ console.log(` ${colors.BWhite('Current:')} ${colors.White(currentVersion)}`);
71
+ console.log(` ${colors.BWhite('New:')} ${colors.BGreen(newVersion)}`);
72
+ console.log(` ${colors.BWhite('Bump Type:')} ${colors.White(bumpType)}`);
73
+ console.log();
74
+
75
+ if (files.length > 0) {
76
+ log.info(SYMBOLS.INFO, 'Files to Update:');
77
+ console.log();
78
+
79
+ files.forEach((file, index) => {
80
+ const icon = file.filename === 'package.json' ? '📦' :
81
+ file.type === 'php' ? '🐘' :
82
+ file.type === 'text' ? '📄' : '📋';
83
+
84
+ console.log(` ${index + 1}. ${icon} ${colors.BWhite(file.filename)} ${colors.Gray(`(${file.currentVersion} → ${newVersion})`)}`);
85
+ });
86
+ console.log();
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Handle version bump operation
92
+ * @param {string} bumpType - Type of bump (major, minor, patch, or specific version)
93
+ * @param {Object} options - Command options
94
+ */
95
+ async function handleVersionBump(bumpType, options) {
96
+ const { dryRun, tag, tagMessage, force } = options;
97
+
98
+ log.info(SYMBOLS.INFO, `${dryRun ? 'DRY RUN: ' : ''}Version Bump Operation`);
99
+ console.log();
100
+
101
+ // Get current version information
102
+ const versionInfo = await getCurrentVersion();
103
+
104
+ if (!versionInfo.current && !force) {
105
+ console.error(colors.Red(`${SYMBOLS.CROSS} No current version detected`));
106
+ console.log();
107
+ log.warning(SYMBOLS.INFO, 'Use --force to create initial version');
108
+ return;
109
+ }
110
+
111
+ // Determine new version
112
+ let newVersion;
113
+ if (versionInfo.current) {
114
+ newVersion = bumpVersion(versionInfo.current, bumpType);
115
+ } else {
116
+ // No current version, check if bumpType is a specific version
117
+ const validation = validateVersion(bumpType);
118
+ if (validation.valid) {
119
+ newVersion = bumpType;
120
+ } else {
121
+ newVersion = '1.0.0'; // Default initial version
122
+ }
123
+ }
124
+
125
+ if (!newVersion) {
126
+ console.error(colors.Red(`${SYMBOLS.CROSS} Invalid bump type: ${bumpType}`));
127
+ console.log();
128
+ log.warning(SYMBOLS.INFO, 'Valid types: major, minor, patch, or specific version (e.g., 2.1.0)');
129
+ return;
130
+ }
131
+
132
+ // Validate new version
133
+ const validation = validateVersion(newVersion);
134
+ if (!validation.valid) {
135
+ console.error(colors.Red(`${SYMBOLS.CROSS} Invalid version format: ${newVersion}`));
136
+ console.log(colors.Red(` ${validation.error}`));
137
+ return;
138
+ }
139
+
140
+ // Display preview
141
+ displayBumpPreview(versionInfo.current || '(none)', newVersion, bumpType, versionInfo.files);
142
+
143
+ // Confirm operation unless dry run or force
144
+ if (!dryRun && !force) {
145
+ const confirm = await getSingleCharInput(colors.BCyan('Proceed with version bump? [Y/n] '));
146
+ if (confirm === 'n') {
147
+ log.warning(SYMBOLS.INFO, 'Version bump cancelled');
148
+ return;
149
+ }
150
+ }
151
+
152
+ // Update version files
153
+ if (versionInfo.files.length > 0) {
154
+ log.blue(SYMBOLS.INFO, `${dryRun ? 'Would update' : 'Updating'} version files...`);
155
+
156
+ const updateResult = await updateVersionFiles(newVersion, versionInfo.files, dryRun);
157
+
158
+ if (updateResult.success) {
159
+ updateResult.updated.forEach(update => {
160
+ log.success(SYMBOLS.CHECKMARK, `${update.file} ${colors.Gray(`(${update.oldVersion} → ${update.newVersion})`)}`);
161
+ });
162
+
163
+ if (updateResult.failed.length > 0) {
164
+ console.log();
165
+ log.warning(SYMBOLS.WARNING, 'Some files failed to update:');
166
+ updateResult.failed.forEach(failure => {
167
+ console.log(colors.Red(`${SYMBOLS.CROSS} ${failure.file}: ${failure.error}`));
168
+ });
169
+ }
170
+ } else {
171
+ console.error(colors.Red(`${SYMBOLS.CROSS} Failed to update version files`));
172
+ return;
173
+ }
174
+ } else {
175
+ log.warning(SYMBOLS.WARNING, 'No version files to update');
176
+ }
177
+
178
+ // Create git tag if requested
179
+ if (tag && !dryRun) {
180
+ console.log();
181
+ log.blue(SYMBOLS.INFO, 'Creating git tag...');
182
+
183
+ const tagResult = await createVersionTag(newVersion, tagMessage);
184
+
185
+ if (tagResult.success) {
186
+ log.success(SYMBOLS.CHECKMARK, `Created tag: ${newVersion}`);
187
+ if (tagResult.message) {
188
+ console.log(colors.Gray(` Message: ${tagResult.message}`));
189
+ }
190
+ } else {
191
+ console.error(colors.Red(`${SYMBOLS.CROSS} Failed to create tag: ${tagResult.error}`));
192
+ }
193
+ } else if (tag && dryRun) {
194
+ console.log();
195
+ log.blue(SYMBOLS.INFO, `Would create git tag: ${newVersion}`);
196
+ if (tagMessage) {
197
+ console.log(colors.Gray(` Message: ${tagMessage}`));
198
+ }
199
+ }
200
+
201
+ console.log();
202
+ if (dryRun) {
203
+ log.success(SYMBOLS.CHECKMARK, 'Dry run completed successfully');
204
+ log.blue(SYMBOLS.INFO, 'Run without --dry-run to apply changes');
205
+ } else {
206
+ log.success(SYMBOLS.CHECKMARK, `Version bump completed: ${versionInfo.current || '(none)'} → ${newVersion}`);
207
+ }
208
+ }
209
+
210
+ /**
211
+ * Handle version command
212
+ * @param {Object} args - Command arguments from yargs
213
+ */
214
+ export async function handleVersionCommand(args) {
215
+ const {
216
+ _: positionalArgs,
217
+ 'dry-run': dryRun,
218
+ tag,
219
+ 'tag-message': tagMessage,
220
+ force,
221
+ current
222
+ } = args;
223
+
224
+ try {
225
+ // If --current flag is used, just show current version info
226
+ if (current) {
227
+ const versionInfo = await getCurrentVersion();
228
+ displayVersionInfo(versionInfo);
229
+ return;
230
+ }
231
+
232
+ // If no positional arguments, show current version info
233
+ if (positionalArgs.length === 0) {
234
+ const versionInfo = await getCurrentVersion();
235
+ displayVersionInfo(versionInfo);
236
+ return;
237
+ }
238
+
239
+ // Get bump type from first positional argument
240
+ const bumpType = positionalArgs[0];
241
+
242
+ // Handle version bump
243
+ await handleVersionBump(bumpType, {
244
+ dryRun,
245
+ tag,
246
+ tagMessage,
247
+ force
248
+ });
249
+
250
+ } catch (error) {
251
+ console.error(colors.Red(`${SYMBOLS.CROSS} Version command failed: ${error.message}`));
252
+ if (process.env.MAIASS_DEBUG === 'true') {
253
+ console.error(colors.Gray(error.stack));
254
+ }
255
+ }
256
+ }