@defrex/autobuild 0.8.0 → 0.10.0

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 (182) hide show
  1. package/README.md +1 -1
  2. package/SPEC.md +323 -26
  3. package/bin/ab-build-runner.ts +8 -2
  4. package/docs/architecture.md +166 -14
  5. package/docs/assets/headline-wide.png +0 -0
  6. package/docs/configuration.md +175 -28
  7. package/docs/hosted-dispatcher.md +69 -13
  8. package/docs/operator-api.md +2 -2
  9. package/docs/remote-store-protocol.md +204 -16
  10. package/docs/remote-ticket-protocol.md +1 -1
  11. package/docs/setup.md +12 -9
  12. package/docs/website.md +14 -0
  13. package/package.json +45 -23
  14. package/packages/core/src/cli/artifact.ts +130 -6
  15. package/packages/core/src/cli/binary.ts +9 -1
  16. package/packages/core/src/cli/build-control.ts +110 -13
  17. package/packages/core/src/cli/context.ts +46 -0
  18. package/packages/core/src/cli/dashboard/facts.ts +215 -0
  19. package/packages/core/src/cli/dashboard/frame-parse.ts +223 -0
  20. package/packages/core/src/cli/dashboard/model.ts +141 -153
  21. package/packages/core/src/cli/dashboard/poll.ts +76 -12
  22. package/packages/core/src/cli/dashboard/render.ts +34 -5
  23. package/packages/core/src/cli/dispatch-frontend.ts +54 -5
  24. package/packages/core/src/cli/dispatch-process.ts +1 -13
  25. package/packages/core/src/cli/dispatch.ts +392 -75
  26. package/packages/core/src/cli/harvest.ts +122 -8
  27. package/packages/core/src/cli/help.ts +62 -9
  28. package/packages/core/src/cli/init-readiness-remote.ts +110 -0
  29. package/packages/core/src/cli/init-readiness-shared.ts +72 -0
  30. package/packages/core/src/cli/init-validation.ts +266 -222
  31. package/packages/core/src/cli/installation.ts +50 -8
  32. package/packages/core/src/cli/main.ts +70 -11
  33. package/packages/core/src/cli/mcp.ts +23 -1
  34. package/packages/core/src/cli/plugin.ts +7 -4
  35. package/packages/core/src/cli/remote-poll.ts +277 -0
  36. package/packages/core/src/cli/repo-state.ts +22 -0
  37. package/packages/core/src/cli/repository-status.ts +39 -1
  38. package/packages/core/src/cli/self-update.ts +77 -2
  39. package/packages/core/src/cli/status.ts +150 -28
  40. package/packages/core/src/cli/terminals.ts +2 -1
  41. package/packages/core/src/cli/ticket-assets.ts +247 -0
  42. package/packages/core/src/cli/ticket.ts +453 -8
  43. package/packages/core/src/cli/wait.ts +157 -41
  44. package/packages/core/src/cli/watch.ts +138 -168
  45. package/packages/core/src/config/live.ts +23 -0
  46. package/packages/core/src/config/pipeline-source.ts +388 -0
  47. package/packages/core/src/config/schema.ts +251 -19
  48. package/packages/core/src/events/catalog.ts +1 -0
  49. package/packages/core/src/events/globs.ts +47 -0
  50. package/packages/core/src/events/payloads.ts +52 -2
  51. package/packages/core/src/events/repository.ts +52 -1
  52. package/packages/core/src/events/sessions.ts +69 -10
  53. package/packages/core/src/events/workspace-remote.ts +12 -0
  54. package/packages/core/src/integration/harness.ts +115 -2
  55. package/packages/core/src/kernel/__snapshots__/reducer-registry.test.ts.snap +1369 -0
  56. package/packages/core/src/kernel/auto-merge-default.ts +157 -0
  57. package/packages/core/src/kernel/auto-merge.ts +99 -22
  58. package/packages/core/src/kernel/dispatch-settings.ts +42 -17
  59. package/packages/core/src/kernel/dispatch-status.ts +23 -0
  60. package/packages/core/src/kernel/engine.ts +9 -438
  61. package/packages/core/src/kernel/generators/build-log.ts +259 -0
  62. package/packages/core/src/kernel/generators/repository-journals.ts +206 -0
  63. package/packages/core/src/kernel/generators/session-log.ts +72 -0
  64. package/packages/core/src/kernel/harvest.ts +62 -18
  65. package/packages/core/src/kernel/incremental-contract.ts +75 -0
  66. package/packages/core/src/kernel/incremental-fixtures.ts +211 -0
  67. package/packages/core/src/kernel/incremental.ts +53 -0
  68. package/packages/core/src/kernel/log-index.ts +620 -0
  69. package/packages/core/src/kernel/phases.ts +16 -2
  70. package/packages/core/src/kernel/pr-attachments.ts +164 -46
  71. package/packages/core/src/kernel/reducer-registry.ts +164 -0
  72. package/packages/core/src/kernel/reducer.ts +254 -73
  73. package/packages/core/src/operator/annotations.ts +6 -0
  74. package/packages/core/src/operator/control.ts +19 -5
  75. package/packages/core/src/operator/index.ts +71 -6
  76. package/packages/core/src/operator/query.ts +253 -24
  77. package/packages/core/src/operator/read-view.ts +98 -0
  78. package/packages/core/src/operator/registry.ts +55 -10
  79. package/packages/core/src/operator/requests.ts +9 -6
  80. package/packages/core/src/operator/sandbox-host.ts +140 -0
  81. package/packages/core/src/operator/sandbox.ts +247 -14
  82. package/packages/core/src/operator/ticket-source-backend.ts +47 -0
  83. package/packages/core/src/orchestrator/approvals.ts +115 -0
  84. package/packages/core/src/orchestrator/conversation.ts +167 -0
  85. package/packages/core/src/orchestrator/model.ts +86 -0
  86. package/packages/core/src/orchestrator/prompt.ts +61 -0
  87. package/packages/core/src/orchestrator/tools.ts +117 -0
  88. package/packages/core/src/orchestrator/turn-runner.ts +457 -0
  89. package/packages/core/src/plugin-sdk/index.ts +51 -1
  90. package/packages/core/src/plugins/load.ts +135 -7
  91. package/packages/core/src/plugins/manifest.ts +183 -10
  92. package/packages/core/src/plugins/registry.ts +73 -4
  93. package/packages/core/src/ports/forge/create.ts +1 -1
  94. package/packages/core/src/ports/forge/fake.ts +31 -0
  95. package/packages/core/src/ports/forge/github-transport.ts +13 -2
  96. package/packages/core/src/ports/forge/github.ts +13 -2
  97. package/packages/core/src/ports/forge/local-git.ts +31 -1
  98. package/packages/core/src/ports/runner/claude.ts +2 -2
  99. package/packages/core/src/ports/runner/codex.ts +6 -2
  100. package/packages/core/src/ports/runner/fake.ts +7 -1
  101. package/packages/core/src/ports/runner/pi.ts +8 -6
  102. package/packages/core/src/ports/runner/provider-error.ts +13 -3
  103. package/packages/core/src/ports/tickets/fake.ts +5 -1
  104. package/packages/core/src/ports/tickets/file.ts +169 -48
  105. package/packages/core/src/ports/tickets/{remote-index.ts → hosted-index.ts} +3 -2
  106. package/packages/core/src/ports/tickets/linear.ts +33 -1
  107. package/packages/core/src/ports/tickets/operations.ts +1 -1
  108. package/packages/core/src/ports/tickets/remote.ts +8 -1
  109. package/packages/core/src/ports/types.ts +49 -3
  110. package/packages/core/src/ports/workspace/builtin-capabilities.ts +114 -0
  111. package/packages/core/src/ports/workspace/create.ts +74 -39
  112. package/packages/core/src/ports/workspace/distribution-archive.ts +171 -12
  113. package/packages/core/src/ports/workspace/fake.ts +169 -4
  114. package/packages/core/src/ports/workspace/git-worktree.ts +246 -26
  115. package/packages/core/src/ports/workspace/github-origin.ts +36 -0
  116. package/packages/core/src/ports/workspace/operator-sandbox.ts +7 -1
  117. package/packages/core/src/ports/workspace/provider-capabilities.ts +171 -0
  118. package/packages/core/src/ports/workspace/vercel-capabilities.ts +110 -0
  119. package/packages/core/src/ports/workspace/vercel-sandbox.ts +142 -114
  120. package/packages/core/src/processes/build-child.ts +17 -2
  121. package/packages/core/src/processes/build-execution-state.ts +68 -15
  122. package/packages/core/src/processes/build-runner.ts +238 -93
  123. package/packages/core/src/processes/dispatcher-selectors.ts +123 -0
  124. package/packages/core/src/processes/dispatcher.ts +501 -201
  125. package/packages/core/src/processes/execution-settlement.ts +72 -39
  126. package/packages/core/src/processes/harvest-child.ts +5 -0
  127. package/packages/core/src/processes/harvest-execution-state.ts +41 -29
  128. package/packages/core/src/processes/harvest-runner.ts +66 -19
  129. package/packages/core/src/processes/harvest.ts +196 -24
  130. package/packages/core/src/processes/infrastructure-failure-budget.ts +31 -18
  131. package/packages/core/src/processes/orchestrator-tick.ts +360 -0
  132. package/packages/core/src/processes/publication-state.ts +164 -52
  133. package/packages/core/src/processes/repo-view.ts +1436 -0
  134. package/packages/core/src/processes/sandbox-state.ts +36 -2
  135. package/packages/core/src/processes/tick-state.ts +33 -0
  136. package/packages/core/src/store/adapter.ts +41 -0
  137. package/packages/core/src/store/build-scope.ts +90 -0
  138. package/packages/core/src/store/contract.ts +1205 -0
  139. package/packages/core/src/store/digest.ts +102 -0
  140. package/packages/core/src/store/local/schema.ts +46 -2
  141. package/packages/core/src/store/local/store.ts +445 -4
  142. package/packages/core/src/store/memory.ts +246 -0
  143. package/packages/core/src/store/new-build.ts +17 -0
  144. package/packages/core/src/store/phase-session.ts +94 -0
  145. package/packages/core/src/store/remote/client.ts +310 -2
  146. package/packages/core/src/store/remote/index.ts +14 -2
  147. package/packages/core/src/store/remote/protocol.ts +115 -12
  148. package/packages/core/src/store/remote/version.ts +6 -2
  149. package/packages/core/src/store/repo-state-events.ts +205 -0
  150. package/packages/core/src/store/retention.ts +7 -0
  151. package/packages/core/src/store/session-handle.ts +94 -0
  152. package/packages/core/src/{sessions/reducer.ts → store/session-reducer.ts} +79 -19
  153. package/packages/core/src/store/snapshots.ts +88 -0
  154. package/packages/core/src/store/streams/session-writer.ts +42 -2
  155. package/packages/core/src/store/streams/wait.ts +4 -5
  156. package/packages/core/src/store/ticket-assets.ts +458 -0
  157. package/packages/core/src/store/types.ts +160 -1
  158. package/packages/core/src/testing/index.ts +59 -0
  159. package/skills/code-review/SKILL.md +5 -1
  160. package/skills/guide/SKILL.md +152 -40
  161. package/skills/guide/references/operator-api.md +2 -2
  162. package/skills/guide/references/plugin-authoring.md +17 -0
  163. package/skills/guide/references/remote-store-protocol.md +204 -16
  164. package/skills/guide/references/remote-ticket-protocol.md +1 -1
  165. package/skills/guide/references/setup.md +12 -9
  166. package/skills/implement/SKILL.md +3 -0
  167. package/skills/operate/SKILL.md +126 -0
  168. package/skills/plan/SKILL.md +4 -0
  169. package/skills/plan-review/SKILL.md +5 -1
  170. package/skills/spec/SKILL.md +46 -3
  171. package/skills/tickets/SKILL.md +57 -5
  172. package/packages/core/src/cli/dashboard/frame-image.ts +0 -373
  173. package/packages/core/src/cli/store-opening.contract.ts +0 -289
  174. package/packages/core/src/cli/testkit.ts +0 -194
  175. package/packages/core/src/markdown.ts +0 -67
  176. package/packages/core/src/operator/client.ts +0 -311
  177. package/packages/core/src/operator/server.ts +0 -616
  178. package/packages/core/src/operator/sessions.ts +0 -223
  179. package/packages/core/src/ports/runner/live-contract-fixture.ts +0 -176
  180. package/packages/core/src/ports/tickets/remote-server.ts +0 -185
  181. package/packages/core/src/store/remote/server.ts +0 -923
  182. package/packages/core/src/testing/store-failures.ts +0 -32
@@ -3,7 +3,7 @@ import { humanActor } from '../events/envelope'
3
3
  import type { RepositoryEvent } from '../events/repository'
4
4
  import { reduceDispatchStatus, type DispatchStatus } from '../kernel/dispatch-status'
5
5
  import type { BuildState } from '../kernel/reducer'
6
- import { scanUnclaimedObservations } from '../processes/harvest'
6
+ import { sampleUnclaimedObservationCount } from '../processes/harvest'
7
7
  import {
8
8
  controlHarvestRun,
9
9
  OperatorControlError,
@@ -120,6 +120,9 @@ export class DispatchFrontend {
120
120
  private readonly keyboard
121
121
  private child: DispatchChildHandle | undefined
122
122
  private repositorySeq = 0
123
+ /** Set only after a successful initial fold; every later `events()` call
124
+ * takes the delta path. */
125
+ private seeded = false
123
126
  private repositoryEvents: RepositoryEvent[] = []
124
127
  private dispatchStatus: DispatchStatus = reduceDispatchStatus([], this.runId)
125
128
  private eventRefreshTail: Promise<void> = Promise.resolve()
@@ -164,6 +167,36 @@ export class DispatchFrontend {
164
167
  * are retained for their existing replay reducers. */
165
168
  private async events(): Promise<RepositoryEvent[]> {
166
169
  const refresh = this.eventRefreshTail.then(async () => {
170
+ if (!this.seeded) {
171
+ // Initial fold (AUT-534): the whole-journal read the first poll used
172
+ // to pay is replaced by AUT-489's bounded read where that is provably
173
+ // equivalent. The bounded attempt is confined to the pre-launch
174
+ // window (`this.child === undefined`): before `launchChild` no
175
+ // run-scoped journal fact can carry `this.runId` (only the supervised
176
+ // child appends run-scoped facts with it), so every run-scoped event
177
+ // in the bounded subset is skipped by `reduceDispatchStatus` exactly
178
+ // as it would be in a full replay, and the dashboard filter keeps
179
+ // only durable types, which the subset carries in full. After launch
180
+ // a bounded subset cannot guarantee the child's `run-started` under a
181
+ // competing dispatcher's later anchor — dropping it would leave
182
+ // `effectiveConfig` unset and the first frame would never render —
183
+ // so a post-launch seed always takes the full read (the pre-AUT-534
184
+ // behavior). `once` mode's teardown fold runs after the child exits,
185
+ // so the same guard routes it to the full read.
186
+ const seed =
187
+ this.child === undefined
188
+ ? await this.opts.store.getRepoStateEvents(this.opts.repo).catch(() =>
189
+ // Bounded-read failure falls back to the exact pre-AUT-534
190
+ // full read within this same seed attempt.
191
+ this.opts.store.getRepoEvents(this.opts.repo, 0),
192
+ )
193
+ : await this.opts.store.getRepoEvents(this.opts.repo, 0)
194
+ this.repositorySeq = seed.at(-1)?.seq ?? 0
195
+ this.dispatchStatus = reduceDispatchStatus(seed, this.runId)
196
+ this.repositoryEvents.push(...seed.filter(isDashboardRepositoryEvent))
197
+ this.seeded = true
198
+ return
199
+ }
167
200
  const delta = await this.opts.store.getRepoEvents(this.opts.repo, this.repositorySeq)
168
201
  if (delta.length === 0) return
169
202
  this.repositorySeq = delta.at(-1)!.seq
@@ -295,8 +328,14 @@ export class DispatchFrontend {
295
328
  }
296
329
  const config = await this.loadConfig(ref.kind, ref.rev)
297
330
  try {
298
- const scan = await scanUnclaimedObservations(this.opts.store, this.opts.repo)
299
- this.observationCount = scan.observations.length
331
+ // Journal + digests (AUT-487): one journal read for the claimed set
332
+ // (this class's cached `repositoryEvents` is dashboard-filtered, so the
333
+ // claimed set needs the full journal, exactly as the old per-build scan
334
+ // read it) plus one repo-scoped digest read — the sample's store
335
+ // traffic stays flat as finished builds accumulate. A journal record
336
+ // that does not yet exist reads as an empty journal (AUT-524); the
337
+ // sample writes nothing.
338
+ this.observationCount = await sampleUnclaimedObservationCount(this.opts.store, this.opts.repo)
300
339
  } catch {
301
340
  // Before the first successful sample there is no factual zero to place in
302
341
  // a complete frame. Leave the prior frame untouched and retry on the next
@@ -677,6 +716,7 @@ export class DispatchFrontend {
677
716
  repo: this.opts.repo,
678
717
  user: buildControlUser(this.opts.env),
679
718
  setting: 'intake',
719
+ run: this.runId,
680
720
  })
681
721
  await this.report(`dispatcher intake ${event.enabled ? 'ON' : 'OFF'}`)
682
722
  await this.renderOnce()
@@ -688,6 +728,7 @@ export class DispatchFrontend {
688
728
  repo: this.opts.repo,
689
729
  user: buildControlUser(this.opts.env),
690
730
  setting: 'auto-merge-default',
731
+ run: this.runId,
691
732
  })
692
733
  await this.report(`dispatcher auto-merge default ${event.enabled ? 'ON' : 'OFF'}`)
693
734
  await this.renderOnce()
@@ -990,17 +1031,25 @@ export class DispatchFrontend {
990
1031
  await this.opts.store.appendRepo(this.opts.repo, {
991
1032
  actor,
992
1033
  type: 'dispatcher.intake-set',
993
- payload: { enabled: this.opts.intake },
1034
+ payload: { enabled: this.opts.intake, run: this.runId },
994
1035
  })
995
1036
  }
996
1037
  if (this.opts.defaultAutoMerge !== undefined) {
997
1038
  await this.opts.store.appendRepo(this.opts.repo, {
998
1039
  actor,
999
1040
  type: 'dispatcher.auto-merge-default-set',
1000
- payload: { enabled: this.opts.defaultAutoMerge },
1041
+ payload: { enabled: this.opts.defaultAutoMerge, run: this.runId },
1001
1042
  })
1002
1043
  }
1003
1044
 
1045
+ // Warm the initial fold before `launchChild` (AUT-534): the bounded seed
1046
+ // is only safe while `this.child === undefined`, so the one opportunity
1047
+ // to take it is here. A failed warm-up leaves the seed unset; the poll
1048
+ // loop's existing failure reporting covers the retry, which then takes
1049
+ // the full-read path post-launch. `once` mode gains no read — its single
1050
+ // fold runs from `finishPresentation()` after the child exits.
1051
+ if (!this.opts.once) await this.events().catch(() => {})
1052
+
1004
1053
  const options: DispatchChildOptions = {
1005
1054
  targetRepo: this.opts.checkout ?? this.opts.repo,
1006
1055
  storeRef: this.opts.storeRef,
@@ -1,6 +1,6 @@
1
1
  import { distributionPath } from '../distribution'
2
2
  import { DISPATCHER } from '../events/envelope'
3
- import type { RepositoryEvent } from '../events/repository'
3
+ import { hasOpenTick } from '../processes/tick-state'
4
4
  import type { BuildStore } from '../store/types'
5
5
 
6
6
  export const DISPATCH_CHILD_OPTIONS_ENV = 'AB_DISPATCH_CHILD_OPTIONS'
@@ -132,18 +132,6 @@ export interface DispatchChildSupervisorDeps {
132
132
  }) => DispatchSubprocess
133
133
  }
134
134
 
135
- function hasOpenTick(events: readonly RepositoryEvent[], run: string): boolean {
136
- const boundary = events.findLast(
137
- (event) =>
138
- 'run' in event.payload &&
139
- event.payload.run === run &&
140
- (event.type === 'dispatcher.tick-started' ||
141
- event.type === 'dispatcher.tick-completed' ||
142
- event.type === 'dispatcher.tick-failed'),
143
- )
144
- return boundary?.type === 'dispatcher.tick-started'
145
- }
146
-
147
135
  function defaultSpawn(input: {
148
136
  entrypoint: string
149
137
  cwd: string