diff --git a/.changeset/fix-3197-gsd-tools-config-whitelist.md b/.changeset/fix-3197-gsd-tools-config-whitelist.md new file mode 100644 index 000000000..4c28b261a --- /dev/null +++ b/.changeset/fix-3197-gsd-tools-config-whitelist.md @@ -0,0 +1,5 @@ +--- +type: Fixed +pr: 3197 +--- +**`gsd-tools config-set workflow._auto_chain_active` no longer rejected** — `workflow._auto_chain_active` is an internal runtime-state key written by plan-phase, execute-phase, discuss-phase, and transition workflows. PR #3162 added it to `RUNTIME_STATE_KEYS` in the SDK's `config-schema.ts` but did not mirror the change to the CJS `config-schema.cjs` used by `gsd-tools.cjs`. Users routed through `gsd-tools.cjs` continued to see "Unknown config key" (#3033). The fix adds `RUNTIME_STATE_KEYS` to `config-schema.cjs`, exports it alongside `VALID_CONFIG_KEYS`, and updates `isValidConfigKey()` to accept runtime-state keys. The SDK `config-mutation.ts` is updated to import and check the same set. A new CI parity assertion ensures the two `RUNTIME_STATE_KEYS` sets stay in sync. (#3197) diff --git a/tests/bug-3197-gsd-tools-config-whitelist.test.cjs b/tests/bug-3197-gsd-tools-config-whitelist.test.cjs new file mode 100644 index 000000000..6b41a67e4 --- /dev/null +++ b/tests/bug-3197-gsd-tools-config-whitelist.test.cjs @@ -0,0 +1,60 @@ +'use strict'; + +/** + * Regression test for #3197 — gsd-tools config-set rejects workflow._auto_chain_active. + * + * Root cause: RUNTIME_STATE_KEYS was added to sdk/src/query/config-schema.ts in #3162 + * but not to get-shit-done/bin/lib/config-schema.cjs, so gsd-tools.cjs users still hit + * "Unknown config key" when setting workflow._auto_chain_active. + */ + +const { describe, test } = require('node:test'); +const assert = require('node:assert/strict'); +const fs = require('node:fs'); +const path = require('node:path'); +const { createTempProject, cleanup, runGsdTools } = require('./helpers.cjs'); + +describe('#3197 — gsd-tools.cjs config-set workflow._auto_chain_active', () => { + test('config-set workflow._auto_chain_active true succeeds via gsd-tools.cjs (CJS path)', (t) => { + const tmpDir = createTempProject(); + t.after(() => cleanup(tmpDir)); + + const result = runGsdTools(['config-set', 'workflow._auto_chain_active', 'true'], tmpDir); + assert.ok( + result.success, + `config-set workflow._auto_chain_active true should succeed, got:\nstdout: ${result.output}\nstderr: ${result.error}` + ); + }); + + test('config-set workflow._auto_chain_active true writes value to config.json', (t) => { + const tmpDir = createTempProject(); + t.after(() => cleanup(tmpDir)); + + runGsdTools(['config-set', 'workflow._auto_chain_active', 'true'], tmpDir); + + const configPath = path.join(tmpDir, '.planning', 'config.json'); + assert.ok(fs.existsSync(configPath), '.planning/config.json must exist after config-set'); + + const config = JSON.parse(fs.readFileSync(configPath, 'utf8')); + assert.ok( + config.workflow !== undefined && config.workflow._auto_chain_active === true, + `Expected workflow._auto_chain_active: true in config.json, got: ${JSON.stringify(config)}` + ); + }); + + test('config-set workflow._auto_chain_active false writes false to config.json', (t) => { + const tmpDir = createTempProject(); + t.after(() => cleanup(tmpDir)); + + runGsdTools(['config-set', 'workflow._auto_chain_active', 'false'], tmpDir); + + const configPath = path.join(tmpDir, '.planning', 'config.json'); + assert.ok(fs.existsSync(configPath), '.planning/config.json must exist after config-set'); + + const config = JSON.parse(fs.readFileSync(configPath, 'utf8')); + assert.ok( + config.workflow !== undefined && config.workflow._auto_chain_active === false, + `Expected workflow._auto_chain_active: false in config.json, got: ${JSON.stringify(config)}` + ); + }); +});