#!/usr/bin/env node import util from "node:util"; import { createOpenAICompatible } from "@ai-sdk/openai-compatible"; import { streamText } from "ai"; import chalk from "chalk"; import wrapAnsi from "wrap-ansi"; import { initConfig, loadConfig } from "./src/config"; import { Conversation } from "./src/conversation"; import Renderer from "./src/render"; async function main() { const { values: args, positionals } = util.parseArgs({ args: process.argv.slice(2), options: { model: { type: "string" }, m: { type: "string" }, new: { type: "boolean" }, n: { type: "boolean" }, config: { type: "boolean" }, c: { type: "boolean" }, plain: { type: "boolean" }, "plain-out": { type: "boolean" }, "plain-err": { type: "boolean" }, version: { type: "boolean" }, v: { type: "boolean" }, "git-message": { type: "boolean" }, g: { type: "boolean" }, review: { type: "boolean" }, r: { type: "boolean" }, }, strict: true, allowPositionals: true, }); const newConvo = args.new ?? args.n; const plainOut = args["plain-out"] ?? args.plain ?? !process.stdout.isTTY; const plainErr = args["plain-err"] ?? args.plain ?? !process.stderr.isTTY; const modelFlag = args.model ?? args.m; const versionFlag = args.version ?? args.v; const configFlag = args.config ?? args.c; const messageFlag = args["git-message"] ?? args.g; const reviewFlag = args.review ?? args.r; if (versionFlag) { console.log("0.0.0"); return; } const config = await loadConfig(configFlag); if (configFlag || !config) { await initConfig(config); return; } const model = modelFlag ?? config.model; const renderer = new Renderer(plainOut, plainErr); const provider = createOpenAICompatible({ name: "llama.cpp", apiKey: "local", baseURL: config.baseURL, includeUsage: true, // Include usage information in streaming responses }); const convo = new Conversation(model); if (!newConvo) { await convo.load(); if (modelFlag) convo.model = modelFlag; } let prompt = "Introduce yourself."; const input = positionals.join(" ").trim(); if (messageFlag) { prompt = `\`\`\`diff ${input} \`\`\` Generate a conventional commit message for this diff. If you are unable to generate a reasonable option, ask for more context.`; } else if (reviewFlag) { prompt = `\`\`\`diff ${input} \`\`\` Review the above diff for any potential bugs, best practices, performance issues, or security flaws. Let me know if you need any more context to compelete your review.`; } else if (input) { prompt = input; } convo.messages.push({ role: "user", content: prompt }); const { fullStream, text, totalUsage } = streamText({ model: provider(convo.model), messages: convo.messages, }); await renderer.renderStream(fullStream); convo.messages.push({ role: "assistant", content: await text }); await convo.save(); await renderer.renderStats(totalUsage); } main().catch((err) => { if ("message" in err) { const [columns] = process.stderr.getWindowSize(); console.error(wrapAnsi(chalk.red(err.message), columns)); } else console.log(err); process.exit(1); });