codecanon
Version:
CLI tool that downloads documentation from 3rd party libraries, converts them to Markdown, and optimizes for LLMs
79 lines (75 loc) • 3.21 kB
JavaScript
import { promises as fs } from "fs";
import { join } from "path";
import { getWorkspacePaths, isWorkspaceInitialized, loadWorkspaceConfig, } from "./workspace.js";
/**
* Query the local documentation context using natural language
*/
export async function queryContext(options) {
// Ensure workspace is initialized
if (!(await isWorkspaceInitialized(options.cwd))) {
throw new Error("No CodeCanon workspace found. Run 'canon init' first.");
}
const config = await loadWorkspaceConfig(options.cwd);
if (config.packages.length === 0) {
throw new Error("No packages in workspace. Use 'canon add <package>' to add documentation first.");
}
// Filter packages if specified
const targetPackages = options.packages
? config.packages.filter((p) => options.packages.includes(p.name))
: config.packages;
if (targetPackages.length === 0) {
throw new Error("No matching packages found in workspace.");
}
// TODO: Implement actual LLM querying with RAG
// For now, return a placeholder response
const contextChunks = await loadRelevantContext(options, targetPackages);
const answer = await generateAnswer(options, contextChunks);
return {
answer,
sources: contextChunks.map((chunk) => ({
package: chunk.package,
section: chunk.section,
url: chunk.url,
})),
};
}
/**
* Load relevant context chunks for the query (placeholder implementation)
*/
async function loadRelevantContext(options, packages) {
const paths = getWorkspacePaths(options.cwd);
const chunks = [];
// TODO: Implement vector similarity search
// For now, just load some content from each package
for (const pkg of packages.slice(0, options.contextLimit)) {
try {
const chunkPath = join(paths.cache, pkg.name, pkg.version, "chunks", "README.chunk.md");
const content = await fs.readFile(chunkPath, "utf-8");
chunks.push({
package: pkg.name,
section: "README",
content: content.slice(0, 1000), // Limit content length
url: pkg.documentationUrl,
});
}
catch (error) {
console.warn(`Warning: Could not load content for ${pkg.name}`);
}
}
return chunks;
}
/**
* Generate an answer using the context chunks (placeholder implementation)
*/
async function generateAnswer(options, contextChunks) {
// TODO: Implement actual LLM API calls
// For now, return a mock response that incorporates the context
const packageNames = contextChunks.map((c) => c.package).join(", ");
return `This is a placeholder answer for your question: "${options.question}"
Based on the documentation for packages: ${packageNames}
The actual LLM integration will be implemented later. This would normally:
1. Use the selected model (${options.model || "default"})
2. Include relevant context from ${contextChunks.length} documentation chunks
3. Generate a comprehensive answer using RAG (Retrieval-Augmented Generation)
Context loaded from: ${contextChunks.map((c) => `${c.package}/${c.section}`).join(", ")}`;
}