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,116 @@
1
+ import { createInterface } from 'readline';
2
+ import colors from './colors.js';
3
+
4
+ /**
5
+ * Format a user input prompt with distinct visual styling
6
+ * @param {string} message - The prompt message
7
+ * @returns {string} Formatted prompt
8
+ */
9
+ function formatPrompt(message) {
10
+ // Format: |)) ? message (bold yellow for calls to action)
11
+ return `\n${colors.BSoftPink('|))')} ${colors.BBlueOnWhite(' ? ')} ${colors.BYellow(message)}`;
12
+ }
13
+
14
+ /**
15
+ * Get single character input from user
16
+ * @param {string} prompt - Prompt message to display
17
+ * @returns {Promise<string>} Single character input
18
+ */
19
+ export function getSingleCharInput(prompt) {
20
+ return new Promise((resolve) => {
21
+ // Use formatted prompt for better visibility
22
+ process.stdout.write(formatPrompt(prompt));
23
+
24
+ // Store original state
25
+ const wasRawMode = process.stdin.isRaw;
26
+
27
+ // Set raw mode to capture single characters
28
+ process.stdin.setRawMode(true);
29
+ process.stdin.resume();
30
+
31
+ const onData = (key) => {
32
+ // Handle Ctrl+C
33
+ if (key[0] === 3) {
34
+ console.log('\n');
35
+ process.exit(0);
36
+ }
37
+
38
+ // Get only the first character and convert to lowercase
39
+ const char = key.toString().charAt(0).toLowerCase();
40
+
41
+ // Echo the character and newline
42
+ process.stdout.write(char + '\n');
43
+
44
+ // Clean up
45
+ process.stdin.removeListener('data', onData);
46
+ process.stdin.setRawMode(wasRawMode);
47
+ process.stdin.pause();
48
+
49
+ resolve(char);
50
+ };
51
+
52
+ process.stdin.on('data', onData);
53
+ });
54
+ }
55
+
56
+ /**
57
+ * Get multi-line input from user
58
+ * @param {string} prompt - Prompt message to display
59
+ * @returns {Promise<string>} Multi-line input
60
+ */
61
+ export function getMultiLineInput(prompt) {
62
+ return new Promise((resolve) => {
63
+ const rl = createInterface({
64
+ input: process.stdin,
65
+ output: process.stdout
66
+ });
67
+
68
+ console.log(formatPrompt(prompt));
69
+
70
+ const lines = [];
71
+ let emptyLineCount = 0;
72
+
73
+ rl.on('line', (line) => {
74
+ if (line.trim() === '') {
75
+ emptyLineCount++;
76
+ if (emptyLineCount >= 3) {
77
+ rl.close();
78
+ resolve(lines.join('\n').trim());
79
+ return;
80
+ }
81
+ } else {
82
+ emptyLineCount = 0;
83
+ lines.push(line);
84
+ }
85
+ });
86
+
87
+ rl.on('SIGINT', () => {
88
+ console.log('\n');
89
+ process.exit(0);
90
+ });
91
+ });
92
+ }
93
+
94
+ /**
95
+ * Get simple line input from user
96
+ * @param {string} prompt - Prompt message to display
97
+ * @returns {Promise<string>} Single line input
98
+ */
99
+ export function getLineInput(prompt) {
100
+ return new Promise((resolve) => {
101
+ const rl = createInterface({
102
+ input: process.stdin,
103
+ output: process.stdout
104
+ });
105
+
106
+ rl.question(formatPrompt(prompt), (answer) => {
107
+ rl.close();
108
+ resolve(answer.trim());
109
+ });
110
+
111
+ rl.on('SIGINT', () => {
112
+ console.log('\n');
113
+ process.exit(0);
114
+ });
115
+ });
116
+ }
package/lib/logger.js ADDED
@@ -0,0 +1,285 @@
1
+ // Centralized logger for MAIASS CLI with consistent branding
2
+ import colors from './colors.js';
3
+ import chalk from 'chalk';
4
+ import fs from 'fs';
5
+ import path from 'path';
6
+ import os from 'os';
7
+
8
+ // Store environment variables
9
+ let env = {};
10
+
11
+ // Debug collection system
12
+ let debugBuffer = [];
13
+ let sessionId = null;
14
+
15
+ /**
16
+ * Initialize debug collection session
17
+ */
18
+ function initDebugSession() {
19
+ sessionId = `maiass-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
20
+ debugBuffer = [];
21
+ }
22
+
23
+ /**
24
+ * Add entry to debug buffer
25
+ * @param {string} level - Log level
26
+ * @param {string} message - Log message
27
+ * @param {Object} metadata - Additional metadata
28
+ */
29
+ function addToDebugBuffer(level, message, metadata = {}) {
30
+ if (!sessionId) initDebugSession();
31
+
32
+ debugBuffer.push({
33
+ timestamp: new Date().toISOString(),
34
+ level,
35
+ message,
36
+ ...metadata
37
+ });
38
+ }
39
+
40
+ /**
41
+ * Write debug buffer to temporary file
42
+ * @returns {string} Path to debug file
43
+ */
44
+ export function writeDebugFile() {
45
+ if (!sessionId || debugBuffer.length === 0) return null;
46
+
47
+ try {
48
+ const tempDir = os.tmpdir();
49
+ const debugFile = path.join(tempDir, `${sessionId}.debug.log`);
50
+
51
+ const debugContent = debugBuffer
52
+ .map(entry => `[${entry.timestamp}] ${entry.level.toUpperCase()}: ${entry.message}`)
53
+ .join('\n');
54
+
55
+ fs.writeFileSync(debugFile, debugContent, 'utf8');
56
+ return debugFile;
57
+ } catch (error) {
58
+ console.error('Failed to write debug file:', error.message);
59
+ return null;
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Get current debug session info
65
+ * @returns {Object} Session info
66
+ */
67
+ export function getDebugSession() {
68
+ return {
69
+ sessionId,
70
+ entryCount: debugBuffer.length,
71
+ hasErrors: debugBuffer.some(entry => entry.level === 'error')
72
+ };
73
+ }
74
+
75
+ /**
76
+ * Initialize logger with environment variables
77
+ * @param {Object} environment - Environment variables
78
+ */
79
+ export function initLogger(environment) {
80
+ env = { ...environment };
81
+ }
82
+
83
+ /**
84
+ * Check if message should be shown based on verbosity level
85
+ * @param {string} level - Message level: 'error', 'warning', 'info', 'debug', 'critical', 'prompt'
86
+ * @returns {boolean} - Whether to show the message
87
+ */
88
+ function shouldLog(level) {
89
+ const verbosity = env.MAIASS_VERBOSITY || process.env.MAIASS_VERBOSITY || 'brief';
90
+
91
+ // Always show errors, prompts, and critical messages
92
+ if (['error', 'critical', 'prompt'].includes(level)) return true;
93
+
94
+ // For brief: only errors, critical messages, prompts, final results, and important warnings
95
+ if (verbosity === 'brief') {
96
+ return ['error', 'critical', 'prompt', 'success', 'warning'].includes(level);
97
+ }
98
+
99
+ // For normal: errors, warnings, success, and important info
100
+ if (verbosity === 'normal') {
101
+ return ['error', 'warning', 'success', 'info', 'critical', 'prompt'].includes(level);
102
+ }
103
+
104
+ // For verbose/debug: show everything
105
+ if (verbosity === 'verbose' || verbosity === 'debug') {
106
+ return true;
107
+ }
108
+
109
+ return false;
110
+ }
111
+
112
+ // Bold soft pink prefix for MAIASS branding
113
+ const MAIASS_PREFIX = colors.BSoftPink('|))');
114
+
115
+ export const log = {
116
+ logThis: (prefix, icon, message) => {
117
+ // Format: |)) icon message (prefix always first)
118
+ const prefixPart = prefix ? `${prefix} ` : '';
119
+ const iconPart = icon ? `${icon} ` : '';
120
+ console.log(`${prefixPart}${iconPart}${message}`);
121
+ addToDebugBuffer('info', `${icon} ${message}`);
122
+ },
123
+
124
+ // Main branded message types with icons
125
+ info: (icon, message, bold=false) => {
126
+ if (!shouldLog('info')) return;
127
+ log.logThis(MAIASS_PREFIX, colors.BCyan(icon), bold?colors.BCyan(message):colors.Cyan(message));
128
+ },
129
+
130
+ success: (icon, message, bold=false) => {
131
+ if (!shouldLog('success')) return;
132
+ log.logThis(MAIASS_PREFIX, colors.BGreen(icon), bold?colors.BGreen(message):colors.Green(message));
133
+ },
134
+
135
+ aisuggestion: (icon, message, bold=true) => {
136
+ if (!shouldLog('prompt')) return;
137
+ log.logThis('', colors.BYellowBright(icon), bold?colors.BYellowBright(message):colors.BYellowBright(message));
138
+ },
139
+
140
+ warning: (icon, message, bold=false) => {
141
+ if (!shouldLog('warning')) return;
142
+ log.logThis(MAIASS_PREFIX, colors.BOrange(icon), bold?colors.BOrange(message):colors.Orange(message));
143
+ },
144
+
145
+ error: (icon, message, bold=false) => {
146
+ const msg = bold ? colors.BRed(message) : colors.Red(message);
147
+ const fullMessage = `${MAIASS_PREFIX} ${colors.BRed(icon)} ${msg}`;
148
+ console.error(fullMessage);
149
+ addToDebugBuffer('error', `${icon} ${message}`);
150
+ },
151
+
152
+ blue: (icon, message, bold=false) => {
153
+ if (!shouldLog('info')) return;
154
+ log.logThis(MAIASS_PREFIX, colors.BBlue(icon), bold?colors.BBlue(message):colors.Blue(message));
155
+ },
156
+
157
+ purple: (icon, message, bold=false) => {
158
+ if (!shouldLog('info')) return;
159
+ log.logThis(MAIASS_PREFIX, colors.BPurple(icon), bold?colors.BPurple(message):colors.Purple(message));
160
+ },
161
+
162
+ BWhite: (icon, message, bold=false) => {
163
+ if (!shouldLog('info')) return;
164
+ log.logThis(MAIASS_PREFIX, colors.BWhite(icon), bold?colors.BWhite(message):colors.White(message));
165
+ },
166
+
167
+ blueOnWhite: (icon, message, bold=false) => {
168
+ if (!shouldLog('info')) return;
169
+ log.logThis(MAIASS_PREFIX, colors.BBlueOnWhite(icon), bold?colors.BBlueOnWhite(message):colors.BlueOnWhite(message));
170
+ },
171
+
172
+ // Custom color variants
173
+ custom: (icon, message, colorFn) => {
174
+ if (!shouldLog('info')) return;
175
+ log.logThis(MAIASS_PREFIX, colorFn(icon), colorFn(message));
176
+ },
177
+
178
+ // Plain messages without icons (for indented content, spacing, etc.)
179
+ plain: (message) => {
180
+ if (!shouldLog('info')) return;
181
+ console.log(message);
182
+ },
183
+
184
+ // Branded plain message (no icon, but with | )) prefix)
185
+ branded: (message, colorFn = colors.White) => {
186
+ if (!shouldLog('info')) return;
187
+ console.log(`${MAIASS_PREFIX} ${colorFn(message)}`);
188
+ },
189
+
190
+ // Empty line
191
+ space: () => {
192
+ if (!shouldLog('info')) return;
193
+ console.log();
194
+ },
195
+
196
+ // Indented content (for sub-items under main messages)
197
+ indent: (message, colorFn = colors.Gray) => {
198
+ if (!shouldLog('info')) return;
199
+ console.log(` ${colorFn(message)}`);
200
+ },
201
+
202
+ // Critical messages that should always show regardless of verbosity
203
+ critical: (icon, message, bold=false) => {
204
+ log.logThis(MAIASS_PREFIX, colors.BCyan(icon), bold?colors.BCyan(message):colors.Cyan(message));
205
+ },
206
+
207
+ // User prompts that should always show
208
+ prompt: (message, colorFn = colors.White) => {
209
+ console.log(colorFn(message));
210
+ },
211
+
212
+ // debug message (with MAIASS branding)
213
+ debug: (label, data) => {
214
+ const debugEnabled = env.MAIASS_DEBUG === 'true' || env.MAIASS_DEBUG === true ||
215
+ process.env.MAIASS_DEBUG === 'true' || process.env.MAIASS_DEBUG === true;
216
+ if (!debugEnabled) return;
217
+
218
+ const timestamp = new Date().toISOString();
219
+ const debugPrefix = colors.Blue('🐛 |)) ');
220
+ const timestampStr = colors.Gray(`[${timestamp}]`);
221
+
222
+ // Ensure we're writing to stderr to avoid mixing with other output
223
+ const output = process.stderr;
224
+
225
+ // Write the debug message header
226
+ output.write(`${debugPrefix} ${timestampStr} ${colors.Blue(label)}\n`);
227
+
228
+ // If we have data, pretty-print it with 2-space indentation
229
+ if (data !== undefined) {
230
+ const jsonStr = typeof data === 'string' ? data : JSON.stringify(data, null, 2);
231
+ // Split into lines and indent each line
232
+ const lines = jsonStr.split('\n');
233
+ for (const line of lines) {
234
+ output.write(` ${colors.Gray(line)}\n`);
235
+ }
236
+ }
237
+
238
+ // Ensure everything is flushed
239
+ output.write('');
240
+ },
241
+
242
+ // Indented with arrow (for config values, etc.)
243
+ indentArrow: (message, colorFn = colors.Gray) => {
244
+ if (!shouldLog('info')) return;
245
+ console.log(` ${colorFn('→')} ${colorFn(message)}`);
246
+ }
247
+
248
+ };
249
+
250
+ // Convenience methods for common patterns
251
+ export const logger = {
252
+ ...log,
253
+
254
+ // Common CLI patterns
255
+ header: (icon, title) => {
256
+ log.info(icon, title);
257
+ log.space();
258
+ },
259
+
260
+ section: (title, colorFn = colors.BBlue) => {
261
+ log.custom('📁', title, colorFn);
262
+ log.space();
263
+ },
264
+
265
+ configItem: (key, value, source = '', description = '') => {
266
+ const keyColor = colors.BWhite;
267
+ const valueColor = colors.White;
268
+ const sourceColor = colors.Gray;
269
+
270
+ log.plain(` ${keyColor(key.padEnd(25))} = ${valueColor(value)}`);
271
+ if (source) {
272
+ log.plain(` ${' '.repeat(25)} ${sourceColor(`→ ${source}`)} ${colors.Gray(`(${description})`)}`);
273
+ }
274
+ log.space();
275
+ },
276
+
277
+ usage: (examples) => {
278
+ log.blue('ℹ️', 'Usage examples:');
279
+ examples.forEach(example => {
280
+ log.plain(` ${example}`);
281
+ });
282
+ }
283
+ };
284
+
285
+ export default logger;
@@ -0,0 +1,229 @@
1
+ // Machine fingerprinting for abuse prevention
2
+ // Generates stable device identifiers using hardware characteristics
3
+ // Matches bashmaiass implementation: MAC|CPU|Disk|Kernel → SHA-256 hex
4
+
5
+ import os from 'os';
6
+ import crypto from 'crypto';
7
+ import { execSync } from 'child_process';
8
+ import { logger } from './logger.js';
9
+
10
+ /**
11
+ * Get MAC address for fingerprinting
12
+ * @returns {string} MAC address of primary network interface
13
+ */
14
+ function getMacAddress() {
15
+ try {
16
+ const platform = os.platform();
17
+
18
+ if (platform === 'linux') {
19
+ // Use ip command on Linux
20
+ const result = execSync('ip link | awk \'/ether/ {print $2; exit}\'',
21
+ { encoding: 'utf8', timeout: 3000 }).trim();
22
+ if (result && result !== '') {
23
+ return result;
24
+ }
25
+ } else if (platform === 'darwin') {
26
+ // macOS - match bashmaiass exactly
27
+ const result = execSync('networksetup -listallhardwareports | awk \'/Wi-Fi|Ethernet/{getline; print $2; exit}\'',
28
+ { encoding: 'utf8', timeout: 3000 }).trim();
29
+ if (result && result !== '') {
30
+ return result;
31
+ }
32
+ }
33
+
34
+ // Fallback: try to get from network interfaces
35
+ const interfaces = os.networkInterfaces();
36
+ for (const name of Object.keys(interfaces)) {
37
+ const iface = interfaces[name];
38
+ if (iface) {
39
+ for (const alias of iface) {
40
+ if (!alias.internal && alias.mac && alias.mac !== '00:00:00:00:00:00') {
41
+ return alias.mac;
42
+ }
43
+ }
44
+ }
45
+ }
46
+ } catch (error) {
47
+ logger.debug('Could not get MAC address:', error.message);
48
+ }
49
+ return 'unknown-mac';
50
+ }
51
+
52
+ /**
53
+ * Get CPU information for fingerprinting
54
+ * @returns {string} CPU brand string
55
+ */
56
+ function getCpuInfo() {
57
+ try {
58
+ const platform = os.platform();
59
+
60
+ if (platform === 'darwin') {
61
+ // Use sysctl on macOS to match bashmaiass
62
+ const result = execSync('sysctl -n machdep.cpu.brand_string',
63
+ { encoding: 'utf8', timeout: 3000 }).trim();
64
+ if (result && result !== '') {
65
+ return result;
66
+ }
67
+ } else if (platform === 'linux') {
68
+ // Use /proc/cpuinfo on Linux
69
+ const result = execSync('grep -m1 "model name" /proc/cpuinfo | cut -d ":" -f 2 | xargs',
70
+ { encoding: 'utf8', timeout: 3000 }).trim();
71
+ if (result && result !== '') {
72
+ return result;
73
+ }
74
+ }
75
+
76
+ // Fallback to Node.js os.cpus()
77
+ const cpus = os.cpus();
78
+ if (cpus && cpus.length > 0) {
79
+ return cpus[0].model;
80
+ }
81
+ } catch (error) {
82
+ logger.debug('Could not get CPU info:', error.message);
83
+ }
84
+ return 'unknown-cpu';
85
+ }
86
+
87
+ /**
88
+ * Get disk identifier for fingerprinting
89
+ * @returns {string} Disk/volume identifier
90
+ */
91
+ function getDiskIdentifier() {
92
+ try {
93
+ const platform = os.platform();
94
+
95
+ if (platform === 'darwin') {
96
+ // Get volume UUID on macOS - match bashmaiass exactly
97
+ const result = execSync('diskutil info / | grep "Volume UUID" | awk \'{print $3}\'',
98
+ { encoding: 'utf8', timeout: 3000 }).trim();
99
+ if (result && result !== '') {
100
+ return result;
101
+ }
102
+ } else if (platform === 'linux') {
103
+ // Get disk serial on Linux
104
+ const rootDisk = execSync('df / | tail -1 | awk \'{print $1}\' | sed \'s/[0-9]*$//\'',
105
+ { encoding: 'utf8', timeout: 3000 }).trim();
106
+ if (rootDisk) {
107
+ const serial = execSync(`lsblk -no SERIAL "${rootDisk}" 2>/dev/null || echo "unknown-serial"`,
108
+ { encoding: 'utf8', timeout: 3000 }).trim();
109
+ if (serial && serial !== '') {
110
+ return serial;
111
+ }
112
+ }
113
+ }
114
+ } catch (error) {
115
+ logger.debug('Could not get disk identifier:', error.message);
116
+ }
117
+ return 'unknown-disk';
118
+ }
119
+
120
+ /**
121
+ * Get kernel information for fingerprinting
122
+ * @returns {string} Kernel info (system, release, machine)
123
+ */
124
+ function getKernelInfo() {
125
+ try {
126
+ // Use uname -srm to match bashmaiass
127
+ const result = execSync('uname -srm',
128
+ { encoding: 'utf8', timeout: 3000 }).trim();
129
+ if (result && result !== '') {
130
+ return result;
131
+ }
132
+ } catch (error) {
133
+ logger.debug('Could not get kernel info:', error.message);
134
+ }
135
+
136
+ // Fallback using Node.js os module
137
+ return `${os.type()} ${os.release()} ${os.arch()}`;
138
+ }
139
+
140
+ /**
141
+ * Generate a stable machine fingerprint for abuse prevention - V1 (LEGACY)
142
+ * Algorithm: MAC|CPU|Disk|Kernel → SHA-256 hex
143
+ * WARNING: Includes kernel version which changes on OS updates
144
+ * @returns {string} SHA-256 hex fingerprint hash
145
+ * @deprecated Use generateMachineFingerprint() (V2) instead
146
+ */
147
+ export function generateMachineFingerprintV1() {
148
+ try {
149
+ const mac = getMacAddress();
150
+ const cpu = getCpuInfo();
151
+ const disk = getDiskIdentifier();
152
+ const kernel = getKernelInfo();
153
+
154
+ // V1: Includes kernel (causes issues on OS updates)
155
+ const fingerprintInput = `${mac}|${cpu}|${disk}|${kernel}`;
156
+
157
+ const hash = crypto.createHash('sha256').update(fingerprintInput).digest('hex');
158
+
159
+ logger.debug('Machine fingerprint V1 components:', {
160
+ mac: mac,
161
+ cpu: cpu,
162
+ disk: disk,
163
+ kernel: kernel,
164
+ input: fingerprintInput
165
+ });
166
+
167
+ return hash;
168
+ } catch (error) {
169
+ logger.error('Failed to generate machine fingerprint V1:', error.message);
170
+ const fallback = `${os.platform()}-${os.arch()}-${os.userInfo().username}-FALLBACK`;
171
+ return crypto.createHash('sha256').update(fallback).digest('hex');
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Generate a stable machine fingerprint for abuse prevention - V2 (CURRENT)
177
+ * Algorithm: MAC|CPU|Disk → SHA-256 hex (hardware-only, no kernel)
178
+ * This version excludes kernel to prevent fingerprint changes on OS updates
179
+ * Matches bashmaiass V2 implementation
180
+ * @returns {string} SHA-256 hex fingerprint hash
181
+ */
182
+ export function generateMachineFingerprint() {
183
+ try {
184
+ // Get hardware components only (no kernel)
185
+ const mac = getMacAddress();
186
+ const cpu = getCpuInfo();
187
+ const disk = getDiskIdentifier();
188
+
189
+ // V2: Hardware-only (no kernel version)
190
+ // This prevents fingerprint changes on OS updates
191
+ const fingerprintInput = `${mac}|${cpu}|${disk}`;
192
+
193
+ // Generate SHA-256 hash in hex format to match bashmaiass
194
+ const hash = crypto.createHash('sha256').update(fingerprintInput).digest('hex');
195
+
196
+ logger.debug('Machine fingerprint V2 components:', {
197
+ mac: mac,
198
+ cpu: cpu,
199
+ disk: disk,
200
+ input: fingerprintInput,
201
+ version: 'V2 (hardware-only)'
202
+ });
203
+
204
+ return hash;
205
+ } catch (error) {
206
+ logger.error('Failed to generate machine fingerprint V2:', error.message);
207
+ logger.warn('SECURITY WARNING: Using minimal fallback fingerprint');
208
+ const fallback = `${os.platform()}-${os.arch()}-${os.userInfo().username}-FALLBACK`;
209
+ return crypto.createHash('sha256').update(fallback).digest('hex');
210
+ }
211
+ }
212
+
213
+ /**
214
+ * Get a shortened machine fingerprint for display/logging
215
+ * @returns {string} First 12 characters of the fingerprint
216
+ */
217
+ export function getShortFingerprint() {
218
+ return generateMachineFingerprint().substring(0, 12);
219
+ }
220
+
221
+ /**
222
+ * Validate that the current machine fingerprint matches a stored one
223
+ * @param {string} storedFingerprint - Previously stored fingerprint
224
+ * @returns {boolean} True if fingerprints match
225
+ */
226
+ export function validateMachineFingerprint(storedFingerprint) {
227
+ const currentFingerprint = generateMachineFingerprint();
228
+ return currentFingerprint === storedFingerprint;
229
+ }
@@ -0,0 +1,79 @@
1
+ import { log, logger } from './logger.js';
2
+ import { SYMBOLS } from './symbols.js';
3
+ import { runMaiassPipeline } from './maiass-pipeline.js';
4
+ import colors from './colors.js';
5
+
6
+ /**
7
+ * Handle the main MAIASS command
8
+ * @param {Object} args - Command arguments from yargs
9
+ */
10
+ export async function handleMaiassCommand(args) {
11
+ const {
12
+ _: positionalArgs,
13
+ 'commits-only': commitsOnly,
14
+ 'auto-stage': autoStage,
15
+ 'version-bump': versionBump,
16
+ 'dry-run': dryRun,
17
+ tag,
18
+ force,
19
+ silent
20
+ } = args;
21
+
22
+ // Extract version bump from positional arguments if provided
23
+ let bumpType = versionBump;
24
+ if (positionalArgs.length > 0 && !bumpType) {
25
+ bumpType = positionalArgs[0];
26
+ }
27
+
28
+ // Default to 'patch' if no version bump specified and not commits-only
29
+ if (!bumpType && !commitsOnly) {
30
+ bumpType = 'patch';
31
+ }
32
+
33
+ logger.header('', 'MAIASS - Modular AI-Assisted Semantic Scribe');
34
+
35
+ try {
36
+ // Run the complete MAIASS pipeline
37
+ const result = await runMaiassPipeline({
38
+ commitsOnly,
39
+ autoStage,
40
+ versionBump: bumpType,
41
+ dryRun,
42
+ tag,
43
+ force,
44
+ silent
45
+ });
46
+
47
+ if (result.success) {
48
+ // Success message already shown in pipeline
49
+
50
+ // Display summary if not commits-only
51
+ if (!commitsOnly && result.versionResult && !result.versionResult.skipped) {
52
+ log.space();
53
+ log.info(SYMBOLS.INFO, 'Workflow Summary:');
54
+ log.indent(`${colors.Gray('Phase:')} ${colors.White('Complete Pipeline')}`);
55
+ if (result.versionResult.bumpType) {
56
+ log.indent(`${colors.Gray('Version Bump:')} ${colors.White(result.versionResult.bumpType)}`);
57
+ }
58
+ if (result.mergeResult && result.mergeResult.merged) {
59
+ log.indent(`${colors.Gray('Merge:')} ${colors.White('Completed')}`);
60
+ }
61
+ }
62
+
63
+ log.space();
64
+ log.blue(SYMBOLS.INFO, 'Thank you for using MAIASS!');
65
+ } else if (result.cancelled) {
66
+ log.warning(SYMBOLS.INFO, 'Workflow cancelled by user');
67
+ } else {
68
+ console.error(colors.Red(`${SYMBOLS.CROSS} Workflow failed: ${result.error || 'Unknown error'}`));
69
+ process.exit(1);
70
+ }
71
+
72
+ } catch (error) {
73
+ console.error(colors.Red(`${SYMBOLS.CROSS} MAIASS command failed: ${error.message}`));
74
+ if (process.env.MAIASS_DEBUG === 'true') {
75
+ console.error(colors.Gray(error.stack));
76
+ }
77
+ process.exit(1);
78
+ }
79
+ }