Unify task concurrency around authoritative project settings and expose the effective admission ceiling. - Resolve maxConcurrent and maxWorktrees through a shared core capacity model with consistent defaults. - Apply the effective limit across scheduler, engine, runtime, CLI, API, and project-manager admission paths. - Surface configured and binding concurrency values in dashboard controls, status views, diagnostics, and documentation. - Add regression coverage for settings persistence, routing, scheduling, UI surfaces, and worktree-bound capacity. Files changed: .../fn-9185-max-concurrent-effective-limit.md | 7 + docs/architecture.md | 8 +- docs/cli-reference.md | 1 + docs/dashboard-guide.md | 4 + docs/settings-reference.md | 4 +- .../dashboard-concurrency-settings.test.ts | 166 +++++++++++++++++++++ packages/cli/src/commands/dashboard.ts | 28 ++-- packages/cli/src/commands/onboard.ts | 4 +- packages/cli/src/project-resolver.ts | 27 +++- .../concurrency-capacity-resolver.test.ts | 46 ++++++ .../src/__tests__/worktree-capacity-limit.test.ts | 51 +++++-- packages/core/src/index.gate.ts | 2 +- packages/core/src/index.ts | 2 +- packages/core/src/workflows/workflow-capacity.ts | 61 ++++++-- packages/dashboard/app/App.tsx | 2 + .../app/__tests__/concurrency-ui-surfaces.test.tsx | 155 +++++++++++++++++++ .../scheduling-effective-concurrency.test.tsx | 48 ++++++ packages/dashboard/app/api/projects/projects.ts | 10 +- packages/dashboard/app/api/settings/settings.ts | 14 +- packages/dashboard/app/components/Board.tsx | 7 +- packages/dashboard/app/components/Column.tsx | 13 +- .../dashboard/app/components/EngineControlMenu.tsx | 17 ++- .../command-center/CommandCenterControls.tsx | 17 ++- .../components/command-center/areas/TeamArea.tsx | 10 +- .../app/components/dashboard/MainContent.tsx | 3 + .../dashboard/app/components/dashboard/types.ts | 2 + .../settings/sections/SchedulingSection.tsx | 12 +- packages/dashboard/app/hooks/useAppSettings.ts | 9 +- packages/dashboard/app/hooks/useExecutorStats.ts | 10 +- .../app/utils/__tests__/worktreeGrouping.test.ts | 12 +- packages/dashboard/app/utils/worktreeGrouping.ts | 8 +- packages/dashboard/src/routes.ts | 6 +- ...concurrency-authoritative-source-routes.test.ts | 90 +++++++++++ .../register-config-mcp-pi-settings-routes.test.ts | 29 +++- .../register-config-mcp-pi-settings-routes.ts | 17 ++- .../src/routes/register-project-routes.ts | 14 +- .../concurrency-effective-limit-surfaces.test.ts | 34 +++++ .../src/__tests__/project-engine-manager.test.ts | 19 +++ .../__tests__/scheduler-workflow-cutover.test.ts | 6 +- packages/engine/src/concurrency/concurrency.ts | 23 ++- packages/engine/src/concurrency/hybrid-executor.ts | 35 ++++- .../engine/src/executor/create-spawn-agent-tool.ts | 8 +- packages/engine/src/project-engine-manager.ts | 50 +++++-- packages/engine/src/project-engine.ts | 12 +- packages/engine/src/project/project-manager.ts | 26 +++- packages/engine/src/runtimes/in-process-runtime.ts | 12 +- packages/engine/src/scheduler.ts | 31 ++-- packages/engine/src/triage.ts | 15 +- 48 files changed, 1028 insertions(+), 159 deletions(-) Fusion-Task-Id: FN-9185 Fusion-Task-Lineage: 6294456c-d417-40a5-a5fa-2035c6b964a6 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
76 lines
2.6 KiB
TypeScript
76 lines
2.6 KiB
TypeScript
/**
|
|
* FNXC:CodeOrganization 2026-07-16-14:00:
|
|
* Settings/config/update client API peeled from legacy.ts.
|
|
*/
|
|
import type { Settings } from "@fusion/core";
|
|
import { api } from "../client/client.js";
|
|
import type { FetchOptions } from "../client/client.js";
|
|
import { withProjectId } from "../client/health.js";
|
|
import type { UpdateCheckResponse } from "../client/health.js";
|
|
import { dedupe } from "../client/dedupe.js";
|
|
|
|
export function fetchConfig(projectId?: string): Promise<{
|
|
maxConcurrent: number;
|
|
effectiveMaxConcurrent: number;
|
|
concurrencyBindingKnob: "maxConcurrent" | "maxWorktrees";
|
|
rootDir: string;
|
|
}> {
|
|
const path = withProjectId("/config", projectId);
|
|
return dedupe(path, () => api<{
|
|
maxConcurrent: number;
|
|
effectiveMaxConcurrent: number;
|
|
concurrencyBindingKnob: "maxConcurrent" | "maxWorktrees";
|
|
rootDir: string;
|
|
}>(path));
|
|
}
|
|
|
|
export function fetchSettings(projectId?: string, options?: FetchOptions): Promise<Settings> {
|
|
const path = withProjectId("/settings", projectId);
|
|
return dedupe(path, () => api<Settings>(path), options);
|
|
}
|
|
|
|
export function fetchTaskEffectiveSettings(taskId: string, projectId?: string, options?: FetchOptions): Promise<Settings> {
|
|
const path = withProjectId(`/tasks/${taskId}/effective-settings`, projectId);
|
|
return dedupe(path, () => api<Settings>(path), options);
|
|
}
|
|
|
|
export function updateSettings(settings: Partial<Settings>, projectId?: string): Promise<Settings> {
|
|
return api<Settings>(withProjectId("/settings", projectId), {
|
|
method: "PUT",
|
|
body: JSON.stringify(settings),
|
|
});
|
|
}
|
|
|
|
export function checkForUpdate(projectId?: string): Promise<UpdateCheckResponse> {
|
|
return api<UpdateCheckResponse>(withProjectId("/update-check", projectId));
|
|
}
|
|
|
|
export function refreshUpdateCheck(projectId?: string): Promise<UpdateCheckResponse> {
|
|
return api<UpdateCheckResponse>(withProjectId("/update-check/refresh", projectId), {
|
|
method: "POST",
|
|
});
|
|
}
|
|
|
|
export interface UpdateInstallResponse {
|
|
currentVersion: string;
|
|
latestVersion: string | null;
|
|
updated: boolean;
|
|
outcome?: "installed" | "no-update-available" | "check-failed" | "unsupported-install-method" | "failed";
|
|
message?: string;
|
|
error?: string;
|
|
restartAttempted?: boolean;
|
|
restartScheduled?: boolean;
|
|
/** PID of the process that accepted an automatic update restart. */
|
|
priorPid?: number;
|
|
}
|
|
|
|
/** The old dashboard process retains this successful install until it restarts. */
|
|
export type PendingUpdateInstall = UpdateInstallResponse;
|
|
|
|
export function installUpdate(projectId?: string): Promise<UpdateInstallResponse> {
|
|
return api<UpdateInstallResponse>(withProjectId("/update-check/install", projectId), {
|
|
method: "POST",
|
|
});
|
|
}
|
|
|