@agi-cli/server 0.1.67 → 0.1.68
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/package.json +3 -3
- package/src/index.ts +9 -0
- package/src/routes/ask.ts +6 -6
- package/src/routes/config.ts +196 -159
- package/src/routes/git.ts +28 -16
- package/src/routes/session-messages.ts +114 -95
- package/src/routes/sessions.ts +5 -2
- package/src/runtime/api-error.ts +191 -0
- package/src/runtime/debug-state.ts +124 -0
- package/src/runtime/debug.ts +43 -30
- package/src/runtime/logger.ts +204 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized logging utility
|
|
3
|
+
*
|
|
4
|
+
* Provides structured logging with debug mode awareness.
|
|
5
|
+
* Replaces scattered console.log calls throughout the codebase.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { isDebugEnabled, isTraceEnabled } from './debug-state';
|
|
9
|
+
|
|
10
|
+
export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Format a log message with optional metadata
|
|
14
|
+
*/
|
|
15
|
+
function _formatMessage(
|
|
16
|
+
level: LogLevel,
|
|
17
|
+
message: string,
|
|
18
|
+
meta?: Record<string, unknown>,
|
|
19
|
+
): string {
|
|
20
|
+
const timestamp = new Date().toISOString();
|
|
21
|
+
const prefix = `[${timestamp}] [${level.toUpperCase()}]`;
|
|
22
|
+
|
|
23
|
+
if (meta && Object.keys(meta).length > 0) {
|
|
24
|
+
return `${prefix} ${message} ${JSON.stringify(meta)}`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return `${prefix} ${message}`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Log at debug level (only when debug mode is enabled)
|
|
32
|
+
*/
|
|
33
|
+
export function debug(message: string, meta?: Record<string, unknown>): void {
|
|
34
|
+
if (!isDebugEnabled()) return;
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
if (meta && Object.keys(meta).length > 0) {
|
|
38
|
+
console.log(`[debug] ${message}`, meta);
|
|
39
|
+
} else {
|
|
40
|
+
console.log(`[debug] ${message}`);
|
|
41
|
+
}
|
|
42
|
+
} catch {
|
|
43
|
+
// Silently fail
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Log informational messages
|
|
49
|
+
*/
|
|
50
|
+
export function info(message: string, meta?: Record<string, unknown>): void {
|
|
51
|
+
try {
|
|
52
|
+
if (meta && Object.keys(meta).length > 0) {
|
|
53
|
+
console.log(`[info] ${message}`, meta);
|
|
54
|
+
} else {
|
|
55
|
+
console.log(`[info] ${message}`);
|
|
56
|
+
}
|
|
57
|
+
} catch {
|
|
58
|
+
// Silently fail
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Log warning messages
|
|
64
|
+
*/
|
|
65
|
+
export function warn(message: string, meta?: Record<string, unknown>): void {
|
|
66
|
+
try {
|
|
67
|
+
if (meta && Object.keys(meta).length > 0) {
|
|
68
|
+
console.warn(`[warn] ${message}`, meta);
|
|
69
|
+
} else {
|
|
70
|
+
console.warn(`[warn] ${message}`);
|
|
71
|
+
}
|
|
72
|
+
} catch {
|
|
73
|
+
// Silently fail
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Log error messages (only in debug mode, stack trace only with --trace)
|
|
79
|
+
*/
|
|
80
|
+
export function error(
|
|
81
|
+
message: string,
|
|
82
|
+
err?: unknown,
|
|
83
|
+
meta?: Record<string, unknown>,
|
|
84
|
+
): void {
|
|
85
|
+
// Only log errors when debug mode is enabled
|
|
86
|
+
if (!isDebugEnabled()) return;
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
const logMeta: Record<string, unknown> = { ...meta };
|
|
90
|
+
|
|
91
|
+
if (err) {
|
|
92
|
+
if (err instanceof Error) {
|
|
93
|
+
// Always show error name and message in debug mode
|
|
94
|
+
logMeta.error = {
|
|
95
|
+
name: err.name,
|
|
96
|
+
message: err.message,
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// Show full stack trace only with --trace flag
|
|
100
|
+
if (isTraceEnabled() && err.stack) {
|
|
101
|
+
logMeta.error.stack = err.stack;
|
|
102
|
+
}
|
|
103
|
+
} else if (typeof err === 'string') {
|
|
104
|
+
logMeta.error = err;
|
|
105
|
+
} else if (err && typeof err === 'object') {
|
|
106
|
+
// For other error objects, try to extract useful info
|
|
107
|
+
const errObj = err as Record<string, unknown>;
|
|
108
|
+
logMeta.error = {
|
|
109
|
+
...(typeof errObj.name === 'string' ? { name: errObj.name } : {}),
|
|
110
|
+
...(typeof errObj.message === 'string'
|
|
111
|
+
? { message: errObj.message }
|
|
112
|
+
: {}),
|
|
113
|
+
...(typeof errObj.code === 'string' ? { code: errObj.code } : {}),
|
|
114
|
+
...(typeof errObj.status === 'number'
|
|
115
|
+
? { status: errObj.status }
|
|
116
|
+
: {}),
|
|
117
|
+
...(typeof errObj.statusCode === 'number'
|
|
118
|
+
? { statusCode: errObj.statusCode }
|
|
119
|
+
: {}),
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
// Include stack in trace mode
|
|
123
|
+
if (isTraceEnabled() && typeof errObj.stack === 'string') {
|
|
124
|
+
logMeta.error.stack = errObj.stack;
|
|
125
|
+
}
|
|
126
|
+
} else {
|
|
127
|
+
// Fallback for primitive types
|
|
128
|
+
logMeta.error = String(err);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (Object.keys(logMeta).length > 0) {
|
|
133
|
+
console.error(`[error] ${message}`, logMeta);
|
|
134
|
+
} else {
|
|
135
|
+
console.error(`[error] ${message}`);
|
|
136
|
+
}
|
|
137
|
+
} catch (logErr) {
|
|
138
|
+
// Last resort: at least try to log something
|
|
139
|
+
try {
|
|
140
|
+
console.error(`[error] ${message} (logging failed:`, logErr, ')');
|
|
141
|
+
} catch {
|
|
142
|
+
// Give up silently
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Logger object with all methods
|
|
149
|
+
*/
|
|
150
|
+
export const logger = {
|
|
151
|
+
debug,
|
|
152
|
+
info,
|
|
153
|
+
warn,
|
|
154
|
+
error,
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Timing utilities (integrates with existing debug.ts timing)
|
|
159
|
+
*/
|
|
160
|
+
function nowMs(): number {
|
|
161
|
+
const perf = (globalThis as { performance?: { now?: () => number } })
|
|
162
|
+
.performance;
|
|
163
|
+
if (perf && typeof perf.now === 'function') return perf.now();
|
|
164
|
+
return Date.now();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
type Timer = {
|
|
168
|
+
end(meta?: Record<string, unknown>): void;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Create a timer for performance measurement
|
|
173
|
+
* Only active when debug mode is enabled
|
|
174
|
+
*/
|
|
175
|
+
export function time(label: string): Timer {
|
|
176
|
+
if (!isDebugEnabled()) {
|
|
177
|
+
return { end() {} };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const start = nowMs();
|
|
181
|
+
let finished = false;
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
end(meta?: Record<string, unknown>) {
|
|
185
|
+
if (finished) return;
|
|
186
|
+
finished = true;
|
|
187
|
+
const duration = nowMs() - start;
|
|
188
|
+
|
|
189
|
+
try {
|
|
190
|
+
const line = `[timing] ${label} ${duration.toFixed(1)}ms`;
|
|
191
|
+
if (meta && Object.keys(meta).length) {
|
|
192
|
+
console.log(line, meta);
|
|
193
|
+
} else {
|
|
194
|
+
console.log(line);
|
|
195
|
+
}
|
|
196
|
+
} catch {
|
|
197
|
+
// Silently fail
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Export legacy compatibility
|
|
204
|
+
export { isDebugEnabled, isTraceEnabled };
|