@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
@@ -7,11 +7,11 @@ import type { Context } from "./context-schema.js";
7
7
  * Tools can access this through the config parameter.
8
8
  */
9
9
  export interface ToolRuntime {
10
- /** The context object containing working directory and metadata */
11
- context?: Context;
10
+ /** The context object containing working directory and metadata */
11
+ context?: Context;
12
12
 
13
- /** Additional runtime properties if needed for future extensions */
14
- [key: string]: unknown;
13
+ /** Additional runtime properties if needed for future extensions */
14
+ [key: string]: unknown;
15
15
  }
16
16
 
17
17
  /**
package/src/cli.ts CHANGED
@@ -1,20 +1,25 @@
1
1
  #!/usr/bin/env bun
2
2
 
3
- import { Command } from 'commander';
4
- import { Librarian } from './index.js';
5
- import { loadConfig } from './config.js';
6
- import { logger } from './utils/logger.js';
7
- import { expandTilde } from './utils/path-utils.js';
8
- import path from 'node:path';
9
- import os from 'node:os';
10
-
11
- async function handleStreamingOutput(stream: AsyncIterable<string>): Promise<void> {
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import { Command } from "commander";
6
+ import { loadConfig } from "./config.js";
7
+ import { Librarian } from "./index.js";
8
+ import { logger } from "./utils/logger.js";
9
+ import { expandTilde } from "./utils/path-utils.js";
10
+
11
+ async function handleStreamingOutput(
12
+ stream: AsyncIterable<string>
13
+ ): Promise<void> {
12
14
  try {
13
15
  for await (const chunk of stream) {
14
16
  Bun.stdout.write(new TextEncoder().encode(chunk));
15
17
  }
16
18
  } catch (error) {
17
- console.error('\nStreaming interrupted or failed:', error instanceof Error ? error.message : 'Unknown error');
19
+ console.error(
20
+ "\nStreaming interrupted or failed:",
21
+ error instanceof Error ? error.message : "Unknown error"
22
+ );
18
23
  process.exit(1);
19
24
  }
20
25
  }
@@ -23,12 +28,12 @@ async function handleTechnologyQuery(
23
28
  librarian: Librarian,
24
29
  techName: string,
25
30
  query: string,
26
- noStream: boolean,
31
+ noStream: boolean
27
32
  ): Promise<void> {
28
33
  if (noStream) {
29
34
  const result = await librarian.queryRepository(techName, query);
30
35
  console.log(result);
31
- logger.info('CLI', 'Explore query completed (non-streaming)');
36
+ logger.info("CLI", "Explore query completed (non-streaming)");
32
37
  } else {
33
38
  await handleStreamingOutput(librarian.streamRepository(techName, query));
34
39
  }
@@ -38,19 +43,24 @@ async function handleGroupQuery(
38
43
  librarian: Librarian,
39
44
  groupName: string,
40
45
  query: string,
41
- noStream: boolean,
46
+ noStream: boolean
42
47
  ): Promise<void> {
43
48
  if (noStream) {
44
49
  const result = await librarian.queryGroup(groupName, query);
45
50
  console.log(result);
46
- logger.info('CLI', 'Explore group query completed (non-streaming)');
51
+ logger.info("CLI", "Explore group query completed (non-streaming)");
47
52
  } else {
48
53
  await handleStreamingOutput(librarian.streamGroup(groupName, query));
49
54
  }
50
55
  }
51
56
 
52
- function displayTechnologies(groups: Record<string, Record<string, { description?: string; branch?: string }>>): void {
53
- console.log('Available Technologies:');
57
+ function displayTechnologies(
58
+ groups: Record<
59
+ string,
60
+ Record<string, { description?: string; branch?: string }>
61
+ >
62
+ ): void {
63
+ console.log("Available Technologies:");
54
64
  for (const [groupName, techs] of Object.entries(groups)) {
55
65
  if (!techs || Object.keys(techs).length === 0) {
56
66
  continue;
@@ -58,8 +68,8 @@ function displayTechnologies(groups: Record<string, Record<string, { description
58
68
 
59
69
  console.log(`\n[${groupName}]`);
60
70
  for (const [techName, details] of Object.entries(techs)) {
61
- const desc = details.description ? ` - ${details.description}` : '';
62
- const branch = details.branch ? ` (${details.branch})` : '';
71
+ const desc = details.description ? ` - ${details.description}` : "";
72
+ const branch = details.branch ? ` (${details.branch})` : "";
63
73
  console.log(` - ${techName}${branch}${desc}`);
64
74
  }
65
75
  }
@@ -69,19 +79,22 @@ export function createProgram() {
69
79
  const program = new Command();
70
80
 
71
81
  program
72
- .name('librarian')
73
- .description('CLI to interact with technology repositories using AI')
74
- .version('0.1.0')
75
- .option('--debug', 'Enable debug logging');
82
+ .name("librarian")
83
+ .description("CLI to interact with technology repositories using AI")
84
+ .version("0.1.0")
85
+ .option("--debug", "Enable debug logging");
76
86
 
77
87
  program
78
- .command('explore')
79
- .description('Explore technologies or groups')
80
- .argument('<query>', 'The question or exploration query')
81
- .option('-t, --tech <technology>', 'Specific technology to explore')
82
- .option('-g, --group <group>', 'Technology group to explore')
83
- .option('-c, --config <path>', 'Path to configuration file')
84
- .option('--no-stream', 'Disable streaming output (streaming is enabled by default)')
88
+ .command("explore")
89
+ .description("Explore technologies or groups")
90
+ .argument("<query>", "The question or exploration query")
91
+ .option("-t, --tech <technology>", "Specific technology to explore")
92
+ .option("-g, --group <group>", "Technology group to explore")
93
+ .option("-c, --config <path>", "Path to configuration file")
94
+ .option(
95
+ "--no-stream",
96
+ "Disable streaming output (streaming is enabled by default)"
97
+ )
85
98
  .action(async (query, options) => {
86
99
  try {
87
100
  // Set debug mode from global options
@@ -89,18 +102,23 @@ export function createProgram() {
89
102
  logger.setDebugMode(programOptions.debug);
90
103
 
91
104
  // Log command execution
92
- logger.info('CLI', 'Starting explore command', {
105
+ logger.info("CLI", "Starting explore command", {
93
106
  queryLength: query.length,
94
107
  tech: options.tech || null,
95
108
  group: options.group || null,
96
109
  noStream: options.noStream,
97
- debug: programOptions.debug
110
+ debug: programOptions.debug,
98
111
  });
99
112
 
100
113
  // Validate: only one of --tech or --group should be specified
101
114
  if (options.tech && options.group) {
102
- logger.error('CLI', 'Cannot use both --tech and --group flags simultaneously');
103
- console.error('Error: Cannot use both --tech and --group flags simultaneously');
115
+ logger.error(
116
+ "CLI",
117
+ "Cannot use both --tech and --group flags simultaneously"
118
+ );
119
+ console.error(
120
+ "Error: Cannot use both --tech and --group flags simultaneously"
121
+ );
104
122
  process.exit(1);
105
123
  }
106
124
 
@@ -111,43 +129,57 @@ export function createProgram() {
111
129
  if (options.tech) {
112
130
  const techDetails = librarian.resolveTechnology(options.tech);
113
131
  if (!techDetails) {
114
- throw new Error(`Technology ${options.tech} not found in configuration`);
132
+ throw new Error(
133
+ `Technology ${options.tech} not found in configuration`
134
+ );
115
135
  }
116
136
 
117
- await handleTechnologyQuery(librarian, techDetails.name, query, options.noStream);
137
+ await handleTechnologyQuery(
138
+ librarian,
139
+ techDetails.name,
140
+ query,
141
+ options.noStream
142
+ );
118
143
  } else if (options.group) {
119
- await handleGroupQuery(librarian, options.group, query, options.noStream);
144
+ await handleGroupQuery(
145
+ librarian,
146
+ options.group,
147
+ query,
148
+ options.noStream
149
+ );
120
150
  } else {
121
- console.error('Error: Either --tech or --group must be specified');
151
+ console.error("Error: Either --tech or --group must be specified");
122
152
  process.exit(1);
123
153
  }
124
154
  } catch (error: unknown) {
125
155
  if (error instanceof Error) {
126
- console.error('Error:', error.message);
156
+ console.error("Error:", error.message);
127
157
  } else {
128
- console.error('Error:', String(error));
158
+ console.error("Error:", String(error));
129
159
  }
130
160
  process.exit(1);
131
161
  }
132
162
  });
133
163
 
134
164
  program
135
- .command('list')
136
- .description('List available technologies')
137
- .option('-g, --group <group>', 'Filter technologies by group')
138
- .option('-c, --config <path>', 'Path to configuration file')
165
+ .command("list")
166
+ .description("List available technologies")
167
+ .option("-g, --group <group>", "Filter technologies by group")
168
+ .option("-c, --config <path>", "Path to configuration file")
139
169
  .action(async (options) => {
140
170
  try {
141
171
  // Set debug mode from global options
142
172
  const programOptions = program.opts();
143
173
  logger.setDebugMode(programOptions.debug);
144
174
 
145
- logger.info('CLI', 'Starting list command', { group: options.group || null });
175
+ logger.info("CLI", "Starting list command", {
176
+ group: options.group || null,
177
+ });
146
178
 
147
179
  const config = await loadConfig(options.config);
148
180
 
149
181
  const groupsToDisplay = options.group
150
- ? { [options.group]: config.technologies[options.group]! }
182
+ ? { [options.group]: config.technologies[options.group] ?? {} }
151
183
  : config.technologies;
152
184
 
153
185
  if (options.group && !config.technologies[options.group]) {
@@ -156,41 +188,47 @@ export function createProgram() {
156
188
 
157
189
  displayTechnologies(groupsToDisplay);
158
190
 
159
- logger.info('CLI', 'List command completed');
191
+ logger.info("CLI", "List command completed");
160
192
  } catch (error: unknown) {
161
- logger.error('CLI', 'List command failed', error instanceof Error ? error : undefined);
193
+ logger.error(
194
+ "CLI",
195
+ "List command failed",
196
+ error instanceof Error ? error : undefined
197
+ );
162
198
  if (error instanceof Error) {
163
- console.error('Error:', error.message);
199
+ console.error("Error:", error.message);
164
200
  } else {
165
- console.error('Error:', String(error));
201
+ console.error("Error:", String(error));
166
202
  }
167
203
  process.exit(1);
168
204
  }
169
205
  });
170
206
 
171
207
  program
172
- .command('config')
173
- .description('Display or update configuration')
174
- .option('-p, --path', 'Show config file path')
175
- .option('-c, --config <path>', 'Path to configuration file')
208
+ .command("config")
209
+ .description("Display or update configuration")
210
+ .option("-p, --path", "Show config file path")
211
+ .option("-c, --config <path>", "Path to configuration file")
176
212
  .action((options) => {
177
213
  // Set debug mode from global options
178
214
  const programOptions = program.opts();
179
215
  logger.setDebugMode(programOptions.debug);
180
216
 
181
- logger.info('CLI', 'Starting config command', { path: options.path });
217
+ logger.info("CLI", "Starting config command", { path: options.path });
182
218
 
183
219
  if (options.path) {
184
220
  const configPath = options.config
185
221
  ? path.resolve(expandTilde(options.config))
186
- : path.join(os.homedir(), '.config', 'librarian', 'config.yaml');
222
+ : path.join(os.homedir(), ".config", "librarian", "config.yaml");
187
223
  console.log(`Config file path: ${configPath}`);
188
- logger.info('CLI', 'Config path displayed', { configPath: configPath.replace(os.homedir(), '~') });
224
+ logger.info("CLI", "Config path displayed", {
225
+ configPath: configPath.replace(os.homedir(), "~"),
226
+ });
189
227
  }
190
228
  });
191
229
 
192
230
  // Handle uncaught errors globally for CLI
193
- program.hook('preAction', (thisCommand) => {
231
+ program.hook("preAction", (thisCommand) => {
194
232
  // Set debug mode before each command
195
233
  const opts = thisCommand.opts();
196
234
  if (opts.debug !== undefined) {