@agile-vibe-coding/avc 0.1.0 → 0.1.1
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 +2 -0
- package/cli/agents/documentation.md +302 -0
- package/cli/build-docs.js +277 -0
- package/cli/command-logger.js +208 -0
- package/cli/index.js +3 -25
- package/cli/init.js +705 -77
- package/cli/llm-claude.js +27 -0
- package/cli/llm-gemini.js +30 -0
- package/cli/llm-provider.js +63 -0
- package/cli/logger.js +32 -5
- package/cli/process-manager.js +261 -0
- package/cli/repl-ink.js +1784 -219
- package/cli/template-processor.js +274 -73
- package/cli/templates/vitepress-config.mts.template +33 -0
- package/package.json +17 -3
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command Logger - Creates individual log files for each command execution
|
|
3
|
+
*
|
|
4
|
+
* Each command creates a timestamped log file in .avc/logs/ directory:
|
|
5
|
+
* - init-2026-01-31-13-05-23.log
|
|
6
|
+
* - sponsor-call-2026-01-31-13-10-45.log
|
|
7
|
+
* - status-2026-01-31-13-15-30.log
|
|
8
|
+
* - remove-2026-01-31-13-20-15.log
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import fs from 'fs';
|
|
12
|
+
import path from 'path';
|
|
13
|
+
|
|
14
|
+
class CommandLogger {
|
|
15
|
+
constructor(commandName, projectRoot = process.cwd()) {
|
|
16
|
+
this.commandName = commandName;
|
|
17
|
+
this.projectRoot = projectRoot;
|
|
18
|
+
this.logsDir = path.join(projectRoot, '.avc', 'logs');
|
|
19
|
+
|
|
20
|
+
// Create timestamp for this command execution
|
|
21
|
+
const now = new Date();
|
|
22
|
+
const timestamp = now.toISOString()
|
|
23
|
+
.replace(/T/, '-')
|
|
24
|
+
.replace(/:/g, '-')
|
|
25
|
+
.replace(/\..+/, '');
|
|
26
|
+
|
|
27
|
+
this.logFileName = `${commandName}-${timestamp}.log`;
|
|
28
|
+
this.logFilePath = path.join(this.logsDir, this.logFileName);
|
|
29
|
+
|
|
30
|
+
// Store original console methods
|
|
31
|
+
this.originalLog = console.log;
|
|
32
|
+
this.originalError = console.error;
|
|
33
|
+
this.originalWarn = console.warn;
|
|
34
|
+
this.originalInfo = console.info;
|
|
35
|
+
|
|
36
|
+
// Buffer for logs
|
|
37
|
+
this.logBuffer = [];
|
|
38
|
+
|
|
39
|
+
// Initialize log file
|
|
40
|
+
this.initializeLogFile();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Initialize log file and directory
|
|
45
|
+
*/
|
|
46
|
+
initializeLogFile() {
|
|
47
|
+
try {
|
|
48
|
+
// Create logs directory if it doesn't exist
|
|
49
|
+
if (!fs.existsSync(this.logsDir)) {
|
|
50
|
+
fs.mkdirSync(this.logsDir, { recursive: true });
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Write header to log file
|
|
54
|
+
const header = [
|
|
55
|
+
'='.repeat(80),
|
|
56
|
+
`AVC Command Log: ${this.commandName}`,
|
|
57
|
+
`Timestamp: ${new Date().toISOString()}`,
|
|
58
|
+
`Project: ${this.projectRoot}`,
|
|
59
|
+
`Log File: ${this.logFileName}`,
|
|
60
|
+
'='.repeat(80),
|
|
61
|
+
''
|
|
62
|
+
].join('\n');
|
|
63
|
+
|
|
64
|
+
fs.writeFileSync(this.logFilePath, header, 'utf8');
|
|
65
|
+
} catch (error) {
|
|
66
|
+
// If we can't create the log file, just continue without logging
|
|
67
|
+
this.logFilePath = null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Write a log entry to the file
|
|
73
|
+
*/
|
|
74
|
+
writeLog(level, ...args) {
|
|
75
|
+
if (!this.logFilePath) return;
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
const timestamp = new Date().toISOString();
|
|
79
|
+
const message = args.map(arg => {
|
|
80
|
+
if (typeof arg === 'object') {
|
|
81
|
+
return JSON.stringify(arg, null, 2);
|
|
82
|
+
}
|
|
83
|
+
return String(arg);
|
|
84
|
+
}).join(' ');
|
|
85
|
+
|
|
86
|
+
const logEntry = `[${timestamp}] [${level}] ${message}\n`;
|
|
87
|
+
|
|
88
|
+
fs.appendFileSync(this.logFilePath, logEntry, 'utf8');
|
|
89
|
+
} catch (error) {
|
|
90
|
+
// Silently fail if we can't write to log
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Start capturing console output
|
|
96
|
+
*/
|
|
97
|
+
start() {
|
|
98
|
+
// Intercept console.log
|
|
99
|
+
console.log = (...args) => {
|
|
100
|
+
this.writeLog('INFO', ...args);
|
|
101
|
+
this.originalLog(...args); // Still output to console
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// Intercept console.error
|
|
105
|
+
console.error = (...args) => {
|
|
106
|
+
this.writeLog('ERROR', ...args);
|
|
107
|
+
this.originalError(...args);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// Intercept console.warn
|
|
111
|
+
console.warn = (...args) => {
|
|
112
|
+
this.writeLog('WARN', ...args);
|
|
113
|
+
this.originalWarn(...args);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// Intercept console.info
|
|
117
|
+
console.info = (...args) => {
|
|
118
|
+
this.writeLog('INFO', ...args);
|
|
119
|
+
this.originalInfo(...args);
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Stop capturing console output and write footer
|
|
125
|
+
*/
|
|
126
|
+
stop() {
|
|
127
|
+
// Restore original console methods
|
|
128
|
+
console.log = this.originalLog;
|
|
129
|
+
console.error = this.originalError;
|
|
130
|
+
console.warn = this.originalWarn;
|
|
131
|
+
console.info = this.originalInfo;
|
|
132
|
+
|
|
133
|
+
// Write footer
|
|
134
|
+
if (this.logFilePath) {
|
|
135
|
+
try {
|
|
136
|
+
const footer = [
|
|
137
|
+
'',
|
|
138
|
+
'='.repeat(80),
|
|
139
|
+
`Command completed: ${new Date().toISOString()}`,
|
|
140
|
+
`Log saved: ${this.logFilePath}`,
|
|
141
|
+
'='.repeat(80)
|
|
142
|
+
].join('\n');
|
|
143
|
+
|
|
144
|
+
fs.appendFileSync(this.logFilePath, footer, 'utf8');
|
|
145
|
+
} catch (error) {
|
|
146
|
+
// Silently fail
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Get the path to the log file
|
|
153
|
+
*/
|
|
154
|
+
getLogPath() {
|
|
155
|
+
return this.logFilePath;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Clean up old log files (keep last N logs per command)
|
|
160
|
+
*/
|
|
161
|
+
static cleanupOldLogs(projectRoot = process.cwd(), keepCount = 10) {
|
|
162
|
+
const logsDir = path.join(projectRoot, '.avc', 'logs');
|
|
163
|
+
|
|
164
|
+
if (!fs.existsSync(logsDir)) return;
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
const files = fs.readdirSync(logsDir);
|
|
168
|
+
|
|
169
|
+
// Group files by command name
|
|
170
|
+
const filesByCommand = {};
|
|
171
|
+
files.forEach(file => {
|
|
172
|
+
if (!file.endsWith('.log')) return;
|
|
173
|
+
|
|
174
|
+
const commandName = file.split('-')[0];
|
|
175
|
+
if (!filesByCommand[commandName]) {
|
|
176
|
+
filesByCommand[commandName] = [];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
filesByCommand[commandName].push({
|
|
180
|
+
name: file,
|
|
181
|
+
path: path.join(logsDir, file),
|
|
182
|
+
mtime: fs.statSync(path.join(logsDir, file)).mtime
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// For each command, keep only the latest N files
|
|
187
|
+
Object.keys(filesByCommand).forEach(commandName => {
|
|
188
|
+
const files = filesByCommand[commandName];
|
|
189
|
+
|
|
190
|
+
// Sort by modification time (newest first)
|
|
191
|
+
files.sort((a, b) => b.mtime - a.mtime);
|
|
192
|
+
|
|
193
|
+
// Delete old files
|
|
194
|
+
files.slice(keepCount).forEach(file => {
|
|
195
|
+
try {
|
|
196
|
+
fs.unlinkSync(file.path);
|
|
197
|
+
} catch (error) {
|
|
198
|
+
// Ignore deletion errors
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
} catch (error) {
|
|
203
|
+
// Silently fail
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export { CommandLogger };
|
package/cli/index.js
CHANGED
|
@@ -1,28 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { startRepl
|
|
3
|
+
import { startRepl } from './repl-ink.js';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*
|
|
8
|
-
* Supports both interactive REPL mode and direct command execution
|
|
9
|
-
*
|
|
10
|
-
* Usage:
|
|
11
|
-
* avc - Start interactive REPL
|
|
12
|
-
* avc help - Show help and exit
|
|
13
|
-
* avc init - Run init command and exit
|
|
14
|
-
* avc status - Run status command and exit
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
const args = process.argv.slice(2);
|
|
18
|
-
|
|
19
|
-
if (args.length === 0) {
|
|
20
|
-
// No arguments - start interactive REPL
|
|
21
|
-
startRepl();
|
|
22
|
-
} else {
|
|
23
|
-
// Command provided - execute non-interactively
|
|
24
|
-
const command = args[0].startsWith('/') ? args[0] : `/${args[0]}`;
|
|
25
|
-
executeCommand(command).catch(() => {
|
|
26
|
-
process.exit(1);
|
|
27
|
-
});
|
|
28
|
-
}
|
|
5
|
+
// Always start interactive REPL — commands are only available inside it.
|
|
6
|
+
startRepl();
|