mirror of
https://github.com/glittercowboy/get-shit-done
synced 2026-04-25 17:25:23 +02:00
docs(config): document missing config keys in planning-config.md (#1947)
* fix(core): resolve @file: references in gsd-tools stdout (#1891) Workflows used bash-specific `if [[ "$INIT" == @file:* ]]` to detect when large JSON was written to a temp file. This syntax breaks on PowerShell and other non-bash shells. Intercept stdout in gsd-tools.cjs to transparently resolve @file: references before they reach the caller, matching the existing --pick path behavior. The bash checks in workflow files become harmless no-ops and can be removed over time. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(config): add missing config fields to planning-config.md (#1880) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Tibsfox <tibsfox@tibsfox.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -366,7 +366,27 @@ async function main() {
|
||||
return;
|
||||
}
|
||||
|
||||
await runCommand(command, args, cwd, raw, defaultValue);
|
||||
// Intercept stdout to transparently resolve @file: references (#1891).
|
||||
// core.cjs output() writes @file:<path> when JSON > 50KB. The --pick path
|
||||
// already resolves this, but the normal path wrote @file: to stdout, forcing
|
||||
// every workflow to have a bash-specific `if [[ "$INIT" == @file:* ]]` check
|
||||
// that breaks on PowerShell and other non-bash shells.
|
||||
const origWriteSync2 = fs.writeSync;
|
||||
const outChunks = [];
|
||||
fs.writeSync = function (fd, data, ...rest) {
|
||||
if (fd === 1) { outChunks.push(String(data)); return; }
|
||||
return origWriteSync2.call(fs, fd, data, ...rest);
|
||||
};
|
||||
try {
|
||||
await runCommand(command, args, cwd, raw, defaultValue);
|
||||
} finally {
|
||||
fs.writeSync = origWriteSync2;
|
||||
}
|
||||
let captured = outChunks.join('');
|
||||
if (captured.startsWith('@file:')) {
|
||||
captured = fs.readFileSync(captured.slice(6), 'utf-8');
|
||||
}
|
||||
origWriteSync2.call(fs, 1, captured);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -234,6 +234,7 @@ Generated from `CONFIG_DEFAULTS` (core.cjs) and `VALID_CONFIG_KEYS` (config.cjs)
|
||||
| `response_language` | string\|null | `null` | Any language name | Language for user-facing prompts (e.g., `"Portuguese"`, `"Japanese"`) |
|
||||
| `context_window` | number | `200000` | `200000`, `1000000` | Context window size; set `1000000` for 1M-context models |
|
||||
| `resolve_model_ids` | boolean\|string | `false` | `false`, `true`, `"omit"` | Map model aliases to full Claude IDs; `"omit"` returns empty string |
|
||||
| `context` | string\|null | `null` | `"dev"`, `"research"`, `"review"` | Execution context profile that adjusts agent behavior: `"dev"` for development tasks, `"research"` for investigation/exploration, `"review"` for code review workflows |
|
||||
|
||||
### Workflow Fields
|
||||
|
||||
@@ -256,6 +257,8 @@ Set via `workflow.*` namespace in config.json (e.g., `"workflow": { "research":
|
||||
| `workflow.skip_discuss` | boolean | `false` | `true`, `false` | Skip discuss phase entirely |
|
||||
| `workflow.use_worktrees` | boolean | `true` | `true`, `false` | Run executor agents in isolated git worktrees |
|
||||
| `workflow.subagent_timeout` | number | `300000` | Any positive integer (ms) | Timeout for parallel subagent tasks (default: 5 minutes) |
|
||||
| `workflow.code_review` | boolean | `true` | `true`, `false` | Enable built-in code review step in the ship workflow |
|
||||
| `workflow.code_review_depth` | string | `"standard"` | `"light"`, `"standard"`, `"deep"` | Depth level for code review analysis in the ship workflow |
|
||||
| `workflow._auto_chain_active` | boolean | `false` | `true`, `false` | Internal: tracks whether autonomous chaining is active |
|
||||
|
||||
### Git Fields
|
||||
@@ -287,6 +290,7 @@ Set via `features.*` namespace (e.g., `"features": { "thinking_partner": true }`
|
||||
| Key | Type | Default | Allowed Values | Description |
|
||||
|-----|------|---------|----------------|-------------|
|
||||
| `features.thinking_partner` | boolean | `false` | `true`, `false` | Enable conditional extended thinking at workflow decision points (used by discuss-phase and plan-phase for architectural tradeoff analysis) |
|
||||
| `features.global_learnings` | boolean | `false` | `true`, `false` | Enable injection of global learnings from `~/.gsd/learnings/` into agent prompts |
|
||||
|
||||
### Hook Fields
|
||||
|
||||
@@ -296,6 +300,14 @@ Set via `hooks.*` namespace (e.g., `"hooks": { "context_warnings": true }`).
|
||||
|-----|------|---------|----------------|-------------|
|
||||
| `hooks.context_warnings` | boolean | `true` | `true`, `false` | Show warnings when context budget is exceeded |
|
||||
|
||||
### Learnings Fields
|
||||
|
||||
Set via `learnings.*` namespace (e.g., `"learnings": { "max_inject": 5 }`). Used together with `features.global_learnings`.
|
||||
|
||||
| Key | Type | Default | Allowed Values | Description |
|
||||
|-----|------|---------|----------------|-------------|
|
||||
| `learnings.max_inject` | number | `10` | Any positive integer | Maximum number of global learning entries to inject into agent prompts per session |
|
||||
|
||||
### Manager Fields
|
||||
|
||||
Set via `manager.*` namespace (e.g., `"manager": { "flags": { "discuss": "--auto" } }`).
|
||||
|
||||
58
tests/bug-1891-file-resolution.test.cjs
Normal file
58
tests/bug-1891-file-resolution.test.cjs
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Regression tests for bug #1891
|
||||
*
|
||||
* gsd-tools.cjs must transparently resolve @file: references in stdout
|
||||
* so that workflows never see the @file: prefix. This eliminates the
|
||||
* bash-specific `if [[ "$INIT" == @file:* ]]` check that breaks on
|
||||
* PowerShell and other non-bash shells.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const { describe, test, before } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const GSD_TOOLS_SRC = path.join(__dirname, '..', 'get-shit-done', 'bin', 'gsd-tools.cjs');
|
||||
|
||||
describe('bug #1891: @file: resolution in gsd-tools.cjs', () => {
|
||||
let src;
|
||||
|
||||
before(() => {
|
||||
src = fs.readFileSync(GSD_TOOLS_SRC, 'utf-8');
|
||||
});
|
||||
|
||||
test('main() intercepts stdout and resolves @file: references', () => {
|
||||
// The non-pick path should have @file: resolution, just like the --pick path
|
||||
assert.ok(
|
||||
src.includes("captured.startsWith('@file:')") ||
|
||||
src.includes('captured.startsWith(\'@file:\')'),
|
||||
'main() should check for @file: prefix in captured output'
|
||||
);
|
||||
});
|
||||
|
||||
test('@file: resolution reads file content via readFileSync', () => {
|
||||
// Verify the resolution reads the actual file
|
||||
assert.ok(
|
||||
src.includes("readFileSync(captured.slice(6)") ||
|
||||
src.includes('readFileSync(captured.slice(6)'),
|
||||
'@file: resolution should read file at the path after the prefix'
|
||||
);
|
||||
});
|
||||
|
||||
test('stdout interception wraps runCommand in the non-pick path', () => {
|
||||
// The main function should intercept fs.writeSync for fd=1
|
||||
// in BOTH the pick path AND the normal path
|
||||
const mainFunc = src.slice(src.indexOf('async function main()'));
|
||||
const pickInterception = mainFunc.indexOf('// When --pick is active');
|
||||
const fileResolution = mainFunc.indexOf('@file:');
|
||||
|
||||
// There should be at least two @file: resolution points:
|
||||
// one in the --pick path and one in the normal path
|
||||
const firstAt = mainFunc.indexOf("'@file:'");
|
||||
const secondAt = mainFunc.indexOf("'@file:'", firstAt + 1);
|
||||
assert.ok(secondAt > firstAt,
|
||||
'Both --pick and normal paths should resolve @file: references');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user