import { type CompileLabelsResult } from '../write/compileLabels.js'; import type { ProgressReporter } from '../../utils/progressReporter.js'; import { type RuntimeRestartResult } from './aosRuntime.js'; export interface XppcDiagnostic { severity: 'error' | 'warning'; /** Element kind as reported by xppc, e.g. "Class Method", "Table Field" */ kind?: string; model?: string; object?: string; member?: string; line?: number; column?: number; message: string; } /** Prefix-only test, for deciding which log lines are worth keeping in an excerpt. */ export declare const DIAG_LINE_TEST: RegExp; /** Errors xppc counted in this log, or null when it printed no tally. */ export declare function xppcReportedErrorCount(logContent: string): number | null; /** Parse xppc log content into structured diagnostics. */ export declare function parseXppcDiagnostics(logContent: string): XppcDiagnostic[]; /** * What to say when the compiler failed and this parser cannot show why. * * A FAILED headline over a list of warnings reads as though the warnings are * the cause, and invites deleting whatever is nearest to clear the red. Name * the gap instead. Returns '' when the parsed errors do explain the failure. */ export declare function renderUnexplainedFailure(parsed: XppcDiagnostic[], logContent: string): string; /** * Render diagnostics as a numbered, machine-actionable block. Errors come * first; duplicate messages are collapsed; the first few distinct errors are * enriched with a fix hint from the get_d365fo_error_help knowledge base so * the model can correct everything in one round. */ export declare function formatStructuredDiagnostics(diagnostics: XppcDiagnostic[], maxItems?: number): string; interface BuildJobState { jobId?: string; ownerPid?: number; resultDelivered?: boolean; restartWorkflow?: { request: { aosUrl: string; aosUrlSource?: string; bpCheck?: boolean; dbSync?: boolean | string[]; projectPath?: string; packagePath?: string; }; stage: 'pending' | 'prerequisites' | 'restarting' | 'complete' | 'uncertain'; bpSection?: string; sync?: { section: string; failed: boolean; }; result?: RuntimeRestartResult; }; pid: number; modelName: string; targetModel: string; tool: string; startTime: string; sourcesAsOf?: string; logFile: string; status: 'running' | 'succeeded' | 'failed'; phase?: 'compiling' | 'finalizing'; exitCode?: number; endTime?: string; fullBuild?: boolean; } /** * True when any source file in the model package changed after `since` (epoch * ms). Short-circuits on the first hit, so the "something changed" case — the * one that must not be missed — is also the fast one. * * On a blown time budget or an unreadable tree it returns TRUE. Both failure * directions are not equal: a needless rebuild costs minutes, while a wrongly * reused result reports a compile that never happened. */ export declare function hasSourceChangesSince(modelDir: string, since: number, budgetMs?: number): Promise; /** * Whether a finished build result still describes what is on disk. * * A finished state left on disk used to be returned verbatim to the NEXT * call, which then read as that call's own result. Observed 2026-07-28 while * capturing the L2-coc-inherited-method golden: a wrapper was edited to a * deliberately uncompilable signature, and the following build reported * "✅ Build succeeded / Errors: 0" with byte-identical phase timings from the * previous run. The poisoned file was written at 15:05:46; the build log had * last been touched at 15:05:04 — 42 s EARLIER. Nothing had been compiled. * * That is the worst failure this tool can have: pass@build is the gate the * whole eval loop leans on, and a green that describes a tree nobody compiled * is indistinguishable from a real one without checking log timestamps by hand. */ export declare function finishedResultStillDescribesDisk(state: BuildJobState, targetModel: string, customPackagesPath: string): Promise; /** * Log excerpt for a SUCCEEDED build. * * A green build returned the raw 60-line tail, which is almost entirely xppc's * phase-timing table — measured at ~2.6 KB of a ~3.1 KB response — and nothing * downstream reads a timing row. Keep the lines a green build can still say * something with: the diagnostic (warning) lines, and the trailing summary counts. * * The input is deliberately the same 60-line tail the raw version returned, so * the warnings verdict computed from that tail is unchanged by this trim; a * warning that never reached the tail was already invisible before. */ export declare function trimSucceededLog(logTail: string, keepTail?: number): string; /** * The log section of a FAILED build's response. * * `build_d365fo_project` is deliberately 'uncapped' in the response capper, and * a failure used to return BOTH the structured diagnostics (up to 25) AND up to * 300 lines of raw log — measured at the host's logging cap on all 43 build * calls in a 1,400-call sample, 13 of them failures. Every byte of that lands in * the context and is re-billed on every later request in the session. * * So the raw log is included in full only in the case it is actually evidence * for: the parser produced NO structured diagnostic, so the raw text is the only * statement of why the build failed (this is the case renderUnexplainedFailure * points at — "read the raw log at the end of this response"). When diagnostics * WERE parsed they already carry object, member, line, column and message, and * the raw log restates them inside a phase table; a short tail is enough to see * the summary counts, and the path is enough to read the rest on demand. */ export declare function renderFailureLog(logFile: string, /** * Do the parsed diagnostics EXPLAIN the failure — i.e. is at least one of them * an error? Callers used to pass `parsed.length > 0`, which counts warnings: * a build that failed in a shape the regexes do not match, but whose log * carries BP warnings, then got a 40-line tail instead of the log, and the * error that actually stopped it is rarely in the last 40 lines. */ hasStructuredDiagnostics: boolean): Promise; /** * Log excerpt for a failed build that always includes diagnostic lines. A * naive head+tail can miss errors when long phase-timing tables precede them, * so instead: find every diagnostic line, include a context window around * each, always include the invocation header and the trailing summary lines, * and cap the number of diagnostic windows shown (MAX_DIAGS) to bound the * response size. */ export declare function readFullLog(logFile: string, maxLines?: number): Promise; /** * The label-compilation outcome as it should appear at the top of the build * log. A clean run is silent — nothing was wrong, and a note per build would * only crowd out the compiler output. A FAILED run is loud and says what it * costs, because the symptom it produces (`BPErrorUnknownLabel` on a label * that plainly exists, plus the `BPUnusedStrFmtArgument` warnings that cascade * from it) otherwise reads as broken source code. */ export declare function describeLabelCompilation(modelName: string, result: CompileLabelsResult): string; export declare function summarizeBpOutput(text: string, findings: Array<{ moniker: string | null; target: string; severity?: string; path?: string; }>, savedTo?: string): string; type BuildToolResult = { content: Array<{ type: string; text: string; }>; isError?: boolean; }; export declare const buildProjectTool: (params: any, context: any, onProgress?: ProgressReporter) => Promise; export {}; //# sourceMappingURL=buildProject.d.ts.map