ai-foreman 1.7.20 → 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.
Files changed (189) hide show
  1. package/README.md +12 -2
  2. package/dist/activity.d.ts +3 -0
  3. package/dist/activity.js +18 -6
  4. package/dist/adapters/claude.d.ts +16 -0
  5. package/dist/adapters/claude.js +28 -3
  6. package/dist/adapters/codex.d.ts +20 -0
  7. package/dist/adapters/codex.js +99 -5
  8. package/dist/adapters/recovering.d.ts +9 -0
  9. package/dist/adapters/recovering.js +10 -0
  10. package/dist/adapters/types.d.ts +15 -0
  11. package/dist/agentRun.d.ts +7 -0
  12. package/dist/agentRun.js +24 -13
  13. package/dist/branch/currentGuard.d.ts +1 -0
  14. package/dist/branch/currentGuard.js +1 -0
  15. package/dist/branch/finalization.js +6 -1
  16. package/dist/branch/git.d.ts +1 -0
  17. package/dist/branch/git.js +15 -1
  18. package/dist/branch/runner.d.ts +2 -0
  19. package/dist/branch/runner.js +90 -4
  20. package/dist/buildAdmission.js +2 -0
  21. package/dist/buildAssignment.d.ts +33 -0
  22. package/dist/buildAssignment.js +215 -0
  23. package/dist/buildInterventions.d.ts +90 -0
  24. package/dist/buildInterventions.js +334 -0
  25. package/dist/buildOwnershipReconciliation.d.ts +19 -0
  26. package/dist/buildOwnershipReconciliation.js +41 -0
  27. package/dist/buildOwnershipRepair.d.ts +33 -0
  28. package/dist/buildOwnershipRepair.js +111 -0
  29. package/dist/buildRuns.d.ts +6 -0
  30. package/dist/buildRuns.js +23 -17
  31. package/dist/buildSyntheticWork.d.ts +2 -0
  32. package/dist/buildSyntheticWork.js +30 -0
  33. package/dist/buildWorkAdmission.d.ts +17 -0
  34. package/dist/buildWorkAdmission.js +57 -0
  35. package/dist/buildWorkAuthorization.d.ts +2 -0
  36. package/dist/buildWorkAuthorization.js +23 -0
  37. package/dist/buildWorkContext.d.ts +3 -0
  38. package/dist/buildWorkContext.js +6 -0
  39. package/dist/buildWorkMigration.d.ts +9 -0
  40. package/dist/buildWorkMigration.js +206 -0
  41. package/dist/buildWorkReconciliation.d.ts +12 -0
  42. package/dist/buildWorkReconciliation.js +70 -0
  43. package/dist/builderGuidanceFollowup.d.ts +15 -0
  44. package/dist/builderGuidanceFollowup.js +34 -0
  45. package/dist/cli/doctor.js +3 -2
  46. package/dist/cli/graph.d.ts +2 -0
  47. package/dist/cli/graph.js +75 -0
  48. package/dist/cli/manager.d.ts +8 -0
  49. package/dist/cli/manager.js +234 -12
  50. package/dist/cli/recovery.js +3 -2
  51. package/dist/cli/runtimeAuthPrompt.js +28 -8
  52. package/dist/cli/start.js +152 -48
  53. package/dist/cli/status.js +20 -5
  54. package/dist/cli/tickets.js +9 -7
  55. package/dist/continuity.d.ts +11 -0
  56. package/dist/continuity.js +22 -6
  57. package/dist/foreman.d.ts +10 -2
  58. package/dist/foreman.js +330 -39
  59. package/dist/graph/boundary.d.ts +15 -0
  60. package/dist/graph/boundary.js +50 -0
  61. package/dist/graph/bridge.d.ts +9 -0
  62. package/dist/graph/bridge.js +146 -0
  63. package/dist/graph/bridge.py +205 -0
  64. package/dist/graph/config.d.ts +11 -0
  65. package/dist/graph/config.js +40 -0
  66. package/dist/graph/corpus.d.ts +16 -0
  67. package/dist/graph/corpus.js +188 -0
  68. package/dist/graph/derived.d.ts +17 -0
  69. package/dist/graph/derived.js +73 -0
  70. package/dist/graph/host.d.ts +4 -0
  71. package/dist/graph/host.js +160 -0
  72. package/dist/graph/install.d.ts +3 -0
  73. package/dist/graph/install.js +50 -0
  74. package/dist/graph/lifecycle.d.ts +11 -0
  75. package/dist/graph/lifecycle.js +124 -0
  76. package/dist/graph/maintenance.d.ts +43 -0
  77. package/dist/graph/maintenance.js +301 -0
  78. package/dist/graph/manager.d.ts +9 -0
  79. package/dist/graph/manager.js +92 -0
  80. package/dist/graph/preparation.d.ts +41 -0
  81. package/dist/graph/preparation.js +43 -0
  82. package/dist/graph/read.d.ts +27 -0
  83. package/dist/graph/read.js +152 -0
  84. package/dist/graph/semantic.d.ts +17 -0
  85. package/dist/graph/semantic.js +27 -0
  86. package/dist/graph/session.d.ts +8 -0
  87. package/dist/graph/session.js +92 -0
  88. package/dist/graph/sources.d.ts +4 -0
  89. package/dist/graph/sources.js +11 -0
  90. package/dist/graph/storage.d.ts +38 -0
  91. package/dist/graph/storage.js +159 -0
  92. package/dist/graph/turn.d.ts +17 -0
  93. package/dist/graph/turn.js +360 -0
  94. package/dist/graph/util.d.ts +5 -0
  95. package/dist/graph/util.js +51 -0
  96. package/dist/handoffs.d.ts +1 -0
  97. package/dist/handoffs.js +5 -1
  98. package/dist/humanDecision.d.ts +21 -2
  99. package/dist/humanDecision.js +169 -11
  100. package/dist/index.js +2 -0
  101. package/dist/installOwnership.d.ts +46 -0
  102. package/dist/installOwnership.js +440 -0
  103. package/dist/linuxProbeInventory.d.ts +12 -0
  104. package/dist/linuxProbeInventory.js +48 -0
  105. package/dist/log.d.ts +1 -1
  106. package/dist/log.js +7 -1
  107. package/dist/managerEvidence.d.ts +25 -0
  108. package/dist/managerEvidence.js +326 -0
  109. package/dist/managerEvidenceArtifacts.d.ts +38 -0
  110. package/dist/managerEvidenceArtifacts.js +118 -0
  111. package/dist/managerPacket.d.ts +2 -0
  112. package/dist/managerPacket.js +23 -0
  113. package/dist/markers.d.ts +1 -1
  114. package/dist/markers.js +2 -2
  115. package/dist/observability.js +1 -1
  116. package/dist/processIdentity.js +7 -0
  117. package/dist/providerPhase.d.ts +13 -0
  118. package/dist/providerPhase.js +26 -0
  119. package/dist/qaAuthorizedDisposition.d.ts +24 -0
  120. package/dist/qaAuthorizedDisposition.js +26 -0
  121. package/dist/qaBuildGate.d.ts +4 -0
  122. package/dist/qaBuildGate.js +216 -0
  123. package/dist/qaBuilderCoverage.d.ts +5 -0
  124. package/dist/qaBuilderCoverage.js +78 -0
  125. package/dist/qaContractCoverage.d.ts +10 -0
  126. package/dist/qaContractCoverage.js +55 -0
  127. package/dist/qaContractDelivery.d.ts +23 -0
  128. package/dist/qaContractDelivery.js +145 -0
  129. package/dist/qaContractFreshness.d.ts +15 -0
  130. package/dist/qaContractFreshness.js +36 -0
  131. package/dist/qaDeliveryJournal.d.ts +10 -0
  132. package/dist/qaDeliveryJournal.js +16 -1
  133. package/dist/qaEffectiveConfig.d.ts +20 -0
  134. package/dist/qaEffectiveConfig.js +40 -0
  135. package/dist/qaEvidenceReader.d.ts +14 -0
  136. package/dist/qaEvidenceReader.js +176 -0
  137. package/dist/qaFailureDelivery.d.ts +2 -0
  138. package/dist/qaFailureDelivery.js +107 -10
  139. package/dist/qaHandbackMigration.d.ts +1 -1
  140. package/dist/qaHandbackMigration.js +3 -3
  141. package/dist/qaPreparation.d.ts +26 -0
  142. package/dist/qaPreparation.js +150 -0
  143. package/dist/qaPreparationInputs.d.ts +8 -0
  144. package/dist/qaPreparationInputs.js +47 -0
  145. package/dist/qaPreparationMetrics.d.ts +145 -0
  146. package/dist/qaPreparationMetrics.js +120 -0
  147. package/dist/qaPreparationPolicy.d.ts +5 -0
  148. package/dist/qaPreparationPolicy.js +51 -0
  149. package/dist/qaPreparationStore.d.ts +157 -0
  150. package/dist/qaPreparationStore.js +412 -0
  151. package/dist/qaProtocolV2.d.ts +28 -0
  152. package/dist/qaProtocolV2.js +12 -0
  153. package/dist/qaReview.d.ts +6 -0
  154. package/dist/qaReview.js +234 -24
  155. package/dist/qaTimeline.d.ts +18 -0
  156. package/dist/qaTimeline.js +123 -0
  157. package/dist/qaVerificationContract.d.ts +17 -0
  158. package/dist/qaVerificationContract.js +236 -0
  159. package/dist/readinessCleanup.js +12 -5
  160. package/dist/recoveryGuidance.d.ts +9 -0
  161. package/dist/recoveryGuidance.js +13 -0
  162. package/dist/runtimeAuth.d.ts +1 -0
  163. package/dist/runtimeAuth.js +5 -1
  164. package/dist/runtimeReadiness.d.ts +1 -0
  165. package/dist/runtimeReadiness.js +13 -1
  166. package/dist/sessionIdentity.d.ts +2 -0
  167. package/dist/sessionIdentity.js +14 -0
  168. package/dist/sessionLifecycle.js +3 -3
  169. package/dist/sources/sourceRegistry.js +7 -0
  170. package/dist/stateTransfer.js +50 -1
  171. package/dist/statusReporter.d.ts +1 -0
  172. package/dist/statusReporter.js +1 -0
  173. package/dist/supervisedStart.js +18 -8
  174. package/dist/terminalStyle.d.ts +21 -0
  175. package/dist/terminalStyle.js +50 -0
  176. package/dist/ticketPopulation.d.ts +1 -0
  177. package/dist/ticketPopulation.js +5 -1
  178. package/dist/tickets/commands.js +2 -2
  179. package/dist/tickets/queue.js +1 -1
  180. package/dist/tickets/ticketSchema.d.ts +198 -0
  181. package/dist/tickets/ticketSchema.js +2 -0
  182. package/dist/workflowDb.d.ts +51 -5
  183. package/dist/workflowDb.js +338 -7
  184. package/dist/workflowReader.d.ts +109 -2
  185. package/dist/workflowReader.js +48 -4
  186. package/package.json +84 -7
  187. package/scripts/copy-graph-assets.mjs +3 -0
  188. package/scripts/graph-benchmark.mjs +20 -0
  189. package/scripts/graph-evaluation.mjs +85 -0
@@ -1,3 +1,4 @@
1
+ import { dispatchWithGraphAccess, withGraphSessionAccess } from "./graph/session.js";
1
2
  import { localBuildAuthority } from "./buildAdmission.js";
2
3
  import { randomUUID, createHash } from "node:crypto";
3
4
  import { BuilderEventQueue } from "./activity.js";
@@ -109,6 +110,11 @@ export function continuityInstruction(role) {
109
110
  export class ContinuityAdapter {
110
111
  options;
111
112
  adapter;
113
+ contractCapabilities() { return this.adapter.contractCapabilities?.() ?? { sameSessionAcceptance: false, nativeCompactionBarrier: false }; }
114
+ contractEnforcing = false;
115
+ enableContractEnforcement() { this.contractEnforcing = true; this.adapter.enableContractEnforcement?.(); }
116
+ contractCompactionSequence() { return this.adapter.contractCompactionSequence?.() ?? 0; }
117
+ acceptContractDelivery(sequence) { this.adapter.acceptContractDelivery?.(sequence); }
112
118
  queue = new BuilderEventQueue();
113
119
  sourcePump;
114
120
  recoveryLeasePending;
@@ -168,6 +174,9 @@ export class ContinuityAdapter {
168
174
  }
169
175
  get agent() { return this.adapter.agent; }
170
176
  async sendTurn(instruction, policy) {
177
+ return withGraphSessionAccess(this.options.projectDir, this.adapter, () => this.sendTurnOwned(instruction, policy));
178
+ }
179
+ async sendTurnOwned(instruction, policy) {
171
180
  const db = new WorkflowDb(this.options.projectDir);
172
181
  try {
173
182
  db.appendContinuityEvent({ runId: this.options.runId, role: "host", kind: "turn_started", payload: { role: this.options.role, instructionDigest: sha(instruction), instructionBytes: Buffer.byteLength(instruction) }, authoritativeStateRevision: this.revision() });
@@ -202,7 +211,7 @@ export class ContinuityAdapter {
202
211
  journal.updateOperation(dispatchId, "in_progress");
203
212
  });
204
213
  try {
205
- original = await this.adapter.sendTurn(providerInstruction, policy);
214
+ original = await dispatchWithGraphAccess(this.options.projectDir, this.adapter, providerInstruction, policy, (text, p) => this.adapter.sendTurn(text, p));
206
215
  }
207
216
  catch (error) {
208
217
  journal.updateOperation(dispatchId, "uncertain", { error: String(error) });
@@ -253,7 +262,7 @@ export class ContinuityAdapter {
253
262
  return this.sendTurn([
254
263
  "Continue the frozen action after the accepted Rafi handoff. Do not repeat completed side effects.",
255
264
  instruction,
256
- ].join("\n\n"));
265
+ ].join("\n\n"), policy);
257
266
  }
258
267
  return { ...original, text: parsed.cleanText, hostInstruction: instruction, providerInstruction: original.providerInstruction ?? providerInstruction,
259
268
  rawResponse: original.rawResponse ?? original.text, cleanedResponse: parsed.cleanText };
@@ -280,12 +289,12 @@ export class ContinuityAdapter {
280
289
  finally {
281
290
  budget.close();
282
291
  }
283
- const repair = await this.adapter.sendTurn([
292
+ const repair = await dispatchWithGraphAccess(this.options.projectDir, this.adapter, [
284
293
  "Continuity protocol repair only. Do not run tools, repeat work, or change files.",
285
294
  `Your prior turn's continuity record was invalid: ${parsed.error?.problems.join("; ")}.`,
286
295
  continuityInstruction(),
287
296
  "Return only the continuity record.",
288
- ].join("\n"), { ...policy, responseOnly: true });
297
+ ].join("\n"), { ...policy, purpose: "response-repair", responseOnly: true }, (text, p) => this.adapter.sendTurn(text, p));
289
298
  const repaired = parseContinuityDelta(repair.text);
290
299
  if (repaired.delta && !repair.isError && !repair.failure) {
291
300
  this.publish(repaired.delta, "turn_completed_after_repair", original);
@@ -293,7 +302,7 @@ export class ContinuityAdapter {
293
302
  const successor = await this.options.handleHandoffRequest?.(original.text, this.adapter, instruction);
294
303
  if (successor && successor !== this.adapter) {
295
304
  await this.adoptValidatedSuccessor(successor);
296
- return this.sendTurn(["Continue the frozen action after the accepted Rafi handoff. Do not repeat completed side effects.", instruction].join("\n\n"));
305
+ return this.sendTurn(["Continue the frozen action after the accepted Rafi handoff. Do not repeat completed side effects.", instruction].join("\n\n"), policy);
297
306
  }
298
307
  return { ...original, text: parsed.cleanText, hostInstruction: instruction, providerInstruction: original.providerInstruction ?? providerInstruction,
299
308
  rawResponse: original.rawResponse ?? original.text, cleanedResponse: parsed.cleanText };
@@ -330,7 +339,7 @@ export class ContinuityAdapter {
330
339
  if (!this.options.createSuccessor)
331
340
  throw new ContinuityRecoveryRequiredError(this.options.runId, this.options.role, "continuity repair failed in the original session and no validated successor is configured");
332
341
  const successor = await this.options.createSuccessor(handoff);
333
- const accepted = await successor.sendTurn(`${handoff}\n\nReply with HANDOFF_ACCEPTED on the first line, then ${continuityInstruction()}`);
342
+ const accepted = await dispatchWithGraphAccess(this.options.projectDir, successor, `${handoff}\n\nReply with HANDOFF_ACCEPTED on the first line, then ${continuityInstruction()}`, { purpose: "contract-acceptance", responseOnly: true }, (text, p) => successor.sendTurn(text, p));
334
343
  const successorDelta = parseContinuityDelta(accepted.text);
335
344
  const firstAcceptanceLine = accepted.text.split(/\r?\n/).map((line) => line.trim()).find(Boolean);
336
345
  if (firstAcceptanceLine !== "HANDOFF_ACCEPTED" || !successorDelta.delta || !successor.sessionId()) {
@@ -378,12 +387,19 @@ export class ContinuityAdapter {
378
387
  restoreNativeCompactions(compactions) { this.adapter.restoreNativeCompactions?.(compactions); }
379
388
  contextUsageAfterNativeCompaction(compaction) { return this.adapter.contextUsageAfterNativeCompaction?.(compaction) ?? Promise.resolve(undefined); }
380
389
  contextUsage() { return this.adapter.contextUsage?.() ?? Promise.resolve(undefined); }
390
+ graphRuntimeSettings() { return this.adapter.graphRuntimeSettings?.(); }
381
391
  sessionUsage() { return this.adapter.sessionUsage?.() ?? Promise.resolve(undefined); }
382
392
  switchSettings(settings) { return this.adapter.switchSettings ? this.adapter.switchSettings(settings) : Promise.resolve({ ok: false, error: "provider adapter does not support settings changes" }); }
383
393
  events() { return this.queue; }
384
394
  async close() { await this.adapter.close(); await this.sourcePump?.catch(() => { }); this.queue.close(); }
385
395
  /** Keep the observable wrapper and event stream stable while moving to an accepted successor. */
386
396
  async adoptValidatedSuccessor(successor) {
397
+ if (this.contractEnforcing) {
398
+ successor.enableContractEnforcement?.();
399
+ if (successor !== this.adapter)
400
+ await successor.close().catch(() => { });
401
+ throw new ContinuityRecoveryRequiredError(this.options.runId, this.options.role, "Replacement Builder requires host contract delivery before any continuation; completed turn must be reconciled without automatic replay");
402
+ }
387
403
  if (successor === this.adapter)
388
404
  return;
389
405
  const prior = this.adapter;
package/dist/foreman.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { GraphPurpose } from "rafi-spec";
1
2
  import type { BuilderAdapter, PermissionHandler, PermissionRequest, TurnResult } from "./adapters/types.js";
2
3
  import type { PermissionPolicy } from "./permissions/policy.js";
3
4
  import { type AnsweredProviderQuestion } from "./providerQuestions.js";
@@ -85,19 +86,25 @@ export declare class Foreman {
85
86
  /** Exact durable build-run scope. Observability is never an identity authority. */
86
87
  private readonly qaRunId;
87
88
  private readonly continueIndependentTickets;
89
+ private readonly builderWorktree?;
90
+ private readonly decisionPrompt?;
91
+ private graphPurpose;
92
+ setGraphPurpose(purpose: GraphPurpose): void;
88
93
  private readonly ticketsEnabled;
89
94
  private readonly notificationsEnabled;
90
95
  private readonly terminalBellEnabled;
91
96
  private readonly qaStream;
92
97
  private builderWorkSessions;
93
98
  private currentTicketId?;
99
+ private preflightPlan;
100
+ approvedPlanText(): string;
94
101
  constructor(builder: BuilderAdapter, log: Log, notifications?: boolean | ForemanNotificationOptions, qaEnabled?: boolean, qaMaxCycles?: number, projectDir?: string | undefined,
95
102
  /** @deprecated QA must be created by qaFactory in a disposable snapshot. */
96
103
  _deprecatedSameSessionReviewer?: BuilderAdapter, qaFactory?: ((cwd: string, sessionId?: string) => Promise<QaSessionHandle>) | undefined, qaSessionStrategy?: SessionStrategy, builderFactory?: ((cwd: string, sessionId?: string) => Promise<BuilderAdapter>) | undefined, builderSessionStrategy?: SessionStrategy, qaNonconvergence?: ((context: QaNonconvergenceContext) => Promise<QaNonconvergenceDecision>) | undefined, beforeBuilderTurn?: ((adapter: BuilderAdapter, frozenAction: string) => Promise<BuilderAdapter>) | undefined, builderSessionBoundary?: ((adapter: BuilderAdapter, frozenAction: string, strategy: SessionStrategy) => Promise<BuilderAdapter>) | undefined, qaSessionBoundary?: ((handle: QaSessionHandle, frozenAction: string, strategy: SessionStrategy, cwd: string, recovery?: QaSessionBoundaryRecovery) => Promise<QaSessionBoundaryResult>) | undefined, observeQaNativeCompactions?: ((adapter: BuilderAdapter) => Promise<void>) | undefined,
97
104
  /** Persist a Builder's provider-native event immediately after every turn. */
98
105
  observeBuilderNativeCompactions?: ((adapter: BuilderAdapter) => Promise<void>) | undefined, observer?: RunObserver | undefined, qaRuntimeContext?: unknown | undefined, qaContinuityManaged?: boolean, qaReportRecovery?: QaReportRecoveryHandler | undefined, qaResumedRecovery?: QaRecoveryPacket | undefined,
99
106
  /** Exact durable build-run scope. Observability is never an identity authority. */
100
- qaRunId?: string, continueIndependentTickets?: boolean, initialTicketId?: string);
107
+ qaRunId?: string, continueIndependentTickets?: boolean, initialTicketId?: string, builderWorktree?: string | undefined, decisionPrompt?: ((decision: import("rafi-spec").PendingHumanDecision) => Promise<string | undefined>) | undefined);
101
108
  private waitForUserInput;
102
109
  /**
103
110
  * Send one instruction and resolve any needs_input exchanges before returning.
@@ -106,6 +113,7 @@ export declare class Foreman {
106
113
  private doTurn;
107
114
  private prepareBuilderBoundary;
108
115
  private doTurnWith;
116
+ private doTurnWithOwned;
109
117
  /** Send a planning turn and return the builder's response text. Does not count toward steps. */
110
118
  runPreflight(n: number, ticketsContent?: string, preferredTicketId?: string, executionTickets?: readonly string[]): Promise<string>;
111
119
  /** Send user feedback on the plan; builder responds with a revised list. Does not count toward steps. */
@@ -140,7 +148,7 @@ export declare class Foreman {
140
148
  passCertificateId?: string;
141
149
  sourceStateDigest?: string;
142
150
  }>;
143
- /** Complete only the pending QA boundary and its tracker transition. No Builder work turn is sent. */
151
+ /** Resume the pending boundary, including authorized waiting guidance, then complete its tracker transition. */
144
152
  completePendingQaRecovery(ticketId: string): Promise<{
145
153
  outcome: "passed" | "blocked" | "needs-human" | "waived";
146
154
  detail?: string;