Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions bin/gstack-config
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ lookup_default() {
skill_prefix) echo "false" ;;
checkpoint_mode) echo "explicit" ;;
checkpoint_push) echo "false" ;;
explain_level) echo "default" ;;
codex_reviews) echo "enabled" ;;
gstack_contributor) echo "false" ;;
skip_eng_review) echo "false" ;;
Expand Down Expand Up @@ -169,8 +170,8 @@ case "${1:-}" in
echo ""
echo "# ─── Active values (including defaults for unset keys) ───"
for KEY in proactive routing_declined telemetry auto_upgrade update_check \
skill_prefix checkpoint_mode checkpoint_push codex_reviews \
gstack_contributor skip_eng_review workspace_root \
skill_prefix checkpoint_mode checkpoint_push explain_level \
codex_reviews gstack_contributor skip_eng_review workspace_root \
artifacts_sync_mode artifacts_sync_mode_prompted; do
VALUE=$(grep -E "^${KEY}:" "$CONFIG_FILE" 2>/dev/null | tail -1 | awk '{print $2}' | tr -d '[:space:]' || true)
SOURCE="default"
Expand All @@ -185,8 +186,8 @@ case "${1:-}" in
defaults)
echo "# gstack-config defaults"
for KEY in proactive routing_declined telemetry auto_upgrade update_check \
skill_prefix checkpoint_mode checkpoint_push codex_reviews \
gstack_contributor skip_eng_review workspace_root \
skill_prefix checkpoint_mode checkpoint_push explain_level \
codex_reviews gstack_contributor skip_eng_review workspace_root \
artifacts_sync_mode artifacts_sync_mode_prompted; do
printf ' %-24s %s\n' "$KEY:" "$(lookup_default "$KEY")"
done
Expand Down
35 changes: 30 additions & 5 deletions test/docs-config-keys.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ function scanDocsForConfigKeys(): { docPath: string; key: string; line: number }
return hits;
}

function runConfig(args: string[], tmpHome: string) {
return spawnSync(CONFIG_BIN, args, {
encoding: 'utf-8',
env: { ...process.env, HOME: tmpHome, GSTACK_HOME: tmpHome },
timeout: 5000,
});
}

describe('docs ↔ gstack-config key drift guard', () => {
test('docs/ references at least one config key (smoke)', () => {
const hits = scanDocsForConfigKeys();
Expand All @@ -65,15 +73,32 @@ describe('docs ↔ gstack-config key drift guard', () => {
// without a Git Bash interpreter shim. Skip on Windows — the deprecated-key
// denylist test above already pins the v1.27.0.0 rename behavior at the
// doc layer, which is the actual invariant this wave defends.
test.skipIf(process.platform === 'win32')('`explain_level` is exposed as a documented default', () => {
const tmpHome = fs.mkdtempSync(path.join(require('os').tmpdir(), 'gstack-cfg-'));
try {
const get = runConfig(['get', 'explain_level'], tmpHome);
expect(get.status).toBe(0);
expect(get.stdout.trim()).toBe('default');

const defaults = runConfig(['defaults'], tmpHome);
expect(defaults.status).toBe(0);
expect(defaults.stdout).toContain('explain_level:');
expect(defaults.stdout).toContain('default');

const list = runConfig(['list'], tmpHome);
expect(list.status).toBe(0);
expect(list.stdout).toContain('explain_level:');
expect(list.stdout).toContain('default');
} finally {
fs.rmSync(tmpHome, { recursive: true, force: true });
}
});

test.skipIf(process.platform === 'win32')('`gstack-config get artifacts_sync_mode` returns a value (the rename landed)', () => {
// Run from a clean HOME so the user's local config doesn't pollute.
const tmpHome = fs.mkdtempSync(path.join(require('os').tmpdir(), 'gstack-cfg-'));
try {
const result = spawnSync(CONFIG_BIN, ['get', 'artifacts_sync_mode'], {
encoding: 'utf-8',
env: { ...process.env, HOME: tmpHome, GSTACK_HOME: tmpHome },
timeout: 5000,
});
const result = runConfig(['get', 'artifacts_sync_mode'], tmpHome);
expect(result.status).toBe(0);
// A known key returns its default value, not the "unknown key" error string.
expect(result.stderr).not.toContain('not recognized');
Expand Down
Loading