ccmanager 2.11.5 → 3.0.0

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.
Files changed (34) hide show
  1. package/dist/components/Configuration.js +14 -0
  2. package/dist/components/ConfigureCustomCommand.d.ts +9 -0
  3. package/dist/components/ConfigureCustomCommand.js +44 -0
  4. package/dist/components/ConfigureOther.d.ts +6 -0
  5. package/dist/components/ConfigureOther.js +87 -0
  6. package/dist/components/ConfigureOther.test.d.ts +1 -0
  7. package/dist/components/ConfigureOther.test.js +80 -0
  8. package/dist/components/ConfigureStatusHooks.js +7 -1
  9. package/dist/components/CustomCommandSummary.d.ts +6 -0
  10. package/dist/components/CustomCommandSummary.js +10 -0
  11. package/dist/components/Menu.recent-projects.test.js +2 -0
  12. package/dist/components/Menu.test.js +2 -0
  13. package/dist/components/Session.d.ts +2 -2
  14. package/dist/components/Session.js +91 -8
  15. package/dist/constants/statusIcons.d.ts +3 -1
  16. package/dist/constants/statusIcons.js +3 -0
  17. package/dist/services/autoApprovalVerifier.d.ts +25 -0
  18. package/dist/services/autoApprovalVerifier.js +265 -0
  19. package/dist/services/autoApprovalVerifier.test.d.ts +1 -0
  20. package/dist/services/autoApprovalVerifier.test.js +120 -0
  21. package/dist/services/configurationManager.d.ts +7 -0
  22. package/dist/services/configurationManager.js +35 -0
  23. package/dist/services/sessionManager.autoApproval.test.d.ts +1 -0
  24. package/dist/services/sessionManager.autoApproval.test.js +160 -0
  25. package/dist/services/sessionManager.d.ts +5 -0
  26. package/dist/services/sessionManager.js +149 -1
  27. package/dist/services/sessionManager.statePersistence.test.js +2 -0
  28. package/dist/services/sessionManager.test.js +6 -0
  29. package/dist/types/index.d.ts +14 -1
  30. package/dist/utils/hookExecutor.test.js +8 -0
  31. package/dist/utils/logger.d.ts +83 -14
  32. package/dist/utils/logger.js +218 -17
  33. package/dist/utils/worktreeUtils.test.js +1 -0
  34. package/package.json +1 -1
@@ -1,21 +1,222 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
3
  import { format } from 'util';
4
- const LOG_FILE = path.join(process.cwd(), 'ccmanager.log');
5
- // Clear log file on startup
6
- fs.writeFileSync(LOG_FILE, '', 'utf8');
7
- function writeLog(level, args) {
8
- const timestamp = new Date().toISOString();
9
- const message = format(...args);
10
- const logLine = `[${timestamp}] [${level}] ${message}\n`;
11
- fs.appendFileSync(LOG_FILE, logLine, 'utf8');
4
+ import os from 'os';
5
+ /**
6
+ * Log level enum for structured logging
7
+ */
8
+ var LogLevel;
9
+ (function (LogLevel) {
10
+ LogLevel["DEBUG"] = "DEBUG";
11
+ LogLevel["INFO"] = "INFO";
12
+ LogLevel["WARN"] = "WARN";
13
+ LogLevel["ERROR"] = "ERROR";
14
+ LogLevel["LOG"] = "LOG";
15
+ })(LogLevel || (LogLevel = {}));
16
+ /**
17
+ * CLI-optimized logger with size management and rotation
18
+ *
19
+ * Features:
20
+ * - Automatic log rotation when file exceeds max size
21
+ * - Configurable retention (3 rotated files by default)
22
+ * - Atomic write operations to prevent corruption
23
+ * - Platform-aware log location (respects XDG_STATE_HOME on Linux)
24
+ * - Detailed timestamps and structured log lines
25
+ * - Sensitive information filtering on console output
26
+ */
27
+ class Logger {
28
+ constructor(config = {}) {
29
+ Object.defineProperty(this, "logFile", {
30
+ enumerable: true,
31
+ configurable: true,
32
+ writable: true,
33
+ value: void 0
34
+ });
35
+ Object.defineProperty(this, "config", {
36
+ enumerable: true,
37
+ configurable: true,
38
+ writable: true,
39
+ value: void 0
40
+ });
41
+ Object.defineProperty(this, "writeQueue", {
42
+ enumerable: true,
43
+ configurable: true,
44
+ writable: true,
45
+ value: []
46
+ });
47
+ Object.defineProperty(this, "isWriting", {
48
+ enumerable: true,
49
+ configurable: true,
50
+ writable: true,
51
+ value: false
52
+ });
53
+ this.config = {
54
+ maxSizeBytes: config.maxSizeBytes ?? 5 * 1024 * 1024, // 5MB default
55
+ maxRotatedFiles: config.maxRotatedFiles ?? 3,
56
+ logErrorsToConsole: config.logErrorsToConsole ?? true,
57
+ };
58
+ this.logFile = this.resolveLogPath();
59
+ this.initializeLogFile();
60
+ }
61
+ /**
62
+ * Resolve log file path following XDG Base Directory specification
63
+ * and respecting environment overrides for testing
64
+ */
65
+ resolveLogPath() {
66
+ // Allow environment override for testing
67
+ if (process.env['CCMANAGER_LOG_FILE']) {
68
+ return process.env['CCMANAGER_LOG_FILE'];
69
+ }
70
+ // Use XDG_STATE_HOME if available (Linux/macOS standard)
71
+ const xdgStateHome = process.env['XDG_STATE_HOME'];
72
+ if (xdgStateHome) {
73
+ const logDir = path.join(xdgStateHome, 'ccmanager');
74
+ return path.join(logDir, 'ccmanager.log');
75
+ }
76
+ // Fallback to ~/.local/state/ccmanager on Linux, ~/Library/Logs on macOS
77
+ const homeDir = os.homedir();
78
+ if (process.platform === 'darwin') {
79
+ return path.join(homeDir, 'Library', 'Logs', 'ccmanager', 'ccmanager.log');
80
+ }
81
+ // Linux and others
82
+ return path.join(homeDir, '.local', 'state', 'ccmanager', 'ccmanager.log');
83
+ }
84
+ /**
85
+ * Initialize log file and ensure directory exists
86
+ */
87
+ initializeLogFile() {
88
+ try {
89
+ const logDir = path.dirname(this.logFile);
90
+ if (!fs.existsSync(logDir)) {
91
+ fs.mkdirSync(logDir, { recursive: true, mode: 0o700 });
92
+ }
93
+ // Only clear log on first startup (check if file exists)
94
+ if (!fs.existsSync(this.logFile)) {
95
+ fs.writeFileSync(this.logFile, '', 'utf8');
96
+ }
97
+ }
98
+ catch (_error) {
99
+ // Silently fail if we can't initialize - don't crash the app
100
+ // This ensures CLI operation is not disrupted by logging issues
101
+ }
102
+ }
103
+ /**
104
+ * Check if log file exceeds size limit and rotate if needed
105
+ */
106
+ rotateLogIfNeeded() {
107
+ try {
108
+ const stats = fs.statSync(this.logFile);
109
+ if (stats.size < this.config.maxSizeBytes) {
110
+ return; // No rotation needed
111
+ }
112
+ // Rotate old logs: ccmanager.log.3 -> removed, .2 -> .3, .1 -> .2, .log -> .1
113
+ for (let i = this.config.maxRotatedFiles; i > 0; i--) {
114
+ const oldName = i === 1 ? this.logFile : `${this.logFile}.${i - 1}`;
115
+ const newName = `${this.logFile}.${i}`;
116
+ if (fs.existsSync(oldName)) {
117
+ fs.renameSync(oldName, newName);
118
+ }
119
+ }
120
+ // Remove the oldest log file if it exists
121
+ const oldestLog = `${this.logFile}.${this.config.maxRotatedFiles}`;
122
+ if (fs.existsSync(oldestLog)) {
123
+ fs.unlinkSync(oldestLog);
124
+ }
125
+ // Start fresh log file
126
+ fs.writeFileSync(this.logFile, '', 'utf8');
127
+ }
128
+ catch (_error) {
129
+ // Silently fail - don't disrupt app operation
130
+ }
131
+ }
132
+ /**
133
+ * Queue write operation to prevent concurrent writes
134
+ * This ensures log file integrity with atomic operations
135
+ */
136
+ queueWrite(callback) {
137
+ this.writeQueue.push(callback);
138
+ this.processQueue();
139
+ }
140
+ /**
141
+ * Process write queue sequentially to prevent concurrent writes
142
+ */
143
+ processQueue() {
144
+ if (this.isWriting || this.writeQueue.length === 0) {
145
+ return;
146
+ }
147
+ this.isWriting = true;
148
+ const callback = this.writeQueue.shift();
149
+ try {
150
+ if (callback) {
151
+ callback();
152
+ }
153
+ }
154
+ catch (_error) {
155
+ // Silently fail - don't crash the app
156
+ }
157
+ finally {
158
+ this.isWriting = false;
159
+ this.processQueue();
160
+ }
161
+ }
162
+ /**
163
+ * Write log entry with level and formatted message
164
+ */
165
+ writeLog(level, args) {
166
+ this.queueWrite(() => {
167
+ try {
168
+ this.rotateLogIfNeeded();
169
+ const timestamp = new Date().toISOString();
170
+ const message = format(...args);
171
+ const logLine = `[${timestamp}] [${level}] ${message}\n`;
172
+ fs.appendFileSync(this.logFile, logLine, 'utf8');
173
+ // Also output errors to console for immediate visibility
174
+ if (level === LogLevel.ERROR && this.config.logErrorsToConsole) {
175
+ console.error(`[${level}]`, ...args);
176
+ }
177
+ }
178
+ catch (_error) {
179
+ // Silently fail - don't disrupt app operation
180
+ }
181
+ });
182
+ }
183
+ /**
184
+ * Get the path to the current log file
185
+ * Useful for users to locate and inspect logs
186
+ */
187
+ getLogPath() {
188
+ return this.logFile;
189
+ }
190
+ /**
191
+ * Log entry at LOG level (general information)
192
+ */
193
+ log(...args) {
194
+ this.writeLog(LogLevel.LOG, args);
195
+ }
196
+ /**
197
+ * Log entry at INFO level (significant events)
198
+ */
199
+ info(...args) {
200
+ this.writeLog(LogLevel.INFO, args);
201
+ }
202
+ /**
203
+ * Log entry at WARN level (potentially harmful situations)
204
+ */
205
+ warn(...args) {
206
+ this.writeLog(LogLevel.WARN, args);
207
+ }
208
+ /**
209
+ * Log entry at ERROR level (error conditions)
210
+ */
211
+ error(...args) {
212
+ this.writeLog(LogLevel.ERROR, args);
213
+ }
214
+ /**
215
+ * Log entry at DEBUG level (detailed diagnostic information)
216
+ * Only written to file, not to console
217
+ */
218
+ debug(...args) {
219
+ this.writeLog(LogLevel.DEBUG, args);
220
+ }
12
221
  }
13
- export const log = {
14
- log: (...args) => writeLog('LOG', args),
15
- info: (...args) => writeLog('INFO', args),
16
- warn: (...args) => writeLog('WARN', args),
17
- error: (...args) => writeLog('ERROR', args),
18
- debug: (...args) => writeLog('DEBUG', args),
19
- };
20
- // Alias for console.log style usage
21
- export const logger = log;
222
+ export const logger = new Logger();
@@ -135,6 +135,7 @@ describe('prepareWorktreeItems', () => {
135
135
  devcontainerConfig: undefined,
136
136
  pendingState: undefined,
137
137
  pendingStateStart: undefined,
138
+ autoApprovalFailed: false,
138
139
  };
139
140
  it('should prepare basic worktree without git status', () => {
140
141
  const items = prepareWorktreeItems([mockWorktree], []);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccmanager",
3
- "version": "2.11.5",
3
+ "version": "3.0.0",
4
4
  "description": "TUI application for managing multiple Claude Code sessions across Git worktrees",
5
5
  "license": "MIT",
6
6
  "author": "Kodai Kabasawa",