From 7b85d9e6891fc4bdb91bfa445d2d8c3f7c98d913 Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Wed, 15 Apr 2026 14:59:12 -0400 Subject: [PATCH] fix(cli): audit-open crashes with ReferenceError: output is not defined (#2236) (#2238) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The audit-open case in gsd-tools.cjs called bare output() on both the --json and text paths. output is never in scope at the call site — the entire core module is imported as `const core`, so every other command uses core.output(). Two-part fix: - Replace output(...) with core.output(...) on both branches - Pass result (the raw object) on the --json path, not JSON.stringify(result) — core.output always calls JSON.stringify internally, so pre-serialising caused double-encoding and agents received a string instead of an object Adds three CLI-level regression tests to milestone-audit.test.cjs that invoke audit-open through runGsdTools (the same path the agent uses), so a recurrence at the dispatch layer is caught even if lib-level tests continue to pass. Closes #2236 Co-authored-by: Claude Sonnet 4.6 --- get-shit-done/bin/gsd-tools.cjs | 4 ++-- tests/milestone-audit.test.cjs | 42 ++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/get-shit-done/bin/gsd-tools.cjs b/get-shit-done/bin/gsd-tools.cjs index 833e7277..90506e13 100755 --- a/get-shit-done/bin/gsd-tools.cjs +++ b/get-shit-done/bin/gsd-tools.cjs @@ -781,9 +781,9 @@ async function runCommand(command, args, cwd, raw, defaultValue) { const includeRaw = args.includes('--json'); const result = auditOpenArtifacts(cwd); if (includeRaw) { - output(JSON.stringify(result, null, 2), raw); + core.output(result, raw); } else { - output(formatAuditReport(result), raw); + core.output(formatAuditReport(result), raw); } break; } diff --git a/tests/milestone-audit.test.cjs b/tests/milestone-audit.test.cjs index 0329f7d8..9f4678c4 100644 --- a/tests/milestone-audit.test.cjs +++ b/tests/milestone-audit.test.cjs @@ -3,7 +3,7 @@ const { describe, test, beforeEach, afterEach } = require('node:test'); const assert = require('node:assert/strict'); const fs = require('fs'); const path = require('path'); -const { createTempProject, cleanup } = require('./helpers.cjs'); +const { createTempProject, cleanup, runGsdTools } = require('./helpers.cjs'); describe('audit.cjs module (#2158)', () => { let tmpDir; @@ -143,3 +143,43 @@ describe('state.md template has Deferred Items section (#2158)', () => { 'state.md template missing Deferred Items section'); }); }); + +describe('audit-open CLI command — ReferenceError regression (#2236)', () => { + // The audit-open case in gsd-tools.cjs called bare output() instead of + // core.output(), crashing with ReferenceError: output is not defined + // on every invocation. These tests exercise the CLI dispatch directly so + // a regression at the call site is caught even if the lib tests all pass. + let tmpDir; + + beforeEach(() => { + tmpDir = createTempProject('audit-open-cli-test'); + }); + + afterEach(() => { + cleanup(tmpDir); + }); + + test('audit-open exits without error on an empty project', () => { + const result = runGsdTools(['audit-open'], tmpDir); + assert.ok(result.success, `audit-open crashed: ${result.error}`); + }); + + test('audit-open --json exits without error and returns valid JSON', () => { + const result = runGsdTools(['audit-open', '--json'], tmpDir); + assert.ok(result.success, `audit-open --json crashed: ${result.error}`); + let parsed; + assert.doesNotThrow(() => { parsed = JSON.parse(result.output); }, 'output must be valid JSON'); + assert.ok(typeof parsed === 'object', 'parsed output must be an object'); + assert.ok(typeof parsed.counts === 'object', 'JSON output must include counts'); + }); + + test('audit-open error is not ReferenceError: output is not defined', () => { + // Even if the command fails for some other reason, it must not throw the + // specific ReferenceError that was the bug in #2236. + const result = runGsdTools(['audit-open'], tmpDir); + assert.ok( + !String(result.error).includes('output is not defined'), + `ReferenceError regression: ${result.error}` + ); + }); +});