Merge pull request #1390 from jeremymcs/fix/prefs-gaps
fix(prefs): close merge, validation, serialization, and docs gaps
This commit is contained in:
commit
9ac9cb06e2
5 changed files with 83 additions and 1 deletions
|
|
@ -738,10 +738,14 @@ export function serializePreferencesToFrontmatter(prefs: Record<string, unknown>
|
|||
const orderedKeys = [
|
||||
"version", "mode", "always_use_skills", "prefer_skills", "avoid_skills",
|
||||
"skill_rules", "custom_instructions", "models", "skill_discovery",
|
||||
"auto_supervisor", "uat_dispatch", "unique_milestone_ids",
|
||||
"skill_staleness_days", "auto_supervisor", "uat_dispatch", "unique_milestone_ids",
|
||||
"budget_ceiling", "budget_enforcement", "context_pause_threshold",
|
||||
"notifications", "remote_questions", "git",
|
||||
"post_unit_hooks", "pre_dispatch_hooks",
|
||||
"dynamic_routing", "token_profile", "phases", "parallel",
|
||||
"auto_visualize", "auto_report",
|
||||
"verification_commands", "verification_auto_fix", "verification_max_retries",
|
||||
"search_provider", "compression_strategy", "context_selection",
|
||||
];
|
||||
|
||||
const seen = new Set<string>();
|
||||
|
|
|
|||
|
|
@ -134,6 +134,10 @@ Setting `prefer_skills: []` does **not** disable skill discovery — it just mea
|
|||
- `isolation`: `"worktree"`, `"branch"`, or `"none"` — controls auto-mode git isolation strategy. `"worktree"` creates a milestone worktree for isolated work; `"branch"` works directly in the project root but creates a milestone branch (useful for submodule-heavy repos); `"none"` works directly on the current branch with no worktree or milestone branch (ideal for step-mode with hot reloads). Default: `"worktree"`.
|
||||
- `manage_gitignore`: boolean — when `false`, GSD will not touch `.gitignore` at all. Useful when your project has a strictly managed `.gitignore` and you don't want GSD adding entries. Default: `true`.
|
||||
- `worktree_post_create`: string — script to run after a worktree is created (both auto-mode and manual `/worktree`). Receives `SOURCE_DIR` and `WORKTREE_DIR` as environment variables. Can be absolute or relative to project root. Runs with 30-second timeout. Failure is non-fatal (logged as warning). Default: none.
|
||||
- `auto_pr`: boolean — automatically create a GitHub pull request after a milestone branch is merged. Requires `gh` CLI to be installed. Default: `false`.
|
||||
- `pr_target_branch`: string — branch to target when `auto_pr` is enabled. Defaults to `main_branch` when omitted.
|
||||
- **Deprecated:** `commit_docs` — no longer valid; `.gsd/` is always gitignored. Remove this setting.
|
||||
- **Deprecated:** `merge_to_main` — no longer valid; milestone-level merge is always used. Remove this setting.
|
||||
|
||||
- `unique_milestone_ids`: boolean — when `true`, generates milestone IDs in `M{seq}-{rand6}` format (e.g. `M001-eh88as`) instead of plain sequential `M001`. Prevents ID collisions in team workflows where multiple contributors create milestones concurrently. Both formats coexist — existing `M001`-style milestones remain valid. Default: `false`.
|
||||
|
||||
|
|
@ -181,6 +185,12 @@ Setting `prefer_skills: []` does **not** disable skill discovery — it just mea
|
|||
|
||||
- `auto_report`: boolean — generate an HTML report snapshot after each milestone completion. Default: `true`.
|
||||
|
||||
- `search_provider`: `"brave"`, `"tavily"`, `"ollama"`, `"native"`, or `"auto"` — selects the search backend for research phases. `"native"` forces Anthropic's built-in web search only; provider values force that backend and disable native search; `"auto"` uses the default heuristic. Default: `"auto"`.
|
||||
|
||||
- `compression_strategy`: `"truncate"` or `"compress"` — controls how context that exceeds the budget is reduced. `"truncate"` (default) drops sections from the end. `"compress"` applies heuristic compression before truncating, preserving more content at the cost of some fidelity. Default: `"truncate"`.
|
||||
|
||||
- `context_selection`: `"full"` or `"smart"` — controls how files are inlined into context. `"full"` inlines entire files; `"smart"` uses semantic chunking to include only the most relevant sections. Default is derived from `token_profile`.
|
||||
|
||||
- `parallel`: configures parallel orchestration for running multiple slices concurrently. Keys:
|
||||
- `enabled`: boolean — enable parallel execution. Default: `false`.
|
||||
- `max_workers`: number — maximum concurrent workers (1-4). Default: `2`.
|
||||
|
|
|
|||
|
|
@ -586,5 +586,43 @@ export function validatePreferences(preferences: GSDPreferences): {
|
|||
}
|
||||
}
|
||||
|
||||
// ─── Auto Visualize ─────────────────────────────────────────────────
|
||||
if (preferences.auto_visualize !== undefined) {
|
||||
if (typeof preferences.auto_visualize === "boolean") {
|
||||
validated.auto_visualize = preferences.auto_visualize;
|
||||
} else {
|
||||
errors.push("auto_visualize must be a boolean");
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Auto Report ────────────────────────────────────────────────────
|
||||
if (preferences.auto_report !== undefined) {
|
||||
if (typeof preferences.auto_report === "boolean") {
|
||||
validated.auto_report = preferences.auto_report;
|
||||
} else {
|
||||
errors.push("auto_report must be a boolean");
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Compression Strategy ───────────────────────────────────────────
|
||||
if (preferences.compression_strategy !== undefined) {
|
||||
const validStrategies = new Set(["truncate", "compress"]);
|
||||
if (typeof preferences.compression_strategy === "string" && validStrategies.has(preferences.compression_strategy)) {
|
||||
validated.compression_strategy = preferences.compression_strategy as GSDPreferences["compression_strategy"];
|
||||
} else {
|
||||
errors.push(`compression_strategy must be one of: truncate, compress`);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Context Selection ──────────────────────────────────────────────
|
||||
if (preferences.context_selection !== undefined) {
|
||||
const validModes = new Set(["full", "smart"]);
|
||||
if (typeof preferences.context_selection === "string" && validModes.has(preferences.context_selection)) {
|
||||
validated.context_selection = preferences.context_selection as GSDPreferences["context_selection"];
|
||||
} else {
|
||||
errors.push(`context_selection must be one of: full, smart`);
|
||||
}
|
||||
}
|
||||
|
||||
return { preferences: validated, errors, warnings };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -252,6 +252,8 @@ function mergePreferences(base: GSDPreferences, override: GSDPreferences): GSDPr
|
|||
search_provider: override.search_provider ?? base.search_provider,
|
||||
compression_strategy: override.compression_strategy ?? base.compression_strategy,
|
||||
context_selection: override.context_selection ?? base.context_selection,
|
||||
auto_visualize: override.auto_visualize ?? base.auto_visualize,
|
||||
auto_report: override.auto_report ?? base.auto_report,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -175,6 +175,34 @@ test("git fields comprehensive validation", () => {
|
|||
assert.equal(preferences.git?.isolation, "branch");
|
||||
});
|
||||
|
||||
test("auto_visualize, auto_report, compression_strategy, context_selection validate correctly", () => {
|
||||
const { preferences, errors } = validatePreferences({
|
||||
auto_visualize: true,
|
||||
auto_report: false,
|
||||
compression_strategy: "compress",
|
||||
context_selection: "smart",
|
||||
});
|
||||
assert.equal(errors.length, 0);
|
||||
assert.equal(preferences.auto_visualize, true);
|
||||
assert.equal(preferences.auto_report, false);
|
||||
assert.equal(preferences.compression_strategy, "compress");
|
||||
assert.equal(preferences.context_selection, "smart");
|
||||
});
|
||||
|
||||
test("auto_visualize, auto_report, compression_strategy, context_selection reject invalid values", () => {
|
||||
const { errors: e1 } = validatePreferences({ auto_visualize: "yes" as never });
|
||||
assert.ok(e1.some(e => e.includes("auto_visualize")));
|
||||
|
||||
const { errors: e2 } = validatePreferences({ auto_report: 1 as never });
|
||||
assert.ok(e2.some(e => e.includes("auto_report")));
|
||||
|
||||
const { errors: e3 } = validatePreferences({ compression_strategy: "shrink" as never });
|
||||
assert.ok(e3.some(e => e.includes("compression_strategy")));
|
||||
|
||||
const { errors: e4 } = validatePreferences({ context_selection: "partial" as never });
|
||||
assert.ok(e4.some(e => e.includes("context_selection")));
|
||||
});
|
||||
|
||||
test("all wizard fields together produce no errors", () => {
|
||||
const { errors, warnings } = validatePreferences({
|
||||
version: 1,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue