@delegance/claude-autopilot 7.11.0-pre.2 → 7.11.0-pre.4

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.
@@ -232,6 +232,43 @@ export function renderEventLine(ev, runningTotal, opts) {
232
232
  case 'replay.override': {
233
233
  return `${ts} ${colorize(verb, 'magenta', opts.ansi)} ${ev.phase} reason=${ev.reason}`;
234
234
  }
235
+ // v7.11.0 concurrent subagent dispatch events. Detailed renderers will
236
+ // land in PR 6 (#193) when the watch UI exposes the per-task pane.
237
+ // For now, render a single-line summary so existing `runs watch`
238
+ // sessions don't silently skip these events.
239
+ case 'task.started': {
240
+ return `${ts} ${colorize(verb, 'cyan', opts.ansi)} ${ev.task_id} branch=${ev.branch}`;
241
+ }
242
+ case 'task.budget_reserved': {
243
+ return `${ts} ${colorize(verb, 'cyan', opts.ansi)} ${ev.task_id} reserved=${fmtUSD(ev.reserved_usd)}`;
244
+ }
245
+ case 'task.budget_increased_reservation': {
246
+ return `${ts} ${colorize(verb, 'cyan', opts.ansi)} ${ev.task_id} ${fmtUSD(ev.prior_reserved_usd)}→${fmtUSD(ev.new_reserved_usd)} ${ev.reason}`;
247
+ }
248
+ case 'task.budget_released': {
249
+ return `${ts} ${colorize(verb, 'cyan', opts.ansi)} ${ev.task_id} actual=${fmtUSD(ev.actual_cost_usd)} delta=${fmtUSD(ev.delta_vs_reservation_usd)}`;
250
+ }
251
+ case 'task.completed': {
252
+ return `${ts} ${colorize(verb, 'green', opts.ansi)} ${ev.task_id} status=${ev.exit_status} commits=${ev.commit_shas.length}`;
253
+ }
254
+ case 'task.failed': {
255
+ return `${ts} ${colorize(verb, 'red', opts.ansi)} ${ev.task_id} type=${ev.error_type} ${ev.error_message}`;
256
+ }
257
+ case 'task.merged': {
258
+ return `${ts} ${colorize(verb, 'green', opts.ansi)} ${ev.task_id}`;
259
+ }
260
+ case 'task.merge_conflict': {
261
+ return `${ts} ${colorize(verb, 'red', opts.ansi)} ${ev.task_id} paths=${ev.conflicting_paths.length}`;
262
+ }
263
+ case 'task.merge_aborted': {
264
+ return `${ts} ${colorize(verb, 'red', opts.ansi)} ${ev.task_id} reason=${ev.reason}`;
265
+ }
266
+ case 'task.timeout': {
267
+ return `${ts} ${colorize(verb, 'yellow', opts.ansi)} ${ev.task_id} ${ev.timeout_ms}ms signal=${ev.killed_signal}`;
268
+ }
269
+ case 'task.budget_halt': {
270
+ return `${ts} ${colorize(verb, 'red', opts.ansi)} ${ev.task_id} remaining=${fmtUSD(ev.budget_remaining_usd)} needed=${fmtUSD(ev.preflight_estimate_usd)}`;
271
+ }
235
272
  default: {
236
273
  // Exhaustiveness guard. New event variants must be added here so a
237
274
  // future RunEvent extension forces a compile error rather than
@@ -7,7 +7,5 @@ export type { BudgetCaps, BudgetReplaySummary, IncreaseReservationOptions, Relea
7
7
  export { WorktreeLifecycle, assertRunWorktreesDirAvailable, } from './worktree-lifecycle.ts';
8
8
  export type { CommitVerification, CreatedTaskWorktree, TaskTerminalState, WorktreeLifecycleOptions, } from './worktree-lifecycle.ts';
9
9
  export { runScheduler, computeEffectiveConcurrency, } from './scheduler.ts';
10
- export type { ConcurrencyConfig, MergeDecision, MergeOrchestrator as SchedulerMergeOrchestratorCallback, MergeOrchestratorInput, SchedulerDiagnostics, SchedulerOptions, SchedulerResult, SubagentRunInput, SubagentRunner, SubagentRunResult, } from './scheduler.ts';
11
- export { createMergeOrchestrator, toSchedulerCallback, } from './merge-orchestrator.ts';
12
- export type { MergeableTask, MergeOrchestrator, MergeOrchestratorOptions, MergeResult, } from './merge-orchestrator.ts';
10
+ export type { ConcurrencyConfig, MergeDecision, MergeOrchestrator, MergeOrchestratorInput, SchedulerDiagnostics, SchedulerOptions, SchedulerResult, SubagentRunInput, SubagentRunner, SubagentRunResult, } from './scheduler.ts';
13
11
  //# sourceMappingURL=index.d.ts.map
@@ -7,7 +7,7 @@
7
7
  // - Git operation queue (PR 2, #198)
8
8
  // - Budget reservation ledger + caps (PR 3, #199)
9
9
  // - Scheduler + worktree lifecycle (PR 4, this PR)
10
- // - Merge orchestrator (PR 5, #192)
10
+ // - Merge orchestrator (PR 5, #192 — not yet exported)
11
11
  //
12
12
  // Importers should reach for THIS module rather than the underlying files so
13
13
  // the internal layout can be reorganized without breaking call sites.
@@ -17,5 +17,4 @@ export { GitOperationQueue } from "./git-op-queue.js";
17
17
  export { BudgetReservation, BudgetExceededError, } from "./budget-reservation.js";
18
18
  export { WorktreeLifecycle, assertRunWorktreesDirAvailable, } from "./worktree-lifecycle.js";
19
19
  export { runScheduler, computeEffectiveConcurrency, } from "./scheduler.js";
20
- export { createMergeOrchestrator, toSchedulerCallback, } from "./merge-orchestrator.js";
21
20
  //# sourceMappingURL=index.js.map
@@ -406,6 +406,24 @@ function applyEvent(state, ev) {
406
406
  // events.ndjson directly to compute actualSoFar — replay does not
407
407
  // need to track budget decisions for state-correctness purposes.
408
408
  break;
409
+ case 'task.started':
410
+ case 'task.budget_reserved':
411
+ case 'task.budget_increased_reservation':
412
+ case 'task.budget_released':
413
+ case 'task.completed':
414
+ case 'task.failed':
415
+ case 'task.merged':
416
+ case 'task.merge_conflict':
417
+ case 'task.merge_aborted':
418
+ case 'task.timeout':
419
+ case 'task.budget_halt':
420
+ // v7.11.0 concurrent-dispatch task events. State for these lives in
421
+ // the dispatch layer (budget-reservation ledger + scheduler), NOT in
422
+ // the per-phase RunState snapshot — phases remain the coarse-grained
423
+ // unit for the run-state engine. Replay is handled by
424
+ // `budgetReservation.replayFromEvents()` for cost reconstruction and
425
+ // by the scheduler's resume path for task-level state.
426
+ break;
409
427
  case 'phase.start': {
410
428
  state.status = 'running';
411
429
  state.currentPhaseIdx = ev.phaseIdx;
@@ -251,9 +251,135 @@ export interface ReplayOverrideEvent extends RunEventBase {
251
251
  /** Refs the underlying refusal cited (echoed for triage). */
252
252
  refsConsulted: ExternalRef[];
253
253
  }
254
+ /** Subagent dispatch — emitted AFTER `task.budget_reserved` succeeds and the
255
+ * worktree is created. Carries the immutable `base_sha` so resume / merge
256
+ * can verify ancestry against an unforgeable reference. */
257
+ export interface TaskStartedEvent extends RunEventBase {
258
+ event: 'task.started';
259
+ task_id: string;
260
+ worktree_path: string;
261
+ branch: string;
262
+ base_sha: string;
263
+ subagent_id: string;
264
+ /** ISO timestamp the subagent process was spawned. */
265
+ dispatched_at: string;
266
+ preflight_cost_estimate_usd: number;
267
+ }
268
+ /** Budget reservation — emitted atomically with the (replay → check → append
269
+ * → fsync) critical section under the writer's exclusive lock. Two
270
+ * concurrent callers cannot both pass the budget check. */
271
+ export interface TaskBudgetReservedEvent extends RunEventBase {
272
+ event: 'task.budget_reserved';
273
+ task_id: string;
274
+ reserved_usd: number;
275
+ /** `perRunUSD - reserved_total` AFTER this reservation lands. May be 0,
276
+ * never negative (would have failed the check). */
277
+ run_budget_remaining_after_reservation_usd: number;
278
+ }
279
+ /** Mid-execution reservation bump — emitted when telemetry from the subagent
280
+ * shows actual cost is approaching the reservation. Re-checks `perRunUSD`
281
+ * under the writer lock; halts the run if exceeded. */
282
+ export interface TaskBudgetIncreasedReservationEvent extends RunEventBase {
283
+ event: 'task.budget_increased_reservation';
284
+ task_id: string;
285
+ prior_reserved_usd: number;
286
+ new_reserved_usd: number;
287
+ reason: string;
288
+ }
289
+ /** Reservation closed — emitted on task completion OR failure. The
290
+ * `delta_vs_reservation_usd` (positive = under, negative = over) lets
291
+ * cost-analytics consumers spot estimate drift. */
292
+ export interface TaskBudgetReleasedEvent extends RunEventBase {
293
+ event: 'task.budget_released';
294
+ task_id: string;
295
+ actual_cost_usd: number;
296
+ delta_vs_reservation_usd: number;
297
+ }
298
+ /** Successful subagent exit with commits on the task branch. The
299
+ * `task_branch_tip_sha` is the IMMUTABLE authoritative ref for all
300
+ * subsequent merge / resume operations — `task_branch_name` is for
301
+ * diagnostics only (branch can be tampered with). */
302
+ export interface TaskCompletedEvent extends RunEventBase {
303
+ event: 'task.completed';
304
+ task_id: string;
305
+ base_sha: string;
306
+ task_branch_tip_sha: string;
307
+ task_branch_name: string;
308
+ /** Ordered list of commit SHAs `base_sha..tip_sha` (oldest first, from
309
+ * `git rev-list --reverse`). Empty array implies `task.failed` should
310
+ * have been emitted with `error_type: 'no_commits'` instead. */
311
+ commit_shas: string[];
312
+ completed_at: string;
313
+ actual_cost_usd: number;
314
+ exit_status: 'success' | 'failure';
315
+ }
316
+ /** Subagent terminal failure. `error_type` is the resume classifier — see
317
+ * spec "Resume semantics" for the classification table. */
318
+ export interface TaskFailedEvent extends RunEventBase {
319
+ event: 'task.failed';
320
+ task_id: string;
321
+ error_message: string;
322
+ error_type: 'timeout' | 'no_commits' | 'ancestry_violation' | 'budget_exceeded' | 'crash' | 'other';
323
+ failed_at: string;
324
+ actual_cost_usd: number;
325
+ }
326
+ /** Cherry-pick chain landed on the integration worktree. The
327
+ * `feature_branch_sha_after_merge` is recorded so the next merge can
328
+ * verify preconditions (HEAD matches the last `task.merged`). */
329
+ export interface TaskMergedEvent extends RunEventBase {
330
+ event: 'task.merged';
331
+ task_id: string;
332
+ feature_branch_sha_after_merge: string;
333
+ merged_at: string;
334
+ }
335
+ /** Cherry-pick conflict captured BEFORE `cherry-pick --abort` runs.
336
+ * Diagnostics are also persisted to `conflict_report_path`
337
+ * (`.claude/run-state/<run-ulid>/conflicts/<task-id>.md`). */
338
+ export interface TaskMergeConflictEvent extends RunEventBase {
339
+ event: 'task.merge_conflict';
340
+ task_id: string;
341
+ conflicting_paths: string[];
342
+ /** Output of `git ls-files -u` — index stages 1/2/3 for each conflicted
343
+ * path. Free-form lines preserved verbatim. */
344
+ index_stages: string[];
345
+ /** Output of `git status --porcelain`. */
346
+ porcelain: string;
347
+ conflict_report_path: string;
348
+ }
349
+ /** Merge precondition violation — dirty tree, wrong HEAD, in-progress
350
+ * cherry-pick / rebase, or ancestry violation at merge time. Halts the
351
+ * run; user must resolve before resume. */
352
+ export interface TaskMergeAbortedEvent extends RunEventBase {
353
+ event: 'task.merge_aborted';
354
+ task_id: string;
355
+ reason: string;
356
+ precondition_violated: string;
357
+ occurred_at: string;
358
+ }
359
+ /** Subagent exceeded `perSubagentTimeoutMs`. Informational — the resume
360
+ * classifier requires a paired `task.failed` event with
361
+ * `error_type: 'timeout'` for terminal classification. */
362
+ export interface TaskTimeoutEvent extends RunEventBase {
363
+ event: 'task.timeout';
364
+ task_id: string;
365
+ timeout_ms: number;
366
+ /** `SIGTERM` or `SIGKILL` — set to `SIGKILL` when the 30s grace after
367
+ * SIGTERM elapsed without process exit. */
368
+ killed_signal: 'SIGTERM' | 'SIGKILL';
369
+ }
370
+ /** Pre-dispatch budget halt — emitted when `reserve()` finds remaining
371
+ * budget insufficient for the new task's preflight estimate. The task
372
+ * never dispatches; the scheduler halts the run with this event as the
373
+ * terminal record. */
374
+ export interface TaskBudgetHaltEvent extends RunEventBase {
375
+ event: 'task.budget_halt';
376
+ task_id: string;
377
+ budget_remaining_usd: number;
378
+ preflight_estimate_usd: number;
379
+ }
254
380
  /** Discriminated union of every event variant. Add new variants here and
255
381
  * the code that switches over `event` will type-error at compile time. */
256
- export type RunEvent = RunStartEvent | RunCompleteEvent | RunWarningEvent | RunRecoveryEvent | PhaseStartEvent | PhaseSuccessEvent | PhaseFailedEvent | PhaseAbortedEvent | PhaseCostEvent | PhaseExternalRefEvent | PhaseNeedsHumanEvent | LockTakeoverEvent | IndexRebuiltEvent | BudgetCheckEvent | ReplayOverrideEvent;
382
+ export type RunEvent = RunStartEvent | RunCompleteEvent | RunWarningEvent | RunRecoveryEvent | PhaseStartEvent | PhaseSuccessEvent | PhaseFailedEvent | PhaseAbortedEvent | PhaseCostEvent | PhaseExternalRefEvent | PhaseNeedsHumanEvent | LockTakeoverEvent | IndexRebuiltEvent | BudgetCheckEvent | ReplayOverrideEvent | TaskStartedEvent | TaskBudgetReservedEvent | TaskBudgetIncreasedReservationEvent | TaskBudgetReleasedEvent | TaskCompletedEvent | TaskFailedEvent | TaskMergedEvent | TaskMergeConflictEvent | TaskMergeAbortedEvent | TaskTimeoutEvent | TaskBudgetHaltEvent;
257
383
  /** Distributive Omit so the discriminated-union shape is preserved when we
258
384
  * strip the fields the appender fills in. Plain `Omit<RunEvent, ...>`
259
385
  * collapses the union into a single intersection and loses variant-specific
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@delegance/claude-autopilot",
3
- "version": "7.11.0-pre.2",
3
+ "version": "7.11.0-pre.4",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "tag": "next"