fix: sync semaphore concurrency limit on every settings change

The cachedMaxConcurrent variable driving the AgentSemaphore was only
updated during unpause transitions and merge retry timers. Changing
maxConcurrent in the dashboard had no effect on the semaphore until one
of those events fired, causing fewer tasks to run than configured.

Also adds HeartbeatMonitor and HeartbeatTriggerScheduler wiring to both
serve and dashboard commands, with tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-04-09 09:56:32 -07:00
parent ac07be790b
commit 1c6c3d1700
5 changed files with 200 additions and 9 deletions

View File

@@ -123,6 +123,17 @@ vi.mock("@fusion/engine", async (importOriginal) => {
scanIdleWorktrees: vi.fn().mockResolvedValue([]),
cleanupOrphanedWorktrees: vi.fn().mockResolvedValue(0),
createAiPromptExecutor: vi.fn().mockResolvedValue(vi.fn().mockResolvedValue("mock AI response")),
HeartbeatMonitor: vi.fn().mockImplementation(() => ({
start: vi.fn(),
stop: vi.fn(),
executeHeartbeat: vi.fn().mockResolvedValue({ id: "run-1" }),
})),
HeartbeatTriggerScheduler: vi.fn().mockImplementation(() => ({
start: vi.fn(),
stop: vi.fn(),
registerAgent: vi.fn(),
getRegisteredAgents: vi.fn().mockReturnValue([]),
})),
};
});

View File

@@ -298,6 +298,17 @@ vi.mock("@fusion/engine", () => ({
SelfHealingManager: mocks.selfHealingCtor,
MissionAutopilot: mocks.missionAutopilotCtor,
createAiPromptExecutor: vi.fn().mockResolvedValue(vi.fn().mockResolvedValue("ok")),
HeartbeatMonitor: vi.fn().mockImplementation(() => ({
start: vi.fn(),
stop: vi.fn(),
executeHeartbeat: vi.fn().mockResolvedValue({ id: "run-1" }),
})),
HeartbeatTriggerScheduler: vi.fn().mockImplementation(() => ({
start: vi.fn(),
stop: vi.fn(),
registerAgent: vi.fn(),
getRegisteredAgents: vi.fn().mockReturnValue([]),
})),
}));
vi.mock("@mariozechner/pi-coding-agent", () => ({