feat(FN-1062): fix step status tracking and expose step session settings in CLI
- Fix step status not being tracked correctly in executor callbacks (done/skipped were not updated) - Expose runStepsInNewSessions and maxParallelSteps settings in CLI settings command - Add AGENTS.md documentation for runStepsInNewSessions and maxParallelSteps settings - Add changeset for the published CLI package - Add tests for CLI settings validation and executor step status tracking
This commit is contained in:
@@ -139,4 +139,70 @@ describe("settings commands", () => {
|
||||
expect(errorSpy).toHaveBeenCalledWith('Error: Setting "maxConcurrent" is project-only. Use --project or run from a project directory.');
|
||||
expect(resolveProject).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("runSettingsSet with project updates runStepsInNewSessions", async () => {
|
||||
const updateSettings = vi.fn().mockResolvedValue(makeSettings({ runStepsInNewSessions: true }));
|
||||
const getSettings = vi.fn().mockResolvedValue(makeSettings({ runStepsInNewSessions: true }));
|
||||
vi.mocked(resolveProject).mockResolvedValue({
|
||||
projectId: "proj-1",
|
||||
projectName: "demo-project",
|
||||
projectPath: "/projects/demo",
|
||||
isRegistered: true,
|
||||
store: { updateSettings, getSettings } as any,
|
||||
});
|
||||
|
||||
await runSettingsSet("runStepsInNewSessions", "true", "demo-project");
|
||||
|
||||
expect(updateSettings).toHaveBeenCalledWith({ runStepsInNewSessions: true });
|
||||
});
|
||||
|
||||
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",
|
||||
projectName: "demo-project",
|
||||
projectPath: "/projects/demo",
|
||||
isRegistered: true,
|
||||
store: { updateSettings, getSettings } as any,
|
||||
});
|
||||
|
||||
await runSettingsSet("maxParallelSteps", "3", "demo-project");
|
||||
|
||||
expect(updateSettings).toHaveBeenCalledWith({ maxParallelSteps: 3 });
|
||||
});
|
||||
|
||||
it("rejects maxParallelSteps values outside range", async () => {
|
||||
vi.mocked(resolveProject).mockResolvedValue({
|
||||
projectId: "proj-1",
|
||||
projectName: "demo-project",
|
||||
projectPath: "/projects/demo",
|
||||
isRegistered: true,
|
||||
store: { updateSettings: vi.fn(), getSettings: vi.fn() } as any,
|
||||
});
|
||||
|
||||
await expect(runSettingsSet("maxParallelSteps", "5", "demo-project")).rejects.toThrow("process.exit:1");
|
||||
expect(errorSpy).toHaveBeenCalledWith(expect.stringContaining("Value out of range for maxParallelSteps"));
|
||||
});
|
||||
|
||||
it("runSettingsShow displays Execution section with step-session settings", async () => {
|
||||
const getSettings = vi.fn().mockResolvedValue(makeSettings({
|
||||
runStepsInNewSessions: true,
|
||||
maxParallelSteps: 3,
|
||||
}));
|
||||
vi.mocked(resolveProject).mockResolvedValue({
|
||||
projectId: "proj-1",
|
||||
projectName: "demo-project",
|
||||
projectPath: "/projects/demo",
|
||||
isRegistered: true,
|
||||
store: { getSettings } as any,
|
||||
});
|
||||
|
||||
await runSettingsShow("demo-project");
|
||||
|
||||
const output = logSpy.mock.calls.map((args) => args.join(" ")).join("\n");
|
||||
expect(output).toContain("Execution");
|
||||
expect(output).toContain("Run Steps In New Sessions");
|
||||
expect(output).toContain("Max Parallel Steps");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,6 +13,8 @@ export const VALID_SETTINGS = [
|
||||
"requirePlanApproval",
|
||||
"ntfyEnabled",
|
||||
"defaultModel",
|
||||
"runStepsInNewSessions",
|
||||
"maxParallelSteps",
|
||||
] as const;
|
||||
|
||||
const GLOBAL_ONLY_SETTINGS = ["ntfyEnabled", "ntfyTopic", "defaultModel"] as const;
|
||||
@@ -24,6 +26,8 @@ const PROJECT_ONLY_SETTINGS = [
|
||||
"autoResolveConflicts",
|
||||
"smartConflictResolution",
|
||||
"requirePlanApproval",
|
||||
"runStepsInNewSessions",
|
||||
"maxParallelSteps",
|
||||
] as const;
|
||||
|
||||
type ValidSettingKey = (typeof VALID_SETTINGS)[number];
|
||||
@@ -34,9 +38,10 @@ const BOOLEAN_SETTINGS: readonly string[] = [
|
||||
"smartConflictResolution",
|
||||
"requirePlanApproval",
|
||||
"ntfyEnabled",
|
||||
"runStepsInNewSessions",
|
||||
];
|
||||
|
||||
const NUMBER_SETTINGS: readonly string[] = ["maxConcurrent", "maxWorktrees"];
|
||||
const NUMBER_SETTINGS: readonly string[] = ["maxConcurrent", "maxWorktrees", "maxParallelSteps"];
|
||||
|
||||
const ENUM_SETTINGS: Record<string, readonly string[]> = {
|
||||
worktreeNaming: ["random", "task-id", "task-title"],
|
||||
@@ -48,6 +53,7 @@ const STRING_SETTINGS: readonly string[] = ["taskPrefix", "ntfyTopic", "defaultM
|
||||
const NUMBER_RANGES: Record<string, { min: number; max: number }> = {
|
||||
maxConcurrent: { min: 1, max: 10 },
|
||||
maxWorktrees: { min: 1, max: 20 },
|
||||
maxParallelSteps: { min: 1, max: 4 },
|
||||
};
|
||||
|
||||
async function getGlobalSettingsStore(): Promise<GlobalSettingsStore> {
|
||||
@@ -185,6 +191,10 @@ export async function runSettingsShow(projectName?: string): Promise<void> {
|
||||
title: "Engine",
|
||||
keys: ["maxConcurrent", "maxWorktrees", "autoResolveConflicts", "smartConflictResolution"],
|
||||
},
|
||||
{
|
||||
title: "Execution",
|
||||
keys: ["runStepsInNewSessions", "maxParallelSteps"],
|
||||
},
|
||||
{
|
||||
title: "Worktrees",
|
||||
keys: ["worktreeNaming", "recycleWorktrees"],
|
||||
|
||||
Reference in New Issue
Block a user