@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.
Files changed (76) hide show
  1. package/README.md +4 -16
  2. package/dist/agents/context-schema.d.ts +1 -1
  3. package/dist/agents/context-schema.d.ts.map +1 -1
  4. package/dist/agents/context-schema.js +5 -2
  5. package/dist/agents/context-schema.js.map +1 -1
  6. package/dist/agents/react-agent.d.ts.map +1 -1
  7. package/dist/agents/react-agent.js +36 -27
  8. package/dist/agents/react-agent.js.map +1 -1
  9. package/dist/agents/tool-runtime.d.ts.map +1 -1
  10. package/dist/cli.d.ts +1 -1
  11. package/dist/cli.d.ts.map +1 -1
  12. package/dist/cli.js +53 -49
  13. package/dist/cli.js.map +1 -1
  14. package/dist/config.d.ts +1 -1
  15. package/dist/config.d.ts.map +1 -1
  16. package/dist/config.js +115 -69
  17. package/dist/config.js.map +1 -1
  18. package/dist/index.d.ts +1 -1
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +246 -150
  21. package/dist/index.js.map +1 -1
  22. package/dist/tools/file-finding.tool.d.ts +1 -1
  23. package/dist/tools/file-finding.tool.d.ts.map +1 -1
  24. package/dist/tools/file-finding.tool.js +70 -130
  25. package/dist/tools/file-finding.tool.js.map +1 -1
  26. package/dist/tools/file-listing.tool.d.ts +7 -1
  27. package/dist/tools/file-listing.tool.d.ts.map +1 -1
  28. package/dist/tools/file-listing.tool.js +96 -80
  29. package/dist/tools/file-listing.tool.js.map +1 -1
  30. package/dist/tools/file-reading.tool.d.ts +4 -1
  31. package/dist/tools/file-reading.tool.d.ts.map +1 -1
  32. package/dist/tools/file-reading.tool.js +107 -45
  33. package/dist/tools/file-reading.tool.js.map +1 -1
  34. package/dist/tools/grep-content.tool.d.ts +13 -1
  35. package/dist/tools/grep-content.tool.d.ts.map +1 -1
  36. package/dist/tools/grep-content.tool.js +186 -144
  37. package/dist/tools/grep-content.tool.js.map +1 -1
  38. package/dist/utils/error-utils.d.ts +9 -0
  39. package/dist/utils/error-utils.d.ts.map +1 -0
  40. package/dist/utils/error-utils.js +61 -0
  41. package/dist/utils/error-utils.js.map +1 -0
  42. package/dist/utils/file-utils.d.ts +1 -0
  43. package/dist/utils/file-utils.d.ts.map +1 -1
  44. package/dist/utils/file-utils.js +81 -9
  45. package/dist/utils/file-utils.js.map +1 -1
  46. package/dist/utils/format-utils.d.ts +25 -0
  47. package/dist/utils/format-utils.d.ts.map +1 -0
  48. package/dist/utils/format-utils.js +111 -0
  49. package/dist/utils/format-utils.js.map +1 -0
  50. package/dist/utils/gitignore-service.d.ts +10 -0
  51. package/dist/utils/gitignore-service.d.ts.map +1 -0
  52. package/dist/utils/gitignore-service.js +91 -0
  53. package/dist/utils/gitignore-service.js.map +1 -0
  54. package/dist/utils/logger.d.ts +2 -2
  55. package/dist/utils/logger.d.ts.map +1 -1
  56. package/dist/utils/logger.js +35 -34
  57. package/dist/utils/logger.js.map +1 -1
  58. package/dist/utils/path-utils.js +3 -3
  59. package/dist/utils/path-utils.js.map +1 -1
  60. package/package.json +1 -1
  61. package/src/agents/context-schema.ts +5 -2
  62. package/src/agents/react-agent.ts +667 -641
  63. package/src/agents/tool-runtime.ts +4 -4
  64. package/src/cli.ts +95 -57
  65. package/src/config.ts +192 -90
  66. package/src/index.ts +402 -180
  67. package/src/tools/file-finding.tool.ts +198 -310
  68. package/src/tools/file-listing.tool.ts +245 -202
  69. package/src/tools/file-reading.tool.ts +225 -138
  70. package/src/tools/grep-content.tool.ts +387 -307
  71. package/src/utils/error-utils.ts +95 -0
  72. package/src/utils/file-utils.ts +104 -19
  73. package/src/utils/format-utils.ts +190 -0
  74. package/src/utils/gitignore-service.ts +123 -0
  75. package/src/utils/logger.ts +112 -77
  76. package/src/utils/path-utils.ts +3 -3
@@ -5,13 +5,23 @@
5
5
  * Metadata-only logging (no sensitive data)
6
6
  */
7
7
 
8
- import { mkdir } from 'node:fs/promises';
9
- import path from 'node:path';
10
- import os from 'node:os';
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 = 'INFO' | 'DEBUG' | 'WARN' | 'ERROR';
14
- export type LogComponent = 'CLI' | 'CONFIG' | 'LIBRARIAN' | 'AGENT' | 'TOOL' | 'LLM' | 'GIT' | 'PATH' | 'LOGGER' | 'TIMING';
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
- * Initialize the log file with timestamp
50
- * Format: ~/.config/librarian/logs/YYYY-MM-DD_HH-MM-SS_mmm-librarian.log
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('Failed to generate timestamp');
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, '0');
65
- const day = String(now.getDate()).padStart(2, '0');
66
- const hours = String(now.getHours()).padStart(2, '0');
67
- const minutes = String(now.getMinutes()).padStart(2, '0');
68
- const seconds = String(now.getSeconds()).padStart(2, '0');
69
- const ms = String(now.getMilliseconds()).padStart(3, '0');
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(), '.config', 'librarian', 'logs');
84
+ const logDir = path.join(os.homedir(), ".config", "librarian", "logs");
75
85
 
76
- // Ensure directory exists
77
- if (!(await Bun.file(logDir).exists())) {
78
- await mkdir(logDir, { recursive: true });
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
- // Create write stream
86
- const logFile = Bun.file(logPath);
87
- this.writer = logFile.writer();
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, '0');
104
- const day = String(now.getDate()).padStart(2, '0');
105
- const hours = String(now.getHours()).padStart(2, '0');
106
- const minutes = String(now.getMinutes()).padStart(2, '0');
107
- const seconds = String(now.getSeconds()).padStart(2, '0');
108
- const ms = String(now.getMilliseconds()).padStart(3, '0');
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 (['apiKey', 'token', 'secret', 'password'].includes(lowerKey)) {
130
- return '[REDACTED]';
138
+ if (["apiKey", "token", "secret", "password"].includes(lowerKey)) {
139
+ return "[REDACTED]";
131
140
  }
132
141
 
133
- if ((key === 'query' || key === 'content') && typeof value === 'string') {
142
+ if ((key === "query" || key === "content") && typeof value === "string") {
134
143
  return value.length;
135
144
  }
136
145
 
137
- if ((key === 'repoUrl' || key === 'baseURL') && typeof value === 'string') {
146
+ if ((key === "repoUrl" || key === "baseURL") && typeof value === "string") {
138
147
  return this.redactUrl(value);
139
148
  }
140
149
 
141
- if (key === 'workingDir' && typeof value === 'string') {
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 (typeof value === 'string' && (value.includes(os.homedir()) || value.includes('/home/'))) {
146
- return value.replace(os.homedir(), '~');
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 '[INVALID_URL]';
169
+ return "[INVALID_URL]";
158
170
  }
159
171
  }
160
172
 
161
173
  /**
162
174
  * Format log entry
163
175
  */
164
- private formatLogEntry(level: LogLevel, component: LogComponent, message: string, metadata?: LogMetadata): string {
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
- * Write log entry to file
178
- */
179
- private writeLog(entry: string): void {
180
- try {
181
- if (this.writer) {
182
- this.writer.write(`${entry}\n`);
183
- }
184
- } catch {
185
- // Silent - do nothing on write errors
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(level: LogLevel, component: LogComponent, message: string, metadata?: LogMetadata): void {
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('INFO', component, message, metadata);
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(component: LogComponent, message: string, metadata?: LogMetadata): void {
233
+ debug(
234
+ component: LogComponent,
235
+ message: string,
236
+ metadata?: LogMetadata
237
+ ): void {
212
238
  if (this.debugMode) {
213
- this.log('DEBUG', component, message, metadata);
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('WARN', component, message, metadata);
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(component: LogComponent, message: string, error?: Error, metadata?: LogMetadata): void {
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('ERROR', component, message, errorMetadata);
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('TIMING', `Started: ${operation}`);
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(operationId: string, component: LogComponent, message?: string): void {
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('TIMING', `Ended: ${timing.operation}`, { durationMs });
310
+ this.debug("TIMING", `Ended: ${timing.operation}`, { durationMs });
276
311
  }
277
312
  }
278
313
  }
279
314
 
280
- /**
281
- * Clean up resources
282
- */
283
- close(): void {
284
- try {
285
- if (this.writer) {
286
- this.writer.end();
287
- }
288
- } catch {
289
- // Silent
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
@@ -3,14 +3,14 @@
3
3
  * Shared utilities for path manipulation
4
4
  */
5
5
 
6
- import path from 'node:path';
7
- import os from 'node:os';
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;