ai-foreman 1.7.5 → 1.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -2
- package/dist/activity.d.ts +3 -0
- package/dist/activity.js +29 -4
- package/dist/adapters/claude.d.ts +33 -2
- package/dist/adapters/claude.js +208 -17
- package/dist/adapters/codex.d.ts +11 -1
- package/dist/adapters/codex.js +195 -20
- package/dist/adapters/recovering.d.ts +8 -2
- package/dist/adapters/recovering.js +23 -3
- package/dist/adapters/sessionFailure.d.ts +18 -0
- package/dist/adapters/sessionFailure.js +51 -0
- package/dist/adapters/types.d.ts +52 -9
- package/dist/agentRun.d.ts +4 -1
- package/dist/agentRun.js +96 -9
- package/dist/branch/currentGuard.d.ts +34 -0
- package/dist/branch/currentGuard.js +65 -0
- package/dist/branch/github.js +3 -2
- package/dist/branch/gitlab.js +3 -2
- package/dist/branch/planner.d.ts +5 -0
- package/dist/branch/planner.js +37 -3
- package/dist/branch/prefix.d.ts +8 -0
- package/dist/branch/prefix.js +26 -0
- package/dist/branch/resume.d.ts +2 -0
- package/dist/branch/resume.js +8 -0
- package/dist/branch/runner.d.ts +14 -2
- package/dist/branch/runner.js +77 -17
- package/dist/buildRuns.d.ts +51 -18
- package/dist/buildRuns.js +318 -31
- package/dist/cli/handoffs.d.ts +2 -0
- package/dist/cli/handoffs.js +74 -0
- package/dist/cli/start.js +1040 -62
- package/dist/cli/tickets.d.ts +10 -1
- package/dist/cli/tickets.js +615 -80
- package/dist/continuity.d.ts +86 -0
- package/dist/continuity.js +365 -0
- package/dist/foreman.d.ts +9 -5
- package/dist/foreman.js +76 -20
- package/dist/handoffs.d.ts +69 -0
- package/dist/handoffs.js +326 -0
- package/dist/log.d.ts +1 -1
- package/dist/permissions/policy.d.ts +5 -1
- package/dist/permissions/policy.js +48 -1
- package/dist/qaReview.d.ts +7 -6
- package/dist/qaReview.js +31 -20
- package/dist/sessionAvailability.d.ts +15 -0
- package/dist/sessionAvailability.js +57 -0
- package/dist/sessionIdentity.d.ts +33 -0
- package/dist/sessionIdentity.js +132 -0
- package/dist/sessionLifecycle.d.ts +102 -3
- package/dist/sessionLifecycle.js +578 -20
- package/dist/statusReporter.d.ts +58 -8
- package/dist/statusReporter.js +210 -14
- package/dist/ticketPlanning.js +8 -0
- package/dist/ticketPopulation.js +88 -12
- package/dist/tickets/commands.js +20 -12
- package/dist/tickets/details.d.ts +17 -0
- package/dist/tickets/details.js +94 -0
- package/dist/tickets/eligibility.d.ts +28 -0
- package/dist/tickets/eligibility.js +71 -0
- package/dist/tickets/groupReset.d.ts +25 -0
- package/dist/tickets/groupReset.js +279 -0
- package/dist/tickets/groups.d.ts +36 -0
- package/dist/tickets/groups.js +68 -0
- package/dist/tickets/importer.js +27 -3
- package/dist/tickets/recommendations.js +31 -7
- package/dist/tickets/reset.d.ts +28 -0
- package/dist/tickets/reset.js +214 -0
- package/dist/tickets/reviewStandards.d.ts +7 -0
- package/dist/tickets/reviewStandards.js +53 -0
- package/dist/tickets/setupConfig.d.ts +23 -0
- package/dist/tickets/setupConfig.js +115 -3
- package/dist/tickets/stateDb.d.ts +42 -1
- package/dist/tickets/stateDb.js +261 -23
- package/dist/tickets/ticketLoader.js +5 -2
- package/dist/tickets/validate.js +4 -0
- package/dist/workflowDb.d.ts +102 -2
- package/dist/workflowDb.js +460 -8
- package/package.json +35 -3
package/dist/branch/runner.js
CHANGED
|
@@ -6,10 +6,12 @@ import { cmdBlock, cmdComplete, cmdUpdate } from "../tickets/commands.js";
|
|
|
6
6
|
import { commitAll, createTicketWorktree, findWorktreeForBranch, currentWorktreeBranch, deleteLocalBranch, ensureCleanBaseWorktree, ensureForemanExcluded, hasTrackerChanges, hasWorktreeChanges, headCommitIfAhead, removeTicketWorktree, mergeBranchToLocalBase, } from "./git.js";
|
|
7
7
|
import { checkGitHubPrMerged, createOrReusePr, enableGitHubAutoMerge, pushBranchForPr } from "./github.js";
|
|
8
8
|
import { checkGitLabMrMerged, createOrReuseMr, enableGitLabAutoMerge, pushBranchForMr } from "./gitlab.js";
|
|
9
|
-
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
10
|
-
import { join } from "node:path";
|
|
9
|
+
import { existsSync, mkdirSync, readFileSync, realpathSync, rmSync, writeFileSync } from "node:fs";
|
|
10
|
+
import { join, resolve } from "node:path";
|
|
11
11
|
import { WorkflowDb } from "../workflowDb.js";
|
|
12
12
|
import { currentActivity, withActivityPhase } from "../activity.js";
|
|
13
|
+
import { SessionUnavailableError } from "../adapters/sessionFailure.js";
|
|
14
|
+
import { SessionUnavailableContinuityError } from "../continuity.js";
|
|
13
15
|
export function readDeliveryUnitSession(projectDir, unitId) {
|
|
14
16
|
const path = deliverySessionPath(projectDir, unitId);
|
|
15
17
|
if (!existsSync(path))
|
|
@@ -46,7 +48,7 @@ export async function runBranchPlan(opts) {
|
|
|
46
48
|
const summaries = [];
|
|
47
49
|
const successfulBranches = new Set();
|
|
48
50
|
const pushedBranches = new Set();
|
|
49
|
-
let
|
|
51
|
+
let builderStream;
|
|
50
52
|
let builderWorkSessions = 0;
|
|
51
53
|
const qaStream = { reviews: 0, modificationViolations: 0 };
|
|
52
54
|
for (const issue of opts.plan.issues) {
|
|
@@ -138,28 +140,51 @@ export async function runBranchPlan(opts) {
|
|
|
138
140
|
base: node.baseBranch,
|
|
139
141
|
worktreePath,
|
|
140
142
|
sessionId: resumeSession.sessionId,
|
|
143
|
+
sessionRef: resumeSession.sessionRef,
|
|
141
144
|
});
|
|
142
145
|
}
|
|
143
146
|
journalTracker(opts.projectDir, opts.runId, `${opts.runId}:tracker-update:${node.ticket.id}:in-progress`, { ticket: node.ticket.id, status: "in_progress" }, () => cmdUpdate(opts.projectDir, node.ticket.id, {
|
|
144
147
|
status: "in_progress", actor: "foreman",
|
|
145
148
|
summary: resumeSession ? `Resuming branch ${node.branch}` : `Starting branch ${node.branch}`,
|
|
146
149
|
}));
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
150
|
+
const ticketInstruction = resumeSession ? buildBranchTicketResumeInstruction(node, opts.trackerPaths) : buildBranchTicketInstruction(node, opts.trackerPaths);
|
|
151
|
+
// Reattach the predecessor even for a `fresh` strategy so the host can
|
|
152
|
+
// publish and validate a cumulative handoff before creating its successor.
|
|
153
|
+
const sameWorktreeStream = builderStream && canonical(builderStream.worktreePath) === canonical(worktreePath) ? builderStream : undefined;
|
|
154
|
+
const continuedBuilderSession = resumeSession?.sessionId ?? sameWorktreeStream?.sessionId;
|
|
155
|
+
const continuedBuilderRef = resumeSession?.sessionRef ?? sameWorktreeStream?.sessionRef;
|
|
156
|
+
builder = await opts.createBuilder(worktreePath, continuedBuilderSession, continuedBuilderRef);
|
|
157
|
+
if (builderWorkSessions > 0 && continuedBuilderSession) {
|
|
158
|
+
const strategy = opts.builderSessionStrategy ?? "compact";
|
|
159
|
+
if (opts.builderSessionBoundary) {
|
|
160
|
+
builder = await opts.builderSessionBoundary(builder, ticketInstruction, strategy, worktreePath);
|
|
161
|
+
}
|
|
162
|
+
else if (strategy === "compact") {
|
|
163
|
+
const compacted = await compactWithRetry(builder);
|
|
164
|
+
if (!compacted.ok) {
|
|
165
|
+
await builder.close();
|
|
166
|
+
builder = await opts.createBuilder(worktreePath);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
152
170
|
await builder.close();
|
|
153
171
|
builder = await opts.createBuilder(worktreePath);
|
|
154
172
|
}
|
|
155
173
|
}
|
|
156
174
|
builderWorkSessions += 1;
|
|
157
175
|
viewer = opts.observeBuilder?.(builder);
|
|
158
|
-
const foreman = new Foreman(builder, opts.log, opts.notificationsEnabled, opts.qaEnabled, 3, undefined);
|
|
159
|
-
const { result, status } = await foreman.runInstruction(
|
|
176
|
+
const foreman = new Foreman(builder, opts.log, opts.notificationsEnabled, opts.qaEnabled, 3, undefined, undefined, undefined, opts.qaSessionStrategy ?? "compact", undefined, opts.builderSessionStrategy ?? "compact", undefined, opts.beforeBuilderTurn ? (adapter, action) => opts.beforeBuilderTurn(adapter, action, worktreePath) : undefined);
|
|
177
|
+
const { result, status } = await foreman.runInstruction(ticketInstruction);
|
|
178
|
+
builder = foreman.builderAdapter();
|
|
160
179
|
workflowCheckpoint(opts.projectDir, opts.runId, "builder-after", node.ticket.id, { status: status.kind, sessionId: builder.sessionId(), worktree: worktreePath });
|
|
161
180
|
const sessionId = builder.sessionId();
|
|
162
|
-
|
|
181
|
+
const sessionRef = builder.sessionRef?.();
|
|
182
|
+
if (sessionId)
|
|
183
|
+
builderStream = { sessionId, ...(sessionRef ? { sessionRef } : {}), worktreePath };
|
|
184
|
+
if (sessionId) {
|
|
185
|
+
opts.recordBuilderSession?.(sessionRef ?? sessionId, node.ticket.id, worktreePath);
|
|
186
|
+
workflowCheckpoint(opts.projectDir, opts.runId, "builder-session-scoped", node.ticket.id, { sessionId, sessionRef, worktree: worktreePath, branch: node.branch });
|
|
187
|
+
}
|
|
163
188
|
if (sessionId) {
|
|
164
189
|
opts.log.write("branch-session", {
|
|
165
190
|
ticket: node.ticket.id,
|
|
@@ -167,6 +192,7 @@ export async function runBranchPlan(opts) {
|
|
|
167
192
|
base: node.baseBranch,
|
|
168
193
|
worktreePath,
|
|
169
194
|
sessionId,
|
|
195
|
+
sessionRef: builder.sessionRef?.(),
|
|
170
196
|
agent: opts.agent,
|
|
171
197
|
model: opts.model,
|
|
172
198
|
effort: opts.effort,
|
|
@@ -183,7 +209,7 @@ export async function runBranchPlan(opts) {
|
|
|
183
209
|
if (node.deliveryUnitId) {
|
|
184
210
|
const path = deliverySessionPath(opts.projectDir, node.deliveryUnitId);
|
|
185
211
|
mkdirSync(join(opts.projectDir, ".foreman", "delivery-sessions"), { recursive: true });
|
|
186
|
-
writeFileSync(path, `${JSON.stringify({ unitId: node.deliveryUnitId, branch: node.branch, worktreePath, sessionId, ticket: node.ticket.id }, null, 2)}\n`, "utf8");
|
|
212
|
+
writeFileSync(path, `${JSON.stringify({ unitId: node.deliveryUnitId, branch: node.branch, worktreePath, sessionId, sessionRef: builder.sessionRef?.(), ticket: node.ticket.id }, null, 2)}\n`, "utf8");
|
|
187
213
|
}
|
|
188
214
|
}
|
|
189
215
|
opts.log.write("step", {
|
|
@@ -215,30 +241,47 @@ export async function runBranchPlan(opts) {
|
|
|
215
241
|
const qa = await runIsolatedQa({
|
|
216
242
|
ticket: node.ticket, builderWorktree: worktreePath, builderSummary: status.summary ?? result.text,
|
|
217
243
|
qaStrategy: opts.qaSessionStrategy ?? "compact", state: qaStream, createQa: opts.createQa, maxCycles: 3,
|
|
244
|
+
sessionBoundary: opts.qaSessionBoundary,
|
|
218
245
|
evidence: (entry) => opts.log.write("qa-evidence", { ticket: node.ticket.id, ...entry }),
|
|
219
246
|
fix: async (issues) => {
|
|
220
247
|
if (!builder)
|
|
221
248
|
return { ok: false, detail: "Builder session unavailable" };
|
|
222
249
|
builderWorkSessions += 1;
|
|
223
|
-
|
|
250
|
+
const digest = (await withActivityPhase("recording QA fix changes", () => changeManifestAsync(worktreePath, (state, detail) => currentActivity()?.update(state, detail), "recording QA fix changes"))).diffDigest;
|
|
251
|
+
const fixInstruction = buildDurableQaFixHandoff(node.ticket, issues, worktreePath, result.text, digest);
|
|
252
|
+
const strategy = opts.builderSessionStrategy ?? "compact";
|
|
253
|
+
if (opts.builderSessionBoundary) {
|
|
254
|
+
builder = await opts.builderSessionBoundary(builder, fixInstruction, strategy, worktreePath);
|
|
255
|
+
}
|
|
256
|
+
else if (strategy === "compact" && builder.sessionId()) {
|
|
224
257
|
const compacted = await compactWithRetry(builder);
|
|
225
258
|
if (!compacted.ok) {
|
|
226
259
|
await builder.close();
|
|
227
260
|
builder = await opts.createBuilder(worktreePath);
|
|
228
261
|
}
|
|
229
262
|
}
|
|
230
|
-
else if (
|
|
263
|
+
else if (strategy === "fresh") {
|
|
231
264
|
await builder.close();
|
|
232
265
|
builder = await opts.createBuilder(worktreePath);
|
|
233
266
|
}
|
|
234
|
-
|
|
235
|
-
|
|
267
|
+
if (opts.beforeBuilderTurn)
|
|
268
|
+
builder = await opts.beforeBuilderTurn(builder, fixInstruction, worktreePath);
|
|
269
|
+
const fixed = await builder.sendTurn(fixInstruction);
|
|
236
270
|
const fixedStatus = parseStepStatus(fixed.text);
|
|
237
|
-
|
|
271
|
+
const fixedSessionId = builder.sessionId();
|
|
272
|
+
const fixedSessionRef = builder.sessionRef?.();
|
|
273
|
+
if (fixedSessionId)
|
|
274
|
+
builderStream = { sessionId: fixedSessionId, ...(fixedSessionRef ? { sessionRef: fixedSessionRef } : {}), worktreePath };
|
|
275
|
+
if (fixedSessionId) {
|
|
276
|
+
opts.recordBuilderSession?.(fixedSessionRef ?? fixedSessionId, node.ticket.id, worktreePath);
|
|
277
|
+
workflowCheckpoint(opts.projectDir, opts.runId, "builder-session-scoped", node.ticket.id, { sessionId: fixedSessionId, sessionRef: fixedSessionRef, worktree: worktreePath, branch: node.branch });
|
|
278
|
+
}
|
|
238
279
|
return { ok: !fixed.isError && fixedStatus.kind === "done", detail: fixedStatus.error ?? fixed.text.slice(0, 500) };
|
|
239
280
|
},
|
|
240
281
|
onNonconvergence: opts.qaNonconvergence,
|
|
241
282
|
});
|
|
283
|
+
if (qaStream.sessionId)
|
|
284
|
+
opts.recordQaSession?.(qaStream.sessionRef ?? qaStream.sessionId, node.ticket.id, worktreePath);
|
|
242
285
|
workflowCheckpoint(opts.projectDir, opts.runId, "qa-after", node.ticket.id, { outcome: qa.outcome, detail: qa.detail });
|
|
243
286
|
if (qa.outcome !== "passed" && qa.outcome !== "waived") {
|
|
244
287
|
const detail = qa.detail ?? "QA did not pass";
|
|
@@ -444,6 +487,14 @@ export async function runBranchPlan(opts) {
|
|
|
444
487
|
removeTicketWorktree(opts.projectDir, worktreePath);
|
|
445
488
|
}
|
|
446
489
|
catch (err) {
|
|
490
|
+
if (err instanceof SessionUnavailableError || err instanceof SessionUnavailableContinuityError) {
|
|
491
|
+
const message = err.message;
|
|
492
|
+
opts.log.write("branch-issue", { ticket: node.ticket.id, code: "session_unavailable", message, blocking: true });
|
|
493
|
+
notifyIssue(opts.notificationsEnabled, `${node.ticket.id}: ${message}`);
|
|
494
|
+
summaries.push(summaryFor(node, "blocked", message));
|
|
495
|
+
opts.onSessionUnavailable?.(err);
|
|
496
|
+
return summaries;
|
|
497
|
+
}
|
|
447
498
|
const message = err instanceof Error ? err.message : String(err);
|
|
448
499
|
const code = message.includes("switched branch")
|
|
449
500
|
? "branch_switch"
|
|
@@ -510,6 +561,7 @@ function workflowCheckpoint(projectDir, runId, checkpoint, ticket, payload) {
|
|
|
510
561
|
if (!run)
|
|
511
562
|
return;
|
|
512
563
|
db.transition(runId, { checkpoint, state: { ...run.state, currentTicket: ticket, ...payload }, event: checkpoint, payload: { ticket, ...payload } });
|
|
564
|
+
db.appendContinuityEvent({ runId, role: "host", kind: checkpoint, payload: { ticket, ...payload }, authoritativeStateRevision: db.continuityHead(runId, "run")?.authoritativeStateRevision ?? 0 });
|
|
513
565
|
}
|
|
514
566
|
finally {
|
|
515
567
|
db.close();
|
|
@@ -583,6 +635,14 @@ function autoMergePollMs() {
|
|
|
583
635
|
function sleep(ms) {
|
|
584
636
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
585
637
|
}
|
|
638
|
+
function canonical(path) {
|
|
639
|
+
try {
|
|
640
|
+
return realpathSync.native(path);
|
|
641
|
+
}
|
|
642
|
+
catch {
|
|
643
|
+
return resolve(path);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
586
646
|
function notifyIssue(enabled, message) {
|
|
587
647
|
if (enabled)
|
|
588
648
|
fireNotification("Foreman branch issue", message);
|
package/dist/buildRuns.d.ts
CHANGED
|
@@ -1,42 +1,75 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type { BuildRunRecordV2, ProviderSessionRefV1, ResolvedAgentSettings, SessionAvailabilityV1 } from "rafi-spec";
|
|
2
|
+
import { type ResolveSessionAvailabilityOptions } from "./sessionAvailability.js";
|
|
3
|
+
export declare const BUILD_RUN_VERSION = 2;
|
|
3
4
|
export declare const BUILD_RUN_DIRECTORY = ".foreman/runs";
|
|
4
5
|
export declare const BUILD_HEARTBEAT_MS = 10000;
|
|
5
6
|
export declare const BUILD_LEASE_STALE_MS = 45000;
|
|
6
7
|
export interface CreateBuildRunInput {
|
|
7
8
|
tickets: string[];
|
|
8
9
|
deliveryUnit?: string;
|
|
9
|
-
branchMode?:
|
|
10
|
+
branchMode?: BuildRunRecordV2["branchMode"];
|
|
10
11
|
repositoryRoot: string;
|
|
11
12
|
worktree?: string;
|
|
12
13
|
branch?: string;
|
|
13
14
|
baseHead?: string;
|
|
15
|
+
baseRef?: string;
|
|
14
16
|
startHead?: string;
|
|
15
17
|
builder?: LegacyResolvedAgentSettings;
|
|
16
18
|
qa?: LegacyResolvedAgentSettings;
|
|
19
|
+
runDecisions?: BuildRunRecordV2["runDecisions"];
|
|
17
20
|
now?: Date;
|
|
18
21
|
}
|
|
19
|
-
export declare function createBuildRun(input: CreateBuildRunInput):
|
|
22
|
+
export declare function createBuildRun(input: CreateBuildRunInput): BuildRunRecordV2;
|
|
20
23
|
export declare function resumeBuildRun(projectDir: string, runId: string, patch: {
|
|
21
24
|
builder?: LegacyResolvedAgentSettings;
|
|
22
25
|
qa?: LegacyResolvedAgentSettings;
|
|
23
26
|
builderSessionId?: string | null;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
export declare function
|
|
28
|
-
export declare function
|
|
29
|
-
export declare function
|
|
27
|
+
builderSessionRef?: ProviderSessionRefV1 | null;
|
|
28
|
+
}, now?: Date): BuildRunRecordV2;
|
|
29
|
+
type LegacyResolvedAgentSettings = Omit<ResolvedAgentSettings, "session_strategy" | "settings_revision" | "display_session_cost" | "auto_compact_threshold_percent" | "compact_maximum"> & Partial<Pick<ResolvedAgentSettings, "session_strategy" | "settings_revision" | "display_session_cost" | "auto_compact_threshold_percent" | "compact_maximum">>;
|
|
30
|
+
export declare function saveBuildRun(projectDir: string, run: BuildRunRecordV2, now?: Date): BuildRunRecordV2;
|
|
31
|
+
export declare function checkpointBuildRun(projectDir: string, run: BuildRunRecordV2, checkpoint: string, patch?: Partial<BuildRunRecordV2>): BuildRunRecordV2;
|
|
32
|
+
export declare function persistBuildSession(projectDir: string, run: BuildRunRecordV2, role: "builder" | "qa", session: string | ProviderSessionRefV1): BuildRunRecordV2;
|
|
33
|
+
/** Latest scoped binding, with the narrow legacy Builder inference allowed by the recovery protocol. */
|
|
34
|
+
export declare function buildRunSessionBinding(run: BuildRunRecordV2, role: "builder" | "qa", sessionId?: string): ProviderSessionRefV1 | undefined;
|
|
35
|
+
export declare function recordBuildReceipt(projectDir: string, run: BuildRunRecordV2, operationId: string, detail?: {
|
|
30
36
|
externalId?: string;
|
|
31
37
|
detail?: string;
|
|
32
|
-
}):
|
|
33
|
-
export declare function heartbeatBuildRun(projectDir: string, run:
|
|
34
|
-
export declare function releaseBuildLease(projectDir: string, run:
|
|
35
|
-
export declare function completeBuildRun(projectDir: string, run:
|
|
36
|
-
export declare function readBuildRuns(projectDir: string):
|
|
37
|
-
export declare function recoverableBuildRuns(projectDir: string, now?: Date): Array<
|
|
38
|
+
}): BuildRunRecordV2;
|
|
39
|
+
export declare function heartbeatBuildRun(projectDir: string, run: BuildRunRecordV2, now?: Date): BuildRunRecordV2;
|
|
40
|
+
export declare function releaseBuildLease(projectDir: string, run: BuildRunRecordV2, status?: BuildRunRecordV2["status"]): BuildRunRecordV2;
|
|
41
|
+
export declare function completeBuildRun(projectDir: string, run: BuildRunRecordV2, now?: Date): BuildRunRecordV2;
|
|
42
|
+
export declare function readBuildRuns(projectDir: string): BuildRunRecordV2[];
|
|
43
|
+
export declare function recoverableBuildRuns(projectDir: string, now?: Date): Array<BuildRunRecordV2 & {
|
|
38
44
|
active: boolean;
|
|
39
45
|
}>;
|
|
40
|
-
export declare function isLeaseActive(run:
|
|
41
|
-
export declare function buildRecoveryPreview(run:
|
|
46
|
+
export declare function isLeaseActive(run: BuildRunRecordV2, now?: Date): boolean;
|
|
47
|
+
export declare function buildRecoveryPreview(run: BuildRunRecordV2): string[];
|
|
48
|
+
export interface BuildRecoveryProjection {
|
|
49
|
+
run: BuildRunRecordV2;
|
|
50
|
+
ticketId?: string;
|
|
51
|
+
ticketTitle?: string;
|
|
52
|
+
compactLabel: string;
|
|
53
|
+
compactHint: string;
|
|
54
|
+
completed: string[];
|
|
55
|
+
remaining: string[];
|
|
56
|
+
lastSuccess: string;
|
|
57
|
+
interruption: string;
|
|
58
|
+
validation: string;
|
|
59
|
+
expectedChanges: string[];
|
|
60
|
+
unexpectedChanges: Array<{
|
|
61
|
+
path: string;
|
|
62
|
+
risk: string;
|
|
63
|
+
}>;
|
|
64
|
+
nextAction: string;
|
|
65
|
+
worktree: string;
|
|
66
|
+
branch?: string;
|
|
67
|
+
exactSessionId?: string;
|
|
68
|
+
exactSessionRef?: ProviderSessionRefV1;
|
|
69
|
+
sessionCandidateRef?: ProviderSessionRefV1;
|
|
70
|
+
sessionAvailability?: SessionAvailabilityV1;
|
|
71
|
+
}
|
|
72
|
+
export declare function projectBuildRecovery(projectDir: string, run: BuildRunRecordV2, now?: Date, ticketOverride?: string, sessionAvailability?: SessionAvailabilityV1): BuildRecoveryProjection;
|
|
73
|
+
export declare function resolveBuildRecoveryProjection(projectDir: string, run: BuildRunRecordV2, now?: Date, ticketOverride?: string, probe?: ResolveSessionAvailabilityOptions): Promise<BuildRecoveryProjection>;
|
|
74
|
+
export declare function formatBuildRecoveryProjection(projection: BuildRecoveryProjection): string[];
|
|
42
75
|
export {};
|