ai-foreman 1.7.18 → 1.7.19

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 (83) hide show
  1. package/README.md +18 -7
  2. package/dist/activity.d.ts +11 -1
  3. package/dist/activity.js +70 -15
  4. package/dist/adapters/claude.d.ts +11 -1
  5. package/dist/adapters/claude.js +122 -18
  6. package/dist/adapters/codex.d.ts +13 -1
  7. package/dist/adapters/codex.js +148 -31
  8. package/dist/adapters/recovering.d.ts +3 -1
  9. package/dist/adapters/recovering.js +12 -4
  10. package/dist/adapters/types.d.ts +27 -1
  11. package/dist/agentRun.js +2 -0
  12. package/dist/branch/currentGuard.d.ts +3 -1
  13. package/dist/branch/currentGuard.js +11 -2
  14. package/dist/branch/resume.js +1 -1
  15. package/dist/branch/runner.d.ts +2 -0
  16. package/dist/branch/runner.js +90 -11
  17. package/dist/buildApproval.d.ts +9 -0
  18. package/dist/buildApproval.js +126 -0
  19. package/dist/buildRuns.js +70 -32
  20. package/dist/cli/recovery.js +9 -13
  21. package/dist/cli/runtimeAuthPrompt.d.ts +7 -0
  22. package/dist/cli/runtimeAuthPrompt.js +40 -5
  23. package/dist/cli/start.d.ts +16 -1
  24. package/dist/cli/start.js +159 -79
  25. package/dist/cli/tickets.d.ts +11 -0
  26. package/dist/cli/tickets.js +382 -145
  27. package/dist/continuity.d.ts +7 -1
  28. package/dist/continuity.js +86 -7
  29. package/dist/diagnostics.js +35 -1
  30. package/dist/foreman.d.ts +8 -1
  31. package/dist/foreman.js +144 -29
  32. package/dist/handoffs.js +121 -79
  33. package/dist/humanDecision.d.ts +18 -0
  34. package/dist/humanDecision.js +43 -0
  35. package/dist/index.js +2 -1
  36. package/dist/log.d.ts +1 -1
  37. package/dist/managerPacket.js +1 -0
  38. package/dist/observability.js +2 -1
  39. package/dist/providerQuestions.d.ts +5 -0
  40. package/dist/providerQuestions.js +24 -3
  41. package/dist/qaDeliveryJournal.d.ts +70 -0
  42. package/dist/qaDeliveryJournal.js +1 -0
  43. package/dist/qaFailureDelivery.d.ts +26 -10
  44. package/dist/qaFailureDelivery.js +399 -412
  45. package/dist/qaHandbackHistory.d.ts +4 -0
  46. package/dist/qaHandbackHistory.js +30 -0
  47. package/dist/qaHandbackMigration.d.ts +9 -0
  48. package/dist/qaHandbackMigration.js +147 -0
  49. package/dist/qaPrerequisites.d.ts +26 -0
  50. package/dist/qaPrerequisites.js +61 -0
  51. package/dist/qaProtocolV2.d.ts +8 -0
  52. package/dist/qaProtocolV2.js +3 -3
  53. package/dist/qaReview.d.ts +8 -0
  54. package/dist/qaReview.js +54 -10
  55. package/dist/questionTrace.d.ts +31 -0
  56. package/dist/questionTrace.js +85 -0
  57. package/dist/readOnlyProposal.d.ts +8 -0
  58. package/dist/readOnlyProposal.js +41 -0
  59. package/dist/recoveryPolicy.js +14 -3
  60. package/dist/runtimeAuth.d.ts +2 -1
  61. package/dist/runtimeAuth.js +2 -2
  62. package/dist/runtimeReadiness.d.ts +13 -1
  63. package/dist/runtimeReadiness.js +69 -11
  64. package/dist/sessionLifecycle.d.ts +1 -0
  65. package/dist/sessionLifecycle.js +53 -3
  66. package/dist/sources/sourceRegistry.d.ts +7 -0
  67. package/dist/sources/sourceRegistry.js +14 -0
  68. package/dist/stateTransfer.js +2 -0
  69. package/dist/statusReporter.d.ts +3 -1
  70. package/dist/statusReporter.js +8 -2
  71. package/dist/supervisedStart.d.ts +12 -0
  72. package/dist/supervisedStart.js +276 -0
  73. package/dist/supervisor.js +44 -22
  74. package/dist/ticketPopulation.js +1 -0
  75. package/dist/tickets/setupConfig.d.ts +8 -0
  76. package/dist/tickets/setupConfig.js +38 -4
  77. package/dist/util/deadline.d.ts +13 -0
  78. package/dist/util/deadline.js +60 -0
  79. package/dist/workflowDb.d.ts +55 -11
  80. package/dist/workflowDb.js +288 -63
  81. package/dist/workflowReader.d.ts +10 -2
  82. package/dist/workflowReader.js +35 -1
  83. package/package.json +3 -3
package/README.md CHANGED
@@ -15,9 +15,9 @@ Loop Claude Code or Codex through tickets.
15
15
  - **Rich ticket system** — tickets carry acceptance criteria, required tests, dependencies, priority, size, and risk level. The agent reads the full context before starting each step.
16
16
  - **Future work tracking** — when the builder discovers out-of-scope work during a run, `ai-foreman tickets discover` captures it without derailing the current ticket. Discovered items live in a separate inbox until you promote them.
17
17
  - **QA that actually gates** — QA runs after every completed ticket and checks code quality, test passing, and regression protection. The ticket only closes after QA passes. QA turns do not count against `--steps`.
18
- - **Visible long-running work** — semantic activity rows identify provider, phase, tools, retries, and quiet periods; cursor-capable terminals update changing counters in place, while record-oriented terminals coalesce them.
18
+ - **Visible long-running work** — semantic activity rows identify provider, phase, tools, retries, and quiet periods; safe record output coalesces spinner- and time-only changes.
19
19
 
20
- Provider-managed retries are reported immediately as durable lines. A quiet-provider warning appears after 60 seconds without a signal, but Foreman does not add retries, abort the provider, or change provider retry limits. Non-TTY output receives a heartbeat every 30 seconds while work remains pending. TTY rendering defaults to automatic detection: Codex, CI, and `TERM=dumb` use newline records and suppress spinner- or number-only repeats; other terminals redraw those changes in place and retain a row when the textual status changes. Use `RAFI_ACTIVITY_RENDER_MODE=auto|cursor|records` to override detection.
20
+ Provider-managed retries are reported immediately as durable lines. A quiet-provider warning appears after 60 seconds without a signal, but Foreman does not add retries, abort the provider, or change provider retry limits. Non-TTY output emits the initial and meaningful status changes without ANSI redraws. Automatic TTY output also uses newline records and suppresses spinner-, elapsed-time-, and number-only repeats, making it safe for transcript hosts. Set `RAFI_ACTIVITY_RENDER_MODE=cursor` to explicitly enable animated in-place redraws in a known real terminal; `records` explicitly forces safe records, while `auto` selects the safe default.
21
21
 
22
22
  ## Install
23
23
 
@@ -77,13 +77,14 @@ What each part does:
77
77
 
78
78
  - `./my-project`: the repo Foreman will work on.
79
79
  - `tickets init`: creates the local `.tickets/` tracker.
80
- - `tickets populate`: asks the ticket-maker role to convert project planning material.
80
+ - `tickets populate`: generates tickets from an approved structured Rafi plan, with optional supporting context.
81
81
  - Converted output uses Foreman's schema.
82
82
  - `start`: drives Codex through the next tickets one step at a time.
83
83
 
84
- `tickets populate` can convert:
84
+ In `approved_plan` mode, `tickets populate` requires a validated `<docs.root>/rafi-plan.json`. Supporting documents and URLs add detail but cannot replace its slices. `external_import` is a separate mode for importing configured Linear or Jira tickets.
85
+
86
+ Supporting context can include:
85
87
 
86
- - a managed Rafi plan at `<docs.root>/rafi-plan.md`
87
88
  - plans
88
89
  - TODOs
89
90
  - roadmap docs
@@ -161,6 +162,16 @@ Saved `tickets.build` defaults in `rafi-config.yaml` can enable branch-per-ticke
161
162
 
162
163
  With the saved `current` strategy, Foreman works in the active branch while the user owns Git. It may edit, test, run QA, and update tracker/recovery state, but all branch/worktree, commit, push, merge, rebase, and review lifecycle commands are fenced. An unexpected active ref or worktree change pauses the run. Explicit isolated flags are reported as run overrides.
163
164
 
165
+ Build stall recovery uses current context occupancy, not lifetime token usage. The `compact` session strategy checks occupancy at ordinary boundaries and compacts only when the threshold requires it; `fresh` still creates an intentional new session. Compaction normally has a 120-second deadline, extending to at most 180 seconds only after correlated progress. Late completion is attributed to the original session; unresolved attempts remain quarantined across restart. Unknown completion pauses recovery rather than replaying implementation in a replacement session.
166
+
167
+ Unchanged, source-bound plan and ticket approvals are reused. Material ticket, plan, delivery, or workflow changes require a new decision, including with `--yes`. Legacy approval evidence that cannot prove unchanged scope requires review. `--steps` counts completed tickets or steps; it is neither a wall-clock limit nor a model-turn budget.
168
+
169
+ Questions are persisted before prompting. Redirected or detached runs return a recoverable needs-input outcome (exit 2). Use `rafi build:attach . --run <id>` to see decisions, `rafi build:decide . --run <id> --decision <id> --choice <id>` to answer, and `rafi build:resume . --run <id>` to continue. Custom answers additionally use `--choice custom --answer "text"`. Independent eligible tickets continue around a ticket blocker; dependent and unsafe shared-delivery work stays deferred. Answered ticket questions are reconsidered at safe boundaries.
170
+
171
+ CLI starts run under a durable parent supervisor by default. `--detach` writes output under `.rafi/logs/supervisor-<run>.log`; `--no-supervisor` retains direct execution. A preparation-only worker crash may restart within frozen budgets after proving the worker and registered readiness children are stopped. A worker crash with unresolved provider work pauses for reconciliation: it does not silently repeat a possibly completed action. `build:stop` signals only a verified supervisor process incarnation.
172
+
173
+ Runtime deadlines can be overridden in `autonomy.runtime_deadlines` using positive integer milliseconds: `preparation_ms` (120000), `rpc_ms` (60000), `compaction_ms` (120000), `shutdown_ms` (10000), and `turn_ms` (3600000). They are frozen with the run policy. Transport-idle and hard active-turn deadlines have distinct meanings; neither grants permission to repeat uncertain side effects. Attached-process elapsed time includes waiting and is not provider compute time. Activity warns after five minutes without a completed tool or agent turn; intentional human waits are excluded, and the warning alone does not cancel work. Final paused output lists the durable question and exact run-scoped recovery commands.
174
+
164
175
  The current terminal status includes the role/provider, activity, truthful context state, successful compaction count, and handoff generation. At the Builder threshold, Foreman settles the in-flight action, verifies native compaction plus a fresh provider usage sample, and resumes the frozen action. The configured maximum defaults to ten successful compactions per location-scoped provider session; the next crossing uses a validated fresh handoff instead of exceeding it. Disposable QA snapshots never reuse a prior QA conversation in a new `/tmp/rafi-qa-*` worktree; they transfer cumulative state through an accepted handoff.
165
176
 
166
177
  Failed QA reviews use the versioned `RAFI_QA_FAILURE_REPORT_START` / `RAFI_QA_FAILURE_REPORT_END` JSON contract. Foreman validates the report before Builder remediation, namespaces finding IDs by run, ticket, and review, and durably indexes the exact report, remediation response, and bounded fix summary by digest. A malformed failing report receives two correction-only turns in its original session, then a validated fresh successor performs one complete source-bound review followed by up to two correction-only turns. Any later operator-requested fresh successor performs one complete source-bound review followed by five usable correction-only turns.
@@ -214,11 +225,11 @@ gh repo view <host>/<owner>/<repo>
214
225
  | `-a, --agent <agent>` | `claude` / `codex` | single `rafi-config.yaml` target, otherwise `claude` | Builder agent. Explicit `--agent` always wins. |
215
226
  | `-m, --model <model>` | `gpt-5.5` / any supported agent model | agent default | Overrides the builder model. |
216
227
  | `--effort <level>` | Claude Code: `low` / `medium` / `high` / `xhigh`<br>Codex: `low` / `medium` / `high` / `xhigh` | agent default | Reasoning level. |
217
- | `--sources <paths...>` | `docs/tickets.md docs/plans/**` | Configured Rafi `<docs.root>/rafi-plan.md`, then ticket docs root, then `docs/rafi-plan.md`, otherwise scans | Optional files, folders, or globs for the agent to check first. Any reasonable planning format is OK. |
228
+ | `--sources <paths...>` | `docs/tickets.md docs/plans/**` | saved context, subject to `source_handling` | Supplemental files, folders, URLs, or globs. Passing an approved `rafi-plan.json` remains supported; ordinary documents cannot replace the approved plan. |
218
229
  | `--fast` | flag | off | Lower latency. |
219
230
  | `-y, --yes` | flag | off | Skips confirmation before builder edits ticket files. |
220
231
 
221
- Use `ai-foreman tickets setup:init` or `setup:update` to append local, Linear, or Jira Cloud sources to the project-wide registry in `rafi-config.yaml`. Linear imports use `LINEAR_API_KEY`; Jira Cloud imports use `JIRA_EMAIL` and `JIRA_API_TOKEN`. Credentials are never persisted, and mirrored tickets retain source provenance.
232
+ Use `ai-foreman tickets setup:init` or `setup:update` to manage supporting local/URL context and external Linear/Jira connections in the project-wide registry in `rafi-config.yaml`. Linear imports use `LINEAR_API_KEY`; Jira Cloud imports use `JIRA_EMAIL` and `JIRA_API_TOKEN`. Credentials are never persisted, and mirrored tickets retain source provenance.
222
233
 
223
234
  Use `ai-foreman tickets review` to accept, defer, or dismiss pending split/combine/duplicate recommendations rendered in the progress doc.
224
235
 
@@ -11,7 +11,8 @@ export interface ActivityReporterOptions {
11
11
  tickMs?: number;
12
12
  heartbeatMs?: number;
13
13
  quietWarningMs?: number;
14
- /** Override automatic TTY capability detection for tests or embedding hosts. */
14
+ usefulProgressWarningMs?: number;
15
+ /** Override the safe automatic TTY rendering mode for tests or embedding hosts. */
15
16
  ttyMode?: ActivityTtyMode;
16
17
  }
17
18
  export type ActivityTtyMode = "auto" | "cursor" | "records";
@@ -24,6 +25,10 @@ export declare class ActivityReporter {
24
25
  private readonly tickMs;
25
26
  private readonly heartbeatMs;
26
27
  private readonly quietWarningMs;
28
+ private readonly usefulProgressWarningMs;
29
+ private lastUsefulProgressAt;
30
+ private usefulProgressWarningPrinted;
31
+ private pauseStartedAt;
27
32
  private readonly ttyMode;
28
33
  private readonly commandStartedAt;
29
34
  private readonly phases;
@@ -48,6 +53,8 @@ export declare class ActivityReporter {
48
53
  immediate?: boolean;
49
54
  }): void;
50
55
  pulse(detail?: string): void;
56
+ /** A completed tool or turn is distinct from transport/status activity. */
57
+ completedWork(): void;
51
58
  note(message: string): void;
52
59
  writePersistent(text: string): void;
53
60
  /** Keep role/provider/context state attached to the current activity status. */
@@ -71,5 +78,8 @@ export declare function pauseActivityForInput<T>(operation: () => Promise<T>, _m
71
78
  export declare function reportBuilderEvent(event: BuilderEvent): void;
72
79
  /** Async event queue that also feeds the active CLI reporter without consuming the stream. */
73
80
  export declare class BuilderEventQueue extends AsyncQueue<BuilderEvent> {
81
+ private readonly observers;
82
+ /** Synchronous fan-out; never consumes or competes with the owning iterator. */
83
+ observe(listener: (event: BuilderEvent) => void): () => void;
74
84
  push(event: BuilderEvent): void;
75
85
  }
package/dist/activity.js CHANGED
@@ -10,6 +10,10 @@ export class ActivityReporter {
10
10
  tickMs;
11
11
  heartbeatMs;
12
12
  quietWarningMs;
13
+ usefulProgressWarningMs;
14
+ lastUsefulProgressAt = 0;
15
+ usefulProgressWarningPrinted = false;
16
+ pauseStartedAt = 0;
13
17
  ttyMode;
14
18
  commandStartedAt;
15
19
  phases = new Map();
@@ -37,6 +41,7 @@ export class ActivityReporter {
37
41
  this.tickMs = options.tickMs ?? 1_000;
38
42
  this.heartbeatMs = options.heartbeatMs ?? 30_000;
39
43
  this.quietWarningMs = options.quietWarningMs ?? 60_000;
44
+ this.usefulProgressWarningMs = options.usefulProgressWarningMs ?? 300_000;
40
45
  this.ttyMode = resolveTtyMode(options.ttyMode);
41
46
  this.commandStartedAt = this.now();
42
47
  }
@@ -45,6 +50,8 @@ export class ActivityReporter {
45
50
  this.phases.set(phase.id, phase);
46
51
  if (this.phases.size === 1) {
47
52
  this.lastSignalAt = phase.startedAt;
53
+ this.lastUsefulProgressAt = phase.startedAt;
54
+ this.usefulProgressWarningPrinted = false;
48
55
  this.lastHeartbeatAt = phase.startedAt;
49
56
  this.quietWarningPrinted = false;
50
57
  this.startTimer();
@@ -80,6 +87,11 @@ export class ActivityReporter {
80
87
  this.quietWarningPrinted = false;
81
88
  this.render(this.output.isTTY);
82
89
  }
90
+ /** A completed tool or turn is distinct from transport/status activity. */
91
+ completedWork() {
92
+ this.lastUsefulProgressAt = this.now();
93
+ this.usefulProgressWarningPrinted = false;
94
+ }
83
95
  note(message) {
84
96
  this.clearLine();
85
97
  this.output.write(`${clean(message, 500)}\n`);
@@ -109,6 +121,8 @@ export class ActivityReporter {
109
121
  this.render(true);
110
122
  }
111
123
  pause() {
124
+ if (this.paused === 0)
125
+ this.pauseStartedAt = this.now();
112
126
  this.paused++;
113
127
  this.clearLine();
114
128
  let resumed = false;
@@ -117,6 +131,11 @@ export class ActivityReporter {
117
131
  return;
118
132
  resumed = true;
119
133
  this.paused = Math.max(0, this.paused - 1);
134
+ if (this.paused === 0) {
135
+ const duration = this.now() - this.pauseStartedAt;
136
+ this.lastUsefulProgressAt += duration;
137
+ this.lastSignalAt += duration;
138
+ }
120
139
  this.render(true);
121
140
  };
122
141
  }
@@ -161,9 +180,17 @@ export class ActivityReporter {
161
180
  if (!force && elapsed < this.displayDelayMs)
162
181
  return;
163
182
  const quietFor = now - this.lastSignalAt;
183
+ if (phase && now - this.lastUsefulProgressAt >= this.usefulProgressWarningMs && !this.usefulProgressWarningPrinted) {
184
+ this.usefulProgressWarningPrinted = true;
185
+ this.note(`rafi: no completed tool or agent turn observed for ${formatDuration(now - this.lastUsefulProgressAt)}; current phase: ${phase.label}. The operation remains subject to its configured deadline.`);
186
+ return;
187
+ }
164
188
  if (phase && quietFor >= this.quietWarningMs && !this.quietWarningPrinted) {
165
189
  this.quietWarningPrinted = true;
166
- this.note(`rafi: ${this.provider ?? "provider"} has been quiet for ${formatDuration(quietFor)}; RAFI is still responsive and will keep waiting`);
190
+ const status = phase.label === "answer sent; waiting for Claude"
191
+ ? `Claude has not resumed its stream yet after your answer was sent (${formatDuration(quietFor)})`
192
+ : `${this.provider ?? "provider"} has been quiet for ${formatDuration(quietFor)}`;
193
+ this.note(`rafi: ${status}; RAFI is still responsive and will keep waiting`);
167
194
  return;
168
195
  }
169
196
  const provider = [this.provider, this.model].filter(Boolean).join("/");
@@ -253,22 +280,49 @@ export function reportBuilderEvent(event) {
253
280
  reporter.note(`rafi: ${event.provider} ${clean(event.reason, 300)}; retrying${attempt}${delay}`);
254
281
  reporter.update(`retrying ${event.provider}`, event.reason, { provider: event.provider });
255
282
  }
256
- else if (event.kind === "tool")
257
- reporter.update(`running ${event.name}`, briefInput(event.input));
283
+ else if (event.kind === "tool") {
284
+ switch (event.lifecycle) {
285
+ case "progress":
286
+ reporter.pulse();
287
+ break;
288
+ case "completed":
289
+ reporter.completedWork();
290
+ if (isFailedToolCompletion(event))
291
+ reporter.update("tool failed", event.name);
292
+ else
293
+ reporter.pulse();
294
+ break;
295
+ case "started":
296
+ case undefined:
297
+ // Older event producers omitted lifecycle for a tool start.
298
+ reporter.update(`running ${event.name}`, briefInput(event.input));
299
+ break;
300
+ }
301
+ }
258
302
  else if (event.kind === "text")
259
303
  reporter.update("processing agent response");
260
304
  else if (event.kind === "session-transition")
261
305
  reporter.update(`session ${event.transition}`, event.detail);
262
306
  else if (event.kind === "context-usage")
263
307
  reporter.pulse(event.percentage === undefined ? undefined : `context ${event.percentage.toFixed(0)}%`);
264
- else if (event.kind === "turn-complete")
308
+ else if (event.kind === "turn-complete") {
309
+ reporter.completedWork();
265
310
  reporter.update(event.result.isError ? "agent turn failed" : "agent turn complete");
311
+ }
266
312
  else if (event.kind === "error")
267
313
  reporter.update("provider error", event.message);
268
314
  }
269
315
  /** Async event queue that also feeds the active CLI reporter without consuming the stream. */
270
316
  export class BuilderEventQueue extends AsyncQueue {
317
+ observers = new Set();
318
+ /** Synchronous fan-out; never consumes or competes with the owning iterator. */
319
+ observe(listener) {
320
+ this.observers.add(listener);
321
+ return () => { this.observers.delete(listener); };
322
+ }
271
323
  push(event) {
324
+ for (const listener of this.observers)
325
+ listener(event);
272
326
  reportBuilderEvent(event);
273
327
  super.push(event);
274
328
  }
@@ -280,6 +334,12 @@ function briefInput(input) {
280
334
  const detail = value.command ?? value.file_path ?? value.path ?? value.pattern ?? value.query;
281
335
  return detail === undefined ? undefined : clean(String(detail), 100);
282
336
  }
337
+ function isFailedToolCompletion(event) {
338
+ const status = event.status?.toLowerCase();
339
+ return status === "failed"
340
+ || status === "error"
341
+ || (typeof event.exitCode === "number" && Number.isFinite(event.exitCode) && event.exitCode !== 0);
342
+ }
283
343
  function clean(value, maximum) {
284
344
  return value.replace(/[\r\n\t]+/g, " ").replace(/\s+/g, " ").trim().slice(0, maximum);
285
345
  }
@@ -293,23 +353,18 @@ function semanticStatusKey(body) {
293
353
  .trim();
294
354
  }
295
355
  function resolveTtyMode(requested) {
296
- const configured = requested ?? configuredTtyMode(process.env.RAFI_ACTIVITY_RENDER_MODE);
356
+ const configured = requested === "cursor" || requested === "records"
357
+ ? requested
358
+ : configuredTtyMode(process.env.RAFI_ACTIVITY_RENDER_MODE);
297
359
  if (configured === "cursor" || configured === "records")
298
360
  return configured;
299
- return truthyEnvironmentValue(process.env.CODEX_CI)
300
- || truthyEnvironmentValue(process.env.CI)
301
- || process.env.TERM?.toLowerCase() === "dumb"
302
- ? "records"
303
- : "cursor";
361
+ // A TTY-like output can still be an append-only transcript. Cursor redraws
362
+ // are therefore an explicit opt-in rather than an unsafe capability guess.
363
+ return "records";
304
364
  }
305
365
  function configuredTtyMode(value) {
306
366
  return value === "cursor" || value === "records" || value === "auto" ? value : "auto";
307
367
  }
308
- function truthyEnvironmentValue(value) {
309
- if (value === undefined)
310
- return false;
311
- return !["", "0", "false"].includes(value.trim().toLowerCase());
312
- }
313
368
  function formatDuration(milliseconds) {
314
369
  const seconds = Math.max(0, Math.floor(milliseconds / 1_000));
315
370
  if (seconds < 60)
@@ -58,6 +58,8 @@ export declare class ClaudeAdapter implements BuilderAdapter {
58
58
  private structuredError?;
59
59
  private apiErrorStatus?;
60
60
  private compactResult?;
61
+ private manualCompactionDeadline?;
62
+ private compactionPromise?;
61
63
  private autoCompactionPrepared;
62
64
  private preparedAutoCompactThreshold?;
63
65
  private preparedAutoCompactionPolicy?;
@@ -70,6 +72,8 @@ export declare class ClaudeAdapter implements BuilderAdapter {
70
72
  private activeProviderTurnSpanId?;
71
73
  private readonly toolSpans;
72
74
  private pending?;
75
+ private questionTrace?;
76
+ private responseOnlyTurn;
73
77
  private terminalResult?;
74
78
  private streamEnded;
75
79
  private closed;
@@ -78,7 +82,11 @@ export declare class ClaudeAdapter implements BuilderAdapter {
78
82
  /** Background loop: consume the SDK message stream until it ends. */
79
83
  private pump;
80
84
  private handle;
81
- sendTurn(text: string): Promise<TurnResult>;
85
+ sendTurn(text: string, policy?: {
86
+ handback?: boolean;
87
+ responseOnly?: boolean;
88
+ logicalActionId?: string;
89
+ }): Promise<TurnResult>;
82
90
  private sendTurnInternal;
83
91
  private captureStderr;
84
92
  private observationContext;
@@ -91,12 +99,14 @@ export declare class ClaudeAdapter implements BuilderAdapter {
91
99
  compact(): Promise<CompactResult>;
92
100
  private compactInternal;
93
101
  prepareAutoCompaction(thresholdPercent?: number | undefined): Promise<NativeAutoCompactionPolicy | void>;
102
+ private prepareAutoCompactionInternal;
94
103
  autoCompactionPolicy(): NativeAutoCompactionPolicy | undefined;
95
104
  drainNativeCompactions(): NativeCompaction[];
96
105
  restoreNativeCompactions(compactions: NativeCompaction[]): void;
97
106
  contextUsage(): Promise<ContextUsage | undefined>;
98
107
  sessionUsage(): Promise<ProviderSessionUsage | undefined>;
99
108
  switchSettings(settings: ProviderSettingSwitch): Promise<CompactResult>;
109
+ observeEvents(listener: (event: BuilderEvent) => void): () => void;
100
110
  events(): AsyncIterable<BuilderEvent>;
101
111
  close(): Promise<void>;
102
112
  private failSessionIdentity;