Last active
June 12, 2026 13:52
-
-
Save atuttle/dfbedc2773f4028bd0da1f6f9425724f to your computer and use it in GitHub Desktop.
CFStack: CLI utility for trimming down a CFML stacktrace to just the bits you want to dump into an LLM to make it fix the error.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env node | |
| /* | |
| Run it bare and it will prompt you to paste a stack trace, | |
| or feed it the stack trace from stdin and copy from stdout | |
| hint: pbpaste | cfstack | pbcopy | |
| */ | |
| 'use strict'; | |
| function usage() { | |
| process.stderr.write( | |
| 'Usage: cfstack\n\nPaste a CFML stacktrace, then press Enter to get to a blank line and Ctrl-D when done.\n', | |
| ); | |
| } | |
| function filterStackTrace(input) { | |
| const lines = input | |
| .replace(/\r\n/g, '\n') | |
| .replace(/\r/g, '\n') | |
| .replace(/ at /g, '\n at ') | |
| .split('\n'); | |
| if (lines.length > 0 && lines[lines.length - 1] === '') { | |
| lines.pop(); | |
| } | |
| return lines | |
| .filter((line, index) => { | |
| if (index === 0) { | |
| return true; | |
| } | |
| return line.toLowerCase().includes('.cfc:') || line.toLowerCase().includes('.cfm:'); | |
| }) | |
| .map((line, index) => { | |
| const normalized = line.replace(/\t/g, ' '); | |
| if (index === 0) { | |
| return normalized; | |
| } | |
| const wrappedPath = normalized.match(/\(([^()]*\.(?:cfc|cfm):\d+)\)\s*$/i); | |
| if (wrappedPath) { | |
| return `at ${wrappedPath[1]}`; | |
| } | |
| const barePath = normalized.match(/^\s*at\s+([^()]*\.(?:cfc|cfm):\d+)\s*$/i); | |
| if (barePath) { | |
| return `at ${barePath[1]}`; | |
| } | |
| return normalized; | |
| }) | |
| .join('\n'); | |
| } | |
| async function main() { | |
| const args = process.argv.slice(2); | |
| if (args.includes('-h') || args.includes('--help')) { | |
| usage(); | |
| return; | |
| } | |
| if (args.length > 0) { | |
| process.stderr.write('cfstack does not accept arguments. Paste or pipe a stacktrace into stdin.\n'); | |
| process.exitCode = 1; | |
| return; | |
| } | |
| if (process.stdin.isTTY) { | |
| process.stderr.write('Paste CFML stacktrace, then press Enter to get to a blank line and Ctrl-D when done:\n'); | |
| } | |
| process.stdin.setEncoding('utf8'); | |
| const chunks = []; | |
| for await (const chunk of process.stdin) { | |
| chunks.push(chunk); | |
| } | |
| const output = filterStackTrace(chunks.join('')); | |
| if (process.stdin.isTTY) { | |
| process.stdout.write('\n'); | |
| } | |
| process.stdout.write(output); | |
| if (output.length > 0 && !output.endsWith('\n')) { | |
| process.stdout.write('\n'); | |
| } | |
| } | |
| main().catch((error) => { | |
| process.stderr.write(`${error?.stack || error}\n`); | |
| process.exitCode = 1; | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment