Skip to content

Instantly share code, notes, and snippets.

@atuttle
Last active June 12, 2026 13:52
Show Gist options
  • Select an option

  • Save atuttle/dfbedc2773f4028bd0da1f6f9425724f to your computer and use it in GitHub Desktop.

Select an option

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.
#!/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