@defrex/autobuild 0.8.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 (251) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +192 -0
  3. package/SPEC.md +2269 -0
  4. package/bin/ab-build-runner.ts +47 -0
  5. package/bin/ab-dev.ts +27 -0
  6. package/bin/ab-dispatch-kernel.ts +92 -0
  7. package/bin/ab-harvest-runner.ts +29 -0
  8. package/bin/ab-init-probe.ts +19 -0
  9. package/bin/ab-process-group-reaper.ts +32 -0
  10. package/bin/ab.ts +6 -0
  11. package/bin/agent/ab +3 -0
  12. package/docs/answering-blocked-builds.md +89 -0
  13. package/docs/architecture.md +726 -0
  14. package/docs/assets/headline-wide.png +0 -0
  15. package/docs/configuration.md +1623 -0
  16. package/docs/hosted-dispatcher-cutover-validation.md +178 -0
  17. package/docs/hosted-dispatcher.md +204 -0
  18. package/docs/mcp.md +119 -0
  19. package/docs/operator-api.md +186 -0
  20. package/docs/remote-store-protocol.md +972 -0
  21. package/docs/remote-ticket-protocol.md +79 -0
  22. package/docs/setup.md +289 -0
  23. package/docs/spec-standard.md +63 -0
  24. package/docs/ticket-dependencies.md +59 -0
  25. package/docs/vercel-sandbox-rollout-probe.md +7 -0
  26. package/package.json +135 -0
  27. package/packages/core/src/cli/args.ts +74 -0
  28. package/packages/core/src/cli/artifact.ts +182 -0
  29. package/packages/core/src/cli/binary.ts +198 -0
  30. package/packages/core/src/cli/build-control.ts +789 -0
  31. package/packages/core/src/cli/build-progress.ts +55 -0
  32. package/packages/core/src/cli/bulk-control.ts +385 -0
  33. package/packages/core/src/cli/context.ts +470 -0
  34. package/packages/core/src/cli/dashboard/actions.ts +59 -0
  35. package/packages/core/src/cli/dashboard/cells.ts +92 -0
  36. package/packages/core/src/cli/dashboard/composer.ts +230 -0
  37. package/packages/core/src/cli/dashboard/detail.ts +100 -0
  38. package/packages/core/src/cli/dashboard/frame-image.ts +373 -0
  39. package/packages/core/src/cli/dashboard/live.ts +152 -0
  40. package/packages/core/src/cli/dashboard/model.ts +1173 -0
  41. package/packages/core/src/cli/dashboard/poll.ts +196 -0
  42. package/packages/core/src/cli/dashboard/render.ts +1568 -0
  43. package/packages/core/src/cli/dashboard/selection.ts +66 -0
  44. package/packages/core/src/cli/dashboard/session-feed.ts +244 -0
  45. package/packages/core/src/cli/dashboard/session-view.ts +506 -0
  46. package/packages/core/src/cli/dashboard/transcript.ts +108 -0
  47. package/packages/core/src/cli/dev.ts +46 -0
  48. package/packages/core/src/cli/dispatch-frontend.ts +1045 -0
  49. package/packages/core/src/cli/dispatch-process.ts +259 -0
  50. package/packages/core/src/cli/dispatch.ts +3692 -0
  51. package/packages/core/src/cli/dotenv.ts +48 -0
  52. package/packages/core/src/cli/env.ts +206 -0
  53. package/packages/core/src/cli/harvest.ts +698 -0
  54. package/packages/core/src/cli/help.ts +713 -0
  55. package/packages/core/src/cli/init-agent.ts +106 -0
  56. package/packages/core/src/cli/init-validation.ts +583 -0
  57. package/packages/core/src/cli/init.ts +756 -0
  58. package/packages/core/src/cli/installation.ts +333 -0
  59. package/packages/core/src/cli/keyboard.ts +261 -0
  60. package/packages/core/src/cli/main.ts +1399 -0
  61. package/packages/core/src/cli/mcp.ts +279 -0
  62. package/packages/core/src/cli/models.ts +65 -0
  63. package/packages/core/src/cli/observe.ts +55 -0
  64. package/packages/core/src/cli/plugin.ts +227 -0
  65. package/packages/core/src/cli/pr-attachments.ts +138 -0
  66. package/packages/core/src/cli/pr-summary.ts +124 -0
  67. package/packages/core/src/cli/publication-settlement.ts +188 -0
  68. package/packages/core/src/cli/repo-state.ts +213 -0
  69. package/packages/core/src/cli/repository-status.ts +80 -0
  70. package/packages/core/src/cli/self-update.ts +443 -0
  71. package/packages/core/src/cli/status.ts +895 -0
  72. package/packages/core/src/cli/store-opening.contract.ts +289 -0
  73. package/packages/core/src/cli/store-opening.ts +167 -0
  74. package/packages/core/src/cli/store-ref.ts +33 -0
  75. package/packages/core/src/cli/terminal-restore.ts +174 -0
  76. package/packages/core/src/cli/terminal.ts +361 -0
  77. package/packages/core/src/cli/terminals.ts +995 -0
  78. package/packages/core/src/cli/testkit.ts +194 -0
  79. package/packages/core/src/cli/ticket.ts +484 -0
  80. package/packages/core/src/cli/upgrade-agent.ts +180 -0
  81. package/packages/core/src/cli/upgrade-commit.ts +468 -0
  82. package/packages/core/src/cli/upgrade-notice.ts +91 -0
  83. package/packages/core/src/cli/upgrade-progress.ts +110 -0
  84. package/packages/core/src/cli/upgrade.ts +888 -0
  85. package/packages/core/src/cli/wait.ts +587 -0
  86. package/packages/core/src/cli/watch.ts +932 -0
  87. package/packages/core/src/config/live.ts +255 -0
  88. package/packages/core/src/config/load.ts +98 -0
  89. package/packages/core/src/config/roles.ts +438 -0
  90. package/packages/core/src/config/schema.ts +774 -0
  91. package/packages/core/src/distribution.ts +24 -0
  92. package/packages/core/src/events/catalog.ts +201 -0
  93. package/packages/core/src/events/envelope.ts +59 -0
  94. package/packages/core/src/events/payloads.ts +618 -0
  95. package/packages/core/src/events/repository.ts +559 -0
  96. package/packages/core/src/events/sessions.ts +180 -0
  97. package/packages/core/src/harvest/schema.ts +147 -0
  98. package/packages/core/src/ids.ts +45 -0
  99. package/packages/core/src/integration/harness.ts +681 -0
  100. package/packages/core/src/kernel/auto-merge.ts +259 -0
  101. package/packages/core/src/kernel/converge.ts +117 -0
  102. package/packages/core/src/kernel/dispatch-settings.ts +60 -0
  103. package/packages/core/src/kernel/dispatch-status.ts +141 -0
  104. package/packages/core/src/kernel/engine.ts +1047 -0
  105. package/packages/core/src/kernel/harvest.ts +823 -0
  106. package/packages/core/src/kernel/origin.ts +69 -0
  107. package/packages/core/src/kernel/phases.ts +196 -0
  108. package/packages/core/src/kernel/plan-verify-selection.ts +105 -0
  109. package/packages/core/src/kernel/pr-attachments.ts +82 -0
  110. package/packages/core/src/kernel/reducer.ts +752 -0
  111. package/packages/core/src/kernel/stall.ts +155 -0
  112. package/packages/core/src/kernel/verify-applicability.ts +52 -0
  113. package/packages/core/src/markdown.ts +67 -0
  114. package/packages/core/src/ontology.ts +288 -0
  115. package/packages/core/src/open-map.ts +203 -0
  116. package/packages/core/src/operator/annotations.ts +187 -0
  117. package/packages/core/src/operator/client.ts +311 -0
  118. package/packages/core/src/operator/control.ts +117 -0
  119. package/packages/core/src/operator/index.ts +62 -0
  120. package/packages/core/src/operator/presentation.ts +22 -0
  121. package/packages/core/src/operator/protocol.ts +98 -0
  122. package/packages/core/src/operator/query.ts +201 -0
  123. package/packages/core/src/operator/registry.ts +1043 -0
  124. package/packages/core/src/operator/requests.ts +138 -0
  125. package/packages/core/src/operator/sandbox.ts +458 -0
  126. package/packages/core/src/operator/server.ts +616 -0
  127. package/packages/core/src/operator/sessions.ts +223 -0
  128. package/packages/core/src/operator/tickets.ts +177 -0
  129. package/packages/core/src/plugin-sdk/index.ts +174 -0
  130. package/packages/core/src/plugins/contract-entry.ts +74 -0
  131. package/packages/core/src/plugins/contract-env.ts +3 -0
  132. package/packages/core/src/plugins/load.ts +259 -0
  133. package/packages/core/src/plugins/manifest.ts +236 -0
  134. package/packages/core/src/plugins/registry.ts +274 -0
  135. package/packages/core/src/plugins/runtimes.ts +75 -0
  136. package/packages/core/src/ports/forge/contract.ts +258 -0
  137. package/packages/core/src/ports/forge/create.ts +74 -0
  138. package/packages/core/src/ports/forge/fake.ts +488 -0
  139. package/packages/core/src/ports/forge/github-pr-attachments.ts +351 -0
  140. package/packages/core/src/ports/forge/github-transport.ts +352 -0
  141. package/packages/core/src/ports/forge/github.ts +1162 -0
  142. package/packages/core/src/ports/forge/local-git.ts +568 -0
  143. package/packages/core/src/ports/runner/claude.ts +873 -0
  144. package/packages/core/src/ports/runner/cli-stream.ts +90 -0
  145. package/packages/core/src/ports/runner/codex.ts +873 -0
  146. package/packages/core/src/ports/runner/contract.ts +492 -0
  147. package/packages/core/src/ports/runner/fake.ts +213 -0
  148. package/packages/core/src/ports/runner/json-record.ts +2 -0
  149. package/packages/core/src/ports/runner/live-contract-fixture.ts +176 -0
  150. package/packages/core/src/ports/runner/one-shot.ts +29 -0
  151. package/packages/core/src/ports/runner/pi-bridge-core.ts +136 -0
  152. package/packages/core/src/ports/runner/pi-bridge.js +6 -0
  153. package/packages/core/src/ports/runner/pi-rpc.ts +454 -0
  154. package/packages/core/src/ports/runner/pi.ts +617 -0
  155. package/packages/core/src/ports/runner/production.ts +74 -0
  156. package/packages/core/src/ports/runner/provider-error.ts +121 -0
  157. package/packages/core/src/ports/runner/routing.ts +234 -0
  158. package/packages/core/src/ports/runner/runtime.ts +214 -0
  159. package/packages/core/src/ports/runner/session-env.ts +34 -0
  160. package/packages/core/src/ports/runner/stream-parts.ts +103 -0
  161. package/packages/core/src/ports/tickets/contract.ts +570 -0
  162. package/packages/core/src/ports/tickets/create.ts +135 -0
  163. package/packages/core/src/ports/tickets/fake.ts +215 -0
  164. package/packages/core/src/ports/tickets/file.ts +559 -0
  165. package/packages/core/src/ports/tickets/linear.ts +811 -0
  166. package/packages/core/src/ports/tickets/operations.ts +161 -0
  167. package/packages/core/src/ports/tickets/remote-index.ts +13 -0
  168. package/packages/core/src/ports/tickets/remote-protocol.ts +80 -0
  169. package/packages/core/src/ports/tickets/remote-server.ts +185 -0
  170. package/packages/core/src/ports/tickets/remote.ts +130 -0
  171. package/packages/core/src/ports/tickets/update.ts +51 -0
  172. package/packages/core/src/ports/types.ts +528 -0
  173. package/packages/core/src/ports/workspace/build-execution.ts +123 -0
  174. package/packages/core/src/ports/workspace/contract.ts +136 -0
  175. package/packages/core/src/ports/workspace/create.ts +132 -0
  176. package/packages/core/src/ports/workspace/distribution-archive.ts +317 -0
  177. package/packages/core/src/ports/workspace/fake.ts +432 -0
  178. package/packages/core/src/ports/workspace/git-worktree.ts +848 -0
  179. package/packages/core/src/ports/workspace/harvest-execution.ts +111 -0
  180. package/packages/core/src/ports/workspace/in-process-build-execution.ts +30 -0
  181. package/packages/core/src/ports/workspace/local-build-execution.ts +88 -0
  182. package/packages/core/src/ports/workspace/operator-sandbox.ts +142 -0
  183. package/packages/core/src/ports/workspace/phase-scratch.ts +156 -0
  184. package/packages/core/src/ports/workspace/vercel-sandbox.ts +2541 -0
  185. package/packages/core/src/processes/build-child-exit.ts +78 -0
  186. package/packages/core/src/processes/build-child.ts +119 -0
  187. package/packages/core/src/processes/build-execution-state.ts +95 -0
  188. package/packages/core/src/processes/build-parent-watch.ts +35 -0
  189. package/packages/core/src/processes/build-runner.ts +2614 -0
  190. package/packages/core/src/processes/dispatcher.ts +2825 -0
  191. package/packages/core/src/processes/execution-settlement.ts +171 -0
  192. package/packages/core/src/processes/harvest-child.ts +115 -0
  193. package/packages/core/src/processes/harvest-execution-state.ts +121 -0
  194. package/packages/core/src/processes/harvest-runner.ts +1656 -0
  195. package/packages/core/src/processes/harvest.ts +595 -0
  196. package/packages/core/src/processes/infrastructure-failure-budget.ts +146 -0
  197. package/packages/core/src/processes/phase-failure-budget.ts +52 -0
  198. package/packages/core/src/processes/process-group-reaper.ts +35 -0
  199. package/packages/core/src/processes/process-group.ts +65 -0
  200. package/packages/core/src/processes/publication-loss.ts +62 -0
  201. package/packages/core/src/processes/publication-state.ts +93 -0
  202. package/packages/core/src/processes/sandbox-state.ts +101 -0
  203. package/packages/core/src/registry.ts +24 -0
  204. package/packages/core/src/sessions/reducer.ts +185 -0
  205. package/packages/core/src/skills.ts +7 -0
  206. package/packages/core/src/spec-standard.ts +47 -0
  207. package/packages/core/src/store/adapter.ts +80 -0
  208. package/packages/core/src/store/build-scope.ts +272 -0
  209. package/packages/core/src/store/contract.ts +2581 -0
  210. package/packages/core/src/store/local/blobs.ts +38 -0
  211. package/packages/core/src/store/local/schema.ts +180 -0
  212. package/packages/core/src/store/local/store.ts +1713 -0
  213. package/packages/core/src/store/memory.ts +1138 -0
  214. package/packages/core/src/store/phase-session.ts +425 -0
  215. package/packages/core/src/store/remote/client.ts +780 -0
  216. package/packages/core/src/store/remote/index.ts +12 -0
  217. package/packages/core/src/store/remote/protocol.ts +348 -0
  218. package/packages/core/src/store/remote/server.ts +923 -0
  219. package/packages/core/src/store/remote/token.ts +137 -0
  220. package/packages/core/src/store/remote/version.ts +10 -0
  221. package/packages/core/src/store/retention.ts +91 -0
  222. package/packages/core/src/store/session-handle.ts +265 -0
  223. package/packages/core/src/store/streams/assemble.ts +79 -0
  224. package/packages/core/src/store/streams/lock.ts +42 -0
  225. package/packages/core/src/store/streams/session-writer.ts +306 -0
  226. package/packages/core/src/store/streams/types.ts +171 -0
  227. package/packages/core/src/store/streams/wait.ts +127 -0
  228. package/packages/core/src/store/subscribe.ts +105 -0
  229. package/packages/core/src/store/types.ts +466 -0
  230. package/packages/core/src/testing/fixed.ts +44 -0
  231. package/packages/core/src/testing/store-failures.ts +32 -0
  232. package/packages/core/src/zod-issues.ts +91 -0
  233. package/skills/code-review/SKILL.md +100 -0
  234. package/skills/finalize/SKILL.md +44 -0
  235. package/skills/guide/SKILL.md +1781 -0
  236. package/skills/guide/references/operator-api.md +164 -0
  237. package/skills/guide/references/plugin-authoring.md +354 -0
  238. package/skills/guide/references/remote-store-protocol.md +972 -0
  239. package/skills/guide/references/remote-ticket-protocol.md +79 -0
  240. package/skills/guide/references/setup.md +289 -0
  241. package/skills/guide/references/spec-standard.md +63 -0
  242. package/skills/guide/references/ticket-dependencies.md +59 -0
  243. package/skills/harvest/SKILL.md +66 -0
  244. package/skills/harvest-review/SKILL.md +63 -0
  245. package/skills/implement/SKILL.md +82 -0
  246. package/skills/plan/SKILL.md +123 -0
  247. package/skills/plan-review/SKILL.md +121 -0
  248. package/skills/reconcile/SKILL.md +65 -0
  249. package/skills/spec/SKILL.md +132 -0
  250. package/skills/tickets/SKILL.md +139 -0
  251. package/templates/autobuild.toml +36 -0
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env bun
2
+ /** Private shipped child: one operating-system process per build. */
3
+ import { runBuildChild } from '../packages/core/src/processes/build-child'
4
+ import { BuildChildExitCoordinator } from '../packages/core/src/processes/build-child-exit'
5
+ import { watchBuildParent } from '../packages/core/src/processes/build-parent-watch'
6
+ import { BUILD_RUNNER_OPTIONS_ENV } from '../packages/core/src/ports/workspace/local-build-execution'
7
+ import {
8
+ parseBuildChildLaunch,
9
+ type BuildChildLaunch,
10
+ } from '../packages/core/src/ports/workspace/build-execution'
11
+
12
+ const raw = process.env[BUILD_RUNNER_OPTIONS_ENV]
13
+ let input: BuildChildLaunch | undefined
14
+ try {
15
+ input = parseBuildChildLaunch(raw === undefined ? undefined : JSON.parse(raw))
16
+ } catch {
17
+ // Invalid immutable launch envelope exits below.
18
+ }
19
+ if (input === undefined) process.exit(2)
20
+
21
+ let exitCode = 0
22
+ if (input.supervision.kind === 'local-parent') {
23
+ // Every local exit first transfers group teardown to an owner outside this
24
+ // session. Environment-owned execution deliberately installs neither this
25
+ // group reaper nor a meaningless host-PID watchdog.
26
+ const terminal = new BuildChildExitCoordinator({ groupId: process.pid })
27
+ process.on('SIGINT', () => terminal.terminate(130))
28
+ process.on('SIGTERM', () => terminal.terminate(143))
29
+ terminal.setParentWatch(
30
+ watchBuildParent(input.supervision.parentPid, () => terminal.terminate(143)),
31
+ )
32
+ try {
33
+ await runBuildChild(input, process.env)
34
+ } catch {
35
+ exitCode = 1
36
+ }
37
+ terminal.terminate(exitCode)
38
+ } else {
39
+ // Vercel owns teardown of the complete VM session. Addressing a POSIX group
40
+ // here could leave the SDK believing a still-running environment completed.
41
+ try {
42
+ await runBuildChild(input, process.env)
43
+ } catch {
44
+ exitCode = 1
45
+ }
46
+ process.exit(exitCode)
47
+ }
package/bin/ab-dev.ts ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env bun
2
+ /** Repo-local Bun hot entry. This file is not exposed through package.json#bin. */
3
+ import { runBinary } from '../packages/core/src/cli/binary'
4
+ import { evaluateDevCli, type DevCliState } from '../packages/core/src/cli/dev'
5
+ import { renderDashboard } from '../packages/core/src/cli/dashboard/render'
6
+
7
+ const STATE_KEY = Symbol.for('autobuild.cli.dashboard-dev')
8
+ const globals = globalThis as unknown as Record<symbol, DevCliState | undefined>
9
+ const state = globals[STATE_KEY] ?? {}
10
+ globals[STATE_KEY] = state
11
+
12
+ // Do not top-level-await: Bun must be able to finish evaluating this module and
13
+ // evaluate it again when presentation sources change.
14
+ evaluateDevCli({
15
+ state,
16
+ renderer: renderDashboard,
17
+ launch: (resolveDashboardRenderer) => runBinary(process.argv.slice(2), resolveDashboardRenderer),
18
+ settle: (run) => {
19
+ void run.then(
20
+ (code) => process.exit(code),
21
+ (error: unknown) => {
22
+ console.error(error instanceof Error ? error.message : String(error))
23
+ process.exit(1)
24
+ },
25
+ )
26
+ },
27
+ })
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env bun
2
+ /** Private, shipped child for the interactive `ab dispatch` kernel. It owns no
3
+ * terminal handles; the public command launches it with immutable options. */
4
+ import { abDispatch } from '../packages/core/src/cli/dispatch'
5
+ import {
6
+ DISPATCH_CHILD_OPTIONS_ENV,
7
+ type DispatchChildOptions,
8
+ installDispatchKernelSignalHandlers,
9
+ watchDispatchParent,
10
+ } from '../packages/core/src/cli/dispatch-process'
11
+ import { DISPATCHER } from '../packages/core/src/events/envelope'
12
+ import { spawnExec } from '../packages/core/src/ports/workspace/git-worktree'
13
+ import { resolveRepoState } from '../packages/core/src/cli/repo-state'
14
+ import { openStoreForRepoState } from '../packages/core/src/cli/store-opening'
15
+
16
+ const raw = process.env[DISPATCH_CHILD_OPTIONS_ENV]
17
+ if (raw === undefined) process.exit(2)
18
+ let options: DispatchChildOptions
19
+ try {
20
+ options = JSON.parse(raw) as DispatchChildOptions
21
+ } catch {
22
+ process.exit(2)
23
+ }
24
+
25
+ const stop = new AbortController()
26
+ const requestStop = (): void => stop.abort()
27
+ // Keep both handlers installed through the complete graceful drain. The first
28
+ // targeted SIGINT comes from the supervisor; later foreground-group signals
29
+ // must not regain their default disposition inside an open claim tick.
30
+ const signalHandlers = installDispatchKernelSignalHandlers(requestStop)
31
+ const parentWatch = watchDispatchParent(process.ppid, requestStop)
32
+ let exitCode = 0
33
+
34
+ try {
35
+ await abDispatch({
36
+ targetRepo: options.targetRepo,
37
+ storeRef: options.storeRef,
38
+ env: process.env,
39
+ exec: spawnExec,
40
+ stdout: () => {},
41
+ stderr: () => {},
42
+ once: options.once,
43
+ ...(options.intervalMs !== undefined ? { intervalMs: options.intervalMs } : {}),
44
+ signal: stop.signal,
45
+ plain: true,
46
+ silent: true,
47
+ kernelRunId: options.run,
48
+ })
49
+ } catch (error) {
50
+ exitCode = 1
51
+ // Config/plugin/adapter startup can fail before abDispatch owns a Store and
52
+ // writes run-started. Reopen only the already-resolved Store identity so the
53
+ // terminal frontend receives the actionable failure rather than a generic
54
+ // child exit status.
55
+ try {
56
+ const state = await resolveRepoState({
57
+ targetRepo: options.targetRepo,
58
+ storeRef: options.storeRef,
59
+ exec: spawnExec,
60
+ })
61
+ const opened = openStoreForRepoState(state, { env: process.env })
62
+ try {
63
+ await opened.store.ensureRepo(state.repo)
64
+ const events = await opened.store.getRepoEvents(state.repo)
65
+ if (
66
+ !events.some(
67
+ (event) => event.type === 'dispatcher.run-stopped' && event.payload.run === options.run,
68
+ )
69
+ ) {
70
+ await opened.store.appendRepo(state.repo, {
71
+ actor: DISPATCHER,
72
+ type: 'dispatcher.run-stopped',
73
+ payload: {
74
+ run: options.run,
75
+ outcome: 'abnormal',
76
+ exitCode: 1,
77
+ error: error instanceof Error ? error.message : String(error),
78
+ },
79
+ })
80
+ }
81
+ } finally {
82
+ await opened.store.close()
83
+ }
84
+ } catch {
85
+ // The supervisor still records the process exit if even the Store cannot
86
+ // be opened. Preserve the original startup failure as the exit cause.
87
+ }
88
+ } finally {
89
+ parentWatch.close()
90
+ signalHandlers.close()
91
+ }
92
+ process.exit(exitCode)
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env bun
2
+ /** Private shipped child: one disposable environment per hosted harvest run.
3
+ * The environment owns teardown (no process-group reaper, no parent watchdog)
4
+ * — the same contract as the build child's `environment` branch. */
5
+ import { runHarvestChild } from '../packages/core/src/processes/harvest-child'
6
+ import {
7
+ HARVEST_RUNNER_OPTIONS_ENV,
8
+ parseHarvestRunnerLaunch,
9
+ type HarvestRunnerLaunch,
10
+ } from '../packages/core/src/ports/workspace/harvest-execution'
11
+
12
+ const raw = process.env[HARVEST_RUNNER_OPTIONS_ENV]
13
+ let input: HarvestRunnerLaunch | undefined
14
+ try {
15
+ input = parseHarvestRunnerLaunch(raw === undefined ? undefined : JSON.parse(raw))
16
+ } catch {
17
+ // Invalid immutable launch envelope exits below.
18
+ }
19
+ if (input === undefined) process.exit(2)
20
+
21
+ let exitCode = 0
22
+ try {
23
+ await runHarvestChild(input, process.env)
24
+ } catch {
25
+ // The durable outcome lives in the repository journal; the guest exit code
26
+ // is liveness evidence only.
27
+ exitCode = 1
28
+ }
29
+ process.exit(exitCode)
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env bun
2
+ /** Private shipped child used only inside a disposable readiness workspace. */
3
+ import { INIT_PROBE_MARKER, runGuestReadinessProbe } from '../packages/core/src/cli/init-validation'
4
+
5
+ try {
6
+ const report = await runGuestReadinessProbe({ repo: process.cwd(), env: process.env })
7
+ console.log(`${INIT_PROBE_MARKER}${JSON.stringify(report)}`)
8
+ // A complete report is transport success even when one readiness check fails;
9
+ // the host owns the user-facing nonzero status.
10
+ process.exit(0)
11
+ } catch (error) {
12
+ const detail = error instanceof Error ? error.message : String(error)
13
+ console.log(
14
+ `${INIT_PROBE_MARKER}${JSON.stringify({ checks: [{ name: 'readiness probe', status: 'fail', detail }] })}`,
15
+ )
16
+ // Emitting the structured marker is transport success. The host turns its
17
+ // failing check into the command's user-facing nonzero result.
18
+ process.exit(0)
19
+ }
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env bun
2
+ /** Private shipped helper: reap one abandoned local build process group. */
3
+ import { terminateProcessGroup } from '../packages/core/src/processes/process-group'
4
+ import {
5
+ PROCESS_GROUP_REAPER_OPTIONS_ENV,
6
+ type ProcessGroupReaperOptions,
7
+ } from '../packages/core/src/processes/process-group-reaper'
8
+
9
+ const raw = process.env[PROCESS_GROUP_REAPER_OPTIONS_ENV]
10
+ let options: ProcessGroupReaperOptions | undefined
11
+ try {
12
+ const parsed =
13
+ raw === undefined ? undefined : (JSON.parse(raw) as Partial<ProcessGroupReaperOptions>)
14
+ if (
15
+ parsed !== undefined &&
16
+ Number.isSafeInteger(parsed.groupId) &&
17
+ parsed.groupId! > 0 &&
18
+ Number.isFinite(parsed.stopTimeoutMs) &&
19
+ parsed.stopTimeoutMs! >= 0
20
+ ) {
21
+ options = parsed as ProcessGroupReaperOptions
22
+ }
23
+ } catch {
24
+ // Invalid immutable launch envelope exits below.
25
+ }
26
+ if (options === undefined) process.exit(2)
27
+
28
+ try {
29
+ await terminateProcessGroup(options.groupId, options.stopTimeoutMs)
30
+ } catch {
31
+ process.exit(1)
32
+ }
package/bin/ab.ts ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bun
2
+ /** Published `ab` entry: unconditional production wiring, with no watcher or
3
+ * dev-state branch. The repo-local hot entry lives separately in ab-dev.ts. */
4
+ import { runBinary } from '../packages/core/src/cli/binary'
5
+
6
+ process.exit(await runBinary(process.argv.slice(2)))
package/bin/agent/ab ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bun
2
+ /** Agent-session launcher: delegate to the distribution's canonical CLI entry. */
3
+ import '../ab.ts'
@@ -0,0 +1,89 @@
1
+ # Answering blocked builds
2
+
3
+ A build is **blocked** while one or more escalations are open. Inspect them with
4
+ `ab build status <slug>`, then choose the resolution that matches the problem.
5
+ Every action below is sessionless, records a human-authored fact, and accepts
6
+ `--store <ref>`.
7
+
8
+ | Need | Command | Effect |
9
+ |---|---|---|
10
+ | Give the phase a decision or missing information | `ab answer <slug> <text>` | Records `guidance`. In a review loop it feeds the next producer round. |
11
+ | Try again without guidance | `ab answer <slug>` | Records a bare `retry`; no prose is delivered to an agent. |
12
+ | Widen an exhausted review loop | `ab answer <slug> [<text>] --review-round-ceiling <n>` | Answers the open `review-round-limit` escalation and replaces the configured cap with absolute ceiling `n` for that loop and spec revision only. |
13
+ | Retire a review disagreement | `ab answer <slug> --dismiss` | Records `dismiss-finding` for each escalation that cites a real finding id. The next reviewer is told not to re-raise that chain. |
14
+ | Replace the build contract from a file | `ab answer <slug> --revise-spec <file>` | Records the replacement as the next spec revision and restarts at `plan`. |
15
+ | Re-import an amended ticket | `ab answer <slug> --revise-spec-from-ticket` | Reads the build's recorded ticket and performs the same revision. |
16
+ | Abandon the build | `ab abort <slug>` | Irrevocably requests abort; cleanup returns the ticket to Triage. |
17
+
18
+ The dashboard's blocked-build `r` shortcut requests an inline answer step that
19
+ supports guidance and a blank retry. While that step is open, it is exclusive
20
+ to the selected row: the row exposes only **SUBMIT** and **CANCEL**. Its ordinary
21
+ **RESUME**, **ABORT**, auto-merge, and detail controls are unavailable, and the
22
+ `r` and `a` row shortcuts do not trigger them (those letters remain ordinary
23
+ text while typing in the guidance field).
24
+
25
+ A successful submit records the trimmed guidance, or a bare retry for blank
26
+ input, resumes through the normal answer lifecycle, and closes the local step.
27
+ **CANCEL** or Esc closes it without writing and preserves both the selected
28
+ build and whether its detail was open. A later **RESUME** can request a fresh,
29
+ empty answer step. A later **ABORT** first replaces the row controls with local
30
+ **CONFIRM ABORT** and **CANCEL** confirmation; no durable abort occurs until it
31
+ is confirmed.
32
+
33
+ Controls on unrelated rows retain their established target-aware behavior.
34
+ Activating one leaves the old answer mode, selects that row, and performs its
35
+ normal action. The selected build's full detail names the CLI-only dismissal
36
+ and revision commands; it does not provide a spec editor.
37
+
38
+ Restarting `ab dispatch` or running `ab dispatch --once` is not an answer or a
39
+ retry action. Every open escalation, including every policy and setup cause,
40
+ survives dispatcher startup until a human uses one of the paths above. Startup
41
+ still recovers unblocked work and acknowledges pending operator commands.
42
+
43
+ ## Widening an exhausted review loop
44
+
45
+ `--review-round-ceiling` is available only while the selected build has one open
46
+ `review-round-limit` policy escalation. The positive integer is an absolute
47
+ ceiling, not an increment: setting 12 again leaves the cap at 12. The answer and
48
+ override are one durable human-authored event, so no dispatcher restart is
49
+ needed and replay preserves the value.
50
+
51
+ The escalation's phase selects the plan or code loop. The other loop and every
52
+ other build keep the configured `maxReviewRounds`; `spec.revised` clears both
53
+ loop overrides. The stall threshold still applies before the widened round cap.
54
+ A ceiling cannot be supplied pre-emptively, as a standalone control, or together
55
+ with `--revise-spec`/`--revise-spec-from-ticket` because revision resets the
56
+ round budget itself. Current overrides appear in `ab build status` and on the
57
+ dashboard.
58
+
59
+ ## Dismissing findings
60
+
61
+ Dismissal is evaluated per escalation. A blocker that cites no real
62
+ plan-review or code-review finding remains open, even when another blocker is
63
+ dismissed. Answer the remainder with guidance or a blank retry. Dismissal
64
+ settles only the cited chain: a reviewer can still report a genuinely different
65
+ problem in the same file under a new finding id.
66
+
67
+ ## Revising the spec
68
+
69
+ Revision requires an open escalation because the spec is the contract against
70
+ which every downstream approval is measured. The replacement must satisfy the
71
+ same spec-standard quality gate used at dispatch; a non-conforming body is
72
+ rejected before an artifact or event is recorded, leaving the build blocked on
73
+ its current revision.
74
+
75
+ A successful answer records a human `escalation.answered` fact naming the exact
76
+ replacement artifact, followed by kernel `spec.revised`. The build re-plans and
77
+ pre-revision reviews, verification, and finalize completion do not satisfy the
78
+ new run. Historical phase runs remain pinned to the revision they saw. An
79
+ already-open pull request is retained and updated rather than duplicated.
80
+
81
+ The two events make interrupted work safely resumable. If the answer was
82
+ recorded but `spec.revised` was not, a repeated revision command publishes the
83
+ body named by that earlier answer; it does not read or authorize a newly
84
+ supplied file or ticket body.
85
+
86
+ A build that has already become terminal cannot restart. This includes the
87
+ short windows where its PR has merged or closed and completion is underway, or
88
+ where an abort request is pending. Abort is irrevocable; after cleanup, dispatch
89
+ the returned ticket as a fresh build if work should continue.