feat(FN-4606): complete Step 6 — CLI and dashboard settings surface

Ref: Runfusion/Fusion#321
Fusion-Task-Id: FN-4606
Fusion-Task-Lineage: 94b23f37-944e-4bcd-bfa1-67d0a8c0a267
This commit is contained in:
Fusion
2026-05-15 08:43:25 -07:00
committed by gsxdsm
parent c51646fc66
commit eacb823a37
4 changed files with 53 additions and 5 deletions

View File

@@ -62,6 +62,7 @@ describe("settings commands", () => {
expect(parseValue("ntfyEnabled", "yes")).toBe(true);
expect(parseValue("maxConcurrent", "4")).toBe(4);
expect(parseValue("worktreeNaming", "task-id")).toBe("task-id");
expect(parseValue("worktreesDir", "~/.fn-worktrees/{repo}")).toBe("~/.fn-worktrees/{repo}");
expect(parseValue("defaultNodeId", "node-abc-123")).toBe("node-abc-123");
expect(parseValue("unavailableNodePolicy", "block")).toBe("block");
expect(parseValue("unavailableNodePolicy", "fallback-local")).toBe("fallback-local");
@@ -164,8 +165,23 @@ describe("settings commands", () => {
expect(updateSettings).toHaveBeenCalledWith({ runStepsInNewSessions: true });
});
it("runSettingsSet with project updates maxParallelSteps", async () => {
const updateSettings = vi.fn().mockResolvedValue(makeSettings({ maxParallelSteps: 3 }));
it("runSettingsSet with project updates worktreesDir", async () => {
const updateSettings = vi.fn().mockResolvedValue(makeSettings({ worktreesDir: "~/.fn-worktrees/{repo}" }));
const getSettings = vi.fn().mockResolvedValue(makeSettings({ worktreesDir: "~/.fn-worktrees/{repo}" }));
vi.mocked(resolveProject).mockResolvedValue({
projectId: "proj-1",
projectName: "demo-project",
projectPath: "/projects/demo",
isRegistered: true,
store: { updateSettings, getSettings } as any,
});
await runSettingsSet("worktreesDir", "~/.fn-worktrees/{repo}", "demo-project");
expect(updateSettings).toHaveBeenCalledWith({ worktreesDir: "~/.fn-worktrees/{repo}" });
});
it("runSettingsSet with project updates maxParallelSteps", async () => { const updateSettings = vi.fn().mockResolvedValue(makeSettings({ maxParallelSteps: 3 }));
const getSettings = vi.fn().mockResolvedValue(makeSettings({ maxParallelSteps: 3 }));
vi.mocked(resolveProject).mockResolvedValue({
projectId: "proj-1",

View File

@@ -6,6 +6,7 @@ export const VALID_SETTINGS = [
"maxConcurrent",
"maxWorktrees",
"worktreeNaming",
"worktreesDir",
"taskPrefix",
"ntfyTopic",
"autoResolveConflicts",
@@ -24,6 +25,7 @@ const PROJECT_ONLY_SETTINGS = [
"maxConcurrent",
"maxWorktrees",
"worktreeNaming",
"worktreesDir",
"taskPrefix",
"autoResolveConflicts",
"smartConflictResolution",
@@ -52,7 +54,7 @@ const ENUM_SETTINGS: Record<string, readonly string[]> = {
unavailableNodePolicy: ["block", "fallback-local"],
};
const STRING_SETTINGS: readonly string[] = ["taskPrefix", "ntfyTopic", "defaultModel", "defaultNodeId"];
const STRING_SETTINGS: readonly string[] = ["taskPrefix", "ntfyTopic", "defaultModel", "defaultNodeId", "worktreesDir"];
// Validation ranges for numeric settings
const NUMBER_RANGES: Record<string, { min: number; max: number }> = {
@@ -202,7 +204,7 @@ export async function runSettingsShow(projectName?: string): Promise<void> {
},
{
title: "Worktrees",
keys: ["worktreeNaming", "recycleWorktrees"],
keys: ["worktreeNaming", "worktreesDir", "recycleWorktrees"],
},
{
title: "Tasks",