fix: accept json input for state patch (#356)

* fix: accept json input for state patch

* chore: add changeset
This commit is contained in:
Colin Johnson
2026-05-26 18:55:20 -04:00
committed by GitHub
parent b496737ae1
commit ed149ff283
3 changed files with 48 additions and 5 deletions

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 356
---
Accept JSON object input for state.patch so workflow state updates survive SDK retirement.

View File

@@ -73,11 +73,28 @@ function routeStateCommand({ state, args, cwd, raw, error }) {
null,
() => {
const patches = {};
for (let i = 2; i < args.length; i += 2) {
const key = args[i].replace(/^--/, '');
const value = args[i + 1];
if (key && value !== undefined) {
patches[key] = value;
if (args.length === 3 && typeof args[2] === 'string' && args[2].trim().startsWith('{')) {
let parsed;
try {
parsed = JSON.parse(args[2]);
} catch (err) {
error(`state patch: invalid JSON object: ${err.message}`);
}
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
error('state patch: JSON input must be an object of field/value pairs.');
}
for (const [key, value] of Object.entries(parsed)) {
if (key && value !== undefined) {
patches[key] = String(value);
}
}
} else {
for (let i = 2; i < args.length; i += 2) {
const key = args[i].replace(/^--/, '');
const value = args[i + 1];
if (key && value !== undefined) {
patches[key] = value;
}
}
}
state.cmdStatePatch(cwd, patches, raw);

View File

@@ -922,6 +922,27 @@ describe('cmdStatePatch and cmdStateUpdate (state patch, state update)', () => {
assert.ok(updated.includes('**Last Activity:** 2024-01-15'), 'Last Activity should be unchanged');
});
test('state patch accepts JSON object input from workflows', () => {
fs.writeFileSync(path.join(tmpDir, '.planning', 'STATE.md'), stateMd);
const result = runGsdTools([
'query',
'state.patch',
JSON.stringify({
Status: 'Complete',
'Current Phase': '04',
}),
], tmpDir);
assert.ok(result.success, `Command failed: ${result.error}`);
const output = JSON.parse(result.output);
assert.deepEqual(output.updated.sort(), ['Current Phase', 'Status'].sort());
const updated = fs.readFileSync(path.join(tmpDir, '.planning', 'STATE.md'), 'utf-8');
assert.ok(updated.includes('**Status:** Complete'), 'Status should be updated to Complete');
assert.ok(updated.includes('**Current Phase:** 04'), 'Current Phase should be updated to 04');
});
test('state patch reports failed fields that do not exist', () => {
fs.writeFileSync(path.join(tmpDir, '.planning', 'STATE.md'), stateMd);