@skroyc/librarian 0.1.0 → 0.2.1
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 +63 -170
- 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 +694 -784
- 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/dist/cli.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import { loadConfig } from "./config.js";
|
|
6
|
+
import { Librarian } from "./index.js";
|
|
7
|
+
import { logger } from "./utils/logger.js";
|
|
8
|
+
import { expandTilde } from "./utils/path-utils.js";
|
|
9
9
|
async function handleStreamingOutput(stream) {
|
|
10
10
|
try {
|
|
11
11
|
for await (const chunk of stream) {
|
|
@@ -13,7 +13,7 @@ async function handleStreamingOutput(stream) {
|
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
catch (error) {
|
|
16
|
-
console.error(
|
|
16
|
+
console.error("\nStreaming interrupted or failed:", error instanceof Error ? error.message : "Unknown error");
|
|
17
17
|
process.exit(1);
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -21,7 +21,7 @@ async function handleTechnologyQuery(librarian, techName, query, noStream) {
|
|
|
21
21
|
if (noStream) {
|
|
22
22
|
const result = await librarian.queryRepository(techName, query);
|
|
23
23
|
console.log(result);
|
|
24
|
-
logger.info(
|
|
24
|
+
logger.info("CLI", "Explore query completed (non-streaming)");
|
|
25
25
|
}
|
|
26
26
|
else {
|
|
27
27
|
await handleStreamingOutput(librarian.streamRepository(techName, query));
|
|
@@ -31,22 +31,22 @@ async function handleGroupQuery(librarian, groupName, query, noStream) {
|
|
|
31
31
|
if (noStream) {
|
|
32
32
|
const result = await librarian.queryGroup(groupName, query);
|
|
33
33
|
console.log(result);
|
|
34
|
-
logger.info(
|
|
34
|
+
logger.info("CLI", "Explore group query completed (non-streaming)");
|
|
35
35
|
}
|
|
36
36
|
else {
|
|
37
37
|
await handleStreamingOutput(librarian.streamGroup(groupName, query));
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
function displayTechnologies(groups) {
|
|
41
|
-
console.log(
|
|
41
|
+
console.log("Available Technologies:");
|
|
42
42
|
for (const [groupName, techs] of Object.entries(groups)) {
|
|
43
43
|
if (!techs || Object.keys(techs).length === 0) {
|
|
44
44
|
continue;
|
|
45
45
|
}
|
|
46
46
|
console.log(`\n[${groupName}]`);
|
|
47
47
|
for (const [techName, details] of Object.entries(techs)) {
|
|
48
|
-
const desc = details.description ? ` - ${details.description}` :
|
|
49
|
-
const branch = details.branch ? ` (${details.branch})` :
|
|
48
|
+
const desc = details.description ? ` - ${details.description}` : "";
|
|
49
|
+
const branch = details.branch ? ` (${details.branch})` : "";
|
|
50
50
|
console.log(` - ${techName}${branch}${desc}`);
|
|
51
51
|
}
|
|
52
52
|
}
|
|
@@ -54,32 +54,32 @@ function displayTechnologies(groups) {
|
|
|
54
54
|
export function createProgram() {
|
|
55
55
|
const program = new Command();
|
|
56
56
|
program
|
|
57
|
-
.name(
|
|
58
|
-
.description(
|
|
59
|
-
.version(
|
|
60
|
-
.option(
|
|
57
|
+
.name("librarian")
|
|
58
|
+
.description("CLI to interact with technology repositories using AI")
|
|
59
|
+
.version("0.1.0")
|
|
60
|
+
.option("--debug", "Enable debug logging");
|
|
61
61
|
program
|
|
62
|
-
.command(
|
|
63
|
-
.description(
|
|
64
|
-
.argument(
|
|
65
|
-
.option(
|
|
66
|
-
.option(
|
|
67
|
-
.option(
|
|
68
|
-
.option(
|
|
62
|
+
.command("explore")
|
|
63
|
+
.description("Explore technologies or groups")
|
|
64
|
+
.argument("<query>", "The question or exploration query")
|
|
65
|
+
.option("-t, --tech <technology>", "Specific technology to explore")
|
|
66
|
+
.option("-g, --group <group>", "Technology group to explore")
|
|
67
|
+
.option("-c, --config <path>", "Path to configuration file")
|
|
68
|
+
.option("--no-stream", "Disable streaming output (streaming is enabled by default)")
|
|
69
69
|
.action(async (query, options) => {
|
|
70
70
|
try {
|
|
71
71
|
const programOptions = program.opts();
|
|
72
72
|
logger.setDebugMode(programOptions.debug);
|
|
73
|
-
logger.info(
|
|
73
|
+
logger.info("CLI", "Starting explore command", {
|
|
74
74
|
queryLength: query.length,
|
|
75
75
|
tech: options.tech || null,
|
|
76
76
|
group: options.group || null,
|
|
77
77
|
noStream: options.noStream,
|
|
78
|
-
debug: programOptions.debug
|
|
78
|
+
debug: programOptions.debug,
|
|
79
79
|
});
|
|
80
80
|
if (options.tech && options.group) {
|
|
81
|
-
logger.error(
|
|
82
|
-
console.error(
|
|
81
|
+
logger.error("CLI", "Cannot use both --tech and --group flags simultaneously");
|
|
82
|
+
console.error("Error: Cannot use both --tech and --group flags simultaneously");
|
|
83
83
|
process.exit(1);
|
|
84
84
|
}
|
|
85
85
|
const config = await loadConfig(options.config);
|
|
@@ -96,69 +96,73 @@ export function createProgram() {
|
|
|
96
96
|
await handleGroupQuery(librarian, options.group, query, options.noStream);
|
|
97
97
|
}
|
|
98
98
|
else {
|
|
99
|
-
console.error(
|
|
99
|
+
console.error("Error: Either --tech or --group must be specified");
|
|
100
100
|
process.exit(1);
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
catch (error) {
|
|
104
104
|
if (error instanceof Error) {
|
|
105
|
-
console.error(
|
|
105
|
+
console.error("Error:", error.message);
|
|
106
106
|
}
|
|
107
107
|
else {
|
|
108
|
-
console.error(
|
|
108
|
+
console.error("Error:", String(error));
|
|
109
109
|
}
|
|
110
110
|
process.exit(1);
|
|
111
111
|
}
|
|
112
112
|
});
|
|
113
113
|
program
|
|
114
|
-
.command(
|
|
115
|
-
.description(
|
|
116
|
-
.option(
|
|
117
|
-
.option(
|
|
114
|
+
.command("list")
|
|
115
|
+
.description("List available technologies")
|
|
116
|
+
.option("-g, --group <group>", "Filter technologies by group")
|
|
117
|
+
.option("-c, --config <path>", "Path to configuration file")
|
|
118
118
|
.action(async (options) => {
|
|
119
119
|
try {
|
|
120
120
|
const programOptions = program.opts();
|
|
121
121
|
logger.setDebugMode(programOptions.debug);
|
|
122
|
-
logger.info(
|
|
122
|
+
logger.info("CLI", "Starting list command", {
|
|
123
|
+
group: options.group || null,
|
|
124
|
+
});
|
|
123
125
|
const config = await loadConfig(options.config);
|
|
124
126
|
const groupsToDisplay = options.group
|
|
125
|
-
? { [options.group]: config.technologies[options.group] }
|
|
127
|
+
? { [options.group]: config.technologies[options.group] ?? {} }
|
|
126
128
|
: config.technologies;
|
|
127
129
|
if (options.group && !config.technologies[options.group]) {
|
|
128
130
|
throw new Error(`Group ${options.group} not found in configuration`);
|
|
129
131
|
}
|
|
130
132
|
displayTechnologies(groupsToDisplay);
|
|
131
|
-
logger.info(
|
|
133
|
+
logger.info("CLI", "List command completed");
|
|
132
134
|
}
|
|
133
135
|
catch (error) {
|
|
134
|
-
logger.error(
|
|
136
|
+
logger.error("CLI", "List command failed", error instanceof Error ? error : undefined);
|
|
135
137
|
if (error instanceof Error) {
|
|
136
|
-
console.error(
|
|
138
|
+
console.error("Error:", error.message);
|
|
137
139
|
}
|
|
138
140
|
else {
|
|
139
|
-
console.error(
|
|
141
|
+
console.error("Error:", String(error));
|
|
140
142
|
}
|
|
141
143
|
process.exit(1);
|
|
142
144
|
}
|
|
143
145
|
});
|
|
144
146
|
program
|
|
145
|
-
.command(
|
|
146
|
-
.description(
|
|
147
|
-
.option(
|
|
148
|
-
.option(
|
|
147
|
+
.command("config")
|
|
148
|
+
.description("Display or update configuration")
|
|
149
|
+
.option("-p, --path", "Show config file path")
|
|
150
|
+
.option("-c, --config <path>", "Path to configuration file")
|
|
149
151
|
.action((options) => {
|
|
150
152
|
const programOptions = program.opts();
|
|
151
153
|
logger.setDebugMode(programOptions.debug);
|
|
152
|
-
logger.info(
|
|
154
|
+
logger.info("CLI", "Starting config command", { path: options.path });
|
|
153
155
|
if (options.path) {
|
|
154
156
|
const configPath = options.config
|
|
155
157
|
? path.resolve(expandTilde(options.config))
|
|
156
|
-
: path.join(os.homedir(),
|
|
158
|
+
: path.join(os.homedir(), ".config", "librarian", "config.yaml");
|
|
157
159
|
console.log(`Config file path: ${configPath}`);
|
|
158
|
-
logger.info(
|
|
160
|
+
logger.info("CLI", "Config path displayed", {
|
|
161
|
+
configPath: configPath.replace(os.homedir(), "~"),
|
|
162
|
+
});
|
|
159
163
|
}
|
|
160
164
|
});
|
|
161
|
-
program.hook(
|
|
165
|
+
program.hook("preAction", (thisCommand) => {
|
|
162
166
|
const opts = thisCommand.opts();
|
|
163
167
|
if (opts.debug !== undefined) {
|
|
164
168
|
logger.setDebugMode(opts.debug);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { LibrarianConfig } from
|
|
1
|
+
import type { LibrarianConfig } from "./index.js";
|
|
2
2
|
export declare function loadConfig(configPath?: string): Promise<LibrarianConfig>;
|
|
3
3
|
export declare function createDefaultConfig(configPath: string): Promise<void>;
|
|
4
4
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAqTlD,wBAAsB,UAAU,CAC9B,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,eAAe,CAAC,CA2E1B;AAED,wBAAsB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB3E"}
|
package/dist/config.js
CHANGED
|
@@ -1,48 +1,70 @@
|
|
|
1
|
-
import { mkdir } from
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
1
|
+
import { mkdir } from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { parse, stringify } from "yaml";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { logger } from "./utils/logger.js";
|
|
7
|
+
import { expandTilde } from "./utils/path-utils.js";
|
|
8
8
|
const TechnologySchema = z.object({
|
|
9
9
|
repo: z.string().optional(),
|
|
10
10
|
name: z.string().optional(),
|
|
11
|
-
branch: z.string().default(
|
|
11
|
+
branch: z.string().default("main"),
|
|
12
12
|
description: z.string().optional(),
|
|
13
13
|
});
|
|
14
14
|
const GroupSchema = z.record(z.string(), TechnologySchema);
|
|
15
15
|
const ConfigSchema = z.object({
|
|
16
16
|
technologies: z.record(z.string(), GroupSchema).optional(),
|
|
17
17
|
repositories: z.record(z.string(), z.string()).optional(),
|
|
18
|
-
aiProvider: z
|
|
19
|
-
|
|
18
|
+
aiProvider: z
|
|
19
|
+
.object({
|
|
20
|
+
type: z.enum([
|
|
21
|
+
"openai",
|
|
22
|
+
"anthropic",
|
|
23
|
+
"google",
|
|
24
|
+
"openai-compatible",
|
|
25
|
+
"anthropic-compatible",
|
|
26
|
+
"claude-code",
|
|
27
|
+
"gemini-cli",
|
|
28
|
+
]),
|
|
20
29
|
apiKey: z.string().optional(),
|
|
21
30
|
model: z.string().optional(),
|
|
22
31
|
baseURL: z.string().optional(),
|
|
23
|
-
})
|
|
24
|
-
|
|
32
|
+
})
|
|
33
|
+
.optional(),
|
|
34
|
+
llm_provider: z
|
|
35
|
+
.enum([
|
|
36
|
+
"openai",
|
|
37
|
+
"anthropic",
|
|
38
|
+
"google",
|
|
39
|
+
"openai-compatible",
|
|
40
|
+
"anthropic-compatible",
|
|
41
|
+
"claude-code",
|
|
42
|
+
"gemini-cli",
|
|
43
|
+
])
|
|
44
|
+
.optional(),
|
|
25
45
|
llm_model: z.string().optional(),
|
|
26
46
|
base_url: z.string().optional(),
|
|
27
|
-
workingDir: z.string().default(
|
|
47
|
+
workingDir: z.string().default("./librarian_work"),
|
|
28
48
|
repos_path: z.string().optional(),
|
|
29
49
|
});
|
|
30
50
|
async function loadEnvFile(envPath) {
|
|
31
|
-
logger.debug(
|
|
51
|
+
logger.debug("CONFIG", "Loading .env file", {
|
|
52
|
+
envPath: envPath.replace(os.homedir(), "~"),
|
|
53
|
+
});
|
|
32
54
|
const envFile = Bun.file(envPath);
|
|
33
55
|
if (!(await envFile.exists())) {
|
|
34
|
-
logger.debug(
|
|
56
|
+
logger.debug("CONFIG", ".env file not found, continuing without it");
|
|
35
57
|
return {};
|
|
36
58
|
}
|
|
37
|
-
logger.info(
|
|
59
|
+
logger.info("CONFIG", ".env file found and loading");
|
|
38
60
|
const content = await envFile.text();
|
|
39
61
|
const env = {};
|
|
40
|
-
for (const line of content.split(
|
|
62
|
+
for (const line of content.split("\n")) {
|
|
41
63
|
const trimmed = line.trim();
|
|
42
|
-
if (!trimmed || trimmed.startsWith(
|
|
64
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
43
65
|
continue;
|
|
44
66
|
}
|
|
45
|
-
const equalsIndex = trimmed.indexOf(
|
|
67
|
+
const equalsIndex = trimmed.indexOf("=");
|
|
46
68
|
if (equalsIndex === -1) {
|
|
47
69
|
continue;
|
|
48
70
|
}
|
|
@@ -54,87 +76,101 @@ async function loadEnvFile(envPath) {
|
|
|
54
76
|
}
|
|
55
77
|
env[key] = value;
|
|
56
78
|
}
|
|
57
|
-
logger.debug(
|
|
79
|
+
logger.debug("CONFIG", `.env loaded: ${Object.keys(env).length} variables`);
|
|
58
80
|
return env;
|
|
59
81
|
}
|
|
60
82
|
function validateApiKey(config, envPath, errors) {
|
|
61
|
-
const isCliProvider = config.aiProvider.type ===
|
|
62
|
-
|
|
83
|
+
const isCliProvider = config.aiProvider.type === "claude-code" ||
|
|
84
|
+
config.aiProvider.type === "gemini-cli";
|
|
85
|
+
if (!isCliProvider &&
|
|
86
|
+
(!config.aiProvider.apiKey || config.aiProvider.apiKey.trim() === "")) {
|
|
63
87
|
const errorMsg = `API key is missing or empty. Please set LIBRARIAN_API_KEY in ${envPath}`;
|
|
64
88
|
errors.push(errorMsg);
|
|
65
|
-
logger.debug(
|
|
89
|
+
logger.debug("CONFIG", "Validation failed: API key missing", {
|
|
90
|
+
envPath: envPath.replace(os.homedir(), "~"),
|
|
91
|
+
});
|
|
66
92
|
}
|
|
67
93
|
}
|
|
68
94
|
function validateBaseUrlForCompatibleProviders(config, errors) {
|
|
69
|
-
if (config.aiProvider.type ===
|
|
70
|
-
|
|
95
|
+
if (config.aiProvider.type === "openai-compatible" &&
|
|
96
|
+
!config.aiProvider.baseURL) {
|
|
97
|
+
const errorMsg = "base_url is required for openai-compatible providers";
|
|
71
98
|
errors.push(errorMsg);
|
|
72
|
-
logger.debug(
|
|
99
|
+
logger.debug("CONFIG", "Validation failed: base_url missing for openai-compatible provider");
|
|
73
100
|
}
|
|
74
|
-
if (config.aiProvider.type ===
|
|
101
|
+
if (config.aiProvider.type === "anthropic-compatible") {
|
|
75
102
|
if (!config.aiProvider.baseURL) {
|
|
76
|
-
const errorMsg =
|
|
103
|
+
const errorMsg = "base_url is required for anthropic-compatible providers";
|
|
77
104
|
errors.push(errorMsg);
|
|
78
|
-
logger.debug(
|
|
105
|
+
logger.debug("CONFIG", "Validation failed: base_url missing for anthropic-compatible provider");
|
|
79
106
|
}
|
|
80
107
|
if (!config.aiProvider.model) {
|
|
81
|
-
const errorMsg =
|
|
108
|
+
const errorMsg = "model is required for anthropic-compatible providers";
|
|
82
109
|
errors.push(errorMsg);
|
|
83
|
-
logger.debug(
|
|
110
|
+
logger.debug("CONFIG", "Validation failed: model missing for anthropic-compatible provider");
|
|
84
111
|
}
|
|
85
112
|
}
|
|
86
113
|
}
|
|
87
114
|
function validateReposPath(config, errors) {
|
|
88
115
|
if (!config.repos_path) {
|
|
89
|
-
errors.push(
|
|
116
|
+
errors.push("repos_path is required in configuration");
|
|
90
117
|
}
|
|
91
118
|
}
|
|
92
119
|
function validateTechnologies(config, errors) {
|
|
93
120
|
const hasTechnologies = config.technologies && Object.keys(config.technologies).length > 0;
|
|
94
121
|
if (!hasTechnologies) {
|
|
95
|
-
errors.push(
|
|
122
|
+
errors.push("No technologies defined in configuration");
|
|
96
123
|
}
|
|
97
124
|
if (!config.technologies) {
|
|
98
125
|
return;
|
|
99
126
|
}
|
|
100
127
|
for (const [groupName, group] of Object.entries(config.technologies)) {
|
|
101
|
-
if (groupName.includes(
|
|
128
|
+
if (groupName.includes("..")) {
|
|
102
129
|
errors.push(`Group name "${groupName}" contains invalid path characters`);
|
|
103
|
-
logger.debug(
|
|
130
|
+
logger.debug("CONFIG", "Validation failed: group name contains path traversal", { groupName });
|
|
104
131
|
}
|
|
105
132
|
for (const [techName, tech] of Object.entries(group)) {
|
|
106
133
|
if (!tech.repo) {
|
|
107
134
|
const errorMsg = `Technology "${techName}" in group "${groupName}" is missing required "repo" field`;
|
|
108
135
|
errors.push(errorMsg);
|
|
109
|
-
logger.debug(
|
|
136
|
+
logger.debug("CONFIG", "Validation failed: missing repo field", {
|
|
137
|
+
techName,
|
|
138
|
+
groupName,
|
|
139
|
+
});
|
|
110
140
|
continue;
|
|
111
141
|
}
|
|
112
|
-
const isRemoteUrl = tech.repo.startsWith(
|
|
113
|
-
const isFileUrl = tech.repo.startsWith(
|
|
114
|
-
const hasProtocol = tech.repo.includes(
|
|
142
|
+
const isRemoteUrl = tech.repo.startsWith("http://") || tech.repo.startsWith("https://");
|
|
143
|
+
const isFileUrl = tech.repo.startsWith("file://");
|
|
144
|
+
const hasProtocol = tech.repo.includes("://");
|
|
115
145
|
if (!(isRemoteUrl || isFileUrl) && hasProtocol) {
|
|
116
146
|
const errorMsg = `Technology "${techName}" has invalid repo URL: ${tech.repo}. Must be http://, https://, file://, or a local path`;
|
|
117
147
|
errors.push(errorMsg);
|
|
118
|
-
logger.debug(
|
|
148
|
+
logger.debug("CONFIG", "Validation failed: invalid repo URL", {
|
|
149
|
+
techName,
|
|
150
|
+
groupName,
|
|
151
|
+
repoUrl: tech.repo,
|
|
152
|
+
});
|
|
119
153
|
}
|
|
120
154
|
}
|
|
121
155
|
}
|
|
122
156
|
}
|
|
123
157
|
function reportErrors(errors) {
|
|
124
158
|
if (errors.length > 0) {
|
|
125
|
-
logger.error(
|
|
126
|
-
|
|
159
|
+
logger.error("CONFIG", "Configuration validation failed", undefined, {
|
|
160
|
+
errorCount: errors.length,
|
|
161
|
+
});
|
|
162
|
+
console.error("Configuration validation failed:");
|
|
127
163
|
for (const err of errors) {
|
|
128
164
|
console.error(` - ${err}`);
|
|
129
165
|
}
|
|
130
166
|
process.exit(1);
|
|
131
167
|
}
|
|
132
168
|
else {
|
|
133
|
-
logger.info(
|
|
169
|
+
logger.info("CONFIG", "Configuration validation passed");
|
|
134
170
|
}
|
|
135
171
|
}
|
|
136
172
|
function validateConfig(config, envPath) {
|
|
137
|
-
logger.debug(
|
|
173
|
+
logger.debug("CONFIG", "Validating configuration");
|
|
138
174
|
const errors = [];
|
|
139
175
|
validateApiKey(config, envPath, errors);
|
|
140
176
|
validateBaseUrlForCompatibleProviders(config, errors);
|
|
@@ -149,12 +185,14 @@ function normalizeTechnologies(technologies) {
|
|
|
149
185
|
for (const group of Object.values(technologies ?? {})) {
|
|
150
186
|
for (const tech of Object.values(group ?? {})) {
|
|
151
187
|
if (!tech.repo && tech.name) {
|
|
152
|
-
logger.debug(
|
|
188
|
+
logger.debug("CONFIG", 'Normalizing technology: using "name" as "repo"', { name: tech.name });
|
|
153
189
|
tech.repo = tech.name;
|
|
154
190
|
}
|
|
155
191
|
}
|
|
156
192
|
}
|
|
157
|
-
logger.debug(
|
|
193
|
+
logger.debug("CONFIG", "Technologies normalized", {
|
|
194
|
+
groupCount: Object.keys(technologies).length,
|
|
195
|
+
});
|
|
158
196
|
return technologies;
|
|
159
197
|
}
|
|
160
198
|
function buildAiProvider(validatedConfig, envVars) {
|
|
@@ -162,67 +200,75 @@ function buildAiProvider(validatedConfig, envVars) {
|
|
|
162
200
|
const { type, model, baseURL } = validatedConfig.aiProvider;
|
|
163
201
|
return {
|
|
164
202
|
type,
|
|
165
|
-
apiKey: validatedConfig.aiProvider.apiKey || envVars.LIBRARIAN_API_KEY ||
|
|
203
|
+
apiKey: validatedConfig.aiProvider.apiKey || envVars.LIBRARIAN_API_KEY || "",
|
|
166
204
|
...(model && { model }),
|
|
167
|
-
...(baseURL && { baseURL })
|
|
205
|
+
...(baseURL && { baseURL }),
|
|
168
206
|
};
|
|
169
207
|
}
|
|
170
208
|
if (validatedConfig.llm_provider) {
|
|
171
|
-
logger.debug(
|
|
209
|
+
logger.debug("CONFIG", "Using README-style llm_* keys for AI provider");
|
|
172
210
|
return {
|
|
173
211
|
type: validatedConfig.llm_provider,
|
|
174
|
-
apiKey: envVars.LIBRARIAN_API_KEY ||
|
|
212
|
+
apiKey: envVars.LIBRARIAN_API_KEY || "",
|
|
175
213
|
...(validatedConfig.llm_model && { model: validatedConfig.llm_model }),
|
|
176
|
-
...(validatedConfig.base_url && { baseURL: validatedConfig.base_url })
|
|
214
|
+
...(validatedConfig.base_url && { baseURL: validatedConfig.base_url }),
|
|
177
215
|
};
|
|
178
216
|
}
|
|
179
|
-
logger.error(
|
|
180
|
-
console.error(
|
|
217
|
+
logger.error("CONFIG", "AI provider is required in configuration");
|
|
218
|
+
console.error("Configuration error: llm_provider (or aiProvider) is required in config.yaml");
|
|
181
219
|
process.exit(1);
|
|
182
220
|
}
|
|
183
221
|
export async function loadConfig(configPath) {
|
|
184
|
-
const defaultPath = path.join(os.homedir(),
|
|
222
|
+
const defaultPath = path.join(os.homedir(), ".config", "librarian", "config.yaml");
|
|
185
223
|
const actualPath = configPath ? expandTilde(configPath) : defaultPath;
|
|
186
|
-
logger.info(
|
|
224
|
+
logger.info("CONFIG", "Loading configuration", {
|
|
225
|
+
configPath: actualPath.replace(os.homedir(), "~"),
|
|
226
|
+
});
|
|
187
227
|
const configDir = path.dirname(actualPath);
|
|
188
|
-
const envPath = path.join(configDir,
|
|
228
|
+
const envPath = path.join(configDir, ".env");
|
|
189
229
|
const envVars = await loadEnvFile(envPath);
|
|
190
230
|
if (!(await Bun.file(actualPath).exists())) {
|
|
191
|
-
logger.info(
|
|
231
|
+
logger.info("CONFIG", "Config file not found, creating default config");
|
|
192
232
|
try {
|
|
193
233
|
await createDefaultConfig(actualPath);
|
|
194
|
-
logger.info(
|
|
234
|
+
logger.info("CONFIG", "Default config created successfully");
|
|
195
235
|
}
|
|
196
236
|
catch (error) {
|
|
197
|
-
logger.error(
|
|
237
|
+
logger.error("CONFIG", "Failed to create default config", error instanceof Error ? error : new Error(String(error)), { actualPath: actualPath.replace(os.homedir(), "~") });
|
|
198
238
|
console.error(`Failed to create default config at ${actualPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
199
239
|
process.exit(1);
|
|
200
240
|
}
|
|
201
241
|
}
|
|
202
242
|
const configFileContent = await Bun.file(actualPath).text();
|
|
203
|
-
logger.debug(
|
|
243
|
+
logger.debug("CONFIG", "Config file read successfully", {
|
|
244
|
+
fileSize: configFileContent.length,
|
|
245
|
+
});
|
|
204
246
|
const parsedConfig = parse(configFileContent);
|
|
205
247
|
const validatedConfig = ConfigSchema.parse(parsedConfig);
|
|
206
|
-
logger.debug(
|
|
248
|
+
logger.debug("CONFIG", "Config schema validation passed");
|
|
207
249
|
const technologies = normalizeTechnologies(validatedConfig.technologies);
|
|
208
250
|
const aiProvider = buildAiProvider(validatedConfig, envVars);
|
|
209
|
-
logger.debug(
|
|
251
|
+
logger.debug("CONFIG", "API key source", {
|
|
210
252
|
fromEnv: !!envVars.LIBRARIAN_API_KEY,
|
|
211
|
-
fromConfig: !!validatedConfig.aiProvider?.apiKey
|
|
253
|
+
fromConfig: !!validatedConfig.aiProvider?.apiKey,
|
|
212
254
|
});
|
|
213
255
|
const config = {
|
|
214
256
|
...validatedConfig,
|
|
215
257
|
technologies: technologies || { default: {} },
|
|
216
258
|
aiProvider,
|
|
217
|
-
repos_path: validatedConfig.repos_path
|
|
218
|
-
|
|
259
|
+
repos_path: validatedConfig.repos_path
|
|
260
|
+
? expandTilde(validatedConfig.repos_path)
|
|
261
|
+
: undefined,
|
|
262
|
+
workingDir: expandTilde(validatedConfig.workingDir),
|
|
219
263
|
};
|
|
220
264
|
validateConfig(config, envPath);
|
|
221
|
-
logger.info(
|
|
265
|
+
logger.info("CONFIG", "Config loaded successfully", {
|
|
222
266
|
aiProviderType: config.aiProvider.type,
|
|
223
267
|
model: config.aiProvider.model,
|
|
224
268
|
techGroupsCount: Object.keys(config.technologies || {}).length,
|
|
225
|
-
reposPath: config.repos_path
|
|
269
|
+
reposPath: config.repos_path
|
|
270
|
+
? config.repos_path.replace(os.homedir(), "~")
|
|
271
|
+
: "workingDir",
|
|
226
272
|
});
|
|
227
273
|
return config;
|
|
228
274
|
}
|
|
@@ -232,8 +278,8 @@ export async function createDefaultConfig(configPath) {
|
|
|
232
278
|
aiProvider: {
|
|
233
279
|
type: "openai-compatible",
|
|
234
280
|
model: "grok-code",
|
|
235
|
-
baseURL: "https://opencode.ai/zen/v1"
|
|
236
|
-
}
|
|
281
|
+
baseURL: "https://opencode.ai/zen/v1",
|
|
282
|
+
},
|
|
237
283
|
};
|
|
238
284
|
const configDir = path.dirname(configPath);
|
|
239
285
|
await mkdir(configDir, { recursive: true });
|