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/lib/config.js ADDED
@@ -0,0 +1,150 @@
1
+ // Cross-platform configuration and environment variable loading
2
+ import path from 'path';
3
+ import fs from 'fs';
4
+ import os from 'os';
5
+ import dotenv from 'dotenv';
6
+ import { loadSecureVariables } from './secure-storage.js';
7
+
8
+ /**
9
+ * Get OS-specific config directory paths
10
+ * @returns {Object} Object with config paths for different purposes
11
+ */
12
+ export function getConfigPaths() {
13
+ const platform = os.platform();
14
+ const homedir = os.homedir();
15
+
16
+ let configDir, dataDir;
17
+
18
+ switch (platform) {
19
+ case 'win32':
20
+ configDir = process.env.APPDATA || path.join(homedir, 'AppData', 'Roaming');
21
+ dataDir = process.env.LOCALAPPDATA || path.join(homedir, 'AppData', 'Local');
22
+ break;
23
+ case 'darwin': // macOS
24
+ configDir = path.join(homedir, 'Library', 'Application Support');
25
+ dataDir = path.join(homedir, 'Library', 'Application Support');
26
+ break;
27
+ default: // Linux and others
28
+ configDir = process.env.XDG_CONFIG_HOME || path.join(homedir, '.config');
29
+ dataDir = process.env.XDG_DATA_HOME || path.join(homedir, '.local', 'share');
30
+ break;
31
+ }
32
+
33
+ return {
34
+ config: path.join(configDir, 'maiass'),
35
+ data: path.join(dataDir, 'maiass'),
36
+ home: homedir
37
+ };
38
+ }
39
+
40
+ /**
41
+ * Load environment variables from multiple sources with fallback priority:
42
+ * 1. Current working directory (.env.maiass.local) - highest priority, for sensitive local overrides
43
+ * 2. Current working directory (.env.maiass) - project-specific config
44
+ * 3. Home directory (.maiass.env) - user global config
45
+ * 4. OS-specific config directory (maiass/config.env)
46
+ * 5. OS secure storage (keychain/secret-tool) - lowest priority, for sensitive vars
47
+ */
48
+ export function loadEnvironmentConfig() {
49
+ const paths = getConfigPaths();
50
+
51
+ const loadedFiles = [];
52
+
53
+ // Load files in priority order (lowest to highest priority)
54
+ const orderedFiles = [
55
+ path.join(paths.config, 'config.env'),
56
+ path.join(paths.home, '.maiass.env'),
57
+ path.resolve(process.cwd(), '.env.maiass'), // Project config
58
+ path.resolve(process.cwd(), '.env.maiass.local') // Highest priority - local overrides
59
+ ];
60
+
61
+ // Load all files except the last two without override
62
+ orderedFiles.slice(0, -2).forEach((envFile) => {
63
+ if (fs.existsSync(envFile)) {
64
+ try {
65
+ dotenv.config({ path: envFile });
66
+ loadedFiles.push(envFile);
67
+ } catch (error) {
68
+ console.warn(`Warning: Could not load ${envFile}:`, error.message);
69
+ }
70
+ }
71
+ });
72
+
73
+ // Load project .env.maiass with override
74
+ const projectEnv = orderedFiles[orderedFiles.length - 2];
75
+ if (fs.existsSync(projectEnv)) {
76
+ try {
77
+ dotenv.config({ path: projectEnv, override: true });
78
+ loadedFiles.push(projectEnv);
79
+ } catch (error) {
80
+ console.warn(`Warning: Could not load ${projectEnv}:`, error.message);
81
+ }
82
+ }
83
+
84
+ // Finally, load .env.maiass.local with override to ensure it takes highest precedence
85
+ const localEnv = orderedFiles[orderedFiles.length - 1];
86
+ if (fs.existsSync(localEnv)) {
87
+ try {
88
+ dotenv.config({ path: localEnv, override: true });
89
+ loadedFiles.push(localEnv);
90
+ } catch (error) {
91
+ console.warn(`Warning: Could not load ${localEnv}:`, error.message);
92
+ }
93
+ }
94
+
95
+ // NOW load secure variables after .env files are loaded
96
+ // This ensures MAIASS_AI_HOST is set before determining which keychain to use
97
+ loadSecureVariables();
98
+
99
+ // Return the environment variables along with metadata
100
+ return {
101
+ ...process.env,
102
+ _metadata: {
103
+ loadedFiles,
104
+ configPaths: paths
105
+ }
106
+ };
107
+ }
108
+
109
+ /**
110
+ * Ensure config directories exist
111
+ */
112
+ export function ensureConfigDirectories() {
113
+ const paths = getConfigPaths();
114
+
115
+ [paths.config, paths.data].forEach(dir => {
116
+ if (!fs.existsSync(dir)) {
117
+ try {
118
+ fs.mkdirSync(dir, { recursive: true });
119
+ } catch (error) {
120
+ console.warn(`Warning: Could not create config directory ${dir}:`, error.message);
121
+ }
122
+ }
123
+ });
124
+
125
+ return paths;
126
+ }
127
+
128
+ /**
129
+ * Get the recommended path for storing sensitive environment variables
130
+ */
131
+ export function getSecureEnvPath() {
132
+ const paths = getConfigPaths();
133
+ return path.join(paths.data, 'secure.env');
134
+ }
135
+
136
+ /**
137
+ * Get the recommended path for storing general config
138
+ */
139
+ export function getConfigEnvPath() {
140
+ const paths = getConfigPaths();
141
+ return path.join(paths.config, 'config.env');
142
+ }
143
+
144
+ export default {
145
+ loadEnvironmentConfig,
146
+ ensureConfigDirectories,
147
+ getSecureEnvPath,
148
+ getConfigEnvPath,
149
+ getConfigPaths
150
+ };
package/lib/devlog.js ADDED
@@ -0,0 +1,182 @@
1
+ // Development logging utility for MAIASS
2
+ // Node.js equivalent of the devlog.sh integration from maiass.sh
3
+ import { exec } from 'child_process';
4
+ import { existsSync } from 'fs';
5
+ import path from 'path';
6
+ import colors from './colors.js';
7
+ import { getGitInfo } from './git-info.js';
8
+ import { logger } from './logger.js';
9
+
10
+ /**
11
+ * Check if devlog.sh script exists and is executable
12
+ * @returns {boolean} True if devlog.sh is available
13
+ */
14
+ function isDevlogAvailable() {
15
+ // On Windows, devlog.sh is never available
16
+ if (process.platform === 'win32') {
17
+ return false;
18
+ }
19
+ // Check if devlog.sh exists in common locations (sync check for immediate availability)
20
+ const commonPaths = [
21
+ '/usr/local/bin/devlog.sh',
22
+ '/usr/bin/devlog.sh',
23
+ path.join(process.env.HOME || '', 'bin/devlog.sh'),
24
+ path.join(process.env.HOME || '', '.local/bin/devlog.sh')
25
+ ];
26
+ // Quick sync check for file existence
27
+ if (commonPaths.some(path => existsSync(path))) {
28
+ return true;
29
+ }
30
+ // For PATH check, we'll assume it's available and let the async call handle errors
31
+ return true;
32
+ }
33
+
34
+ /**
35
+ * Extract devlog context from gitInfo object
36
+ * @param {Object} gitInfo - Git information object
37
+ * @returns {Object} Context with project, client, and jiraTicket
38
+ */
39
+ function extractDevlogContext(gitInfo) {
40
+ const remote = gitInfo?.remote || {};
41
+ const project = remote.repo || process.env.MAIASS_DEVLOG_PROJECT || 'unknown-project';
42
+ const client = remote.owner || process.env.MAIASS_DEVLOG_CLIENT || 'unknown-client';
43
+ const jiraTicket = gitInfo?.jiraTicket || process.env.MAIASS_DEVLOG_JIRA_TICKET || 'no-ticket';
44
+
45
+ return { project, client, jiraTicket };
46
+ }
47
+
48
+ /**
49
+ * Log a message using devlog.sh (equivalent to logthis function in maiass.sh)
50
+ * @param {string} message - The message to log
51
+ * @param {Object} options - Logging options
52
+ * @param {string} options.project - Project name (from repo name)
53
+ * @param {string} options.client - Client name (from repo owner/workspace)
54
+ * @param {string} options.jiraTicket - JIRA ticket number (from branch or fallback)
55
+ * @param {string} options.type - Log type (default: c for commit)
56
+ * @returns {string|null} Debug message from devlog.sh or null if not available
57
+ */
58
+ export function logThis(message, options = {}) {
59
+ const {
60
+ project = process.env.MAIASS_DEVLOG_PROJECT || 'unknown-project',
61
+ client = process.env.MAIASS_DEVLOG_CLIENT || 'unknown-client',
62
+ jiraTicket = process.env.MAIASS_DEVLOG_JIRA_TICKET || 'no-ticket',
63
+ type = 'c'
64
+ } = options;
65
+
66
+ // If devlog.sh is not available, return null (equivalent to empty function in bash)
67
+ if (!isDevlogAvailable()) {
68
+ logger.debug(`devlog.sh not available, skipping log: ${message}`);
69
+ return null;
70
+ }
71
+
72
+ // If explicitly disabled, return null
73
+ if (process.env.MAIASS_DEVLOG_ENABLED === 'false') {
74
+ return null;
75
+ }
76
+
77
+ // Escape the message for shell execution
78
+ const escapedMessage = message.replace(/"/g, '\\"').replace(/\n/g, '; ');
79
+
80
+ // Execute devlog.sh with the same parameters as the bash version (async, non-blocking)
81
+ const command = `devlog.sh "${escapedMessage}" "?" "${project}" "${client}" "${jiraTicket}"`;
82
+
83
+ logger.debug(`Executing devlog.sh command: ${command}`);
84
+
85
+ // Execute asynchronously - don't block the main workflow (fire-and-forget)
86
+ exec(command, { encoding: 'utf8' }, (error, stdout, stderr) => {
87
+ if (error) {
88
+
89
+ if (process.env.MAIASS_DEBUG === 'true') {
90
+ logger.error(`devlog.sh error: ${error.message}`);
91
+ }
92
+ return;
93
+ }
94
+
95
+ // Only log success confirmation, not the verbose stdout output
96
+
97
+ logger.debug(`Logged to devlog.sh: ${escapedMessage}`) ;
98
+ });
99
+
100
+ // Return immediately (don't wait for devlog.sh to complete)
101
+ return null;
102
+ }
103
+
104
+ /**
105
+ * Log a commit message (specific use case from maiass.sh)
106
+ * @param {string} commitMessage - The commit message to log
107
+ * @param {Object} gitInfo - Git information object (already extracted)
108
+ * @returns {string|null} Debug message from devlog.sh
109
+ */
110
+ export function logCommit(commitMessage, gitInfo) {
111
+ // Clean up commit message (remove newlines, replace with semicolons)
112
+ const cleanMessage = commitMessage.replace(/\n/g, '; ');
113
+
114
+ // Extract context from already-available gitInfo
115
+ const context = extractDevlogContext(gitInfo);
116
+
117
+ const options = {
118
+ type: 'c', // 'c' for commit
119
+ project: context.project,
120
+ client: context.client,
121
+ jiraTicket: context.jiraTicket
122
+ };
123
+
124
+ return logThis(cleanMessage, options);
125
+ }
126
+
127
+ /**
128
+ * Log a merge operation (specific use case from maiass.sh)
129
+ * @param {string} sourceBranch - Source branch name
130
+ * @param {string} targetBranch - Target branch name
131
+ * @param {Object} gitInfo - Git information object (already extracted)
132
+ * @param {string} operation - Operation type (e.g., "Merged", "Created pull request")
133
+ * @returns {string|null} Debug message from devlog.sh
134
+ */
135
+ export function logMerge(sourceBranch, targetBranch, gitInfo, operation = 'Merged') {
136
+ const message = `${operation} ${sourceBranch} into ${targetBranch}`;
137
+
138
+ // Extract context from already-available gitInfo
139
+ const context = extractDevlogContext(gitInfo);
140
+
141
+ const options = {
142
+ type: 'c', // 'c' for commit/merge
143
+ project: context.project,
144
+ client: context.client,
145
+ jiraTicket: context.jiraTicket
146
+ };
147
+
148
+ return logThis(message, options);
149
+ }
150
+
151
+ /**
152
+ * Log a pull request creation
153
+ * @param {string} version - Version or branch name
154
+ * @returns {string|null} Debug message from devlog.sh
155
+ */
156
+ export function logPullRequest(version) {
157
+ const message = `Created pull request for ${version}`;
158
+ return logThis(message, { type: 'c' });
159
+ }
160
+
161
+ /**
162
+ * Check if devlog functionality is enabled
163
+ * @returns {boolean} True if devlog should be used
164
+ */
165
+ export function isDevlogEnabled() {
166
+ // Check if explicitly disabled
167
+ if (process.env.MAIASS_DEVLOG_ENABLED === 'false') {
168
+ return false;
169
+ }
170
+
171
+ // Check if devlog.sh is available
172
+ return isDevlogAvailable();
173
+ }
174
+
175
+ export default {
176
+ logThis,
177
+ logCommit,
178
+ logMerge,
179
+ logPullRequest,
180
+ isDevlogEnabled,
181
+ isDevlogAvailable
182
+ };
@@ -0,0 +1,162 @@
1
+ // Environment variable display utility for development and debugging
2
+ import colors from './colors.js';
3
+ import { getConfigPaths, loadEnvironmentConfig } from './config.js';
4
+ import { MAIASS_VARIABLES, getVariableSource } from './maiass-variables.js';
5
+ import { log, logger } from './logger.js';
6
+ import { SYMBOLS } from './symbols.js';
7
+ import fs from 'fs';
8
+ import path from 'path';
9
+
10
+ /**
11
+ * Display all environment variables with source information
12
+ * @param {Object} options - Display options
13
+ * @param {boolean} options.showSensitive - Whether to show sensitive variables (masked by default)
14
+ * @param {boolean} options.showSources - Whether to show which file each variable came from
15
+ * @param {boolean} options.showAll - Whether to show all process.env variables
16
+ */
17
+ export function displayEnvironmentVariables(options = {}) {
18
+ const {
19
+ showSensitive = false,
20
+ showSources = true,
21
+ showAll = false
22
+ } = options;
23
+
24
+ log.info(SYMBOLS.GLOBE, 'Environment Variables Status');
25
+ console.log();
26
+ console.log('═'.repeat(50));
27
+ console.log();
28
+
29
+ // Show configuration sources if requested
30
+ if (showSources) {
31
+ displayLoadedConfigFiles();
32
+ }
33
+
34
+ // Get loaded files info for source tracking
35
+ const envConfig = loadEnvironmentConfig();
36
+
37
+ // Display MAIASS-specific variables
38
+ if (showAll) {
39
+ displayAllEnvironmentVariables(showSensitive);
40
+ } else {
41
+ displayMaiassVariables(showSensitive, envConfig.loadedFiles);
42
+ }
43
+
44
+ console.log('═'.repeat(50));
45
+ log.success(SYMBOLS.CHECKMARK, 'Environment display complete');
46
+ log.space();
47
+ }
48
+
49
+ /**
50
+ * Display which config files were loaded
51
+ */
52
+ function displayLoadedConfigFiles() {
53
+ log.warning(SYMBOLS.FOLDER, 'Configuration Sources:');
54
+ console.log();
55
+
56
+ const paths = getConfigPaths();
57
+ const configFiles = [
58
+ { path: path.resolve(process.cwd(), '.env'), label: 'Project .env', priority: 1 },
59
+ { path: path.join(paths.home, '.maiass.env'), label: 'User .maiass.env', priority: 2 },
60
+ { path: path.join(paths.config, 'config.env'), label: 'OS Config', priority: 3 },
61
+ { path: path.join(paths.data, 'secure.env'), label: 'OS Secure', priority: 4 }
62
+ ];
63
+
64
+ configFiles.forEach(({ path: filePath, label, priority }) => {
65
+ const exists = fs.existsSync(filePath);
66
+ const status = exists ? colors.Green(SYMBOLS.CHECK + ' LOADED') : colors.Red(SYMBOLS.X + ' Not found');
67
+ console.log(` ${priority}. ${colors.BBlue(label.padEnd(20))} ${status}`);
68
+ if (exists) {
69
+ console.log(` ${colors.Cyan(filePath)}`);
70
+ }
71
+ });
72
+ }
73
+
74
+ /**
75
+ * Display MAIASS-specific environment variables with sources and defaults
76
+ */
77
+ function displayMaiassVariables(showSensitive, loadedFiles = []) {
78
+ log.warning(SYMBOLS.GEAR, 'MAIASS Variables:');
79
+ console.log();
80
+
81
+ // Get all defined MAIASS variables
82
+ const allVarKeys = Object.keys(MAIASS_VARIABLES).sort();
83
+
84
+ if (allVarKeys.length === 0) {
85
+ console.log(colors.Yellow(' No MAIASS variables defined'));
86
+ return;
87
+ }
88
+
89
+ allVarKeys.forEach(key => {
90
+ const varDef = MAIASS_VARIABLES[key];
91
+ const currentValue = process.env[key];
92
+ const isSensitive = varDef.sensitive || false;
93
+
94
+ let displayValue;
95
+ let source;
96
+
97
+ if (!currentValue) {
98
+ if (varDef.default) {
99
+ displayValue = colors.Cyan(`${varDef.default} (default)`);
100
+ source = colors.Yellow('default');
101
+ } else {
102
+ displayValue = colors.Red('(not set)');
103
+ source = colors.Red('not set');
104
+ }
105
+ } else {
106
+ if (isSensitive && !showSensitive) {
107
+ displayValue = colors.Yellow(`***${currentValue.slice(-4)} (masked)`);
108
+ } else {
109
+ displayValue = colors.Green(currentValue);
110
+ }
111
+ source = getVariableSource(key, currentValue, loadedFiles);
112
+ source = currentValue === varDef.default ? colors.Yellow('default') : colors.Green(source);
113
+ }
114
+
115
+ const keyColor = isSensitive ? colors.BRed : colors.BBlue;
116
+ console.log(` ${keyColor(key.padEnd(35))} = ${displayValue}`);
117
+ console.log(` ${' '.repeat(37)} ${colors.Cyan(SYMBOLS.ARROW)} ${source} ${colors.White('(' + varDef.description + ')')}`);
118
+ });
119
+ }
120
+
121
+ /**
122
+ * Display all MAIASS-related environment variables (filtered)
123
+ */
124
+ function displayAllEnvironmentVariables(showSensitive) {
125
+ log.warning(SYMBOLS.WRENCH, 'All MAIASS Environment Variables:');
126
+ console.log();
127
+
128
+ // Filter to only MAIASS_ prefixed variables
129
+ const allVars = Object.entries(process.env)
130
+ .filter(([key]) => key.startsWith('MAIASS_'))
131
+ .sort();
132
+
133
+ const sensitivePatterns = ['KEY', 'TOKEN', 'SECRET', 'PASSWORD', 'AUTH'];
134
+
135
+ if (allVars.length === 0) {
136
+ console.log(colors.Yellow(' No MAIASS-related environment variables found'));
137
+ return;
138
+ }
139
+
140
+ allVars.forEach(([key, value]) => {
141
+ const isSensitive = sensitivePatterns.some(pattern =>
142
+ key.toUpperCase().includes(pattern)
143
+ );
144
+
145
+ let displayValue;
146
+ if (isSensitive && !showSensitive) {
147
+ displayValue = colors.Yellow('*** (masked - use --show-sensitive)');
148
+ } else {
149
+ // Truncate very long values
150
+ displayValue = value.length > 100
151
+ ? colors.Cyan(value.slice(0, 100) + '...')
152
+ : colors.Cyan(value);
153
+ }
154
+
155
+ const keyColor = isSensitive ? colors.BRed : colors.Blue;
156
+ console.log(` ${keyColor(key.padEnd(30))} = ${displayValue}`);
157
+ });
158
+ }
159
+
160
+ export default {
161
+ displayEnvironmentVariables
162
+ };