ai-foreman 1.7.19 → 1.7.21
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 +29 -5
- package/dist/activity.d.ts +3 -0
- package/dist/activity.js +18 -6
- package/dist/adapters/claude.d.ts +16 -0
- package/dist/adapters/claude.js +28 -3
- package/dist/adapters/codex.d.ts +20 -0
- package/dist/adapters/codex.js +99 -5
- package/dist/adapters/recovering.d.ts +9 -0
- package/dist/adapters/recovering.js +10 -0
- package/dist/adapters/types.d.ts +15 -0
- package/dist/agentRun.d.ts +7 -0
- package/dist/agentRun.js +24 -13
- package/dist/branch/currentGuard.d.ts +1 -0
- package/dist/branch/currentGuard.js +1 -0
- package/dist/branch/finalization.js +6 -1
- package/dist/branch/git.d.ts +1 -0
- package/dist/branch/git.js +15 -1
- package/dist/branch/runner.d.ts +2 -0
- package/dist/branch/runner.js +92 -5
- package/dist/buildAdmission.d.ts +61 -0
- package/dist/buildAdmission.js +286 -0
- package/dist/buildApproval.d.ts +2 -0
- package/dist/buildApproval.js +17 -0
- package/dist/buildAssignment.d.ts +33 -0
- package/dist/buildAssignment.js +215 -0
- package/dist/buildInterventions.d.ts +90 -0
- package/dist/buildInterventions.js +334 -0
- package/dist/buildLaunchGate.d.ts +1 -0
- package/dist/buildLaunchGate.js +36 -0
- package/dist/buildOwnershipReconciliation.d.ts +19 -0
- package/dist/buildOwnershipReconciliation.js +41 -0
- package/dist/buildOwnershipRepair.d.ts +33 -0
- package/dist/buildOwnershipRepair.js +111 -0
- package/dist/buildRuns.d.ts +24 -1
- package/dist/buildRuns.js +216 -70
- package/dist/buildSyntheticWork.d.ts +2 -0
- package/dist/buildSyntheticWork.js +30 -0
- package/dist/buildWorkAdmission.d.ts +17 -0
- package/dist/buildWorkAdmission.js +57 -0
- package/dist/buildWorkAuthorization.d.ts +2 -0
- package/dist/buildWorkAuthorization.js +23 -0
- package/dist/buildWorkContext.d.ts +3 -0
- package/dist/buildWorkContext.js +6 -0
- package/dist/buildWorkMigration.d.ts +9 -0
- package/dist/buildWorkMigration.js +206 -0
- package/dist/buildWorkReconciliation.d.ts +12 -0
- package/dist/buildWorkReconciliation.js +70 -0
- package/dist/builderGuidanceFollowup.d.ts +15 -0
- package/dist/builderGuidanceFollowup.js +34 -0
- package/dist/cli/doctor.js +3 -2
- package/dist/cli/graph.d.ts +2 -0
- package/dist/cli/graph.js +75 -0
- package/dist/cli/manager.d.ts +8 -0
- package/dist/cli/manager.js +234 -12
- package/dist/cli/recovery.js +3 -2
- package/dist/cli/runtimeAuthPrompt.d.ts +5 -0
- package/dist/cli/runtimeAuthPrompt.js +41 -7
- package/dist/cli/start.d.ts +8 -0
- package/dist/cli/start.js +2091 -1849
- package/dist/cli/status.js +20 -5
- package/dist/cli/tickets.js +9 -7
- package/dist/continuity.d.ts +16 -1
- package/dist/continuity.js +68 -12
- package/dist/foreman.d.ts +12 -4
- package/dist/foreman.js +397 -60
- package/dist/graph/boundary.d.ts +15 -0
- package/dist/graph/boundary.js +50 -0
- package/dist/graph/bridge.d.ts +9 -0
- package/dist/graph/bridge.js +146 -0
- package/dist/graph/bridge.py +205 -0
- package/dist/graph/config.d.ts +11 -0
- package/dist/graph/config.js +40 -0
- package/dist/graph/corpus.d.ts +16 -0
- package/dist/graph/corpus.js +188 -0
- package/dist/graph/derived.d.ts +17 -0
- package/dist/graph/derived.js +73 -0
- package/dist/graph/host.d.ts +4 -0
- package/dist/graph/host.js +160 -0
- package/dist/graph/install.d.ts +3 -0
- package/dist/graph/install.js +50 -0
- package/dist/graph/lifecycle.d.ts +11 -0
- package/dist/graph/lifecycle.js +124 -0
- package/dist/graph/maintenance.d.ts +43 -0
- package/dist/graph/maintenance.js +301 -0
- package/dist/graph/manager.d.ts +9 -0
- package/dist/graph/manager.js +92 -0
- package/dist/graph/preparation.d.ts +41 -0
- package/dist/graph/preparation.js +43 -0
- package/dist/graph/read.d.ts +27 -0
- package/dist/graph/read.js +152 -0
- package/dist/graph/semantic.d.ts +17 -0
- package/dist/graph/semantic.js +27 -0
- package/dist/graph/session.d.ts +8 -0
- package/dist/graph/session.js +92 -0
- package/dist/graph/sources.d.ts +4 -0
- package/dist/graph/sources.js +11 -0
- package/dist/graph/storage.d.ts +38 -0
- package/dist/graph/storage.js +159 -0
- package/dist/graph/turn.d.ts +17 -0
- package/dist/graph/turn.js +360 -0
- package/dist/graph/util.d.ts +5 -0
- package/dist/graph/util.js +51 -0
- package/dist/handoffs.d.ts +1 -0
- package/dist/handoffs.js +5 -1
- package/dist/humanDecision.d.ts +21 -2
- package/dist/humanDecision.js +169 -10
- package/dist/index.js +4 -1
- package/dist/installOwnership.d.ts +46 -0
- package/dist/installOwnership.js +440 -0
- package/dist/linuxProbeInventory.d.ts +12 -0
- package/dist/linuxProbeInventory.js +48 -0
- package/dist/log.d.ts +1 -1
- package/dist/log.js +7 -1
- package/dist/managerEvidence.d.ts +25 -0
- package/dist/managerEvidence.js +326 -0
- package/dist/managerEvidenceArtifacts.d.ts +38 -0
- package/dist/managerEvidenceArtifacts.js +118 -0
- package/dist/managerPacket.d.ts +2 -0
- package/dist/managerPacket.js +23 -0
- package/dist/markers.d.ts +1 -1
- package/dist/markers.js +2 -2
- package/dist/observability.js +1 -1
- package/dist/processIdentity.d.ts +21 -1
- package/dist/processIdentity.js +87 -5
- package/dist/providerPhase.d.ts +13 -0
- package/dist/providerPhase.js +26 -0
- package/dist/qaAuthorizedDisposition.d.ts +24 -0
- package/dist/qaAuthorizedDisposition.js +26 -0
- package/dist/qaBuildGate.d.ts +4 -0
- package/dist/qaBuildGate.js +216 -0
- package/dist/qaBuilderCoverage.d.ts +5 -0
- package/dist/qaBuilderCoverage.js +78 -0
- package/dist/qaContractCoverage.d.ts +10 -0
- package/dist/qaContractCoverage.js +55 -0
- package/dist/qaContractDelivery.d.ts +23 -0
- package/dist/qaContractDelivery.js +145 -0
- package/dist/qaContractFreshness.d.ts +15 -0
- package/dist/qaContractFreshness.js +36 -0
- package/dist/qaDeliveryJournal.d.ts +10 -0
- package/dist/qaDeliveryJournal.js +16 -1
- package/dist/qaEffectiveConfig.d.ts +20 -0
- package/dist/qaEffectiveConfig.js +40 -0
- package/dist/qaEvidenceReader.d.ts +14 -0
- package/dist/qaEvidenceReader.js +176 -0
- package/dist/qaFailureDelivery.d.ts +2 -0
- package/dist/qaFailureDelivery.js +107 -10
- package/dist/qaHandbackMigration.d.ts +1 -1
- package/dist/qaHandbackMigration.js +3 -3
- package/dist/qaPreparation.d.ts +26 -0
- package/dist/qaPreparation.js +150 -0
- package/dist/qaPreparationInputs.d.ts +8 -0
- package/dist/qaPreparationInputs.js +47 -0
- package/dist/qaPreparationMetrics.d.ts +145 -0
- package/dist/qaPreparationMetrics.js +120 -0
- package/dist/qaPreparationPolicy.d.ts +5 -0
- package/dist/qaPreparationPolicy.js +51 -0
- package/dist/qaPreparationStore.d.ts +157 -0
- package/dist/qaPreparationStore.js +412 -0
- package/dist/qaProtocolV2.d.ts +28 -0
- package/dist/qaProtocolV2.js +12 -0
- package/dist/qaReview.d.ts +6 -0
- package/dist/qaReview.js +293 -41
- package/dist/qaTimeline.d.ts +18 -0
- package/dist/qaTimeline.js +123 -0
- package/dist/qaVerificationContract.d.ts +17 -0
- package/dist/qaVerificationContract.js +236 -0
- package/dist/readinessCleanup.d.ts +19 -0
- package/dist/readinessCleanup.js +122 -0
- package/dist/readinessGate.d.ts +1 -0
- package/dist/readinessGate.js +82 -0
- package/dist/recoveryGuidance.d.ts +17 -0
- package/dist/recoveryGuidance.js +38 -0
- package/dist/runtimeAuth.d.ts +1 -0
- package/dist/runtimeAuth.js +5 -1
- package/dist/runtimeReadiness.d.ts +13 -0
- package/dist/runtimeReadiness.js +206 -10
- package/dist/sessionIdentity.d.ts +2 -0
- package/dist/sessionIdentity.js +14 -0
- package/dist/sessionLifecycle.js +3 -3
- package/dist/sources/sourceRegistry.js +7 -0
- package/dist/stateTransfer.js +85 -8
- package/dist/statusReporter.d.ts +1 -0
- package/dist/statusReporter.js +1 -0
- package/dist/supervisedStart.d.ts +6 -0
- package/dist/supervisedStart.js +178 -62
- package/dist/supervisor.d.ts +2 -0
- package/dist/supervisor.js +26 -2
- package/dist/terminalStyle.d.ts +21 -0
- package/dist/terminalStyle.js +50 -0
- package/dist/ticketPopulation.d.ts +1 -0
- package/dist/ticketPopulation.js +5 -1
- package/dist/tickets/commands.js +2 -2
- package/dist/tickets/queue.js +1 -1
- package/dist/tickets/ticketSchema.d.ts +198 -0
- package/dist/tickets/ticketSchema.js +2 -0
- package/dist/windowsProbeJob.d.ts +12 -0
- package/dist/windowsProbeJob.js +144 -0
- package/dist/workflowDb.d.ts +121 -6
- package/dist/workflowDb.js +874 -30
- package/dist/workflowReader.d.ts +116 -2
- package/dist/workflowReader.js +131 -4
- package/package.json +89 -8
- package/scripts/copy-graph-assets.mjs +3 -0
- package/scripts/graph-benchmark.mjs +20 -0
- package/scripts/graph-evaluation.mjs +85 -0
package/dist/cli/manager.js
CHANGED
|
@@ -1,16 +1,26 @@
|
|
|
1
|
+
import { dispatchWithGraphAccess } from "../graph/session.js";
|
|
2
|
+
import { createManagerGraphEvidence, parseManagerGraphRequest } from "../graph/manager.js";
|
|
3
|
+
import { prepareOwnershipRepair, repairOwnership } from "../buildOwnershipRepair.js";
|
|
4
|
+
import { BuildInterventionControl, parseManagerAction } from "../buildInterventions.js";
|
|
1
5
|
import { randomUUID } from "node:crypto";
|
|
2
6
|
import { createInterface } from "node:readline/promises";
|
|
3
7
|
import { stdin as input, stdout as output } from "node:process";
|
|
4
8
|
import { resolve } from "node:path";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { mkdtempSync, writeFileSync } from "node:fs";
|
|
11
|
+
import { tmpdir } from "node:os";
|
|
12
|
+
import { ManagerEvidenceService, parseManagerEvidenceRequestV2 } from "../managerEvidence.js";
|
|
13
|
+
import { buildManagerEvidencePacketV2 } from "../managerPacket.js";
|
|
5
14
|
import { Command } from "commander";
|
|
6
15
|
import { createRoleBuilder, readOnlyPermissionConfig } from "../agentRun.js";
|
|
7
16
|
import { Log } from "../log.js";
|
|
8
17
|
import { buildManagerEvidencePacket, buildManagerProjectPacket } from "../managerPacket.js";
|
|
9
18
|
import { ManagerSessionRecorder } from "../observability.js";
|
|
10
19
|
import { collectManagerProjectDiagnostics, executeManagerEvidenceRequest, MANAGER_LOOKUP_MAX_ROUNDS, parseManagerEvidenceRequest, resolveManagerQuestionRuns } from "../projectDiagnostics.js";
|
|
20
|
+
import { accent, sanitizeTerminalText } from "../terminalStyle.js";
|
|
11
21
|
export function buildManagerCommand(options = {}) {
|
|
12
22
|
return new Command("manager")
|
|
13
|
-
.description("
|
|
23
|
+
.description("Inspect retained builds and enqueue explicitly scoped Builder/QA guidance.")
|
|
14
24
|
.argument(options.requireProject ? "<project>" : "[project]", "project directory")
|
|
15
25
|
.option("--run <run-id>", "set the initial focused build run")
|
|
16
26
|
.option("--ask <question>", "ask one question and exit")
|
|
@@ -19,6 +29,7 @@ export function buildManagerCommand(options = {}) {
|
|
|
19
29
|
.option("--effort <level>", "low | medium | high | xhigh")
|
|
20
30
|
.option("--fast", "use the provider fast mode")
|
|
21
31
|
.option("--external <mode>", "auto | on | off", "auto")
|
|
32
|
+
.addHelpText("after", "\nHost evidence commands (also accepted by --ask):\n /qa-work <run>\n /qa-attempts <run> <ticket>\n /qa-report <run> <ticket> <attempt> [occurrence]\n /qa-timeline <run> <ticket>\n /qa-conflicts <run>\n /qa-instruction <run> <work> <instruction>\n /qa-repair-plan <run> <work>\n /qa-repair <JSON request>\n /more <cursor>\n /artifact <handle>\n /qa-export <run> <ticket> <attempt> [occurrence]\n /qa-export <handle> Export protected raw bytes to a private local file.\nScoped controls:\n /guide-builder <run> <work> <text>\n /guide-qa <run> <work> <text>\n /guide-both <run> <work> <text>\n /pause <run> <work> [run]\n /withdraw <run> <work> <instruction>\n /supersede <run> <work> <instruction> <text>\n /request-attempt <run> <work> <reason>\n /answer-question <run> <work> <decision> <revision> <text>\n")
|
|
22
33
|
.action(async (project, opts) => {
|
|
23
34
|
const root = options.resolveProject ? options.resolveProject(project) : resolve(project ?? ".");
|
|
24
35
|
await runManager(root, {
|
|
@@ -30,15 +41,27 @@ export function buildManagerCommand(options = {}) {
|
|
|
30
41
|
export async function runManager(projectDir, options) {
|
|
31
42
|
if (!options.ask && (!input.isTTY || !output.isTTY))
|
|
32
43
|
throw new Error("non-TTY Manager use requires --ask <question>");
|
|
44
|
+
const evidence = new ManagerEvidenceService(projectDir);
|
|
45
|
+
if (options.ask && (options.ask.trim().startsWith("/") || parseManagerAction(options.ask))) {
|
|
46
|
+
try {
|
|
47
|
+
if (!executeManagerHostCommand(evidence, options.ask, text => output.write(text), true))
|
|
48
|
+
throw new Error("Unknown Manager host command; see manager --help");
|
|
49
|
+
}
|
|
50
|
+
finally {
|
|
51
|
+
evidence.close();
|
|
52
|
+
}
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
33
55
|
const initialCollection = collectManagerProjectDiagnostics(projectDir, { initialFocusRunId: options.runId, question: options.ask, external: "off" });
|
|
34
56
|
const initialReport = initialCollection.report;
|
|
35
57
|
let currentFocusRunId = initialReport.initialFocusRunId;
|
|
36
58
|
let referencedRunIds = [currentFocusRunId];
|
|
37
|
-
|
|
38
|
-
output.write(
|
|
39
|
-
output.write(
|
|
59
|
+
const managerLabel = (text) => accent(text, { stream: output, env: process.env, machineReadable: Boolean(options.ask) });
|
|
60
|
+
output.write(`${managerLabel("rafi manager")}: ${initialReport.totalRunCount} retained build run${initialReport.totalRunCount === 1 ? "" : "s"}\n`);
|
|
61
|
+
output.write(`${managerLabel("rafi manager")}: verified active run ${sanitizeTerminalText(initialReport.verifiedActiveRunId ?? "none")}\n`);
|
|
62
|
+
output.write(`${managerLabel("rafi manager")}: initial focus ${sanitizeTerminalText(currentFocusRunId)}\n`);
|
|
40
63
|
if (initialReport.staleRecoveryRunIds.length)
|
|
41
|
-
output.write(
|
|
64
|
+
output.write(`${managerLabel("rafi manager")}: stale recovery state ${initialReport.staleRecoveryRunIds.map(sanitizeTerminalText).join(", ")}\n`);
|
|
42
65
|
const metadata = new ManagerSessionRecorder(projectDir);
|
|
43
66
|
const managerSessionId = randomUUID();
|
|
44
67
|
const startedAt = new Date().toISOString();
|
|
@@ -52,6 +75,9 @@ export async function runManager(projectDir, options) {
|
|
|
52
75
|
const activeRole = role = await createRoleBuilder({ projectDir, role: "manager", agent: options.agent, model: options.model, effort: options.effort, fast: options.fast,
|
|
53
76
|
yes: true, allowSwitch: false, label: "Manager", log: new Log(), permissionConfig: denyManagerTools(), sandboxMode: "read-only", persistSessionBindings: false });
|
|
54
77
|
const ask = async (question) => {
|
|
78
|
+
if (executeManagerHostCommand(evidence, question, text => output.write(text), Boolean(options.ask)))
|
|
79
|
+
return;
|
|
80
|
+
let emittedMachineOutput = false;
|
|
55
81
|
const refreshed = collectManagerProjectDiagnostics(projectDir, { initialFocusRunId: initialReport.initialFocusRunId, currentFocusRunId, referencedRunIds, question, external: "off" });
|
|
56
82
|
const resolved = resolveManagerQuestionRuns(refreshed.allSummaries, question, currentFocusRunId, referencedRunIds);
|
|
57
83
|
currentFocusRunId = resolved.focusRunId;
|
|
@@ -60,16 +86,47 @@ export async function runManager(projectDir, options) {
|
|
|
60
86
|
const report = collection.report;
|
|
61
87
|
const packet = buildManagerProjectPacket(report, question, packetState, referencedRunIds);
|
|
62
88
|
packetState = packet.state;
|
|
63
|
-
|
|
89
|
+
const graphEvidence = createManagerGraphEvidence(projectDir, currentFocusRunId);
|
|
90
|
+
const send = (text) => dispatchWithGraphAccess(projectDir, activeRole.builder, text, undefined, (prompt, policy) => activeRole.builder.sendTurn(prompt, policy), graphEvidence.access());
|
|
91
|
+
let result = await send(`${packet.prompt}\n\n${graphEvidence.guidance}`);
|
|
64
92
|
let questionLookupRounds = 0;
|
|
65
93
|
while (questionLookupRounds < MANAGER_LOOKUP_MAX_ROUNDS) {
|
|
94
|
+
const graphRequest = parseManagerGraphRequest(result.text);
|
|
95
|
+
if (graphRequest) {
|
|
96
|
+
questionLookupRounds++;
|
|
97
|
+
lookupRounds++;
|
|
98
|
+
lookupOperations += graphRequest.operations.length;
|
|
99
|
+
const graphPacket = await graphEvidence.execute(graphRequest);
|
|
100
|
+
result = await send(`Untrusted host-scoped graph evidence; verify claims against source. Remaining lookup rounds: ${MANAGER_LOOKUP_MAX_ROUNDS - questionLookupRounds}. Answer the original question: ${question}\n${graphPacket}`);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const evidenceRequest = parseManagerEvidenceRequestV2(result.text);
|
|
104
|
+
if (evidenceRequest) {
|
|
105
|
+
questionLookupRounds++;
|
|
106
|
+
lookupRounds++;
|
|
107
|
+
lookupOperations++;
|
|
108
|
+
const response = evidence.execute(evidenceRequest);
|
|
109
|
+
if (options.ask) {
|
|
110
|
+
emittedMachineOutput = true;
|
|
111
|
+
output.write(`${JSON.stringify(completeManagerHostEvidence(evidence, response))}\n`);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
if (response.nextCursor)
|
|
115
|
+
output.write(`Evidence continuation: /more ${response.nextCursor}\n`);
|
|
116
|
+
for (const item of response.items)
|
|
117
|
+
if (item && typeof item === "object" && "handle" in item)
|
|
118
|
+
output.write(`Complete report: /artifact ${String(item.handle)}\n`);
|
|
119
|
+
}
|
|
120
|
+
result = await send(buildManagerEvidencePacketV2(response, question));
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
66
123
|
const request = parseManagerEvidenceRequest(result.text);
|
|
67
124
|
if (!request) {
|
|
68
125
|
if (!looksLikeEvidenceRequest(result.text))
|
|
69
126
|
break;
|
|
70
127
|
questionLookupRounds += 1;
|
|
71
128
|
lookupRounds += 1;
|
|
72
|
-
result = await
|
|
129
|
+
result = await send(buildManagerEvidencePacket({ version: 1, requestId: "invalid-request", results: [{ kind: "list_runs", status: "invalid", limitation: "The evidence envelope was invalid. Use only the documented fixed fields and read-only operations, then answer with any remaining limitation disclosed." }], lookupRound: questionLookupRounds, remainingRounds: MANAGER_LOOKUP_MAX_ROUNDS - questionLookupRounds, digest: report.digest }, question));
|
|
73
130
|
continue;
|
|
74
131
|
}
|
|
75
132
|
questionLookupRounds += 1;
|
|
@@ -77,14 +134,34 @@ export async function runManager(projectDir, options) {
|
|
|
77
134
|
lookupOperations += Math.min(6, request.operations.length);
|
|
78
135
|
const response = executeManagerEvidenceRequest(projectDir, request, collection, questionLookupRounds);
|
|
79
136
|
packetState.lastEvidenceScope = request.operations.flatMap(operation => "runIds" in operation ? operation.runIds : []);
|
|
80
|
-
result = await
|
|
137
|
+
result = await send(buildManagerEvidencePacket(response, question));
|
|
81
138
|
}
|
|
82
139
|
const unfulfilled = parseManagerEvidenceRequest(result.text);
|
|
140
|
+
const pendingEvidence = parseManagerEvidenceRequestV2(result.text);
|
|
141
|
+
if (pendingEvidence) {
|
|
142
|
+
const page = evidence.execute(pendingEvidence);
|
|
143
|
+
if (options.ask) {
|
|
144
|
+
emittedMachineOutput = true;
|
|
145
|
+
output.write(`${JSON.stringify(completeManagerHostEvidence(evidence, page))}\n`);
|
|
146
|
+
}
|
|
147
|
+
else
|
|
148
|
+
output.write(`${JSON.stringify(page)}\n${page.nextCursor ? `Continue with /more ${page.nextCursor}` : "Browse reports with /qa-attempts <run> <ticket> and /qa-report <run> <ticket> <attempt>"}\n`);
|
|
149
|
+
}
|
|
83
150
|
if (unfulfilled) {
|
|
84
151
|
const limitation = { version: 1, requestId: unfulfilled.requestId, results: unfulfilled.operations.slice(0, 6).map(operation => ({ kind: operation.kind, status: "limited", limitation: "the two-round evidence lookup budget is exhausted; answer with this limitation disclosed" })), lookupRound: MANAGER_LOOKUP_MAX_ROUNDS, remainingRounds: 0, digest: report.digest };
|
|
85
|
-
result = await
|
|
152
|
+
result = await send(buildManagerEvidencePacket(limitation, question));
|
|
153
|
+
}
|
|
154
|
+
if (!pendingEvidence) {
|
|
155
|
+
const answer = parseManagerEvidenceRequest(result.text) || parseManagerGraphRequest(result.text) || looksLikeEvidenceRequest(result.text)
|
|
156
|
+
? "Manager could not complete an answer within the bounded evidence lookup budget. Continue with /qa-attempts <run> <ticket> or /qa-report <run> <ticket> <attempt>."
|
|
157
|
+
: result.text.trim();
|
|
158
|
+
// One-shot evidence requests can mix JSON with prose, so add the label
|
|
159
|
+
// only when this answer stream has not emitted machine-readable data.
|
|
160
|
+
// Model-provided text is sanitized only for display, never for storage.
|
|
161
|
+
if (!emittedMachineOutput)
|
|
162
|
+
output.write(`${accent("Manager:", { stream: output, env: process.env })} `);
|
|
163
|
+
output.write(`${sanitizeTerminalText(answer)}\n`);
|
|
86
164
|
}
|
|
87
|
-
output.write(`${parseManagerEvidenceRequest(result.text) || looksLikeEvidenceRequest(result.text) ? "Manager could not complete an answer within the bounded evidence lookup budget; the available project report remains partial." : result.text.trim()}\n`);
|
|
88
165
|
usage = await activeRole.builder.sessionUsage?.() ?? usage;
|
|
89
166
|
metadata.record({ sessionId: managerSessionId, runId: initialReport.initialFocusRunId, provider: activeRole.builder.agent, startedAt, reportDigest: report.digest,
|
|
90
167
|
inputTokens: usage?.inputTokens, outputTokens: usage?.outputTokens, costUsd: usage?.authoritativeCostUsd, scope: "project", latestFocusRunId: currentFocusRunId,
|
|
@@ -99,11 +176,11 @@ export async function runManager(projectDir, options) {
|
|
|
99
176
|
readline.on("SIGINT", onInterrupt);
|
|
100
177
|
try {
|
|
101
178
|
while (true) {
|
|
102
|
-
const question = await readline.question("manager>
|
|
179
|
+
const question = await readline.question(`${accent("manager>", { stream: output, env: process.env })} `);
|
|
103
180
|
if (question.trim() === "/exit")
|
|
104
181
|
break;
|
|
105
182
|
if (question.trim())
|
|
106
|
-
await ask(question
|
|
183
|
+
await ask(question);
|
|
107
184
|
}
|
|
108
185
|
}
|
|
109
186
|
catch (error) {
|
|
@@ -124,7 +201,152 @@ export async function runManager(projectDir, options) {
|
|
|
124
201
|
finally {
|
|
125
202
|
await role?.builder.close().catch(() => { });
|
|
126
203
|
metadata.close();
|
|
204
|
+
evidence.close();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
/** Only original user commands enter here. Model output and retained reports cannot export raw bytes. */
|
|
208
|
+
export function executeManagerHostCommand(service, command, write, complete = false) {
|
|
209
|
+
if (command.trim().startsWith("/qa-repair ")) {
|
|
210
|
+
write(`${JSON.stringify(repairOwnership(service.projectDir, JSON.parse(command.trim().slice("/qa-repair ".length)), command))}\n`);
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
213
|
+
if (command.trim().startsWith("/qa-repair-plan ")) {
|
|
214
|
+
const args = command.trim().split(/\s+/);
|
|
215
|
+
if (args.length !== 3)
|
|
216
|
+
throw new Error("/qa-repair-plan requires run and work identities");
|
|
217
|
+
write(`${JSON.stringify(prepareOwnershipRepair(service.projectDir, args[1], args[2]))}\n`);
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
const proposed = parseManagerAction(command);
|
|
221
|
+
if (proposed) {
|
|
222
|
+
const control = new BuildInterventionControl(service.projectDir, proposed.runId, proposed.workId);
|
|
223
|
+
try {
|
|
224
|
+
const request = parseManagerAction(command, proposed.requestId, control.revision());
|
|
225
|
+
const queued = control.enqueue(request, command);
|
|
226
|
+
write(`${JSON.stringify(queued)}\n${request.action === "withdraw" ? "Withdrawn before reservation." : "Queued at the next eligible safe boundary. An active provider turn continues; a stopped owner must resume to consume this instruction."}\n`);
|
|
227
|
+
}
|
|
228
|
+
finally {
|
|
229
|
+
control.close();
|
|
230
|
+
}
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
if (!command.trim().startsWith("/"))
|
|
234
|
+
return false;
|
|
235
|
+
const [name, ...args] = command.trim().split(/\s+/);
|
|
236
|
+
if (name === "/artifact" || name === "/qa-export" && args.length === 1) {
|
|
237
|
+
if (args.length !== 1)
|
|
238
|
+
throw new Error(`${name} requires one host artifact handle`);
|
|
239
|
+
if (name === "/artifact")
|
|
240
|
+
write(`${JSON.stringify(service.artifacts.metadata(args[0]))}\n${service.artifacts.bytes(args[0]).toString("utf8")}\n`);
|
|
241
|
+
else {
|
|
242
|
+
const path = join(mkdtempSync(join(tmpdir(), "rafi-qa-evidence-")), "protected-evidence.txt");
|
|
243
|
+
writeFileSync(path, service.artifacts.bytes(args[0], true), { mode: 0o600 });
|
|
244
|
+
write(`Protected raw evidence exported to ${path}\n${JSON.stringify(service.artifacts.metadata(args[0]))}\n`);
|
|
245
|
+
}
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
if (name === "/more") {
|
|
249
|
+
if (args.length !== 1)
|
|
250
|
+
throw new Error("/more requires one cursor");
|
|
251
|
+
const page = service.more(args[0]);
|
|
252
|
+
write(`${JSON.stringify(complete ? completeManagerHostEvidence(service, page) : page)}\n`);
|
|
253
|
+
return true;
|
|
254
|
+
}
|
|
255
|
+
const requestId = randomUUID();
|
|
256
|
+
const runId = args[0] ?? "";
|
|
257
|
+
const workId = args[1] ?? "";
|
|
258
|
+
let page;
|
|
259
|
+
if (name === "/qa-work" || name === "/qa-conflicts") {
|
|
260
|
+
if (args.length !== 1)
|
|
261
|
+
throw new Error(`${name} requires a run ID`);
|
|
262
|
+
page = service.execute({ version: 2, requestId, operation: { kind: name === "/qa-work" ? "list_build_work" : "get_ownership_conflicts", runId } });
|
|
263
|
+
}
|
|
264
|
+
else if (name === "/qa-attempts" || name === "/qa-timeline") {
|
|
265
|
+
if (args.length !== 2)
|
|
266
|
+
throw new Error(`${name} requires run and ticket IDs`);
|
|
267
|
+
page = service.execute({ version: 2, requestId, operation: { kind: name === "/qa-attempts" ? "list_qa_attempts" : "get_qa_timeline", runId, workId } });
|
|
268
|
+
}
|
|
269
|
+
else if (name === "/qa-instruction") {
|
|
270
|
+
if (args.length !== 3)
|
|
271
|
+
throw new Error("/qa-instruction requires run, work and instruction identities");
|
|
272
|
+
page = service.execute({ version: 2, requestId, operation: { kind: "get_intervention_status", runId, workId, instructionId: args[2] } });
|
|
273
|
+
}
|
|
274
|
+
else if (name === "/qa-report" || name === "/qa-export") {
|
|
275
|
+
if (args.length < 3 || args.length > 4)
|
|
276
|
+
throw new Error(`${name} requires run, ticket, attempt and optional occurrence IDs`);
|
|
277
|
+
const attemptId = args[2];
|
|
278
|
+
const attempts = service.execute({ version: 2, requestId, operation: { kind: "list_qa_attempts", runId, workId } });
|
|
279
|
+
const rows = completeManagerHostEvidence(service, attempts).items;
|
|
280
|
+
const attempt = rows.find(row => row && typeof row === "object" && "attemptId" in row && row.attemptId === attemptId);
|
|
281
|
+
if (!attempt)
|
|
282
|
+
throw new Error("Attempt is not retained in this run/ticket; use /qa-attempts first");
|
|
283
|
+
if (!attempt.reports.length) {
|
|
284
|
+
write(`${JSON.stringify(rows.find(row => row && typeof row === "object" && "attemptId" in row && row.attemptId === attemptId))}\nNo retained failure report body; inspect verification or attempt status above.\n`);
|
|
285
|
+
return true;
|
|
286
|
+
}
|
|
287
|
+
const occurrenceId = args[3] ?? (attempt.reports.length === 1 ? attempt.reports[0].occurrenceId : undefined);
|
|
288
|
+
if (!occurrenceId)
|
|
289
|
+
throw new Error("Report identity is ambiguous; specify a retained occurrence ID");
|
|
290
|
+
page = service.execute({ version: 2, requestId, operation: { kind: "get_qa_report", runId, workId, attemptId, occurrenceId, snapshotId: attempts.snapshotId } });
|
|
291
|
+
const artifact = page.items[0];
|
|
292
|
+
if (artifact?.handle) {
|
|
293
|
+
if (name === "/qa-export") {
|
|
294
|
+
const path = join(mkdtempSync(join(tmpdir(), "rafi-qa-evidence-")), "protected-evidence.txt");
|
|
295
|
+
writeFileSync(path, service.artifacts.bytes(artifact.handle, true), { mode: 0o600 });
|
|
296
|
+
write(`Protected raw evidence exported to ${path}\n${JSON.stringify({ ...service.artifacts.metadata(artifact.handle), snapshotId: page.snapshotId, asOf: page.asOf })}\n`);
|
|
297
|
+
}
|
|
298
|
+
else
|
|
299
|
+
write(`${JSON.stringify({ ...service.artifacts.metadata(artifact.handle), snapshotId: page.snapshotId, asOf: page.asOf, availability: page.availability, omissions: page.omissions.filter(item => !item.startsWith("Complete host rendering:")) })}\n${service.artifacts.bytes(artifact.handle).toString("utf8")}\n`);
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
else
|
|
304
|
+
return false;
|
|
305
|
+
write(`${JSON.stringify(complete ? completeManagerHostEvidence(service, page) : page)}\n`);
|
|
306
|
+
if (!complete && page.nextCursor)
|
|
307
|
+
write(`Continue with /more ${page.nextCursor}\n`);
|
|
308
|
+
return true;
|
|
309
|
+
}
|
|
310
|
+
/** Drain one pinned snapshot and expand every referenced artifact before host close.
|
|
311
|
+
* Errors are returned as incomplete output; an expired snapshot is never refreshed.
|
|
312
|
+
* This host output is deliberately independent of bounded model packets. */
|
|
313
|
+
export function completeManagerHostEvidence(service, first) {
|
|
314
|
+
const result = structuredClone(first);
|
|
315
|
+
result.redactions = service.hostRedactions(first.snapshotId);
|
|
316
|
+
result.items = [];
|
|
317
|
+
const seen = new Set();
|
|
318
|
+
let page = first;
|
|
319
|
+
while (true) {
|
|
320
|
+
for (const item of page.items) {
|
|
321
|
+
const row = item;
|
|
322
|
+
if (row?.metadataArtifact)
|
|
323
|
+
result.items.push(service.hostMetadataItem(row.metadataArtifact.handle));
|
|
324
|
+
else if (row?.handle) {
|
|
325
|
+
if (seen.has(row.handle))
|
|
326
|
+
continue;
|
|
327
|
+
seen.add(row.handle);
|
|
328
|
+
const { handle: _, ...metadata } = service.artifacts.metadata(row.handle);
|
|
329
|
+
result.items.push({ ...metadata, body: service.artifacts.bytes(row.handle).toString("utf8") });
|
|
330
|
+
}
|
|
331
|
+
else
|
|
332
|
+
result.items.push(item);
|
|
333
|
+
}
|
|
334
|
+
if (!page.nextCursor || page.error)
|
|
335
|
+
break;
|
|
336
|
+
const next = service.more(page.nextCursor);
|
|
337
|
+
if (!next.error && next.snapshotId !== first.snapshotId)
|
|
338
|
+
throw new Error("Evidence continuation changed snapshot identity");
|
|
339
|
+
page = next;
|
|
340
|
+
}
|
|
341
|
+
delete result.nextCursor;
|
|
342
|
+
result.complete = page.complete;
|
|
343
|
+
if (page.error) {
|
|
344
|
+
result.error = page.error;
|
|
345
|
+
result.restartAction = page.restartAction;
|
|
346
|
+
result.omissions.push(...page.omissions);
|
|
127
347
|
}
|
|
348
|
+
result.omissions = result.omissions.filter(item => !item.startsWith("Complete host rendering:") && !item.includes("additional redaction spans are available"));
|
|
349
|
+
return result;
|
|
128
350
|
}
|
|
129
351
|
function denyManagerTools() {
|
|
130
352
|
return { ...readOnlyPermissionConfig(), allowBash: [], allowTools: [], escalateBash: [""], escalateTools: ["Read", "Glob", "Grep", "Edit", "Write", "MultiEdit", "NotebookEdit", "TodoWrite", "WebFetch", "WebSearch", "Bash"] };
|
package/dist/cli/recovery.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isLiveProcessIdentity } from "../processIdentity.js";
|
|
2
2
|
import { Command } from "commander";
|
|
3
|
+
import { accent, sanitizeTerminalText, success, warning } from "../terminalStyle.js";
|
|
3
4
|
import { resolve } from "node:path";
|
|
4
5
|
import { readBuildRuns } from "../buildRuns.js";
|
|
5
6
|
import { WorkflowDb } from "../workflowDb.js";
|
|
@@ -16,8 +17,8 @@ export function buildAttachCommand() {
|
|
|
16
17
|
const db = new WorkflowDb(projectDir);
|
|
17
18
|
try {
|
|
18
19
|
const supervisor = db.supervisorState(run.runId);
|
|
19
|
-
console.log(
|
|
20
|
-
console.log(
|
|
20
|
+
console.log(`${accent("rafi:")} run ${sanitizeTerminalText(run.runId)}`);
|
|
21
|
+
console.log(`${accent("rafi:")} phase ${sanitizeTerminalText("phase" in run && typeof run.phase === "string" ? run.phase : run.checkpoint)}; status ${run.status === "completed" ? success(run.status) : warning(run.status)}`);
|
|
21
22
|
console.log(`rafi: supervisor ${supervisor?.status ?? "unavailable"}${supervisor?.pid ? ` pid=${supervisor.pid}` : ""}`);
|
|
22
23
|
const attempts = db.recoveryAttempts(run.runId);
|
|
23
24
|
console.log(`rafi: recovery attempts ${attempts.length}`);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { RuntimeAuthError, type AgentRuntime } from "../runtimeAuth.js";
|
|
2
|
+
import { type BuildReadinessContext } from "../runtimeReadiness.js";
|
|
2
3
|
import type { RuntimeProbeResult } from "rafi-spec";
|
|
3
4
|
export type RuntimeCommandRecoveryChoice = "retry" | "switch" | "cancel";
|
|
4
5
|
export interface RuntimeCommandRecoveryContext {
|
|
@@ -7,6 +8,7 @@ export interface RuntimeCommandRecoveryContext {
|
|
|
7
8
|
}
|
|
8
9
|
export interface RuntimeReadyForCommandOptions {
|
|
9
10
|
label: string;
|
|
11
|
+
build?: BuildReadinessContext;
|
|
10
12
|
timeoutMs?: number;
|
|
11
13
|
durable?: {
|
|
12
14
|
projectDir: string;
|
|
@@ -27,4 +29,7 @@ export interface RuntimeReadyForCommandResult {
|
|
|
27
29
|
fellBack: boolean;
|
|
28
30
|
executable: string;
|
|
29
31
|
}
|
|
32
|
+
export declare function ensureBuildRuntimeReadyForCommand(projectDir: string, runtime: AgentRuntime, opts: RuntimeReadyForCommandOptions & {
|
|
33
|
+
build: BuildReadinessContext;
|
|
34
|
+
}): Promise<RuntimeReadyForCommandResult>;
|
|
30
35
|
export declare function ensureRuntimeReadyForCommand(projectDir: string, runtime: AgentRuntime, labelOrOptions: string | RuntimeReadyForCommandOptions): Promise<RuntimeReadyForCommandResult>;
|
|
@@ -1,17 +1,27 @@
|
|
|
1
1
|
import { select, isCancel, log } from "@clack/prompts";
|
|
2
2
|
import { requireClaudeSDK } from "../adapters/claude.js";
|
|
3
3
|
import { checkRuntimeReady, RuntimeAuthError, runtimeCommandLabel, } from "../runtimeAuth.js";
|
|
4
|
-
import {
|
|
4
|
+
import { BuildOwnershipError } from "../buildAdmission.js";
|
|
5
|
+
import { RuntimeCleanupError, runtimeCleanupRecoveryHelp, resolveExecutablePath } from "../runtimeReadiness.js";
|
|
5
6
|
import { otherRuntime, runtimeDisplayName } from "./runtimeSelection.js";
|
|
6
7
|
import { currentActivity } from "../activity.js";
|
|
7
8
|
import { durableHumanDecision } from "../humanDecision.js";
|
|
8
9
|
import { WorkflowDb } from "../workflowDb.js";
|
|
9
10
|
import { createHash } from "node:crypto";
|
|
11
|
+
export async function ensureBuildRuntimeReadyForCommand(projectDir, runtime, opts) {
|
|
12
|
+
if (!opts.build?.authority)
|
|
13
|
+
throw new BuildOwnershipError("stale-owner", "Build readiness requires original owning-project context");
|
|
14
|
+
return ensureRuntimeReadyForCommand(projectDir, runtime, opts);
|
|
15
|
+
}
|
|
10
16
|
export async function ensureRuntimeReadyForCommand(projectDir, runtime, labelOrOptions) {
|
|
11
17
|
const opts = typeof labelOrOptions === "string"
|
|
12
18
|
? { label: labelOrOptions }
|
|
13
19
|
: labelOrOptions;
|
|
14
|
-
const check = opts.check ?? ((projectDir, runtime) =>
|
|
20
|
+
const check = opts.check ?? (async (projectDir, runtime) => {
|
|
21
|
+
if (opts.durable && !opts.build)
|
|
22
|
+
throw new BuildOwnershipError("stale-owner", "Build readiness requires its original owning-project context");
|
|
23
|
+
return checkRuntimeReady(projectDir, runtime, { build: opts.build, onTrace: opts.onTrace, timeoutMs: opts.timeoutMs });
|
|
24
|
+
});
|
|
15
25
|
const checkClaudeSdk = opts.checkClaudeSdk ?? requireClaudeSDK;
|
|
16
26
|
const allowSwitch = opts.allowSwitch !== false;
|
|
17
27
|
const nonInteractive = !opts.choose && (Boolean(opts.yes) || !process.stdin.isTTY || !process.stdout.isTTY);
|
|
@@ -26,6 +36,8 @@ export async function ensureRuntimeReadyForCommand(projectDir, runtime, labelOrO
|
|
|
26
36
|
return { runtime, model: opts.model, fellBack: false, executable };
|
|
27
37
|
}
|
|
28
38
|
catch (err) {
|
|
39
|
+
if (err instanceof BuildOwnershipError || (err instanceof RuntimeCleanupError && opts.build))
|
|
40
|
+
throw err;
|
|
29
41
|
const failure = err instanceof RuntimeAuthError
|
|
30
42
|
? err
|
|
31
43
|
: new RuntimeAuthError({
|
|
@@ -34,20 +46,21 @@ export async function ensureRuntimeReadyForCommand(projectDir, runtime, labelOrO
|
|
|
34
46
|
stderr: err instanceof Error ? err.message : String(err),
|
|
35
47
|
cause: err,
|
|
36
48
|
});
|
|
37
|
-
if (nonInteractive && !opts.durable) {
|
|
49
|
+
if (nonInteractive && !opts.durable && !(failure.cleanupUnverified && process.stdin.isTTY && process.stdout.isTTY)) {
|
|
38
50
|
throw failure;
|
|
39
51
|
}
|
|
40
52
|
const fallbackRuntime = otherRuntime(runtime);
|
|
53
|
+
const canSwitch = allowSwitch && !failure.cleanupUnverified;
|
|
41
54
|
const choice = opts.durable && !opts.choose
|
|
42
|
-
? await durableRuntimeRecovery(opts.durable, failure, opts.label, fallbackRuntime,
|
|
55
|
+
? await durableRuntimeRecovery(opts.durable, failure, opts.label, fallbackRuntime, canSwitch)
|
|
43
56
|
: opts.choose
|
|
44
|
-
? await opts.choose(failure, { otherRuntime: fallbackRuntime, allowSwitch })
|
|
45
|
-
: await promptRuntimeRecovery(failure, opts.label, fallbackRuntime,
|
|
57
|
+
? await opts.choose(failure, { otherRuntime: fallbackRuntime, allowSwitch: canSwitch })
|
|
58
|
+
: await promptRuntimeRecovery(failure, opts.label, fallbackRuntime, canSwitch);
|
|
46
59
|
if (choice === "retry") {
|
|
47
60
|
currentActivity()?.note(`rafi: retrying ${runtime} readiness check`);
|
|
48
61
|
continue;
|
|
49
62
|
}
|
|
50
|
-
if (choice === "switch" &&
|
|
63
|
+
if (choice === "switch" && canSwitch) {
|
|
51
64
|
currentActivity()?.note(`rafi: checking fallback runtime ${fallbackRuntime}`);
|
|
52
65
|
try {
|
|
53
66
|
const probe = await check(projectDir, fallbackRuntime);
|
|
@@ -64,6 +77,8 @@ export async function ensureRuntimeReadyForCommand(projectDir, runtime, labelOrO
|
|
|
64
77
|
return { runtime: fallbackRuntime, model: undefined, fellBack: true, executable };
|
|
65
78
|
}
|
|
66
79
|
catch (switchErr) {
|
|
80
|
+
if (switchErr instanceof BuildOwnershipError || (switchErr instanceof RuntimeCleanupError && opts.build))
|
|
81
|
+
throw switchErr;
|
|
67
82
|
const switchFailure = switchErr instanceof RuntimeAuthError
|
|
68
83
|
? switchErr
|
|
69
84
|
: new RuntimeAuthError({
|
|
@@ -116,6 +131,25 @@ async function durableRuntimeRecovery(scope, failure, label, fallbackRuntime, al
|
|
|
116
131
|
}
|
|
117
132
|
async function promptRuntimeRecovery(err, label, fallbackRuntime, allowSwitch) {
|
|
118
133
|
log.error(err.message);
|
|
134
|
+
if (err.cleanupUnverified) {
|
|
135
|
+
while (true) {
|
|
136
|
+
const choice = await select({
|
|
137
|
+
message: `${label} is paused until probe cleanup is verified. Choose a resolution.`,
|
|
138
|
+
options: [
|
|
139
|
+
{ value: "retry", label: "Recheck cleanup after repairing process visibility" },
|
|
140
|
+
{ value: "help", label: "Show platform-specific resolution approaches" },
|
|
141
|
+
{ value: "cancel", label: "Cancel deliberately; keep project files" },
|
|
142
|
+
],
|
|
143
|
+
});
|
|
144
|
+
if (isCancel(choice) || choice === "cancel")
|
|
145
|
+
return "cancel";
|
|
146
|
+
if (choice === "help") {
|
|
147
|
+
log.info(runtimeCleanupRecoveryHelp());
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
return "retry";
|
|
151
|
+
}
|
|
152
|
+
}
|
|
119
153
|
log.info("Cancel stops this command and keeps project files in place. It does not uninstall packages, delete generated files, or change configuration.");
|
|
120
154
|
if (!allowSwitch) {
|
|
121
155
|
log.info("Switching runtimes is disabled while resuming because session IDs are runtime-specific.");
|
package/dist/cli/start.d.ts
CHANGED
|
@@ -16,6 +16,14 @@ export declare function formatResumeGuidance(executable: "rafi" | "ai-foreman",
|
|
|
16
16
|
}>;
|
|
17
17
|
}>;
|
|
18
18
|
}): string[];
|
|
19
|
+
/** Save parsed CLI values as argv, never as executable shell text. */
|
|
20
|
+
export declare function savedStartArguments(command: Command, projectDir: string, opts: Record<string, unknown>): string[];
|
|
21
|
+
/** Pure validation shared by interactive start and persisted preparation. */
|
|
22
|
+
export declare function validateStartOptions(opts: Record<string, any>, requireCount: boolean): void;
|
|
23
|
+
/** Validate generated established recovery before reserving execution authority. */
|
|
24
|
+
export declare function validateRecoveryArguments(args: readonly string[], projectDir: string): void;
|
|
25
|
+
/** Validate persisted preparation argv without executing a command or provider. */
|
|
26
|
+
export declare function validatePreparationArguments(args: readonly string[], projectDir: string): string[];
|
|
19
27
|
export declare function buildStartCommand(): Command;
|
|
20
28
|
export declare function createQaNonconvergenceHandler(projectDir: string, noninteractive: boolean, planner?: AgentRoleDefaultsV1, observer?: () => RunObserver | undefined, activeRunId?: () => string): (context: QaNonconvergenceContext) => Promise<QaNonconvergenceDecision>;
|
|
21
29
|
export declare function createQaReportRecoveryHandler(projectDir: string, noninteractive: boolean, observer?: () => RunObserver | undefined): QaReportRecoveryHandler;
|