@skroyc/librarian 0.1.0 → 0.2.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.
- package/README.md +4 -16
- package/dist/agents/context-schema.d.ts +1 -1
- package/dist/agents/context-schema.d.ts.map +1 -1
- package/dist/agents/context-schema.js +5 -2
- package/dist/agents/context-schema.js.map +1 -1
- package/dist/agents/react-agent.d.ts.map +1 -1
- package/dist/agents/react-agent.js +36 -27
- package/dist/agents/react-agent.js.map +1 -1
- package/dist/agents/tool-runtime.d.ts.map +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +53 -49
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +115 -69
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +246 -150
- package/dist/index.js.map +1 -1
- package/dist/tools/file-finding.tool.d.ts +1 -1
- package/dist/tools/file-finding.tool.d.ts.map +1 -1
- package/dist/tools/file-finding.tool.js +70 -130
- package/dist/tools/file-finding.tool.js.map +1 -1
- package/dist/tools/file-listing.tool.d.ts +7 -1
- package/dist/tools/file-listing.tool.d.ts.map +1 -1
- package/dist/tools/file-listing.tool.js +96 -80
- package/dist/tools/file-listing.tool.js.map +1 -1
- package/dist/tools/file-reading.tool.d.ts +4 -1
- package/dist/tools/file-reading.tool.d.ts.map +1 -1
- package/dist/tools/file-reading.tool.js +107 -45
- package/dist/tools/file-reading.tool.js.map +1 -1
- package/dist/tools/grep-content.tool.d.ts +13 -1
- package/dist/tools/grep-content.tool.d.ts.map +1 -1
- package/dist/tools/grep-content.tool.js +186 -144
- package/dist/tools/grep-content.tool.js.map +1 -1
- package/dist/utils/error-utils.d.ts +9 -0
- package/dist/utils/error-utils.d.ts.map +1 -0
- package/dist/utils/error-utils.js +61 -0
- package/dist/utils/error-utils.js.map +1 -0
- package/dist/utils/file-utils.d.ts +1 -0
- package/dist/utils/file-utils.d.ts.map +1 -1
- package/dist/utils/file-utils.js +81 -9
- package/dist/utils/file-utils.js.map +1 -1
- package/dist/utils/format-utils.d.ts +25 -0
- package/dist/utils/format-utils.d.ts.map +1 -0
- package/dist/utils/format-utils.js +111 -0
- package/dist/utils/format-utils.js.map +1 -0
- package/dist/utils/gitignore-service.d.ts +10 -0
- package/dist/utils/gitignore-service.d.ts.map +1 -0
- package/dist/utils/gitignore-service.js +91 -0
- package/dist/utils/gitignore-service.js.map +1 -0
- package/dist/utils/logger.d.ts +2 -2
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +35 -34
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/path-utils.js +3 -3
- package/dist/utils/path-utils.js.map +1 -1
- package/package.json +1 -1
- package/src/agents/context-schema.ts +5 -2
- package/src/agents/react-agent.ts +667 -641
- package/src/agents/tool-runtime.ts +4 -4
- package/src/cli.ts +95 -57
- package/src/config.ts +192 -90
- package/src/index.ts +402 -180
- package/src/tools/file-finding.tool.ts +198 -310
- package/src/tools/file-listing.tool.ts +245 -202
- package/src/tools/file-reading.tool.ts +225 -138
- package/src/tools/grep-content.tool.ts +387 -307
- package/src/utils/error-utils.ts +95 -0
- package/src/utils/file-utils.ts +104 -19
- package/src/utils/format-utils.ts +190 -0
- package/src/utils/gitignore-service.ts +123 -0
- package/src/utils/logger.ts +112 -77
- package/src/utils/path-utils.ts +3 -3
package/src/utils/logger.ts
CHANGED
|
@@ -5,13 +5,23 @@
|
|
|
5
5
|
* Metadata-only logging (no sensitive data)
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { mkdir } from
|
|
9
|
-
import
|
|
10
|
-
import
|
|
8
|
+
import { mkdir } from "node:fs/promises";
|
|
9
|
+
import os from "node:os";
|
|
10
|
+
import path from "node:path";
|
|
11
11
|
import type { FileSink } from "bun";
|
|
12
12
|
|
|
13
|
-
export type LogLevel =
|
|
14
|
-
export type LogComponent =
|
|
13
|
+
export type LogLevel = "INFO" | "DEBUG" | "WARN" | "ERROR";
|
|
14
|
+
export type LogComponent =
|
|
15
|
+
| "CLI"
|
|
16
|
+
| "CONFIG"
|
|
17
|
+
| "LIBRARIAN"
|
|
18
|
+
| "AGENT"
|
|
19
|
+
| "TOOL"
|
|
20
|
+
| "LLM"
|
|
21
|
+
| "GIT"
|
|
22
|
+
| "PATH"
|
|
23
|
+
| "LOGGER"
|
|
24
|
+
| "TIMING";
|
|
15
25
|
|
|
16
26
|
interface LogMetadata {
|
|
17
27
|
[key: string]: unknown;
|
|
@@ -46,9 +56,9 @@ class Logger {
|
|
|
46
56
|
}
|
|
47
57
|
|
|
48
58
|
/**
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
59
|
+
* Initialize the log file with timestamp
|
|
60
|
+
* Format: ~/.config/librarian/logs/YYYY-MM-DD_HH-MM-SS_mmm-librarian.log
|
|
61
|
+
*/
|
|
52
62
|
private async initializeLogFile(): Promise<void> {
|
|
53
63
|
try {
|
|
54
64
|
// Create timestamp for filename
|
|
@@ -56,39 +66,38 @@ class Logger {
|
|
|
56
66
|
const isoString = now.toISOString();
|
|
57
67
|
|
|
58
68
|
if (!isoString) {
|
|
59
|
-
throw new Error(
|
|
69
|
+
throw new Error("Failed to generate timestamp");
|
|
60
70
|
}
|
|
61
71
|
|
|
62
72
|
// Create timestamp: YYYY-MM-DD_HH-MM-SS
|
|
63
73
|
const year = now.getFullYear();
|
|
64
|
-
const month = String(now.getMonth() + 1).padStart(2,
|
|
65
|
-
const day = String(now.getDate()).padStart(2,
|
|
66
|
-
const hours = String(now.getHours()).padStart(2,
|
|
67
|
-
const minutes = String(now.getMinutes()).padStart(2,
|
|
68
|
-
const seconds = String(now.getSeconds()).padStart(2,
|
|
69
|
-
const ms = String(now.getMilliseconds()).padStart(3,
|
|
74
|
+
const month = String(now.getMonth() + 1).padStart(2, "0");
|
|
75
|
+
const day = String(now.getDate()).padStart(2, "0");
|
|
76
|
+
const hours = String(now.getHours()).padStart(2, "0");
|
|
77
|
+
const minutes = String(now.getMinutes()).padStart(2, "0");
|
|
78
|
+
const seconds = String(now.getSeconds()).padStart(2, "0");
|
|
79
|
+
const ms = String(now.getMilliseconds()).padStart(3, "0");
|
|
70
80
|
|
|
71
81
|
const timestamp = `${year}-${month}-${day}_${hours}-${minutes}-${seconds}_${ms}`;
|
|
72
82
|
|
|
73
83
|
// Log directory
|
|
74
|
-
const logDir = path.join(os.homedir(),
|
|
84
|
+
const logDir = path.join(os.homedir(), ".config", "librarian", "logs");
|
|
75
85
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
86
|
+
// Ensure directory exists
|
|
87
|
+
if (!(await Bun.file(logDir).exists())) {
|
|
88
|
+
await mkdir(logDir, { recursive: true });
|
|
89
|
+
}
|
|
80
90
|
|
|
81
91
|
// Log filename
|
|
82
92
|
const logFilename = `${timestamp}-librarian.log`;
|
|
83
93
|
const logPath = path.join(logDir, logFilename);
|
|
84
94
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
// Log initialization
|
|
90
|
-
this.info('LOGGER', `Logging initialized: ${logPath}`);
|
|
95
|
+
// Create write stream
|
|
96
|
+
const logFile = Bun.file(logPath);
|
|
97
|
+
this.writer = logFile.writer();
|
|
91
98
|
|
|
99
|
+
// Log initialization
|
|
100
|
+
this.info("LOGGER", `Logging initialized: ${logPath}`);
|
|
92
101
|
} catch {
|
|
93
102
|
// Silent - do nothing on initialization errors
|
|
94
103
|
}
|
|
@@ -100,12 +109,12 @@ class Logger {
|
|
|
100
109
|
private formatTimestamp(): string {
|
|
101
110
|
const now = new Date();
|
|
102
111
|
const year = now.getFullYear();
|
|
103
|
-
const month = String(now.getMonth() + 1).padStart(2,
|
|
104
|
-
const day = String(now.getDate()).padStart(2,
|
|
105
|
-
const hours = String(now.getHours()).padStart(2,
|
|
106
|
-
const minutes = String(now.getMinutes()).padStart(2,
|
|
107
|
-
const seconds = String(now.getSeconds()).padStart(2,
|
|
108
|
-
const ms = String(now.getMilliseconds()).padStart(3,
|
|
112
|
+
const month = String(now.getMonth() + 1).padStart(2, "0");
|
|
113
|
+
const day = String(now.getDate()).padStart(2, "0");
|
|
114
|
+
const hours = String(now.getHours()).padStart(2, "0");
|
|
115
|
+
const minutes = String(now.getMinutes()).padStart(2, "0");
|
|
116
|
+
const seconds = String(now.getSeconds()).padStart(2, "0");
|
|
117
|
+
const ms = String(now.getMilliseconds()).padStart(3, "0");
|
|
109
118
|
|
|
110
119
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${ms}`;
|
|
111
120
|
}
|
|
@@ -126,24 +135,27 @@ class Logger {
|
|
|
126
135
|
private getRedactedValue(key: string, value: unknown): unknown {
|
|
127
136
|
const lowerKey = key.toLowerCase();
|
|
128
137
|
|
|
129
|
-
if ([
|
|
130
|
-
return
|
|
138
|
+
if (["apiKey", "token", "secret", "password"].includes(lowerKey)) {
|
|
139
|
+
return "[REDACTED]";
|
|
131
140
|
}
|
|
132
141
|
|
|
133
|
-
if ((key ===
|
|
142
|
+
if ((key === "query" || key === "content") && typeof value === "string") {
|
|
134
143
|
return value.length;
|
|
135
144
|
}
|
|
136
145
|
|
|
137
|
-
if ((key ===
|
|
146
|
+
if ((key === "repoUrl" || key === "baseURL") && typeof value === "string") {
|
|
138
147
|
return this.redactUrl(value);
|
|
139
148
|
}
|
|
140
149
|
|
|
141
|
-
if (key ===
|
|
142
|
-
return value.replace(os.homedir(),
|
|
150
|
+
if (key === "workingDir" && typeof value === "string") {
|
|
151
|
+
return value.replace(os.homedir(), "~");
|
|
143
152
|
}
|
|
144
153
|
|
|
145
|
-
if (
|
|
146
|
-
|
|
154
|
+
if (
|
|
155
|
+
typeof value === "string" &&
|
|
156
|
+
(value.includes(os.homedir()) || value.includes("/home/"))
|
|
157
|
+
) {
|
|
158
|
+
return value.replace(os.homedir(), "~");
|
|
147
159
|
}
|
|
148
160
|
|
|
149
161
|
return value;
|
|
@@ -154,14 +166,19 @@ class Logger {
|
|
|
154
166
|
const url = new URL(value);
|
|
155
167
|
return url.hostname;
|
|
156
168
|
} catch {
|
|
157
|
-
return
|
|
169
|
+
return "[INVALID_URL]";
|
|
158
170
|
}
|
|
159
171
|
}
|
|
160
172
|
|
|
161
173
|
/**
|
|
162
174
|
* Format log entry
|
|
163
175
|
*/
|
|
164
|
-
private formatLogEntry(
|
|
176
|
+
private formatLogEntry(
|
|
177
|
+
level: LogLevel,
|
|
178
|
+
component: LogComponent,
|
|
179
|
+
message: string,
|
|
180
|
+
metadata?: LogMetadata
|
|
181
|
+
): string {
|
|
165
182
|
const timestamp = this.formatTimestamp();
|
|
166
183
|
let entry = `[${timestamp}] [${level}] [${component}] ${message}`;
|
|
167
184
|
|
|
@@ -173,23 +190,28 @@ class Logger {
|
|
|
173
190
|
return entry;
|
|
174
191
|
}
|
|
175
192
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
193
|
+
/**
|
|
194
|
+
* Write log entry to file
|
|
195
|
+
*/
|
|
196
|
+
private writeLog(entry: string): void {
|
|
197
|
+
try {
|
|
198
|
+
if (this.writer) {
|
|
199
|
+
this.writer.write(`${entry}\n`);
|
|
200
|
+
}
|
|
201
|
+
} catch {
|
|
202
|
+
// Silent - do nothing on write errors
|
|
203
|
+
}
|
|
204
|
+
}
|
|
188
205
|
|
|
189
206
|
/**
|
|
190
207
|
* Internal logging method
|
|
191
208
|
*/
|
|
192
|
-
private log(
|
|
209
|
+
private log(
|
|
210
|
+
level: LogLevel,
|
|
211
|
+
component: LogComponent,
|
|
212
|
+
message: string,
|
|
213
|
+
metadata?: LogMetadata
|
|
214
|
+
): void {
|
|
193
215
|
try {
|
|
194
216
|
const entry = this.formatLogEntry(level, component, message, metadata);
|
|
195
217
|
this.writeLog(entry);
|
|
@@ -202,15 +224,19 @@ class Logger {
|
|
|
202
224
|
* INFO level - Always logged
|
|
203
225
|
*/
|
|
204
226
|
info(component: LogComponent, message: string, metadata?: LogMetadata): void {
|
|
205
|
-
this.log(
|
|
227
|
+
this.log("INFO", component, message, metadata);
|
|
206
228
|
}
|
|
207
229
|
|
|
208
230
|
/**
|
|
209
231
|
* DEBUG level - Only logged when debug mode is enabled
|
|
210
232
|
*/
|
|
211
|
-
debug(
|
|
233
|
+
debug(
|
|
234
|
+
component: LogComponent,
|
|
235
|
+
message: string,
|
|
236
|
+
metadata?: LogMetadata
|
|
237
|
+
): void {
|
|
212
238
|
if (this.debugMode) {
|
|
213
|
-
this.log(
|
|
239
|
+
this.log("DEBUG", component, message, metadata);
|
|
214
240
|
}
|
|
215
241
|
}
|
|
216
242
|
|
|
@@ -218,13 +244,18 @@ class Logger {
|
|
|
218
244
|
* WARN level - Always logged
|
|
219
245
|
*/
|
|
220
246
|
warn(component: LogComponent, message: string, metadata?: LogMetadata): void {
|
|
221
|
-
this.log(
|
|
247
|
+
this.log("WARN", component, message, metadata);
|
|
222
248
|
}
|
|
223
249
|
|
|
224
250
|
/**
|
|
225
251
|
* ERROR level - Always logged with stack trace
|
|
226
252
|
*/
|
|
227
|
-
error(
|
|
253
|
+
error(
|
|
254
|
+
component: LogComponent,
|
|
255
|
+
message: string,
|
|
256
|
+
error?: Error,
|
|
257
|
+
metadata?: LogMetadata
|
|
258
|
+
): void {
|
|
228
259
|
const errorMetadata: LogMetadata = metadata ? { ...metadata } : {};
|
|
229
260
|
|
|
230
261
|
if (error) {
|
|
@@ -237,7 +268,7 @@ class Logger {
|
|
|
237
268
|
}
|
|
238
269
|
}
|
|
239
270
|
|
|
240
|
-
this.log(
|
|
271
|
+
this.log("ERROR", component, message, errorMetadata);
|
|
241
272
|
}
|
|
242
273
|
|
|
243
274
|
/**
|
|
@@ -248,10 +279,10 @@ class Logger {
|
|
|
248
279
|
const operationId = `${operation}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
249
280
|
this.timingOperations.set(operationId, {
|
|
250
281
|
operation,
|
|
251
|
-
startTime: performance.now()
|
|
282
|
+
startTime: performance.now(),
|
|
252
283
|
});
|
|
253
284
|
|
|
254
|
-
this.debug(
|
|
285
|
+
this.debug("TIMING", `Started: ${operation}`);
|
|
255
286
|
|
|
256
287
|
return operationId;
|
|
257
288
|
}
|
|
@@ -259,7 +290,11 @@ class Logger {
|
|
|
259
290
|
/**
|
|
260
291
|
* End timing an operation
|
|
261
292
|
*/
|
|
262
|
-
timingEnd(
|
|
293
|
+
timingEnd(
|
|
294
|
+
operationId: string,
|
|
295
|
+
component: LogComponent,
|
|
296
|
+
message?: string
|
|
297
|
+
): void {
|
|
263
298
|
const timing = this.timingOperations.get(operationId);
|
|
264
299
|
|
|
265
300
|
if (timing) {
|
|
@@ -272,23 +307,23 @@ class Logger {
|
|
|
272
307
|
this.info(component, logMessage, { duration: `${durationMs}ms` });
|
|
273
308
|
|
|
274
309
|
if (this.debugMode) {
|
|
275
|
-
this.debug(
|
|
310
|
+
this.debug("TIMING", `Ended: ${timing.operation}`, { durationMs });
|
|
276
311
|
}
|
|
277
312
|
}
|
|
278
313
|
}
|
|
279
314
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
315
|
+
/**
|
|
316
|
+
* Clean up resources
|
|
317
|
+
*/
|
|
318
|
+
close(): void {
|
|
319
|
+
try {
|
|
320
|
+
if (this.writer) {
|
|
321
|
+
this.writer.end();
|
|
322
|
+
}
|
|
323
|
+
} catch {
|
|
324
|
+
// Silent
|
|
325
|
+
}
|
|
326
|
+
}
|
|
292
327
|
}
|
|
293
328
|
|
|
294
329
|
// Export singleton instance
|
package/src/utils/path-utils.ts
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
* Shared utilities for path manipulation
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import
|
|
7
|
-
import
|
|
6
|
+
import os from "node:os";
|
|
7
|
+
import path from "node:path";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Expand tilde (~) in file paths to home directory
|
|
11
11
|
*/
|
|
12
12
|
export function expandTilde(filePath: string): string {
|
|
13
|
-
if (filePath.startsWith(
|
|
13
|
+
if (filePath.startsWith("~/")) {
|
|
14
14
|
return path.join(os.homedir(), filePath.slice(2));
|
|
15
15
|
}
|
|
16
16
|
return filePath;
|