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.
- package/LICENSE +26 -0
- package/README.md +347 -0
- package/build.js +127 -0
- package/lib/account-info.js +476 -0
- package/lib/colors.js +49 -0
- package/lib/commit.js +885 -0
- package/lib/config-command.js +310 -0
- package/lib/config-manager.js +344 -0
- package/lib/config.js +150 -0
- package/lib/devlog.js +182 -0
- package/lib/env-display.js +162 -0
- package/lib/git-info.js +509 -0
- package/lib/header.js +152 -0
- package/lib/input-utils.js +116 -0
- package/lib/logger.js +285 -0
- package/lib/machine-fingerprint.js +229 -0
- package/lib/maiass-command.js +79 -0
- package/lib/maiass-pipeline.js +1204 -0
- package/lib/maiass-variables.js +152 -0
- package/lib/secure-storage.js +256 -0
- package/lib/symbols.js +200 -0
- package/lib/token-validator.js +184 -0
- package/lib/version-command.js +256 -0
- package/lib/version-manager.js +902 -0
- package/maiass-standalone.cjs +148 -0
- package/maiass.cjs +34 -0
- package/maiass.mjs +167 -0
- package/package.json +45 -0
- package/setup-env.js +83 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// Complete list of MAIASS environment variables with their defaults
|
|
2
|
+
// Extracted from setup_bumpscript_variables() in maiass.sh
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
|
|
6
|
+
export const MAIASS_VARIABLES = {
|
|
7
|
+
// Core system variables
|
|
8
|
+
'MAIASS_DEBUG': { default: 'false', description: 'Enable debug mode' },
|
|
9
|
+
'MAIASS_AUTOPUSH_COMMITS': { default: 'false', description: 'Automatically push commits' },
|
|
10
|
+
'MAIASS_BRAND': { default: 'MAIASS', description: 'Brand name for display' },
|
|
11
|
+
'MAIASS_VERBOSITY': { default: 'brief', description: 'Verbosity level (brief/normal/verbose)' },
|
|
12
|
+
'MAIASS_LOGGING': { default: 'false', description: 'Enable logging to file' },
|
|
13
|
+
'MAIASS_LOG_FILE': { default: 'maiass.log', description: 'Log file name' },
|
|
14
|
+
|
|
15
|
+
// AI configuration
|
|
16
|
+
'MAIASS_AI_MODE': { default: 'ask', description: 'AI interaction mode' },
|
|
17
|
+
'MAIASS_AI_TOKEN': { default: '', description: 'AI API token', sensitive: true },
|
|
18
|
+
'MAIASS_AI_MODEL': { default: 'gpt-3.5-turbo', description: 'AI model to use' },
|
|
19
|
+
'MAIASS_AI_TEMPERATURE': { default: '0.7', description: 'AI temperature setting' },
|
|
20
|
+
'MAIASS_AI_MAX_CHARACTERS': { default: '8000', description: 'Max characters for AI requests' },
|
|
21
|
+
'MAIASS_AI_COMMIT_MESSAGE_STYLE': { default: 'bullet', description: 'Commit message style' },
|
|
22
|
+
|
|
23
|
+
// Version file system
|
|
24
|
+
'MAIASS_VERSION_PRIMARY_FILE': { default: '', description: 'Primary version file path' },
|
|
25
|
+
'MAIASS_VERSION_PRIMARY_TYPE': { default: '', description: 'Primary version file type' },
|
|
26
|
+
'MAIASS_VERSION_PRIMARY_LINE_START': { default: '', description: 'Line start pattern for version' },
|
|
27
|
+
'MAIASS_VERSION_SECONDARY_FILES': { default: '', description: 'Secondary version files (comma-separated)' },
|
|
28
|
+
|
|
29
|
+
// Branch configuration
|
|
30
|
+
'MAIASS_DEVELOPBRANCH': { default: 'develop', description: 'Development branch name' },
|
|
31
|
+
'MAIASS_STAGINGBRANCH': { default: 'staging', description: 'Staging branch name' },
|
|
32
|
+
'MAIASS_MAINBRANCH': { default: 'main', description: 'Main/Master branch name' },
|
|
33
|
+
|
|
34
|
+
// Changelog configuration
|
|
35
|
+
'MAIASS_CHANGELOG_PATH': { default: '.', description: 'Path to changelog directory' },
|
|
36
|
+
'MAIASS_CHANGELOG_NAME': { default: 'CHANGELOG.md', description: 'Main changelog filename' },
|
|
37
|
+
'MAIASS_CHANGELOG_INTERNAL_NAME': { default: '.CHANGELOG_internal.md', description: 'Internal changelog filename' },
|
|
38
|
+
|
|
39
|
+
// Repository configuration
|
|
40
|
+
'MAIASS_REPO_TYPE': { default: 'bespoke', description: 'Repository type (wordpress-theme/plugin/site, craft, bespoke)' },
|
|
41
|
+
'MAIASS_VERSION_PATH': { default: '.', description: 'Path to version files' },
|
|
42
|
+
'MAIASS_PACKAGE_PATH': { default: '.', description: 'Path to package.json' },
|
|
43
|
+
'MAIASS_WP_FILES_PATH': { default: '', description: 'Path to WordPress files' },
|
|
44
|
+
|
|
45
|
+
// Release configuration
|
|
46
|
+
'MAIASS_AUTO_TAG_RELEASES': { default: 'true', description: 'Automatically tag releases without prompting' },
|
|
47
|
+
|
|
48
|
+
// Pull request configuration
|
|
49
|
+
'MAIASS_STAGING_PULLREQUESTS': { default: 'on', description: 'Enable staging pull requests' },
|
|
50
|
+
'MAIASS_MAIN_PULLREQUESTS': { default: 'on', description: 'Enable main branch pull requests' },
|
|
51
|
+
|
|
52
|
+
// Repository provider configuration
|
|
53
|
+
'MAIASS_BITBUCKET_WORKSPACE': { default: '', description: 'Bitbucket workspace name' },
|
|
54
|
+
'MAIASS_BITBUCKET_REPO_SLUG': { default: '', description: 'Bitbucket repository slug' },
|
|
55
|
+
'MAIASS_GITHUB_OWNER': { default: '', description: 'GitHub repository owner' },
|
|
56
|
+
'MAIASS_GITHUB_REPO': { default: '', description: 'GitHub repository name' }
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Get the source of an environment variable value
|
|
61
|
+
* @param {string} key - Environment variable key
|
|
62
|
+
* @param {string} value - Current value
|
|
63
|
+
* @param {Array} loadedFiles - Array of loaded config files
|
|
64
|
+
* @returns {string} Source description
|
|
65
|
+
*/
|
|
66
|
+
export function getVariableSource(key, value, loadedFiles) {
|
|
67
|
+
const varDef = MAIASS_VARIABLES[key];
|
|
68
|
+
|
|
69
|
+
if (!value) {
|
|
70
|
+
return 'not set';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (varDef && value === varDef.default) {
|
|
74
|
+
return 'default';
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Check which file contains this variable by reading file contents
|
|
78
|
+
// Priority order: .env.maiass.local (highest) -> .env.maiass -> user .maiass.env -> OS config -> OS secure (lowest)
|
|
79
|
+
|
|
80
|
+
// Check project .env.maiass.local first (highest priority)
|
|
81
|
+
const projectLocalEnv = path.resolve(process.cwd(), '.env.maiass.local');
|
|
82
|
+
if (fs.existsSync(projectLocalEnv)) {
|
|
83
|
+
try {
|
|
84
|
+
const content = fs.readFileSync(projectLocalEnv, 'utf8');
|
|
85
|
+
// Use more precise regex to match the exact variable
|
|
86
|
+
const regex = new RegExp(`^\\s*${key}\\s*=`, 'm');
|
|
87
|
+
if (regex.test(content)) {
|
|
88
|
+
return 'project local';
|
|
89
|
+
}
|
|
90
|
+
} catch (error) {
|
|
91
|
+
// File read error, continue checking other files
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Check project .env.maiass (second priority)
|
|
96
|
+
const projectEnv = path.resolve(process.cwd(), '.env.maiass');
|
|
97
|
+
if (fs.existsSync(projectEnv)) {
|
|
98
|
+
try {
|
|
99
|
+
const content = fs.readFileSync(projectEnv, 'utf8');
|
|
100
|
+
const regex = new RegExp(`^\\s*${key}\\s*=`, 'm');
|
|
101
|
+
if (regex.test(content)) {
|
|
102
|
+
return 'project';
|
|
103
|
+
}
|
|
104
|
+
} catch (error) {
|
|
105
|
+
// File read error, continue checking other files
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Check user .maiass.env (global user config)
|
|
110
|
+
const userEnv = loadedFiles.find(f => f.includes('.maiass.env'));
|
|
111
|
+
if (userEnv) {
|
|
112
|
+
try {
|
|
113
|
+
const content = fs.readFileSync(userEnv, 'utf8');
|
|
114
|
+
const regex = new RegExp(`^\\s*${key}\\s*=`, 'm');
|
|
115
|
+
if (regex.test(content)) {
|
|
116
|
+
return 'global';
|
|
117
|
+
}
|
|
118
|
+
} catch (error) {
|
|
119
|
+
// File read error, continue checking other files
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Check OS config
|
|
124
|
+
const osConfig = loadedFiles.find(f => f.includes('config.env'));
|
|
125
|
+
if (osConfig) {
|
|
126
|
+
try {
|
|
127
|
+
const content = fs.readFileSync(osConfig, 'utf8');
|
|
128
|
+
if (content.includes(`${key}=`)) {
|
|
129
|
+
return 'OS config';
|
|
130
|
+
}
|
|
131
|
+
} catch (error) {
|
|
132
|
+
// File read error, continue checking other files
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Check OS secure
|
|
137
|
+
const osSecure = loadedFiles.find(f => f.includes('secure.env'));
|
|
138
|
+
if (osSecure) {
|
|
139
|
+
try {
|
|
140
|
+
const content = fs.readFileSync(osSecure, 'utf8');
|
|
141
|
+
if (content.includes(`${key}=`)) {
|
|
142
|
+
return 'OS secure';
|
|
143
|
+
}
|
|
144
|
+
} catch (error) {
|
|
145
|
+
// File read error, continue checking other files
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return 'environment';
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export default MAIASS_VARIABLES;
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
// Secure storage functionality for nodemaiass
|
|
2
|
+
// Uses OS keychain (macOS) or secret-tool (Linux) for sensitive data storage
|
|
3
|
+
// Compatible with bashmaiass approach but uses NODEMAIASS service names
|
|
4
|
+
|
|
5
|
+
import { execSync } from 'child_process';
|
|
6
|
+
import os from 'os';
|
|
7
|
+
import { log } from './logger.js';
|
|
8
|
+
import { SYMBOLS } from './symbols.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Get environment-specific service name for secure storage
|
|
12
|
+
* Uses NODEMAIASS prefix to differentiate from bashmaiass
|
|
13
|
+
* @returns {string} Service name for secure storage
|
|
14
|
+
*/
|
|
15
|
+
export function getSecureServiceName() {
|
|
16
|
+
const env = process.env.MAIASS_AI_HOST || '';
|
|
17
|
+
let envSuffix = '';
|
|
18
|
+
|
|
19
|
+
if (env.includes('localhost') || env.includes('127.0.0.1')) {
|
|
20
|
+
envSuffix = '_localhost';
|
|
21
|
+
} else if (env.includes('preview') || env.includes('staging')) {
|
|
22
|
+
envSuffix = '_preview';
|
|
23
|
+
}
|
|
24
|
+
// Production uses no suffix
|
|
25
|
+
|
|
26
|
+
// Use 'maiass' (not 'nodemaiass') to share keychain with bashmaiass
|
|
27
|
+
return `maiass${envSuffix}`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Store a sensitive variable in OS secure storage
|
|
32
|
+
* @param {string} varName - Variable name (e.g., 'MAIASS_AI_TOKEN')
|
|
33
|
+
* @param {string} varValue - Variable value
|
|
34
|
+
* @returns {boolean} Success status
|
|
35
|
+
*/
|
|
36
|
+
export function storeSecureVariable(varName, varValue) {
|
|
37
|
+
const serviceName = getSecureServiceName();
|
|
38
|
+
const debugMode = process.env.MAIASS_DEBUG === 'true';
|
|
39
|
+
|
|
40
|
+
if (debugMode) {
|
|
41
|
+
log.debug(SYMBOLS.INFO, `[MAIASS DEBUG] Storing ${varName} in secure storage service: ${serviceName}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
if (os.platform() === 'darwin') {
|
|
46
|
+
// macOS: Use keychain via security command
|
|
47
|
+
execSync(`security add-generic-password -U -s "${serviceName}" -a "${varName}" -w "${varValue}"`, {
|
|
48
|
+
stdio: 'pipe'
|
|
49
|
+
});
|
|
50
|
+
} else {
|
|
51
|
+
// Linux: Use secret-tool if available
|
|
52
|
+
try {
|
|
53
|
+
execSync('which secret-tool', { stdio: 'pipe' });
|
|
54
|
+
execSync(`echo -n "${varValue}" | secret-tool store --label="NODEMAIASS ${varName} (${serviceName})" service "${serviceName}" key "${varName}"`, {
|
|
55
|
+
stdio: 'pipe',
|
|
56
|
+
shell: true
|
|
57
|
+
});
|
|
58
|
+
} catch (error) {
|
|
59
|
+
if (debugMode) {
|
|
60
|
+
log.debug(SYMBOLS.WARNING, '[MAIASS DEBUG] secret-tool not available, secure storage not supported on this system');
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (debugMode) {
|
|
67
|
+
log.debug(SYMBOLS.INFO, `[MAIASS DEBUG] Successfully stored ${varName} in secure storage`);
|
|
68
|
+
}
|
|
69
|
+
return true;
|
|
70
|
+
} catch (error) {
|
|
71
|
+
if (debugMode) {
|
|
72
|
+
log.debug(SYMBOLS.WARNING, `[MAIASS DEBUG] Failed to store ${varName} in secure storage: ${error.message}`);
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Retrieve a sensitive variable from OS secure storage
|
|
80
|
+
* @param {string} varName - Variable name (e.g., 'MAIASS_AI_TOKEN')
|
|
81
|
+
* @returns {string|null} Variable value or null if not found
|
|
82
|
+
*/
|
|
83
|
+
export function retrieveSecureVariable(varName) {
|
|
84
|
+
const serviceName = getSecureServiceName();
|
|
85
|
+
const debugMode = process.env.MAIASS_DEBUG === 'true';
|
|
86
|
+
|
|
87
|
+
if (debugMode) {
|
|
88
|
+
log.debug(SYMBOLS.INFO, `[MAIASS DEBUG] Retrieving ${varName} from secure storage service: ${serviceName}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
let value = null;
|
|
93
|
+
|
|
94
|
+
if (os.platform() === 'darwin') {
|
|
95
|
+
// macOS: Use keychain via security command
|
|
96
|
+
value = execSync(`security find-generic-password -s "${serviceName}" -a "${varName}" -w`, {
|
|
97
|
+
stdio: 'pipe',
|
|
98
|
+
encoding: 'utf8'
|
|
99
|
+
}).trim();
|
|
100
|
+
} else {
|
|
101
|
+
// Linux: Use secret-tool if available
|
|
102
|
+
try {
|
|
103
|
+
execSync('which secret-tool', { stdio: 'pipe' });
|
|
104
|
+
value = execSync(`secret-tool lookup service "${serviceName}" key "${varName}"`, {
|
|
105
|
+
stdio: 'pipe',
|
|
106
|
+
encoding: 'utf8'
|
|
107
|
+
}).trim();
|
|
108
|
+
} catch (error) {
|
|
109
|
+
if (debugMode) {
|
|
110
|
+
log.debug(SYMBOLS.WARNING, '[MAIASS DEBUG] secret-tool not available, secure storage not supported on this system');
|
|
111
|
+
}
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (debugMode && value) {
|
|
117
|
+
log.debug(SYMBOLS.INFO, `[MAIASS DEBUG] Successfully retrieved ${varName} from secure storage`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return value || null;
|
|
121
|
+
} catch (error) {
|
|
122
|
+
if (debugMode) {
|
|
123
|
+
log.debug(SYMBOLS.INFO, `[MAIASS DEBUG] ${varName} not found in secure storage (this is normal for first run)`);
|
|
124
|
+
}
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Remove a sensitive variable from OS secure storage
|
|
131
|
+
* @param {string} varName - Variable name (e.g., 'MAIASS_AI_TOKEN')
|
|
132
|
+
* @returns {boolean} Success status
|
|
133
|
+
*/
|
|
134
|
+
export function removeSecureVariable(varName) {
|
|
135
|
+
const serviceName = getSecureServiceName();
|
|
136
|
+
const debugMode = process.env.MAIASS_DEBUG === 'true';
|
|
137
|
+
|
|
138
|
+
if (debugMode) {
|
|
139
|
+
log.debug(SYMBOLS.INFO, `[MAIASS DEBUG] Removing ${varName} from secure storage service: ${serviceName}`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
if (os.platform() === 'darwin') {
|
|
144
|
+
// macOS: Use keychain via security command
|
|
145
|
+
execSync(`security delete-generic-password -s "${serviceName}" -a "${varName}"`, {
|
|
146
|
+
stdio: 'pipe'
|
|
147
|
+
});
|
|
148
|
+
} else {
|
|
149
|
+
// Linux: secret-tool doesn't have direct delete, but we can try to clear it
|
|
150
|
+
try {
|
|
151
|
+
execSync('which secret-tool', { stdio: 'pipe' });
|
|
152
|
+
// secret-tool doesn't have a delete command, so we store an empty value
|
|
153
|
+
execSync(`echo -n "" | secret-tool store --label="NODEMAIASS ${varName} (${serviceName})" service "${serviceName}" key "${varName}"`, {
|
|
154
|
+
stdio: 'pipe',
|
|
155
|
+
shell: true
|
|
156
|
+
});
|
|
157
|
+
} catch (error) {
|
|
158
|
+
if (debugMode) {
|
|
159
|
+
log.debug(SYMBOLS.WARNING, '[MAIASS DEBUG] secret-tool not available, secure storage not supported on this system');
|
|
160
|
+
}
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (debugMode) {
|
|
166
|
+
log.debug(SYMBOLS.INFO, `[MAIASS DEBUG] Successfully removed ${varName} from secure storage`);
|
|
167
|
+
}
|
|
168
|
+
return true;
|
|
169
|
+
} catch (error) {
|
|
170
|
+
if (debugMode) {
|
|
171
|
+
log.debug(SYMBOLS.WARNING, `[MAIASS DEBUG] Failed to remove ${varName} from secure storage: ${error.message}`);
|
|
172
|
+
}
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Load secure variables into environment
|
|
179
|
+
* Loads MAIASS_AI_TOKEN and MAIASS_SUBSCRIPTION_ID from secure storage
|
|
180
|
+
*/
|
|
181
|
+
export function loadSecureVariables() {
|
|
182
|
+
const secureVars = ['MAIASS_AI_TOKEN', 'MAIASS_SUBSCRIPTION_ID'];
|
|
183
|
+
const debugMode = process.env.MAIASS_DEBUG === 'true';
|
|
184
|
+
const serviceName = getSecureServiceName();
|
|
185
|
+
|
|
186
|
+
if (debugMode) {
|
|
187
|
+
const host = process.env.MAIASS_AI_HOST || 'https://pound.maiass.net';
|
|
188
|
+
log.debug(SYMBOLS.INFO, `[MAIASS DEBUG] Using secure storage service name: ${serviceName} (host: ${host})`);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
secureVars.forEach(varName => {
|
|
192
|
+
const envValue = process.env[varName];
|
|
193
|
+
|
|
194
|
+
if (debugMode) {
|
|
195
|
+
log.debug(SYMBOLS.INFO, `[MAIASS DEBUG] Checking ${varName}: value="${envValue}", type=${typeof envValue}, empty=${!envValue || envValue.trim() === ''}`);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Check if we should prefer secure storage over environment variable
|
|
199
|
+
let preferSecure = false;
|
|
200
|
+
if (varName === 'MAIASS_AI_TOKEN' && envValue) {
|
|
201
|
+
// Check if the existing token looks invalid
|
|
202
|
+
if (/^invalid_|^test_|_test$/.test(envValue) || envValue === 'DISABLED' || envValue.trim() === '') {
|
|
203
|
+
preferSecure = true;
|
|
204
|
+
if (debugMode) {
|
|
205
|
+
log.debug(SYMBOLS.INFO, `[MAIASS DEBUG] Environment token appears invalid, checking secure storage`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Only load if not already set with valid token (unless we want to prefer secure storage)
|
|
211
|
+
if (!envValue || envValue.trim() === '' || preferSecure) {
|
|
212
|
+
const value = retrieveSecureVariable(varName);
|
|
213
|
+
if (value) {
|
|
214
|
+
process.env[varName] = value;
|
|
215
|
+
if (preferSecure) {
|
|
216
|
+
if (debugMode) {
|
|
217
|
+
log.debug(SYMBOLS.INFO, `[MAIASS DEBUG] Replaced invalid environment token with secure storage token`);
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
if (debugMode) {
|
|
221
|
+
log.debug(SYMBOLS.INFO, `[MAIASS DEBUG] Loaded ${varName} from secure storage`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
} else if (debugMode) {
|
|
226
|
+
log.debug(SYMBOLS.INFO, `[MAIASS DEBUG] ${varName} already set in environment, skipping secure storage`);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Check if secure storage is available on this system
|
|
233
|
+
* @returns {boolean} True if secure storage is supported
|
|
234
|
+
*/
|
|
235
|
+
export function isSecureStorageAvailable() {
|
|
236
|
+
try {
|
|
237
|
+
if (os.platform() === 'darwin') {
|
|
238
|
+
execSync('which security', { stdio: 'pipe' });
|
|
239
|
+
return true;
|
|
240
|
+
} else {
|
|
241
|
+
execSync('which secret-tool', { stdio: 'pipe' });
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
} catch (error) {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export default {
|
|
250
|
+
getSecureServiceName,
|
|
251
|
+
storeSecureVariable,
|
|
252
|
+
retrieveSecureVariable,
|
|
253
|
+
removeSecureVariable,
|
|
254
|
+
loadSecureVariables,
|
|
255
|
+
isSecureStorageAvailable
|
|
256
|
+
};
|
package/lib/symbols.js
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
// Cross-platform symbol system with Unicode/ASCII fallbacks
|
|
2
|
+
import os from 'os';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Detect if the current terminal supports Unicode
|
|
6
|
+
* @returns {boolean} True if Unicode is supported
|
|
7
|
+
*/
|
|
8
|
+
function supportsUnicode() {
|
|
9
|
+
// Check environment variable override
|
|
10
|
+
if (process.env.MAIASS_NO_UNICODE === 'true') {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Force Unicode if explicitly enabled
|
|
15
|
+
if (process.env.MAIASS_FORCE_UNICODE === 'true') {
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Check platform and terminal capabilities
|
|
20
|
+
const platform = os.platform();
|
|
21
|
+
|
|
22
|
+
// Windows-specific checks
|
|
23
|
+
if (platform === 'win32') {
|
|
24
|
+
// Modern Windows Terminal supports Unicode
|
|
25
|
+
if (process.env.WT_SESSION) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// PowerShell 7+ generally supports Unicode
|
|
30
|
+
if (process.env.PSModulePath && process.env.POWERSHELL_DISTRIBUTION_CHANNEL) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// VS Code integrated terminal
|
|
35
|
+
if (process.env.VSCODE_INJECTION || process.env.TERM_PROGRAM === 'vscode') {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Default to ASCII for Windows cmd and older terminals
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// macOS and Linux generally support Unicode
|
|
44
|
+
if (platform === 'darwin' || platform === 'linux') {
|
|
45
|
+
// Check if we're in a known Unicode-capable terminal
|
|
46
|
+
const term = process.env.TERM || '';
|
|
47
|
+
const termProgram = process.env.TERM_PROGRAM || '';
|
|
48
|
+
|
|
49
|
+
if (term.includes('xterm') ||
|
|
50
|
+
term.includes('screen') ||
|
|
51
|
+
termProgram === 'vscode' ||
|
|
52
|
+
termProgram === 'iTerm.app' ||
|
|
53
|
+
process.env.COLORTERM === 'truecolor') {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Default to Unicode for non-Windows platforms
|
|
59
|
+
return platform !== 'win32';
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Symbol definitions with Unicode and ASCII fallbacks
|
|
64
|
+
*/
|
|
65
|
+
const SYMBOL_SETS = {
|
|
66
|
+
unicode: {
|
|
67
|
+
globe: 'đ',
|
|
68
|
+
folder: 'đ',
|
|
69
|
+
gear: 'âī¸',
|
|
70
|
+
wrench: 'đ§',
|
|
71
|
+
checkmark: 'â
',
|
|
72
|
+
cross: 'â',
|
|
73
|
+
warning: 'â ī¸',
|
|
74
|
+
info: 'âšī¸',
|
|
75
|
+
smile: 'đ',
|
|
76
|
+
sunglasses: 'đ',
|
|
77
|
+
poo: 'đŠ',
|
|
78
|
+
rocket: 'đ',
|
|
79
|
+
arrow: 'â',
|
|
80
|
+
check: 'â',
|
|
81
|
+
x: 'â',
|
|
82
|
+
bullet: 'âĸ',
|
|
83
|
+
diamond: 'â',
|
|
84
|
+
star: 'â
',
|
|
85
|
+
heart: 'âĨ',
|
|
86
|
+
spade: 'â ',
|
|
87
|
+
club: 'âŖ',
|
|
88
|
+
maiassdot: '(.)',
|
|
89
|
+
maiassass: '|))',
|
|
90
|
+
pushing: 'âââ',
|
|
91
|
+
merging: '<=>',
|
|
92
|
+
pulling: 'âââ',
|
|
93
|
+
brain: 'đ§ ',
|
|
94
|
+
},
|
|
95
|
+
ascii: {
|
|
96
|
+
globe: '[GLOBE]',
|
|
97
|
+
folder: '[FOLDER]',
|
|
98
|
+
gear: '[GEAR]',
|
|
99
|
+
wrench: '[TOOL]',
|
|
100
|
+
checkmark: '[OK]',
|
|
101
|
+
cross: '[ERROR]',
|
|
102
|
+
warning: '[WARN]',
|
|
103
|
+
info: '[INFO]',
|
|
104
|
+
smile: ':)',
|
|
105
|
+
sunglasses: ':D',
|
|
106
|
+
poo: ':(',
|
|
107
|
+
rocket: '[ROCKET]',
|
|
108
|
+
arrow: '->',
|
|
109
|
+
check: '+',
|
|
110
|
+
x: '-',
|
|
111
|
+
bullet: '*',
|
|
112
|
+
diamond: '<>',
|
|
113
|
+
star: '*',
|
|
114
|
+
heart: '<3',
|
|
115
|
+
spade: 'S',
|
|
116
|
+
club: 'C',
|
|
117
|
+
maiassdot: '(.)',
|
|
118
|
+
maiassass: '|))',
|
|
119
|
+
pushing: 'âââ',
|
|
120
|
+
merging: '<=>',
|
|
121
|
+
pulling: 'âââ',
|
|
122
|
+
brain: '[AI]',}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Get the appropriate symbol set based on terminal capabilities
|
|
127
|
+
*/
|
|
128
|
+
const useUnicode = supportsUnicode();
|
|
129
|
+
const symbols = useUnicode ? SYMBOL_SETS.unicode : SYMBOL_SETS.ascii;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Get a symbol with automatic Unicode/ASCII fallback
|
|
133
|
+
* @param {string} name - Symbol name
|
|
134
|
+
* @returns {string} The appropriate symbol for the current terminal
|
|
135
|
+
*/
|
|
136
|
+
export function getSymbol(name) {
|
|
137
|
+
return symbols[name] || name;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Check if Unicode is being used
|
|
142
|
+
* @returns {boolean} True if Unicode symbols are active
|
|
143
|
+
*/
|
|
144
|
+
export function isUnicodeEnabled() {
|
|
145
|
+
return useUnicode;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Get terminal info for debugging
|
|
150
|
+
* @returns {Object} Terminal capability information
|
|
151
|
+
*/
|
|
152
|
+
export function getTerminalInfo() {
|
|
153
|
+
return {
|
|
154
|
+
platform: os.platform(),
|
|
155
|
+
supportsUnicode: useUnicode,
|
|
156
|
+
env: {
|
|
157
|
+
TERM: process.env.TERM,
|
|
158
|
+
TERM_PROGRAM: process.env.TERM_PROGRAM,
|
|
159
|
+
COLORTERM: process.env.COLORTERM,
|
|
160
|
+
WT_SESSION: process.env.WT_SESSION,
|
|
161
|
+
VSCODE_INJECTION: process.env.VSCODE_INJECTION,
|
|
162
|
+
MAIASS_NO_UNICODE: process.env.MAIASS_NO_UNICODE,
|
|
163
|
+
MAIASS_FORCE_UNICODE: process.env.MAIASS_FORCE_UNICODE
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Export individual symbols for convenience
|
|
169
|
+
export const SYMBOLS = {
|
|
170
|
+
GLOBE: getSymbol('globe'),
|
|
171
|
+
FOLDER: getSymbol('folder'),
|
|
172
|
+
GEAR: getSymbol('gear'),
|
|
173
|
+
WRENCH: getSymbol('wrench'),
|
|
174
|
+
CHECKMARK: getSymbol('checkmark'),
|
|
175
|
+
CROSS: getSymbol('cross'),
|
|
176
|
+
WARNING: getSymbol('warning'),
|
|
177
|
+
INFO: getSymbol('info'),
|
|
178
|
+
ARROW: getSymbol('arrow'),
|
|
179
|
+
CHECK: getSymbol('check'),
|
|
180
|
+
X: getSymbol('x'),
|
|
181
|
+
BULLET: getSymbol('bullet'),
|
|
182
|
+
DIAMOND: getSymbol('diamond'),
|
|
183
|
+
STAR: getSymbol('star'),
|
|
184
|
+
HEART: getSymbol('heart'),
|
|
185
|
+
SPADE: getSymbol('spade'),
|
|
186
|
+
CLUB: getSymbol('club'),
|
|
187
|
+
MAIASSDOT: getSymbol('maiassdot'),
|
|
188
|
+
MAIASSASS: getSymbol('maiassass'),
|
|
189
|
+
PUSHING: getSymbol('pushing'),
|
|
190
|
+
MERGING: getSymbol('merging'),
|
|
191
|
+
PULLING: getSymbol('pulling'),
|
|
192
|
+
BRAIN: getSymbol('brain')
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export default {
|
|
196
|
+
getSymbol,
|
|
197
|
+
isUnicodeEnabled,
|
|
198
|
+
getTerminalInfo,
|
|
199
|
+
SYMBOLS
|
|
200
|
+
};
|