From a03e6e94a9e87af9fb52fce3909dfb590f0f5db3 Mon Sep 17 00:00:00 2001 From: mitchell Date: Mon, 8 Jun 2026 16:09:28 -0400 Subject: [PATCH] feat(tts): add --edit flag and fix CLI argument parsing - Improved input trimming and console output formatting in `tts.ts` - Updated codespan colors in the markdown renderer for better visual contrast - Disabled `noPropertyAccessFromIndexSignature` in tsconfig.json --- index.ts | 4 ++-- src/render/markdown.ts | 2 +- tsconfig.json | 4 ++-- tts.ts | 38 ++++++++++++++++++++++++++++++-------- 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/index.ts b/index.ts index cc090fa..41f7431 100644 --- a/index.ts +++ b/index.ts @@ -8,7 +8,7 @@ import { Conversation } from "./src/conversation"; import Renderer from "./src/render"; const { values: args, positionals } = parseArgs({ - args: process.argv, + args: process.argv.slice(2), options: { model: { type: "string" }, m: { type: "string" }, @@ -62,7 +62,7 @@ async function main() { if (modelFlag) convo.model = modelFlag; } - const prompt = positionals.slice(2).join(" ") || "Introduce yourself."; + const prompt = positionals.join(" ") || "Introduce yourself."; convo.messages.push({ role: "user", content: prompt }); const { fullStream, text, totalUsage } = streamText({ diff --git a/src/render/markdown.ts b/src/render/markdown.ts index e3271ae..9e8269e 100644 --- a/src/render/markdown.ts +++ b/src/render/markdown.ts @@ -144,7 +144,7 @@ class LmcRenderer extends Renderer { } override codespan({ text }: Tokens.Codespan) { - return chalk.bgRgb(192, 192, 192).black.bold(text); + return chalk.bgRgb(192, 192, 192).rgb(24, 24, 24).bold(text); } override link({ href, tokens }: Tokens.Link) { diff --git a/tsconfig.json b/tsconfig.json index edeab3e..d5dde93 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,12 +23,12 @@ "noUnusedLocals": true, "noUnusedParameters": true, "noFallthroughCasesInSwitch": true, - "noPropertyAccessFromIndexSignature": true, + "noPropertyAccessFromIndexSignature": false, // Recommended Options "strict": true, "jsx": "react-jsx", - //"allowImportingTsExtensions": true, + "allowImportingTsExtensions": false, "allowArbitraryExtensions": true, "verbatimModuleSyntax": true, "isolatedModules": true, diff --git a/tts.ts b/tts.ts index 1343c24..c6be5bc 100644 --- a/tts.ts +++ b/tts.ts @@ -1,3 +1,4 @@ +import fs from "node:fs/promises"; import os from "node:os"; import process from "node:process"; import { createInterface } from "node:readline"; @@ -18,6 +19,8 @@ async function main() { w: { type: "boolean" }, url: { type: "string" }, u: { type: "string" }, + edit: { type: "boolean" }, + e: { type: "boolean" }, }, strict: true, allowPositionals: false, @@ -25,6 +28,7 @@ async function main() { const wait = args.wait ?? args.w; const url = args.url ?? args.u; + const edit = args.edit ?? args.e; let input = url ? url @@ -34,16 +38,17 @@ async function main() { process.stdin.on("data", (chunk) => (data += chunk)); process.stdin.on("end", () => resolve(data)); }); + input = input.trim(); if (url !== undefined) { - const result = await fetch(input.trim()); - const window = new Window({ url: input.trim() }); + const result = await fetch(input); + const window = new Window({ url: input }); const doc = window.document; doc.write(await result.text()); await window.happyDOM.waitUntilComplete(); const readable = new Readability(doc).parse(); - if (readable?.textContent) input = readable.textContent; - if (input.trim() === result.url) { + if (readable?.textContent) input = readable.textContent.trim(); + if (input === result.url) { console.error("Unable to read web page."); process.exit(1); } @@ -59,6 +64,18 @@ async function main() { await execa({ cwd, shell: true, reject: false })`rm *.wav`; + if (edit) { + const file = await fs.open(`${cwd}input.txt`, "w+"); + await file.writeFile(input); + const editor = process.env.EDITOR || "nano"; + await execa({ + stdin: "inherit", + stdout: "inherit", + })`${editor} ${cwd}input.txt`; + input = await file.readFile("utf8"); + await file.close(); + } + console.log(chalk.blue("Welcome to TTSC!")); console.log( chalk.yellow( @@ -107,9 +124,11 @@ async function main() { const [columns] = process.stdout.getWindowSize(); const text = wrapAnsi(info.text, columns); const file = `${home}/.ttsc/${info.file}.wav`; - console.log(`\n${chalk.blue(file)}:\n${text}\n`); - if (!wait) { + if (wait) { + console.write("."); + } else { + console.log(`\n${chalk.blue(file)}\n${text}\n`); await execa({ cwd, stdin: "ignore", @@ -126,10 +145,9 @@ async function main() { const duration = ((stop - start) / 1000).toFixed(2); console.log(chalk.green(`\nProcessing finished: ${duration}s`)); - console.log(chalk.yellow(`Combining audio with sox...`)); + console.log(chalk.yellow(`Combining audio with sox...\n`)); try { await execa({ cwd, shell: true })`sox *.wav output.wav`; - console.log(chalk.green(`Playing audio from ${cwd}output.wav`)); } catch (err) { if (err instanceof Object && "code" in err && err.code === "ENOENT") { console.error("Sox not found. Unable to combine outputs."); @@ -140,6 +158,10 @@ async function main() { process.exit(); } + const [columns] = process.stdout.getWindowSize(); + console.log(wrapAnsi(input, columns)); + + console.log(chalk.green(`Playing audio from ${cwd}output.wav`)); await execa({ cwd, stdin: "ignore",