This commit is contained in:
@@ -7,6 +7,13 @@ import { logger } from '../logger.js';
|
||||
import { loadConfig } from '../config.js';
|
||||
import { ConfigManager } from '../config-manager.js';
|
||||
import { mountConfigApi } from './config-api.js';
|
||||
import {
|
||||
mountSetupApi,
|
||||
buildNoAuthConfigGate,
|
||||
newNoAuthConfigGateState,
|
||||
ensureSetupToken,
|
||||
clearSetupToken,
|
||||
} from './setup-api.js';
|
||||
import { mountPiecesApi } from './pieces-api.js';
|
||||
import { mountToolsApi } from './tools-api.js';
|
||||
import { mountSkillsApi } from './skills-api.js';
|
||||
@@ -121,6 +128,13 @@ export interface CoreServerOptions {
|
||||
configuredRepos?: string[];
|
||||
generateTitle?: (body: string, ownerId?: string) => Promise<string>;
|
||||
selectPiece?: (body: string, fileNames: string[], userId?: string) => Promise<string>;
|
||||
/** On-demand prompt coach for the create dialog (stateless draft evaluation). */
|
||||
evaluatePrompt?: (req: {
|
||||
instruction: string;
|
||||
piece?: string;
|
||||
userId: string;
|
||||
signal?: AbortSignal;
|
||||
}) => Promise<unknown>;
|
||||
configManager?: ConfigManager;
|
||||
piecesDir?: string;
|
||||
customPiecesDir?: string;
|
||||
@@ -911,6 +925,7 @@ export function createCoreServer(opts: CoreServerOptions): {
|
||||
authActive,
|
||||
generateTitle: opts.generateTitle,
|
||||
selectPiece: opts.selectPiece,
|
||||
evaluatePrompt: opts.evaluatePrompt,
|
||||
pieceExists: opts.piecesDir
|
||||
? (name: string, ownerId?: string) => {
|
||||
// Mirror the worker's per-user → global-custom → builtin resolution order.
|
||||
@@ -966,7 +981,57 @@ export function createCoreServer(opts: CoreServerOptions): {
|
||||
// able to dispatch `/health` to the gateway sub-app when running
|
||||
// (LiteLLM-shape JSON — CRITICAL-3 fix).
|
||||
|
||||
// === Browser setup wizard (fresh no-auth install onboarding) ===
|
||||
// Token lifecycle + endpoints. The no-auth `/api/config` mutation gate
|
||||
// (Codex P1 #3) must register BEFORE mountConfigApi so it intercepts
|
||||
// PUT/POST while a setup window is open. See setup-api.ts.
|
||||
if (opts.configManager) {
|
||||
const setupDataDir = join(process.cwd(), 'data');
|
||||
const setupListenPort =
|
||||
opts.listenPort ?? resolveListenPort(process.env['PORT'], loadConfig().server?.port);
|
||||
// Synchronously seed the gate state to 'pending' (fail-closed for auth
|
||||
// writes) BEFORE the async lifecycle below resolves, so a request arriving
|
||||
// in the boot window can't slip an auth bootstrap through (Codex P1 #2).
|
||||
const setupGateState = newNoAuthConfigGateState();
|
||||
|
||||
// Token lifecycle (needs the async setup-lib import). Created only on a
|
||||
// fresh no-auth install (needs-setup); cleared otherwise so existing
|
||||
// configured deployments keep their prior open behavior. On failure the
|
||||
// gate stays 'pending' (fail-closed), never silently open.
|
||||
void (async () => {
|
||||
try {
|
||||
if (authActive) {
|
||||
clearSetupToken(setupDataDir);
|
||||
return;
|
||||
}
|
||||
const { isLlmConfigured } = await import('../../scripts/setup-lib.mjs');
|
||||
const workers = opts.configManager?.getConfig().provider?.workers ?? [];
|
||||
if (!isLlmConfigured(workers)) {
|
||||
const token = ensureSetupToken(setupDataDir);
|
||||
setupGateState.mode = 'token-required';
|
||||
logger.info(`[setup] open the UI and enter this setup token: ${token}`);
|
||||
logger.info('[setup] llm configured=false → wizard active');
|
||||
} else {
|
||||
clearSetupToken(setupDataDir);
|
||||
setupGateState.mode = 'open';
|
||||
logger.info('[setup] llm configured=true → wizard off');
|
||||
}
|
||||
} catch (e) {
|
||||
logger.warn(`[setup] token lifecycle failed: ${String(e)}`);
|
||||
}
|
||||
})();
|
||||
|
||||
// No-auth /api/config auth-write gate (only mounted in no-auth mode).
|
||||
if (!authActive) {
|
||||
app.use('/api/config', buildNoAuthConfigGate(setupDataDir, setupGateState));
|
||||
}
|
||||
|
||||
mountSetupApi(app, opts.configManager, {
|
||||
authActive,
|
||||
listenPort: setupListenPort,
|
||||
dataDir: setupDataDir,
|
||||
});
|
||||
|
||||
mountConfigApi(app, opts.configManager);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user