@defrex/autobuild 0.8.0 → 0.9.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.
- package/README.md +1 -1
- package/SPEC.md +313 -26
- package/bin/ab-build-runner.ts +8 -2
- package/docs/architecture.md +57 -14
- package/docs/assets/headline-wide.png +0 -0
- package/docs/configuration.md +151 -25
- package/docs/hosted-dispatcher.md +69 -13
- package/docs/operator-api.md +2 -2
- package/docs/remote-store-protocol.md +169 -16
- package/docs/remote-ticket-protocol.md +1 -1
- package/docs/setup.md +12 -9
- package/docs/website.md +10 -0
- package/package.json +43 -23
- package/packages/core/src/cli/artifact.ts +130 -6
- package/packages/core/src/cli/binary.ts +9 -1
- package/packages/core/src/cli/build-control.ts +110 -13
- package/packages/core/src/cli/context.ts +46 -0
- package/packages/core/src/cli/dashboard/model.ts +57 -7
- package/packages/core/src/cli/dashboard/poll.ts +69 -10
- package/packages/core/src/cli/dashboard/render.ts +34 -5
- package/packages/core/src/cli/dispatch-frontend.ts +54 -5
- package/packages/core/src/cli/dispatch.ts +320 -46
- package/packages/core/src/cli/harvest.ts +122 -8
- package/packages/core/src/cli/help.ts +47 -8
- package/packages/core/src/cli/init-readiness-remote.ts +110 -0
- package/packages/core/src/cli/init-readiness-shared.ts +72 -0
- package/packages/core/src/cli/init-validation.ts +248 -222
- package/packages/core/src/cli/main.ts +70 -11
- package/packages/core/src/cli/mcp.ts +23 -1
- package/packages/core/src/cli/plugin.ts +7 -4
- package/packages/core/src/cli/remote-poll.ts +277 -0
- package/packages/core/src/cli/repo-state.ts +22 -0
- package/packages/core/src/cli/repository-status.ts +39 -1
- package/packages/core/src/cli/status.ts +149 -27
- package/packages/core/src/cli/terminals.ts +2 -1
- package/packages/core/src/cli/ticket-assets.ts +247 -0
- package/packages/core/src/cli/ticket.ts +307 -7
- package/packages/core/src/cli/wait.ts +147 -39
- package/packages/core/src/cli/watch.ts +128 -166
- package/packages/core/src/config/live.ts +22 -0
- package/packages/core/src/config/pipeline-source.ts +376 -0
- package/packages/core/src/config/schema.ts +230 -19
- package/packages/core/src/events/catalog.ts +1 -0
- package/packages/core/src/events/globs.ts +47 -0
- package/packages/core/src/events/payloads.ts +52 -2
- package/packages/core/src/events/repository.ts +52 -1
- package/packages/core/src/events/sessions.ts +69 -10
- package/packages/core/src/events/workspace-remote.ts +12 -0
- package/packages/core/src/integration/harness.ts +2 -1
- package/packages/core/src/kernel/auto-merge-default.ts +123 -0
- package/packages/core/src/kernel/phases.ts +16 -2
- package/packages/core/src/kernel/reducer.ts +40 -1
- package/packages/core/src/operator/annotations.ts +6 -0
- package/packages/core/src/operator/control.ts +19 -5
- package/packages/core/src/operator/index.ts +71 -6
- package/packages/core/src/operator/query.ts +208 -19
- package/packages/core/src/operator/registry.ts +55 -10
- package/packages/core/src/operator/requests.ts +9 -6
- package/packages/core/src/operator/sandbox-host.ts +140 -0
- package/packages/core/src/operator/sandbox.ts +247 -14
- package/packages/core/src/operator/ticket-source-backend.ts +47 -0
- package/packages/core/src/orchestrator/approvals.ts +115 -0
- package/packages/core/src/orchestrator/conversation.ts +167 -0
- package/packages/core/src/orchestrator/model.ts +86 -0
- package/packages/core/src/orchestrator/prompt.ts +61 -0
- package/packages/core/src/orchestrator/tools.ts +117 -0
- package/packages/core/src/orchestrator/turn-runner.ts +457 -0
- package/packages/core/src/plugin-sdk/index.ts +51 -1
- package/packages/core/src/plugins/load.ts +135 -7
- package/packages/core/src/plugins/manifest.ts +183 -10
- package/packages/core/src/plugins/registry.ts +73 -4
- package/packages/core/src/ports/forge/create.ts +1 -1
- package/packages/core/src/ports/forge/fake.ts +31 -0
- package/packages/core/src/ports/forge/github-transport.ts +13 -2
- package/packages/core/src/ports/forge/github.ts +13 -2
- package/packages/core/src/ports/forge/local-git.ts +31 -1
- package/packages/core/src/ports/runner/claude.ts +2 -2
- package/packages/core/src/ports/runner/codex.ts +6 -2
- package/packages/core/src/ports/runner/fake.ts +7 -1
- package/packages/core/src/ports/runner/pi.ts +8 -6
- package/packages/core/src/ports/runner/provider-error.ts +13 -3
- package/packages/core/src/ports/tickets/{remote-index.ts → hosted-index.ts} +3 -2
- package/packages/core/src/ports/types.ts +17 -2
- package/packages/core/src/ports/workspace/builtin-capabilities.ts +114 -0
- package/packages/core/src/ports/workspace/create.ts +74 -39
- package/packages/core/src/ports/workspace/distribution-archive.ts +171 -12
- package/packages/core/src/ports/workspace/fake.ts +169 -4
- package/packages/core/src/ports/workspace/git-worktree.ts +246 -26
- package/packages/core/src/ports/workspace/github-origin.ts +36 -0
- package/packages/core/src/ports/workspace/operator-sandbox.ts +7 -1
- package/packages/core/src/ports/workspace/provider-capabilities.ts +171 -0
- package/packages/core/src/ports/workspace/vercel-capabilities.ts +110 -0
- package/packages/core/src/ports/workspace/vercel-sandbox.ts +142 -114
- package/packages/core/src/processes/build-child.ts +17 -2
- package/packages/core/src/processes/build-execution-state.ts +37 -0
- package/packages/core/src/processes/build-runner.ts +54 -3
- package/packages/core/src/processes/dispatcher.ts +247 -41
- package/packages/core/src/processes/harvest-child.ts +5 -0
- package/packages/core/src/processes/harvest-runner.ts +66 -19
- package/packages/core/src/processes/harvest.ts +196 -24
- package/packages/core/src/processes/orchestrator-tick.ts +319 -0
- package/packages/core/src/processes/sandbox-state.ts +10 -0
- package/packages/core/src/store/adapter.ts +32 -0
- package/packages/core/src/store/build-scope.ts +64 -0
- package/packages/core/src/store/contract.ts +868 -0
- package/packages/core/src/store/digest.ts +49 -0
- package/packages/core/src/store/local/schema.ts +29 -2
- package/packages/core/src/store/local/store.ts +338 -4
- package/packages/core/src/store/memory.ts +179 -0
- package/packages/core/src/store/new-build.ts +17 -0
- package/packages/core/src/store/phase-session.ts +71 -0
- package/packages/core/src/store/remote/client.ts +260 -1
- package/packages/core/src/store/remote/index.ts +12 -2
- package/packages/core/src/store/remote/protocol.ts +100 -12
- package/packages/core/src/store/remote/version.ts +6 -2
- package/packages/core/src/store/repo-state-events.ts +140 -0
- package/packages/core/src/store/retention.ts +7 -0
- package/packages/core/src/store/session-handle.ts +64 -0
- package/packages/core/src/{sessions/reducer.ts → store/session-reducer.ts} +28 -9
- package/packages/core/src/store/streams/session-writer.ts +42 -2
- package/packages/core/src/store/streams/wait.ts +4 -5
- package/packages/core/src/store/ticket-assets.ts +425 -0
- package/packages/core/src/store/types.ts +122 -1
- package/packages/core/src/testing/index.ts +59 -0
- package/skills/code-review/SKILL.md +5 -1
- package/skills/guide/SKILL.md +126 -33
- package/skills/guide/references/operator-api.md +2 -2
- package/skills/guide/references/plugin-authoring.md +17 -0
- package/skills/guide/references/remote-store-protocol.md +169 -16
- package/skills/guide/references/remote-ticket-protocol.md +1 -1
- package/skills/guide/references/setup.md +12 -9
- package/skills/implement/SKILL.md +3 -0
- package/skills/operate/SKILL.md +126 -0
- package/skills/plan/SKILL.md +4 -0
- package/skills/plan-review/SKILL.md +5 -1
- package/skills/spec/SKILL.md +46 -3
- package/packages/core/src/cli/dashboard/frame-image.ts +0 -373
- package/packages/core/src/cli/store-opening.contract.ts +0 -289
- package/packages/core/src/cli/testkit.ts +0 -194
- package/packages/core/src/markdown.ts +0 -67
- package/packages/core/src/operator/client.ts +0 -311
- package/packages/core/src/operator/server.ts +0 -616
- package/packages/core/src/operator/sessions.ts +0 -223
- package/packages/core/src/ports/runner/live-contract-fixture.ts +0 -176
- package/packages/core/src/ports/tickets/remote-server.ts +0 -185
- package/packages/core/src/store/remote/server.ts +0 -923
- package/packages/core/src/testing/store-failures.ts +0 -32
package/docs/architecture.md
CHANGED
|
@@ -54,7 +54,15 @@ Git installation never requires a separately published core package.
|
|
|
54
54
|
`packages/core` owns the CLI, kernel, adapters, shared types, dashboard
|
|
55
55
|
projection, plugin SDK, and reusable contract suites. The optional
|
|
56
56
|
`packages/hosted-store-service` workspace composes the public remote-server
|
|
57
|
-
surface with `packages/postgres-store`;
|
|
57
|
+
surface with `packages/postgres-store`; the separate optional
|
|
58
|
+
`packages/hosted-dispatcher` workspace owns the cron-driven hosted dispatcher
|
|
59
|
+
(the `/api/dispatch` route driver, the deploy-time `pack-distribution` command,
|
|
60
|
+
and the packed-distribution trace helper) and peers on both the core and the
|
|
61
|
+
store service. The optional `packages/vercel-sandbox` workspace publishes the
|
|
62
|
+
`@defrex/autobuild-vercel-sandbox` provider plugin (AUT-517): while the
|
|
63
|
+
builtin hosts the implementation, its manifest re-registers the provider name
|
|
64
|
+
over the shared capability object and the loader skips it with a notice.
|
|
65
|
+
Neither optional package enters an ordinary CLI
|
|
58
66
|
installation's runtime dependency closure. `tools/` is repository-only
|
|
59
67
|
maintainer tooling. All workspace manifests share one version because the
|
|
60
68
|
remote-store protocol requires matching client and server versions.
|
|
@@ -68,16 +76,19 @@ remote-store protocol requires matching client and server versions.
|
|
|
68
76
|
| `packages/core/src/ontology.ts` | The shared nouns — findings, verdicts, phases, refs, the canonical verify outcome | §4 |
|
|
69
77
|
| `packages/core/src/events/` | Separate build, repository, and operator-session envelopes/catalogs, frozen payload schemas, actor validation, the `via` attribution marker | §15 |
|
|
70
78
|
| `packages/core/src/harvest/` | Structured occurrence, scan packet, proposal, and ledger schemas | §12 |
|
|
71
|
-
| `packages/core/src/
|
|
79
|
+
| `packages/core/src/store/session-reducer.ts` | The operator-session reducer: status, open turn, pending approval, wake settings and cursors, and the turn list, reduced purely from the session event log | §7.1.1 |
|
|
80
|
+
| `packages/core/src/orchestrator/` | The embedded orchestrator's turn runner: the canonical-skill system prompt, durable conversation reconstruction, registry entries as AI SDK tools with the session's repository injected, gateway model resolution with the typed failure vocabulary, the approval-list configuration, and the CAS-guarded start/resume loop with budget suspension and step-boundary checkpoints | §7.1.2 |
|
|
72
81
|
| `packages/core/src/store/` | BuildStore contract spanning builds, the repository journal, and operator sessions; interface-enforced build, operator-session, and local ambient-session scope wrappers; memory, SQLite/blob, and remote HTTP adapters | §7 |
|
|
73
82
|
| `packages/core/src/store/streams/` | The stream primitive's shared core (§7.6): record/chunk types and the `ai-ui-message-stream/v1` constants, SDK-backed close-time `UIMessage[]` assembly, and the uniform bounded-wait read loop | §7.6 |
|
|
74
|
-
| `packages/hosted-store-service/` | Environment-only hosted Fetch handler, lazy PostgreSQL/blob composition, offline token binary, tests, and deployment guide | §7.2, §18 |
|
|
75
|
-
| `
|
|
83
|
+
| `packages/hosted-store-service/` | Environment-only hosted Fetch handler, lazy PostgreSQL/blob composition, offline token binary, the Next.js operator web app (`app/`, `server.ts`, `next.config.ts`, `vercel.json`), tests, and deployment guide | §7.2, §18 |
|
|
84
|
+
| `packages/hosted-dispatcher/` | The optional cron-driven hosted dispatcher: endpoint driver, deploy-time `pack-distribution` binary, packed-distribution trace helper, tests, and operator guide | §7.2, §12, §18 |
|
|
85
|
+
| `packages/vercel-sandbox/` | Published `@defrex/autobuild-vercel-sandbox` provider plugin: transitional manifest over the shared capability object with a guarded factory (implementation stays builtin-hosted until AUT-505) | §3.2.1 |
|
|
86
|
+
| `packages/hosted-store-service/server.ts`, `packages/hosted-store-service/vercel.json` | One host-neutral Bun listener used locally and by Vercel's Bun preset | §7.2 |
|
|
76
87
|
| `packages/core/src/kernel/` | Phase table, build reducer, engine; pure harvest, dispatcher-settings, dispatcher-status, and PR-attachment selectors; converge, stall detection, verify gating | §5, §7.5, §10, §12, §14, §15.4–15.5 |
|
|
77
88
|
| `packages/core/src/ports/` | TicketSource / Workspace / Forge / AgentRunner / Telemetry interfaces, adapters, and fakes; registry-aware builtin/plugin construction; eager primary/alternate runtime routing and provider-failure classification under `ports/runner/` | §3.2, §9, §13 |
|
|
78
89
|
| `packages/core/src/plugins/` | Strict versioned plugin manifests, dual-root repository/package Bun loading, owner-aware adapter registration, contract/credential metadata, and runtime-factory materialization | §3.2.1, §9 |
|
|
79
90
|
| `packages/core/src/plugin-sdk/` | The sole supported `@defrex/autobuild/plugin-sdk` barrel: port/manifest types, contract suites, and reference fakes | §3.2.1 |
|
|
80
|
-
| `packages/core/src/processes/` | build-runner and standalone child composition, durable execution config/diagnostics, dispatcher (+ janitor duty and
|
|
91
|
+
| `packages/core/src/processes/` | build-runner and standalone child composition, durable execution config/diagnostics, dispatcher (+ janitor duty, harvest trigger, and the last-step orchestrator resume/reap/wake pass, origin-mode-gated), orchestrator tick step, harvest deterministic core + runner | §3.3, §7.1.2, §12, §15.7 |
|
|
81
92
|
| `packages/core/src/cli/` and `bin/` | The `ab` CLI — the only agent↔store channel — plus the shared presentation-only durable-progress projection, init/upgrade, the Store-only dispatch frontend, its private supervised kernel entry, and `bin/ab-build-runner.ts` (one child per build) | §8, §14, §16.3 |
|
|
82
93
|
| `packages/core/src/cli/dashboard/` | `ab dispatch`'s fixed live frame: pure projection, renderer, poll cache, and deterministic image renderer | §14 |
|
|
83
94
|
| `bin/agent/ab` | Private launcher placed first on agent-session `PATH`; delegates to the canonical `bin/ab.ts` | §8.1 |
|
|
@@ -92,10 +103,15 @@ remote-store protocol requires matching client and server versions.
|
|
|
92
103
|
## Key boundaries
|
|
93
104
|
|
|
94
105
|
**Hosted store service.** `@defrex/autobuild/remote-store` is the supported protocol
|
|
95
|
-
|
|
106
|
+
export for the remote store's client half, wire schemas, and token minting; the
|
|
107
|
+
protocol servers (the remote BuildStore HTTP server, the operator API server,
|
|
108
|
+
and the hosted ticket-source server) ship in
|
|
109
|
+
`@defrex/autobuild-hosted-store-service`, which builds against core's
|
|
110
|
+
`remote-store`, `operator`, and `hosted-tickets` subpaths only. The hosted
|
|
111
|
+
workspace validates its environment,
|
|
96
112
|
serves health without touching persistence, and lazily retains one
|
|
97
113
|
`openPostgresBuildStoreFromEnv` promise per warm process. Its Fetch handler has
|
|
98
|
-
no Vercel branch;
|
|
114
|
+
no Vercel branch; the package's `server.ts` is the sole `Bun.serve()` composition point.
|
|
99
115
|
The fixed 1 MiB decoded artifact policy is enforced before backing mutation.
|
|
100
116
|
The `ab-hosted-store` binary signs admin or build/session tokens offline from
|
|
101
117
|
`AB_STORE_SECRET`; the running service exposes no mint endpoint. Machine routes
|
|
@@ -110,7 +126,7 @@ and `packages/core/src/events/sessions.ts`
|
|
|
110
126
|
are the frozen catalogs; every write passes `validateEventWrite` /
|
|
111
127
|
`validateRepositoryEventWrite` / `validateSessionEventWrite`. `packages/core/src/kernel/reducer.ts` derives all build
|
|
112
128
|
status; `packages/core/src/kernel/harvest.ts` and `packages/core/src/kernel/dispatch-settings.ts` reduce
|
|
113
|
-
the repository journal independently of each other; `packages/core/src/
|
|
129
|
+
the repository journal independently of each other; `packages/core/src/store/session-reducer.ts` reduces an operator
|
|
114
130
|
session's status, open turn, pending approval, and wake cursors from its own
|
|
115
131
|
closed catalog. No decision anywhere
|
|
116
132
|
consults a snapshot in place of the append-only log.
|
|
@@ -503,9 +519,16 @@ It follows one dispatch run's repository facts incrementally through
|
|
|
503
519
|
`packages/core/src/kernel/dispatch-status.ts`, retaining only low-volume settings/Harvest
|
|
504
520
|
facts for their replay reducers, validates/caches its effective-config artifact,
|
|
505
521
|
and polls build streams independently while elapsed paints continue from cached
|
|
506
|
-
intervals. The same polling path
|
|
507
|
-
|
|
508
|
-
|
|
522
|
+
intervals. The same polling path samples the header's current count from build
|
|
523
|
+
digests plus the repository journal — one journal read plus one repo-scoped
|
|
524
|
+
digest read, plus a journal-record probe — paired with the effective config's
|
|
525
|
+
`policy.harvestThreshold`. A journal record that does not yet exist reads as an
|
|
526
|
+
empty journal: the sample, the operator query, the dispatcher's
|
|
527
|
+
repository-wide journal reads (controls, settlement stages, and ready
|
|
528
|
+
scans), and the operator sandbox service's journal reads all go through
|
|
529
|
+
the same shared missing-record journal read (the AUT-524 helper in
|
|
530
|
+
`packages/core/src/processes/harvest.ts`), which writes nothing (no
|
|
531
|
+
`ensureRepo` from a display path). That sample
|
|
509
532
|
is process-local presentation state: a failed refresh preserves the last
|
|
510
533
|
successful value and adds a local diagnostic, while an initial failure delays
|
|
511
534
|
the complete frame rather than inventing zero. No repository fact transports
|
|
@@ -579,8 +602,8 @@ bun typecheck # tsc --noEmit
|
|
|
579
602
|
For dashboard presentation work, run the repository-only hot CLI:
|
|
580
603
|
|
|
581
604
|
```sh
|
|
582
|
-
bun run dev -- dispatch
|
|
583
|
-
# Generic form: bun run dev -- <ab arguments>
|
|
605
|
+
bun run dev:cli -- dispatch
|
|
606
|
+
# Generic form: bun run dev:cli -- <ab arguments>
|
|
584
607
|
```
|
|
585
608
|
|
|
586
609
|
Bun keeps the original CLI promise and its `DispatchLoop` alive while hot
|
|
@@ -596,7 +619,7 @@ installed `ab` binary remains the non-watching production entry.
|
|
|
596
619
|
The seams are the contract. Five reusable contract families run the same
|
|
597
620
|
behavioral assertions against every implementation:
|
|
598
621
|
|
|
599
|
-
- `packages/core/src/store/contract.ts` — `BuildStore` and `BlobStore`, including the streams block (§7.6) every adapter runs;
|
|
622
|
+
- `packages/core/src/store/contract.ts` — `BuildStore` and `BlobStore`, including the streams block (§7.6) and the ticket-asset block (§7.1.3) every adapter runs;
|
|
600
623
|
- `packages/core/src/ports/tickets/contract.ts` — `TicketSource`;
|
|
601
624
|
- `packages/core/src/ports/workspace/contract.ts` — `WorkspaceProvider`;
|
|
602
625
|
- `packages/core/src/ports/forge/contract.ts` — `Forge`, including idempotent PR close and
|
|
@@ -618,6 +641,19 @@ A normal `bun test` runs the memory/fake/local registrations, including a fake
|
|
|
618
641
|
selected through the plugin ticket-source registry, the real filesystem and
|
|
619
642
|
local-git adapters, the injected Claude and Codex CLI subprocess contracts,
|
|
620
643
|
and the injected Pi CLI/RPC contract.
|
|
644
|
+
Ticket assets (SPEC §7.1.3) are files attached to a ticket and kept in the
|
|
645
|
+
BuildStore, never in the ticket source. `packages/core/src/store/ticket-assets.ts`
|
|
646
|
+
holds the types, the limits, and the one validator every adapter calls;
|
|
647
|
+
`packages/core/src/cli/ticket-assets.ts` holds the filesystem walk, the download
|
|
648
|
+
writer, and the note builder; `ab ticket attach`, `asset get`, and `asset rm`
|
|
649
|
+
live in `packages/core/src/cli/ticket.ts`. The only thing a ticket source sees is
|
|
650
|
+
a note through `comment()`, so no source or plugin protocol changed.
|
|
651
|
+
A claim freezes the ticket's current assets into the build (SPEC §6.3):
|
|
652
|
+
`build.created.assets` (and, when a spec is revised from the ticket,
|
|
653
|
+
`spec.revised.assets`) record the pinned revisions, `state.pinnedAssets` in the
|
|
654
|
+
reducer projects them, `getPinnedTicketAsset` reads them back by pinned revision,
|
|
655
|
+
and `ab context` writes them under `.ab/assets/`.
|
|
656
|
+
|
|
621
657
|
Both `ab dispatch` and sessionless `ab ticket` load the repository's plugins
|
|
622
658
|
before selecting their TicketSource; dispatch passes that one adapter instance
|
|
623
659
|
through readiness, dependency, harvest, and completion paths. The Linear,
|
|
@@ -626,6 +662,13 @@ but reported as skipped: live provider access requires credentials/resources
|
|
|
626
662
|
and an explicit opt-in. When
|
|
627
663
|
adding an adapter, start from its contract suite, not only the interface.
|
|
628
664
|
|
|
665
|
+
The two remote clients get client-only unit coverage in core itself:
|
|
666
|
+
`RemoteBuildStore` (`store/remote/client.test.ts`, which also pins scoped-token
|
|
667
|
+
minting/verification) and `HostedTicketSource` (`ports/tickets/remote.test.ts`)
|
|
668
|
+
run against an injected `fetchFn` with responses built from the protocol's wire
|
|
669
|
+
schemas. The full over-the-wire seam suites (client → HTTP → server) run in
|
|
670
|
+
`packages/hosted-store-service` in the same `bun test`.
|
|
671
|
+
|
|
629
672
|
To run the Linear contract manually against a destructive scratch target:
|
|
630
673
|
|
|
631
674
|
```sh
|
|
Binary file
|
package/docs/configuration.md
CHANGED
|
@@ -23,7 +23,11 @@ environment. They are published to npm as separate packages alongside the
|
|
|
23
23
|
PostgreSQL, or blob-provider dependencies; a project that embeds the adapter
|
|
24
24
|
or the service adds the package it needs (`bun add
|
|
25
25
|
@defrex/autobuild-postgres-store` or `bun add
|
|
26
|
-
@defrex/autobuild-hosted-store-service`). The
|
|
26
|
+
@defrex/autobuild-hosted-store-service`). The cron-driven hosted dispatcher is
|
|
27
|
+
separately published as `@defrex/autobuild-hosted-dispatcher`; a deployment
|
|
28
|
+
opts into building by installing that package, and its `AB_DISPATCHER_*`
|
|
29
|
+
variables are documented in the [hosted-dispatcher runbook](hosted-dispatcher.md),
|
|
30
|
+
not here. The deployable web application still
|
|
27
31
|
runs from a release checkout: choose the compatible tag shown in
|
|
28
32
|
[GitHub Releases](https://github.com/defrex/autobuild/releases), clone that exact
|
|
29
33
|
revision into a dedicated checkout, and run the idempotent migration there:
|
|
@@ -37,7 +41,9 @@ DATABASE_URL=postgres://… bun run postgres:migrate
|
|
|
37
41
|
|
|
38
42
|
Replace `v0.6.0` with the selected release tag. Schema diagnostics' root
|
|
39
43
|
`postgres:migrate` script is relative to that pinned checkout. A hosted build
|
|
40
|
-
can run the same step itself: `bun run deploy:build`
|
|
44
|
+
can run the same step itself: `bun run deploy:build` — run from the hosted
|
|
45
|
+
store service package directory (`packages/hosted-store-service`), the Next.js
|
|
46
|
+
project directory — migrates against the
|
|
41
47
|
deployment's database URL, logs the host it prepared, and then builds the web
|
|
42
48
|
application, failing the build when no database URL is configured or the
|
|
43
49
|
schema is incompatible. The database
|
|
@@ -146,6 +152,33 @@ snapshot. Raising capacity can fill the new slots immediately; lowering it
|
|
|
146
152
|
prevents new claims without terminating builds already above the limit. `ab
|
|
147
153
|
dispatch --once` performs one pass and does not watch or reload.
|
|
148
154
|
|
|
155
|
+
The sections `autobuild.toml` delivers to a build fall into three ownership
|
|
156
|
+
classes. **Build-owned** sections define the pipeline a build runs — `[verify]`
|
|
157
|
+
with `[verify.<step>]`, `[finalize]` with `[finalize.<step>]`, `[commands]`,
|
|
158
|
+
and `[workspace]` (provider and config, including `provisioning` and
|
|
159
|
+
`runtimeProvisioning`). They are pinned to the build's own branch: the
|
|
160
|
+
dispatcher reads them at the build's recorded base commit, or at its branch
|
|
161
|
+
head once the build has published commits, and records the exact commit in the
|
|
162
|
+
effective-config artifact metadata. In checkout mode the worktree read is the
|
|
163
|
+
exception: when it cannot be attributed to the branch-head commit — because
|
|
164
|
+
the worktree file has uncommitted edits, because the clean/dirty comparison
|
|
165
|
+
could not be performed (non-git workspace or a transient git error), or because
|
|
166
|
+
the branch head never carried the file — the deposit records the source
|
|
167
|
+
`worktree-dirty` with no commit. The build still runs the worktree bytes, but
|
|
168
|
+
provenance declines to attribute them to any commit. **Deployment-owned** sections — `[roles]`
|
|
169
|
+
(runtime, model, args, alternates, per-role `sessionBudgetSeconds`) and
|
|
170
|
+
`[policy]` — keep flowing live. **Dispatcher-owned** sections (`baseBranch`,
|
|
171
|
+
`capacity`, `forge`, `plugins`, `pr`, `tickets`, `orchestrator`) configure the
|
|
172
|
+
dispatcher itself and are never interpreted by the build runner.
|
|
173
|
+
|
|
174
|
+
Consequently, an accepted base-branch reload re-deposits only the
|
|
175
|
+
deployment-owned sections to active builds; it does not retarget an in-flight
|
|
176
|
+
build's verify universe, finalize steps, commands, or provisioning. A build
|
|
177
|
+
that publishes a pipeline change to its own branch picks it up at its next
|
|
178
|
+
launch, so config changes still flow through the pipeline for the build that
|
|
179
|
+
carries them. In-flight environments are never re-provisioned: a fresh build
|
|
180
|
+
from the new base is the path for a changed provisioning definition.
|
|
181
|
+
|
|
149
182
|
Every accepted revision is deposited verbatim as a `dispatcher-config`
|
|
150
183
|
repository artifact and referenced by a `dispatcher.config-reloaded` repository
|
|
151
184
|
event. The dashboard reports the reload and reprojects values such as capacity;
|
|
@@ -164,10 +197,11 @@ These fields hot-reload:
|
|
|
164
197
|
| `baseBranch` | Next dispatch or base fallback decision; existing `build.created` facts remain immutable. |
|
|
165
198
|
| `capacity` | Next dispatcher tick. |
|
|
166
199
|
| `[pr]` | Next build creation. |
|
|
167
|
-
| `[commands]` | Next setup, verify check, or finalize check selected. |
|
|
168
|
-
| `[verify]` and `[finalize]` | Next engine step selection. An approved plan's stored verify selection remains authoritative. |
|
|
169
|
-
| `[
|
|
170
|
-
| `[
|
|
200
|
+
| `[commands]` | Next setup, verify check, or finalize check selected for a build whose OWN branch carries it. A base-branch reload does not retarget an in-flight build. |
|
|
201
|
+
| `[verify]` and `[finalize]` | Next engine step selection for a build whose OWN branch carries it. An approved plan's stored verify selection remains authoritative, and a base-branch reload does not retarget an in-flight build. |
|
|
202
|
+
| `[workspace]` provider and config (including `provisioning`) | Next launch of a build whose OWN branch carries it. A base-branch reload never re-provisions an in-flight build. |
|
|
203
|
+
| `[roles]` | Next agent invocation for that role. Runtime, model, args, alternates, and the session budget are captured together and delivered live. |
|
|
204
|
+
| `[policy]` | Next policy, convergence, or agent-session boundary, delivered live. A running session keeps its captured budget. |
|
|
171
205
|
| `tickets.readyLabels`, `tickets.readyState` | Next ready-ticket scan. |
|
|
172
206
|
| `tickets.triageState`, `tickets.proposalState` | Next dispatcher handback or harvest filing boundary. |
|
|
173
207
|
|
|
@@ -239,6 +273,40 @@ earlier configured plugins are reserved, and declaration order never permits
|
|
|
239
273
|
shadowing. A collision between distinct plugin declarations continues to name
|
|
240
274
|
the conflicting adapter and both owners.
|
|
241
275
|
|
|
276
|
+
Two transitional downgrade paths announce themselves instead of failing
|
|
277
|
+
startup (AUT-517). First, while the builtin hosts the `vercel-sandbox`
|
|
278
|
+
implementation, a configured plugin that re-registers that workspace-provider
|
|
279
|
+
name — `@defrex/autobuild-vercel-sandbox` is exactly such a plugin — is
|
|
280
|
+
skipped with a one-line notice and the builtin keeps serving the provider:
|
|
281
|
+
|
|
282
|
+
```text
|
|
283
|
+
plugin "autobuild-vercel-sandbox" declares only builtin workspace-provider registration(s) "vercel-sandbox"; skipping it — the builtin keeps serving the provider
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
The skip applies only when the manifest declares at least one registration,
|
|
287
|
+
only workspace-provider registrations, and every declared name collides with
|
|
288
|
+
a builtin registration; any other collision still throws. The rule keys on
|
|
289
|
+
builtin ownership, so it retires itself when the builtin is removed and a
|
|
290
|
+
second plugin registering the name collides and fails startup as always.
|
|
291
|
+
`ab plugin list` and `ab plugin doctor` show skipped modules as `SKIP` lines
|
|
292
|
+
and exit 0. Second, guest processes (build and harvest children,
|
|
293
|
+
`ab init`'s guest readiness probe, and scoped phase CLI commands) tolerate a
|
|
294
|
+
configured bare package specifier they cannot resolve — guests never
|
|
295
|
+
construct workspace providers, so a provider plugin they need not load is
|
|
296
|
+
skipped with a notice instead of failing the process:
|
|
297
|
+
|
|
298
|
+
```text
|
|
299
|
+
plugin module "@defrex/autobuild-vercel-sandbox" could not be resolved from repository "…" or installation "…"; guests never construct workspace providers, so the provider plugin is skipped here
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Repository-path specifiers and every post-resolution failure (evaluation,
|
|
303
|
+
manifest, collision) stay fail-closed everywhere, including guests. The guest
|
|
304
|
+
readiness probe surfaces a resolution-stage skip in its `configuration and
|
|
305
|
+
plugins` check detail: the detail names the missing module (the skip notice
|
|
306
|
+
quoted above) and the remediation — add the package to the repository's
|
|
307
|
+
dependencies so it resolves from the repository install during
|
|
308
|
+
`commands.setup`.
|
|
309
|
+
|
|
242
310
|
Plugin authors import the stable surface from `@defrex/autobuild/plugin-sdk`, normally
|
|
243
311
|
with `import type`, and can develop against Autobuild as a dev/peer dependency
|
|
244
312
|
without adding a runtime Autobuild dependency to the plugin. That entry point
|
|
@@ -255,6 +323,24 @@ require `^1.3.0`. API 1.4 adds the optional `Ticket.creationKey` projection: a
|
|
|
255
323
|
ticket-source plugin should return its stable external create/adoption key from
|
|
256
324
|
create, get, and ready listings so dispatch can correlate Autobuild's durable
|
|
257
325
|
in-flight creations. Legacy tickets may omit it and remain dispatchable.
|
|
326
|
+
API 1.6 adds workspace-provider capability declarations: a
|
|
327
|
+
`workspaceProviders` registration may carry a `capabilities` object declaring
|
|
328
|
+
its `[workspace.config]` schema (or an outright refusal), required runtime
|
|
329
|
+
provisioning, supported forges, required environment groups (with per-site
|
|
330
|
+
messages), variables that must exist in the launcher process environment,
|
|
331
|
+
additional operator-sandbox forbidden variable names, HTTPS/token store
|
|
332
|
+
requirements, an origin validator, and a remote readiness validation for
|
|
333
|
+
`ab init --validate`. The host enforces every declared capability at its seam
|
|
334
|
+
without naming the provider; required environment belongs on
|
|
335
|
+
`capabilities.requiredEnv` (a descriptor-level `requiredEnv` is rejected at
|
|
336
|
+
manifest parse), and each `capabilities.requiredEnv` group must declare at
|
|
337
|
+
least one of `dispatchMessage` / `validationMessage` — a group with neither is
|
|
338
|
+
rejected at manifest parse, because the host would silently skip it at both
|
|
339
|
+
enforcement sites. API 1.7 extends the workspace-provider factory context with
|
|
340
|
+
the host-derived seams: `storeRef` and `storeToken` (guaranteed present under
|
|
341
|
+
`capabilities.storeRequirements`), `runtimeReferences`, and the checkout-less
|
|
342
|
+
`origin` and `remoteBranchHead` readers, all optional and ignored by factories
|
|
343
|
+
that do not read them. A plugin reading the new seams should require `^1.7.0`.
|
|
258
344
|
|
|
259
345
|
```ts
|
|
260
346
|
import type { AutobuildPluginManifest } from '@defrex/autobuild/plugin-sdk'
|
|
@@ -438,7 +524,7 @@ gitPasswordEnv = "AB_GIT_READ_TOKEN"
|
|
|
438
524
|
|
|
439
525
|
[workspace.config.runtimeProvisioning.pi]
|
|
440
526
|
install = "npm install --global --ignore-scripts @earendil-works/pi-coding-agent@0.84.4"
|
|
441
|
-
preflight = "test \"$(pi --version)\" = \"0.84.4\""
|
|
527
|
+
preflight = "test \"$(pi --version)\" = \"0.84.4\" && pi update --models"
|
|
442
528
|
```
|
|
443
529
|
|
|
444
530
|
| Vercel field | Default | Constraints |
|
|
@@ -518,13 +604,14 @@ checkout-only hooks such as Husky are not provisioning dependencies. A Bun
|
|
|
518
604
|
install or verification failure identifies the configured image and expected
|
|
519
605
|
universal-image capabilities, deletes the partial environment, and leaves no
|
|
520
606
|
readiness marker. A retry also deletes any named sandbox without that marker
|
|
521
|
-
instead of adopting partial setup. The installed distribution's version
|
|
522
|
-
recorded in the guest's
|
|
523
|
-
reused sandbox whose marker
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
delivery path and the hosted
|
|
607
|
+
instead of adopting partial setup. The installed distribution's identity — package version and remote-store
|
|
608
|
+
protocol version — is recorded in the guest's
|
|
609
|
+
`/opt/autobuild/.distribution-version` marker; a reused sandbox whose marker
|
|
610
|
+
no longer matches the identity the current system would deliver is refreshed
|
|
611
|
+
by reinstalling the archive before reuse, so an upgraded dispatcher retrofits
|
|
612
|
+
its persistent guests (see "Guest distribution version selection and delivery"
|
|
613
|
+
in docs/setup.md for the release-and-upgrade delivery path and the hosted
|
|
614
|
+
store's version-lockstep gate). Immediately
|
|
528
615
|
before every build-child launch, the adapter verifies the
|
|
529
616
|
provisioned absolute Bun executable and every referenced runtime again. A
|
|
530
617
|
failure names the runtime, selecting role/alternate, stage, and provisioning
|
|
@@ -884,7 +971,7 @@ session starts, with a copyable table and all registered runtime names.
|
|
|
884
971
|
| `args` | inherited; otherwise `[]` | optional array of nonempty strings; `[]` allowed | Ordered extra CLI argv tokens applied to every phase and tool-free one-shot invocation. A supplied list replaces, rather than unions with, the inherited list. |
|
|
885
972
|
| `extensions` | no effect | deprecated optional array of nonempty strings | Compatibility-only field. Dispatch warns for each declaring role; migrate explicit runtime options to `args`. |
|
|
886
973
|
| `sessionBudgetSeconds` | inherited; otherwise `[policy].sessionBudgetSeconds` | optional positive integer | Wall-clock budget for each build phase session routed through this logical role. One budget covers the primary and every alternate target. |
|
|
887
|
-
| `alternates` | inherited; otherwise `[]` | optional ordered array of strict `{ runtime?, model?, args?, extensions? }` entries; `[]` allowed | Failure-triggered execution targets. A role's list replaces the inherited list wholesale; each entry overlays that role's effective primary axes. `extensions` is accepted there only as the same deprecated no-op. |
|
|
974
|
+
| `alternates` | inherited; otherwise `[]` | optional ordered array of strict `{ runtime?, model?, args?, extensions? }` entries; `[]` allowed | Failure-triggered execution targets (provider failures and a runtime whose CLI is not installed). A role's list replaces the inherited list wholesale; each entry overlays that role's effective primary axes. `extensions` is accepted there only as the same deprecated no-op. |
|
|
888
975
|
|
|
889
976
|
<!-- config-fragment:roles -->
|
|
890
977
|
```toml
|
|
@@ -984,7 +1071,7 @@ useful; mixed models are not a configuration inconsistency.
|
|
|
984
1071
|
Each session attempt starts with its role's primary. Overload, rate limits, 5xx,
|
|
985
1072
|
timeout, transport, unknown provider failures, and quota/usage/billing
|
|
986
1073
|
exhaustion try alternates in declaration order inside that same phase attempt.
|
|
987
|
-
Authentication, permission, and local runtime-configuration failures do not.
|
|
1074
|
+
Authentication, permission, and local runtime-configuration failures do not, with one exception: a runtime whose CLI executable is not installed is skipped like any other eligible failure, so the phase runs on the first declared target whose CLI is present. An unsupported installed version is still a stopping configuration failure. If no target's CLI is installed, the chain ends in one non-retried `configuration` failure carrying the last target's missing-CLI message. The remote provisioning preflight stays fail-closed: a missing runtime there is a provisioning defect.
|
|
988
1075
|
Each target gets a separate session and transcript; a continuation that moves
|
|
989
1076
|
to another target starts fresh from durable context and cannot inherit the
|
|
990
1077
|
failed provider's conversation. Selection is not sticky: the next phase, next
|
|
@@ -1203,14 +1290,19 @@ Set `COMPANY_TICKET_TOKEN` in the environment, never in this table.
|
|
|
1203
1290
|
|
|
1204
1291
|
## `[orchestrator]`
|
|
1205
1292
|
|
|
1206
|
-
Gates the operator-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
table is closed to unknown keys and
|
|
1293
|
+
Gates the operator-agent feature (AUT-340, AUT-342): the per-operator sandbox
|
|
1294
|
+
environments the `sandbox.*` registry tools drive, and — when the embedded
|
|
1295
|
+
orchestrator is enabled — the turn runner that answers operator sessions and
|
|
1296
|
+
wakes on build events. The table is closed to unknown keys and
|
|
1297
|
+
restart-classified as a whole.
|
|
1210
1298
|
|
|
1211
1299
|
| Field | Default | Constraints | Purpose |
|
|
1212
1300
|
|---|---:|---|---|
|
|
1213
|
-
| `enabled` | `false` | boolean | Master gate. With the table absent or `enabled = false`, the sandbox tools are absent from every binding
|
|
1301
|
+
| `enabled` | `false` | boolean | Master gate. With the table absent or `enabled = false`, the sandbox tools are absent from every binding, no environment is ever provisioned, and no dispatcher tick or message post ever runs orchestrator code — a local dispatcher is inert even when enabled, because the turn runner exists only in the hosted deployment. |
|
|
1302
|
+
| `model` | — | nonblank string, required when `enabled = true` | Provider-qualified model string for the turn runner, in the same vocabulary as `[roles]` model strings (a leading `vercel-ai-gateway/` prefix is accepted and stripped). Resolved through the deployment's gateway credential. |
|
|
1303
|
+
| `invocationBudgetSeconds` | `240` | positive integer, clamped to 300 | Wall-clock budget for one turn invocation. A larger value is clamped — not rejected — to the 300-second hosted function limit the runner executes under (`ORCHESTRATOR_ROUTE_LIMIT_SECONDS`, the same number the operator route pins as `maxDuration`). |
|
|
1304
|
+
| `approvals` | see below | array of `tool` or `tool:qualifier` strings | Registry tool names whose calls suspend a turn until the operator answers. Default: `["builds.control:abort", "builds.control:discard", "builds.answer:revise-spec", "sandbox.publish", "tickets.move:ready"]`. Empty (`[]`) means none — autonomous operation. An entry naming an absent or unknown tool is **inert by design**, never a config error: the list stays stable while the registry grows, and a tool's removal cannot break parsing. A `tool:qualifier` entry applies to the named discriminator value only (for example `tickets.move:ready` approves moving a ticket to `ready`); for a tool without a discriminator, only the bare form matches. |
|
|
1305
|
+
| `wake` | inherits the default | array of event-type globs | The attention events a **new** session wakes for. Kept schema-optional so absent (inherit the default attention set — the build events `ab watch` filters on by default plus the repository-journal events `ab watch --repository` follows) and `[]` (never wake; message-only) stay distinct. Each glob must match at least one build or repository-journal event type, validated with the same compiler `ab watch` uses. Existing sessions never retroactively inherit; an explicit `PUT .../wake` always wins. |
|
|
1214
1306
|
| `sandbox` | — | strict subtable; absence reads as the defaults | Sandbox behavior knobs. |
|
|
1215
1307
|
|
|
1216
1308
|
`[orchestrator.sandbox]` fields:
|
|
@@ -1225,7 +1317,16 @@ forge, ticket-provider, or model credential, and naming any of `AB_STORE`,
|
|
|
1225
1317
|
`AB_TOKEN`, `GITHUB_TOKEN`, `GH_TOKEN`, `LINEAR_API_KEY`, `VERCEL_OIDC_TOKEN`,
|
|
1226
1318
|
`VERCEL_TOKEN`, `VERCEL_TEAM_ID`, `VERCEL_PROJECT_ID`, or `AI_GATEWAY_API_KEY`
|
|
1227
1319
|
in `environmentVariables` is a config error. The typed operator tools remain
|
|
1228
|
-
the only route to build state from inside the sandbox.
|
|
1320
|
+
the only route to build state from inside the sandbox. A workspace-provider
|
|
1321
|
+
plugin can declare additional forbidden names via its registration's
|
|
1322
|
+
`capabilities.sandboxForbiddenEnv`; those are enforced at the post-load seams
|
|
1323
|
+
(provider construction and `ab init --validate`) rather than at config parse,
|
|
1324
|
+
because plugins are not loaded when configuration is parsed — a deliberate
|
|
1325
|
+
deferral, not an oversight. Concretely, the shared names above are rejected
|
|
1326
|
+
when the config is parsed, plugin-declared extras are rejected when the
|
|
1327
|
+
provider is constructed (dispatch and `ab mcp`), and `ab init --validate`
|
|
1328
|
+
re-checks both sets after plugins load, before any infrastructure is
|
|
1329
|
+
provisioned. Tool bounds:
|
|
1229
1330
|
`sandbox.exec` waits at most 300 seconds; stdout and stderr are each truncated
|
|
1230
1331
|
at 65,536 bytes with a `[truncated by autobuild: output exceeded 65536 bytes]`
|
|
1231
1332
|
marker; `sandbox.reset` and archiving an operator's last session are
|
|
@@ -1236,6 +1337,10 @@ one environment per operator and repository.
|
|
|
1236
1337
|
```toml
|
|
1237
1338
|
[orchestrator]
|
|
1238
1339
|
enabled = true
|
|
1340
|
+
model = "anthropic/claude-sonnet-4"
|
|
1341
|
+
invocationBudgetSeconds = 240
|
|
1342
|
+
approvals = ["builds.control:abort", "sandbox.publish", "tickets.move:ready"]
|
|
1343
|
+
# wake omitted: new sessions inherit the default attention set
|
|
1239
1344
|
|
|
1240
1345
|
[orchestrator.sandbox]
|
|
1241
1346
|
idleMinutes = 30
|
|
@@ -1245,6 +1350,25 @@ environmentVariables = ["MY_TOOL_CONFIG"]
|
|
|
1245
1350
|
Set `MY_TOOL_CONFIG` in the host environment of the `ab mcp` process; a missing
|
|
1246
1351
|
value fails the tool call that needs it, named as a typed `environment` error.
|
|
1247
1352
|
|
|
1353
|
+
In the hosted deployment the `sandbox.*` tools are served to orchestrator
|
|
1354
|
+
turns from two bindings, both composing the backend from the repository's
|
|
1355
|
+
deposited effective config: the store service's message-turn runner (and its
|
|
1356
|
+
same-invocation approval resumes), and the origin-mode dispatcher tick's wake
|
|
1357
|
+
and resume runner, which reuses the dispatcher's wired workspace provider and
|
|
1358
|
+
forge. Both use the builtin workspace provider and the builtin `github` forge
|
|
1359
|
+
from that config — a plugin-provider or forgeless config degrades that
|
|
1360
|
+
binding's sandbox tools only, with a reported diagnostic. The store-service
|
|
1361
|
+
path authenticates the Sandbox SDK with the request's `x-vercel-oidc-token`
|
|
1362
|
+
header (or an explicit `VERCEL_OIDC_TOKEN`, which takes precedence, or the
|
|
1363
|
+
durable `VERCEL_TOKEN`/`VERCEL_TEAM_ID`/`VERCEL_PROJECT_ID` triple, which
|
|
1364
|
+
needs no header); the tick path inherits the dispatcher's already-forwarded
|
|
1365
|
+
token. Every serving path derives the same deterministic environment name per
|
|
1366
|
+
(repository origin, operator), so an operator's environment is one
|
|
1367
|
+
environment per repository no matter which binding drove it, and the guest
|
|
1368
|
+
still receives no credential. Serving stays gated exactly as locally: the
|
|
1369
|
+
effective `[orchestrator].enabled`, the registry's closed-table filtering,
|
|
1370
|
+
and the `approvals` suspension list in the turn loop.
|
|
1371
|
+
|
|
1248
1372
|
## Complete example
|
|
1249
1373
|
|
|
1250
1374
|
The following deliberately exercises every fixed table and both verify/finalize
|
|
@@ -1427,8 +1551,10 @@ pre-attempt index and reports the original Git failure; merged worktree files
|
|
|
1427
1551
|
remain in place and the merge's exit status is unchanged. Upgrade never pushes
|
|
1428
1552
|
or rewrites history.
|
|
1429
1553
|
|
|
1430
|
-
Autobuild now installs
|
|
1431
|
-
are model-invocable.
|
|
1554
|
+
Autobuild now installs 12 skills; only `ab-spec`, `ab-tickets`, and `ab-guide`
|
|
1555
|
+
are model-invocable. (`ab-operate` — the embedded orchestrator's operating
|
|
1556
|
+
manual — also carries `disable-model-invocation: true`; it is read by the
|
|
1557
|
+
hosted turn runner, never invoked by a model in a build session.) The setup reference is an ordinary support file in the
|
|
1432
1558
|
editable/pristine `ab-guide` tree and participates in the same three-way
|
|
1433
1559
|
upgrade merge as every other vendored file.
|
|
1434
1560
|
|
|
@@ -1459,7 +1585,7 @@ poll. Editing TOML cannot change them.
|
|
|
1459
1585
|
|---|---:|---|---|
|
|
1460
1586
|
| Ticket intake | on | `ab dispatch --intake` / `--no-intake`; `i` on the dashboard's global row, and `p` (pause all) / `r` (resume all) on that row or their sessionless equivalents `ab pause --all` / `ab resume --all`, which turn intake off and on as part of quiescing the repository | When off, skip only new ticket list/claim/dispatch work. Janitor work, lease recovery, in-flight builds, and harvesting continue. Turning intake off does not hold builds the repository has already accepted — that is the repository pause below. |
|
|
1461
1587
|
| Repository pause | off | `p` (pause all) / `r` (resume all) on the dashboard's global row, or `ab pause --all` / `ab resume --all` | While on, the dashboard controls line shows `repository PAUSED`, and each held queued row shows `(held)` while retaining its literal `QUEUED` status. No dispatcher tick attaches a runner to such a build — recovery, startup resume, and the lease sweep all skip them. Running builds are parked by the per-build pauses the same command writes; the janitor still settles aborts and discards. |
|
|
1462
|
-
|
|
|
1588
|
+
| Repository auto-merge default | off | `ab dispatch --auto-merge` / `--no-auto-merge`; `m` on the global row | Seeds durable auto-merge intent on builds claimed while the setting is enabled, and — on each change — also applies as a bulk action to every current non-terminal build: turning it on requests consent for each build (turning it off withdraws it), attributed to the operator who toggled it exactly as if they had pressed `m` on every row. A per-build toggle overrides its build's state until the global row is toggled again. |
|
|
1463
1589
|
| Harvest gate | on | `h` on the dashboard's global row | Pauses or resumes repository observation harvesting. The header shows the kernel-acknowledged gate, not merely a pending keypress. |
|
|
1464
1590
|
|
|
1465
1591
|
The opposite flag forms for each dispatch setting are mutually exclusive.
|
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
# The hosted dispatcher
|
|
2
2
|
|
|
3
|
-
The optional [hosted
|
|
4
|
-
own the dispatch kernel.
|
|
5
|
-
|
|
3
|
+
The optional [`@defrex/autobuild-hosted-dispatcher`](../packages/hosted-dispatcher/README.md)
|
|
4
|
+
package lets a deployment own the dispatch kernel. Installing it and mounting
|
|
5
|
+
its route — `GET /api/dispatch`, backed by the package's
|
|
6
|
+
`dispatcherEndpoint()` singleton — makes the hosted deployment the kernel
|
|
7
|
+
owner. One authenticated HTTP invocation runs, for each configured
|
|
8
|
+
repository, one bounded origin-mode dispatcher
|
|
6
9
|
tick: the kernel claims ready tickets, provisions and launches sandboxes,
|
|
7
10
|
observes running builds, settles publications, opens and merges PRs, and runs
|
|
8
11
|
the janitor, exactly as a local `ab dispatch --once --repository <origin>`
|
|
9
12
|
pass does. The schedule is what you attach to that endpoint (Vercel Cron calls
|
|
10
13
|
it once a minute by default), so builds no longer depend on a maintainer's
|
|
11
|
-
machine.
|
|
14
|
+
machine. A deployment that does not install the package serves the hosted
|
|
15
|
+
store, ticket, operator, and web endpoints and never attempts a dispatch tick.
|
|
12
16
|
|
|
13
17
|
## Enabling the schedule
|
|
14
18
|
|
|
15
|
-
1. Deploy the hosted service with the dispatcher
|
|
16
|
-
|
|
19
|
+
1. Deploy the hosted service with the dispatcher package installed and the
|
|
20
|
+
dispatcher variables from
|
|
21
|
+
[its README](../packages/hosted-dispatcher/README.md)
|
|
17
22
|
— `AB_DISPATCHER_ORIGIN`, the repository set, `CRON_SECRET`, and the forge
|
|
18
23
|
credentials the kernel needs (`GITHUB_TOKEN` or `GH_TOKEN`, plus any
|
|
19
24
|
guest-forwarded variables such as `AI_GATEWAY_API_KEY`). A deployment
|
|
@@ -44,26 +49,77 @@ Every sandbox installs the Autobuild distribution the launching dispatcher
|
|
|
44
49
|
runs. A local dispatcher packs it from its source checkout with `bun pm pack`;
|
|
45
50
|
a bundled deployment has neither `bun` nor a source tree at runtime, so it
|
|
46
51
|
must pack the archive while both exist — in its build step — and carry it into
|
|
47
|
-
the function bundle
|
|
52
|
+
the function bundle. The script lives in the hosted store service package
|
|
53
|
+
(`packages/hosted-store-service/package.json`), whose directory is the Next.js
|
|
54
|
+
project directory and the deployment build's working directory:
|
|
48
55
|
|
|
49
56
|
```json
|
|
50
|
-
{ "scripts": { "deploy:build": "bun packages/hosted-
|
|
57
|
+
{ "scripts": { "deploy:build": "bun ../../packages/hosted-dispatcher/src/bin.ts pack-distribution --root . && bun ../../packages/postgres-store/src/bin.ts migrate && bun run build && bun ../../packages/hosted-dispatcher/src/ship-packed-distribution.ts && bun ../../packages/hosted-dispatcher/src/ship-provider-plugin.ts" } }
|
|
51
58
|
```
|
|
52
59
|
|
|
53
|
-
`pack-distribution`
|
|
54
|
-
|
|
60
|
+
`pack-distribution` (the `ab-hosted-dispatcher` bin) writes
|
|
61
|
+
`.autobuild-dist/autobuild-<version>.tgz` under the
|
|
62
|
+
distribution root (`--root DIR` overrides) — this deployment passes
|
|
63
|
+
`--root .`, because the packer's default root is the repository's distribution
|
|
64
|
+
root while the trace step below and the Next config's
|
|
55
65
|
`outputFileTracingIncludes: { '/api/dispatch': ['./.autobuild-dist/**'] }`
|
|
56
|
-
|
|
66
|
+
resolve against the deployment build's working directory, where the archive
|
|
67
|
+
must land beside the built output. The Next.js config's
|
|
68
|
+
`outputFileTracingIncludes` records the intent to include that directory in the cron route's bundle, but
|
|
57
69
|
Next 16's default Turbopack builds never apply `outputFileTracingIncludes`
|
|
58
70
|
(only webpack builds do), so a deployment cannot rely on the config alone. The
|
|
59
71
|
autobuild-api pipeline therefore ends `deploy:build` with a post-build trace
|
|
60
|
-
step (`bun
|
|
72
|
+
step (`bun ../../packages/hosted-dispatcher/src/ship-packed-distribution.ts`) that appends the archive to the
|
|
61
73
|
dispatch route's `route.js.nft.json` — the trace file Vercel's Next builder
|
|
62
74
|
consumes when assembling the function bundle — and fails the deploy loudly if
|
|
63
|
-
nothing was packed or the trace file is missing.
|
|
75
|
+
nothing was packed or the trace file is missing. The same step appends the
|
|
76
|
+
distribution root's `package.json`, which provisioning reads for the running
|
|
77
|
+
version and which no import traces once the Next.js project directory sits
|
|
78
|
+
below the repository root. A deployment using this
|
|
64
79
|
pipeline cannot ship without the archive; deployments that skip both packing
|
|
65
80
|
and the trace step still fail at runtime.
|
|
66
81
|
|
|
82
|
+
A second post-build trace step ships the provider plugin package (AUT-517):
|
|
83
|
+
`bun ../../packages/hosted-dispatcher/src/ship-provider-plugin.ts` locates the
|
|
84
|
+
plugin's source through the repository root's `workspaces` tree (never through
|
|
85
|
+
`node_modules`, so a previous run's staged directory cannot shadow the source),
|
|
86
|
+
bundles its entrypoint with `bun build --target=bun --format=esm` into a
|
|
87
|
+
single self-contained module (the plugin-sdk closure inlines — the
|
|
88
|
+
deployment's repository-root `node_modules` carries no `@defrex/autobuild`
|
|
89
|
+
either — while node builtins stay external), stages it into
|
|
90
|
+
`<repoRoot>/node_modules/@defrex/autobuild-vercel-sandbox/` (replacing the
|
|
91
|
+
workspace symlink a local `bun install` leaves there — or a previous run's
|
|
92
|
+
staged directory, which `bun install` does not relink; the deployment never
|
|
93
|
+
runs `bun install` again), and appends the staged files to the dispatch
|
|
94
|
+
route's trace at the same repository-root depth as the existing
|
|
95
|
+
`node_modules/.bun/**` entries. A bare plugin specifier resolves only
|
|
96
|
+
through a `node_modules/` path, and the compiled dispatcher's
|
|
97
|
+
`distributionRoot()` is the repository root, so only this staging makes
|
|
98
|
+
`plugins = ["@defrex/autobuild-vercel-sandbox"]` loadable inside the
|
|
99
|
+
deployed function. The step is idempotent across runs — including in a
|
|
100
|
+
fresh process after an earlier run consumed the workspace link — and fails
|
|
101
|
+
the deploy loudly when the package, its entrypoint, or the trace file is
|
|
102
|
+
missing. The npm published package remains the real `src` — only the
|
|
103
|
+
deployment stages the bundle.
|
|
104
|
+
|
|
105
|
+
What the staged directory does afterwards depends on the build environment.
|
|
106
|
+
Inside a Vercel deployment build (which always sets `VERCEL`, including a
|
|
107
|
+
local `vercel build` run) the staged directory stays: the deployment never
|
|
108
|
+
runs `bun install` again and the function bundle's runtime resolution needs
|
|
109
|
+
it — a deployment building outside Vercel must set `VERCEL=1` in its build
|
|
110
|
+
environment to keep the staged bundle. A plain local `bun run deploy:build`
|
|
111
|
+
(no `VERCEL` environment) removes the staged directory afterwards and
|
|
112
|
+
restores the workspace symlink, so a local run leaves the checkout exactly
|
|
113
|
+
as `bun install` had it and local test runs keep resolving the workspace
|
|
114
|
+
source (the capability parity test's reference equality holds). On checkouts
|
|
115
|
+
of older versions the staged directory stayed behind and survived `bun
|
|
116
|
+
install` — it reports "no changes" because the staged package satisfies the
|
|
117
|
+
manifest — so later local runs resolved the plugin to the self-contained
|
|
118
|
+
bundle and the parity test failed on its reference-equality assertion; the
|
|
119
|
+
recovery is `rm -rf node_modules/@defrex/autobuild-vercel-sandbox && bun
|
|
120
|
+
install`, or simply re-run `deploy:build` locally on a version with this
|
|
121
|
+
fix, which restores the symlink itself.
|
|
122
|
+
|
|
67
123
|
At runtime the kernel takes, in order: `AB_DISTRIBUTION_ARCHIVE` (an explicit
|
|
68
124
|
archive path), the single archive under `.autobuild-dist/` of the
|
|
69
125
|
distribution root or working directory, a source checkout packed on the spot,
|
package/docs/operator-api.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Operator API v1
|
|
2
2
|
|
|
3
3
|
The hosted service exposes the polling-oriented operator surface at
|
|
4
|
-
`/operator/v1/repos/{repo}`. It is versioned with remote store protocol **
|
|
4
|
+
`/operator/v1/repos/{repo}`. It is versioned with remote store protocol **3**.
|
|
5
5
|
Every request must send `X-Autobuild-Version`,
|
|
6
|
-
`X-Autobuild-Protocol-Version:
|
|
6
|
+
`X-Autobuild-Protocol-Version: 3`, and `Authorization: Bearer …`. Identity is
|
|
7
7
|
checked before authentication or resource lookup.
|
|
8
8
|
|
|
9
9
|
Mint a token offline; the signed user is used as the human actor on every write:
|