@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.
- package/README.md +1 -1
- package/SPEC.md +323 -26
- package/bin/ab-build-runner.ts +8 -2
- package/docs/architecture.md +166 -14
- package/docs/assets/headline-wide.png +0 -0
- package/docs/configuration.md +175 -28
- package/docs/hosted-dispatcher.md +69 -13
- package/docs/operator-api.md +2 -2
- package/docs/remote-store-protocol.md +204 -16
- package/docs/remote-ticket-protocol.md +1 -1
- package/docs/setup.md +12 -9
- package/docs/website.md +14 -0
- package/package.json +45 -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/facts.ts +215 -0
- package/packages/core/src/cli/dashboard/frame-parse.ts +223 -0
- package/packages/core/src/cli/dashboard/model.ts +141 -153
- package/packages/core/src/cli/dashboard/poll.ts +76 -12
- 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-process.ts +1 -13
- package/packages/core/src/cli/dispatch.ts +392 -75
- package/packages/core/src/cli/harvest.ts +122 -8
- package/packages/core/src/cli/help.ts +62 -9
- 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 +266 -222
- package/packages/core/src/cli/installation.ts +50 -8
- 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/self-update.ts +77 -2
- package/packages/core/src/cli/status.ts +150 -28
- 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 +453 -8
- package/packages/core/src/cli/wait.ts +157 -41
- package/packages/core/src/cli/watch.ts +138 -168
- package/packages/core/src/config/live.ts +23 -0
- package/packages/core/src/config/pipeline-source.ts +388 -0
- package/packages/core/src/config/schema.ts +251 -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 +115 -2
- package/packages/core/src/kernel/__snapshots__/reducer-registry.test.ts.snap +1369 -0
- package/packages/core/src/kernel/auto-merge-default.ts +157 -0
- package/packages/core/src/kernel/auto-merge.ts +99 -22
- package/packages/core/src/kernel/dispatch-settings.ts +42 -17
- package/packages/core/src/kernel/dispatch-status.ts +23 -0
- package/packages/core/src/kernel/engine.ts +9 -438
- package/packages/core/src/kernel/generators/build-log.ts +259 -0
- package/packages/core/src/kernel/generators/repository-journals.ts +206 -0
- package/packages/core/src/kernel/generators/session-log.ts +72 -0
- package/packages/core/src/kernel/harvest.ts +62 -18
- package/packages/core/src/kernel/incremental-contract.ts +75 -0
- package/packages/core/src/kernel/incremental-fixtures.ts +211 -0
- package/packages/core/src/kernel/incremental.ts +53 -0
- package/packages/core/src/kernel/log-index.ts +620 -0
- package/packages/core/src/kernel/phases.ts +16 -2
- package/packages/core/src/kernel/pr-attachments.ts +164 -46
- package/packages/core/src/kernel/reducer-registry.ts +164 -0
- package/packages/core/src/kernel/reducer.ts +254 -73
- 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 +253 -24
- package/packages/core/src/operator/read-view.ts +98 -0
- 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/fake.ts +5 -1
- package/packages/core/src/ports/tickets/file.ts +169 -48
- package/packages/core/src/ports/tickets/{remote-index.ts → hosted-index.ts} +3 -2
- package/packages/core/src/ports/tickets/linear.ts +33 -1
- package/packages/core/src/ports/tickets/operations.ts +1 -1
- package/packages/core/src/ports/tickets/remote.ts +8 -1
- package/packages/core/src/ports/types.ts +49 -3
- 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 +68 -15
- package/packages/core/src/processes/build-runner.ts +238 -93
- package/packages/core/src/processes/dispatcher-selectors.ts +123 -0
- package/packages/core/src/processes/dispatcher.ts +501 -201
- package/packages/core/src/processes/execution-settlement.ts +72 -39
- package/packages/core/src/processes/harvest-child.ts +5 -0
- package/packages/core/src/processes/harvest-execution-state.ts +41 -29
- package/packages/core/src/processes/harvest-runner.ts +66 -19
- package/packages/core/src/processes/harvest.ts +196 -24
- package/packages/core/src/processes/infrastructure-failure-budget.ts +31 -18
- package/packages/core/src/processes/orchestrator-tick.ts +360 -0
- package/packages/core/src/processes/publication-state.ts +164 -52
- package/packages/core/src/processes/repo-view.ts +1436 -0
- package/packages/core/src/processes/sandbox-state.ts +36 -2
- package/packages/core/src/processes/tick-state.ts +33 -0
- package/packages/core/src/store/adapter.ts +41 -0
- package/packages/core/src/store/build-scope.ts +90 -0
- package/packages/core/src/store/contract.ts +1205 -0
- package/packages/core/src/store/digest.ts +102 -0
- package/packages/core/src/store/local/schema.ts +46 -2
- package/packages/core/src/store/local/store.ts +445 -4
- package/packages/core/src/store/memory.ts +246 -0
- package/packages/core/src/store/new-build.ts +17 -0
- package/packages/core/src/store/phase-session.ts +94 -0
- package/packages/core/src/store/remote/client.ts +310 -2
- package/packages/core/src/store/remote/index.ts +14 -2
- package/packages/core/src/store/remote/protocol.ts +115 -12
- package/packages/core/src/store/remote/version.ts +6 -2
- package/packages/core/src/store/repo-state-events.ts +205 -0
- package/packages/core/src/store/retention.ts +7 -0
- package/packages/core/src/store/session-handle.ts +94 -0
- package/packages/core/src/{sessions/reducer.ts → store/session-reducer.ts} +79 -19
- package/packages/core/src/store/snapshots.ts +88 -0
- 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 +458 -0
- package/packages/core/src/store/types.ts +160 -1
- package/packages/core/src/testing/index.ts +59 -0
- package/skills/code-review/SKILL.md +5 -1
- package/skills/guide/SKILL.md +152 -40
- 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 +204 -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/skills/tickets/SKILL.md +57 -5
- 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
|
@@ -24,7 +24,17 @@ import type {
|
|
|
24
24
|
SessionEventType,
|
|
25
25
|
SessionEventWrite,
|
|
26
26
|
} from '../events/sessions'
|
|
27
|
+
export type { SessionEventEnvelope }
|
|
27
28
|
import type { TicketRef } from '../ontology'
|
|
29
|
+
import type { ReducerSnapshot, SnapshotScope } from './snapshots'
|
|
30
|
+
export type { ReducerSnapshot, SnapshotScope }
|
|
31
|
+
import type {
|
|
32
|
+
TicketAsset,
|
|
33
|
+
TicketAssetInput,
|
|
34
|
+
TicketAssetLimits,
|
|
35
|
+
TicketAssetMeta,
|
|
36
|
+
TicketAssetSummary,
|
|
37
|
+
} from './ticket-assets'
|
|
28
38
|
import type {
|
|
29
39
|
StreamChunk,
|
|
30
40
|
StreamOutcome,
|
|
@@ -64,6 +74,12 @@ export interface NewBuildInput {
|
|
|
64
74
|
repoOrigin?: string
|
|
65
75
|
ticket?: TicketRef
|
|
66
76
|
branch?: string
|
|
77
|
+
/** The build's `build.created` fact, appended as seq 1 in the same atomic
|
|
78
|
+
* step as the record: both exist or neither does, so the claim-time facts it
|
|
79
|
+
* freezes (ticket assets, SPEC §6.3) can never be lost to a crash between
|
|
80
|
+
* the two writes. An invalid payload, or any other event type, rejects and
|
|
81
|
+
* creates nothing. */
|
|
82
|
+
created?: EventWrite<'build.created'>
|
|
67
83
|
}
|
|
68
84
|
|
|
69
85
|
export interface ArtifactMeta {
|
|
@@ -77,6 +93,38 @@ export interface ArtifactMeta {
|
|
|
77
93
|
createdAt: string
|
|
78
94
|
}
|
|
79
95
|
|
|
96
|
+
/** The projection of one build's event log onto exactly the two facts an
|
|
97
|
+
* operator dashboard needs from every build (AUT-487): the latest terminal
|
|
98
|
+
* fact's kind — `done` for `build.completed`, `aborted` for `build.aborted`,
|
|
99
|
+
* in-order overwrite, exactly `reduceBuild`'s terminal rule — and the seqs of
|
|
100
|
+
* the log's `observation.recorded` occurrences. `terminal` is absent while
|
|
101
|
+
* the log carries neither terminal fact (a queued, running, paused, blocked,
|
|
102
|
+
* or mid-cleanup build). Everything else a dashboard shows comes from the
|
|
103
|
+
* journal, the build records, and the full histories of just the builds that
|
|
104
|
+
* render rows. Nothing is persisted: every adapter derives the digest from
|
|
105
|
+
* the event log on each call, so the log stays the sole authority and the
|
|
106
|
+
* digest can always be discarded and rebuilt. */
|
|
107
|
+
export interface BuildDigest {
|
|
108
|
+
slug: string
|
|
109
|
+
terminal?: 'done' | 'aborted'
|
|
110
|
+
/** Ascending-seq `{seq, ts}` pairs for every `observation.recorded` in the
|
|
111
|
+
* build's log; `ts` is the event envelope timestamp (AUT-521: the harvest
|
|
112
|
+
* pressure gate measures drift from the oldest unclaimed occurrence's ts,
|
|
113
|
+
* so per-occurrence timestamps travel with the digest). */
|
|
114
|
+
observations: { seq: number; ts: string }[]
|
|
115
|
+
/** Envelope ts of the log's latest `pr.merged` event, absent when the log
|
|
116
|
+
* has none (AUT-521: latest-wins suffices for drift, which counts a build
|
|
117
|
+
* when any of its merges is strictly after the oldest unclaimed
|
|
118
|
+
* observation). */
|
|
119
|
+
merged?: string
|
|
120
|
+
/** A `pr-attachment.hosted` has no later matching `pr-attachment.reclaimed`
|
|
121
|
+
* (the `pendingPrAttachmentReclaims` rule). Absent otherwise. */
|
|
122
|
+
reclaimPending?: true
|
|
123
|
+
/** The latest `execution.started` has no later `execution.ended` with the
|
|
124
|
+
* same `instance` (the `openExecution` rule). Absent otherwise. */
|
|
125
|
+
executionOpen?: true
|
|
126
|
+
}
|
|
127
|
+
|
|
80
128
|
export interface RepositoryRecord {
|
|
81
129
|
repo: string
|
|
82
130
|
createdAt: string
|
|
@@ -103,7 +151,8 @@ export interface RepositoryArtifact {
|
|
|
103
151
|
/** An operator session: hosted-only durable orchestrator-conversation state
|
|
104
152
|
* (SPEC §7.1.1). The record carries only identity and timestamps; everything
|
|
105
153
|
* else — status, open turn, pending approval, wake settings — is a reduction
|
|
106
|
-
* of the session's own event log (
|
|
154
|
+
* of the session's own event log (the hosted package's session-reducer.ts),
|
|
155
|
+
* never a column. */
|
|
107
156
|
export interface SessionRecord {
|
|
108
157
|
/** Store-assigned (`os_<uuid>`). */
|
|
109
158
|
id: string
|
|
@@ -257,6 +306,18 @@ export interface BuildStore {
|
|
|
257
306
|
opts?: { waitSeconds?: number; signal?: AbortSignal },
|
|
258
307
|
): Promise<AbEvent[]>
|
|
259
308
|
|
|
309
|
+
/** One entry for EVERY build whose record's repo is `repo` (completeness is
|
|
310
|
+
* contractual: a freshly created build whose log holds none of the
|
|
311
|
+
* digest-relevant event types still gets its entry, with empty
|
|
312
|
+
* `observations` and no `terminal`), keyed by slug. A read-only, repo-scoped
|
|
313
|
+
* batch query shaped like `listBuilds`: it performs no `ensureRepo`, never
|
|
314
|
+
* writes, and an unknown or build-less repo answers an empty map rather
|
|
315
|
+
* than rejecting. Derived from the event log on every call — the log is the
|
|
316
|
+
* sole authority, so there is nothing to refresh or invalidate. The
|
|
317
|
+
* derivation is the shared `reduceBuildDigest` (store/digest.ts), so every
|
|
318
|
+
* adapter answers identical results for identical logs. */
|
|
319
|
+
getRepoBuildDigests(repo: string): Promise<Map<string, BuildDigest>>
|
|
320
|
+
|
|
260
321
|
putArtifact(slug: string, artifact: ArtifactInput): Promise<ArtifactMeta>
|
|
261
322
|
/** Latest revision when `rev` is omitted; null if kind (or rev) absent. */
|
|
262
323
|
getArtifact(slug: string, kind: string, rev?: number): Promise<Artifact | null>
|
|
@@ -305,9 +366,92 @@ export interface BuildStore {
|
|
|
305
366
|
sinceSeq?: number,
|
|
306
367
|
opts?: { waitSeconds?: number; signal?: AbortSignal },
|
|
307
368
|
): Promise<RepositoryEvent[]>
|
|
369
|
+
/** Bounded repository-journal read for stateless full-state readers
|
|
370
|
+
* (AUT-489): every durable fact (REPOSITORY_STATE_EVENT_TYPES) plus — when
|
|
371
|
+
* the journal has one — the tail from the latest `dispatcher.run-started`.
|
|
372
|
+
* Reducing this subset with the state readers yields exactly what a full
|
|
373
|
+
* replay yields (`projectRepositoryStateEvents` is the normative oracle).
|
|
374
|
+
* Unknown repo rejects like `getRepoEvents`. */
|
|
375
|
+
getRepoStateEvents(repo: string): Promise<RepositoryEvent[]>
|
|
376
|
+
/** The journal's true high-water mark: the greatest assigned seq of any
|
|
377
|
+
* event type, 0 for an empty journal. Returns no event rows — the cursor a
|
|
378
|
+
* long-lived reader (the dispatcher's repository view) needs to resume with
|
|
379
|
+
* `getRepoEvents(repo, cursor)` even when the bounded subset excludes the
|
|
380
|
+
* journal's trailing events. Unknown repo rejects like `getRepoEvents`;
|
|
381
|
+
* never an `ensureRepo` side effect. */
|
|
382
|
+
getRepoHighWater(repo: string): Promise<number>
|
|
383
|
+
/** The stored reducer snapshot for a scope (a build log or a repository
|
|
384
|
+
* journal), a cache beside the log and never an authority. `null` when
|
|
385
|
+
* absent, when the stored version differs from `version`, when the stored
|
|
386
|
+
* cursor is ahead of the scope's log tail, or when the scope is unknown (no
|
|
387
|
+
* `ensureRepo` side effect, no rejection). A store without snapshot storage
|
|
388
|
+
* answers `null`. */
|
|
389
|
+
getReducerSnapshot(
|
|
390
|
+
scope: SnapshotScope,
|
|
391
|
+
reducer: string,
|
|
392
|
+
version: number,
|
|
393
|
+
): Promise<ReducerSnapshot | null>
|
|
394
|
+
/** Upsert a reducer snapshot; the stored cursor never decreases. Writes only
|
|
395
|
+
* when no row exists, when `cursor` is above the stored one (whatever the
|
|
396
|
+
* versions — a mismatched row is replaced as soon as any writer advances
|
|
397
|
+
* past it), or when the cursor is equal and `version` is higher. Everything
|
|
398
|
+
* else, and any cursor beyond the log tail, is a no-op. Atomic, so
|
|
399
|
+
* concurrent writers cannot undo each other's progress. Resolves `true`
|
|
400
|
+
* when the row was written. */
|
|
401
|
+
putReducerSnapshot(
|
|
402
|
+
scope: SnapshotScope,
|
|
403
|
+
reducer: string,
|
|
404
|
+
snapshot: ReducerSnapshot,
|
|
405
|
+
): Promise<boolean>
|
|
308
406
|
putRepoArtifact(repo: string, artifact: ArtifactInput): Promise<RepositoryArtifactMeta>
|
|
309
407
|
getRepoArtifact(repo: string, kind: string, rev?: number): Promise<RepositoryArtifact | null>
|
|
310
408
|
listRepoArtifacts(repo: string, kind?: string): Promise<RepositoryArtifactMeta[]>
|
|
409
|
+
// ── Ticket assets (SPEC §7.1 — files attached to a ticket) ─────────────
|
|
410
|
+
// Keyed by (repo, ticketId, kind, name); revisions are 0-based. The store
|
|
411
|
+
// owns the bytes, the ticket source only ever gets a note (SPEC §13).
|
|
412
|
+
/** The effective ceilings this store accepts for `repo` (a remote
|
|
413
|
+
* deployment may advertise lower ones than the defaults). */
|
|
414
|
+
ticketAssetLimits(repo: string): Promise<TicketAssetLimits>
|
|
415
|
+
/** Validate, then store a new revision. Over-limit or invalid input rejects
|
|
416
|
+
* with `TicketAssetValidationError` and stores nothing. */
|
|
417
|
+
putTicketAsset(repo: string, ticketId: string, asset: TicketAssetInput): Promise<TicketAssetMeta>
|
|
418
|
+
/** Latest live revision when `rev` is omitted; null when the asset is
|
|
419
|
+
* absent, removed (latest row is a tombstone), or `rev` is not a real
|
|
420
|
+
* revision. An explicit `rev` of an earlier revision keeps working after a
|
|
421
|
+
* removal, so a build that pinned it still retrieves it. */
|
|
422
|
+
getTicketAsset(
|
|
423
|
+
repo: string,
|
|
424
|
+
ticketId: string,
|
|
425
|
+
kind: string,
|
|
426
|
+
name: string,
|
|
427
|
+
rev?: number,
|
|
428
|
+
): Promise<TicketAsset | null>
|
|
429
|
+
/** The ticket asset `kind/name` exactly as build `slug` froze it (SPEC
|
|
430
|
+
* §6.3): the latest pinned revision, or with `rev` any revision the build
|
|
431
|
+
* ever pinned. Reads the build's own events, never the ticket's current
|
|
432
|
+
* state, so it is stable after a replace or removal and works for finished
|
|
433
|
+
* builds. Null when the build never pinned it. Rejects an unknown build. */
|
|
434
|
+
getPinnedTicketAsset(
|
|
435
|
+
slug: string,
|
|
436
|
+
kind: string,
|
|
437
|
+
name: string,
|
|
438
|
+
rev?: number,
|
|
439
|
+
): Promise<TicketAsset | null>
|
|
440
|
+
/** Default: the latest live revision per (kind, name). `revisions: true`:
|
|
441
|
+
* every real revision (no tombstones). Summaries carry no manifest. */
|
|
442
|
+
listTicketAssets(
|
|
443
|
+
repo: string,
|
|
444
|
+
ticketId: string,
|
|
445
|
+
opts?: { revisions?: boolean },
|
|
446
|
+
): Promise<TicketAssetSummary[]>
|
|
447
|
+
/** Tombstone the asset (the next revision number, empty manifest). Returns
|
|
448
|
+
* the removed revision's meta, or null when no live asset exists. */
|
|
449
|
+
removeTicketAsset(
|
|
450
|
+
repo: string,
|
|
451
|
+
ticketId: string,
|
|
452
|
+
kind: string,
|
|
453
|
+
name: string,
|
|
454
|
+
): Promise<TicketAssetMeta | null>
|
|
311
455
|
claimRepoLease(repo: string, holder: string, ttlMs: number): Promise<boolean>
|
|
312
456
|
heartbeatRepo(repo: string, holder: string): Promise<boolean>
|
|
313
457
|
releaseRepoLease(repo: string, holder: string): Promise<void>
|
|
@@ -339,6 +483,21 @@ export interface BuildStore {
|
|
|
339
483
|
id: string,
|
|
340
484
|
event: SessionEventWrite<T>,
|
|
341
485
|
): Promise<SessionEventEnvelope<T>>
|
|
486
|
+
/** Atomically append one validated session event only when the session's
|
|
487
|
+
* current sequence equals `expectedSeq` (0 would only match a session with
|
|
488
|
+
* no facts — impossible, since `session.created` is always seq 1). Returns
|
|
489
|
+
* null when the session has advanced; a comparison miss must not mutate the
|
|
490
|
+
* log or the record's `updatedAt`. The three turn-start sites (message
|
|
491
|
+
* route, answer route, dispatcher tick) race on the same idle session, and
|
|
492
|
+
* two concurrent `turn.started` facts would break the single-open-turn
|
|
493
|
+
* invariant — this is the sessions mirror of the build log's
|
|
494
|
+
* `appendIfCurrent`. Invalid events and unknown sessions reject just as
|
|
495
|
+
* they do for `appendSessionEvent`. */
|
|
496
|
+
appendSessionEventIfCurrent<T extends SessionEventType>(
|
|
497
|
+
id: string,
|
|
498
|
+
expectedSeq: number,
|
|
499
|
+
event: SessionEventWrite<T>,
|
|
500
|
+
): Promise<SessionEventEnvelope<T> | null>
|
|
342
501
|
/** Events with seq strictly greater than `sinceSeq` (default 0), in order.
|
|
343
502
|
* When nothing newer exists, an adapter honors `waitSeconds` with the
|
|
344
503
|
* same clamp/early-return rules as stream reads (§7.6): whole seconds,
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public testing entry point: the deterministic doubles, CLI entry points,
|
|
3
|
+
* and the end-to-end harness that out-of-tree packages' tests build against
|
|
4
|
+
* (the hosted store-service suite is the in-repo consumer). Production code
|
|
5
|
+
* never imports from here — it is test-facing surface, like plugin-sdk's
|
|
6
|
+
* fakes, just CLI-shaped.
|
|
7
|
+
*/
|
|
8
|
+
// The plugin-sdk's contract suites, fakes, and memory stores are the shared
|
|
9
|
+
// testing vocabulary; re-export so `@defrex/autobuild/testing` is one import.
|
|
10
|
+
export * from '../plugin-sdk'
|
|
11
|
+
export { manualClock, steppingClock } from './fixed'
|
|
12
|
+
export { agentActor, DISPATCHER, KERNEL, humanActor, type Via } from '../events/envelope'
|
|
13
|
+
export { EventValidationError } from '../events/catalog'
|
|
14
|
+
export type { EscalationSource } from '../ontology'
|
|
15
|
+
export { abDispatch, type DispatchOpts } from '../cli/dispatch'
|
|
16
|
+
// CLI entry points for the hosted-dispatcher integration test: programmatic
|
|
17
|
+
// `ab` invocation and its environment resolution.
|
|
18
|
+
export { resolveCliEnv } from '../cli/env'
|
|
19
|
+
export { runCli } from '../cli/main'
|
|
20
|
+
// Deterministic id doubles for the hosted-dispatcher integration test.
|
|
21
|
+
export { randomUuids, sequentialIds, type IdSource } from '../ids'
|
|
22
|
+
export { abWatch } from '../cli/watch'
|
|
23
|
+
export { abTicket, type TicketSourceFactory } from '../cli/ticket'
|
|
24
|
+
export { createTerminalModeController } from '../cli/terminal-restore'
|
|
25
|
+
export { abBuildControl, type BuildControlAction } from '../cli/build-control'
|
|
26
|
+
export { abBulkControl } from '../cli/bulk-control'
|
|
27
|
+
export { createTicketSource } from '../ports/tickets/create'
|
|
28
|
+
export { createOperatorSandboxService } from '../operator/sandbox'
|
|
29
|
+
export { parseConfig } from '../config/load'
|
|
30
|
+
export { spawnExec, type Exec } from '../ports/workspace/git-worktree'
|
|
31
|
+
// Durable guest-launch state readers + the in-process guest runner for the
|
|
32
|
+
// hosted-dispatcher integration test's GuestExecution double, which supervises
|
|
33
|
+
// a real BuildRunner exactly as a real sandbox execution would.
|
|
34
|
+
export {
|
|
35
|
+
BUILD_EFFECTIVE_CONFIG_ARTIFACT,
|
|
36
|
+
diagnosticArtifact,
|
|
37
|
+
parseEffectiveBuildConfig,
|
|
38
|
+
selectOpenWorkspace,
|
|
39
|
+
} from '../processes/build-execution-state'
|
|
40
|
+
export {
|
|
41
|
+
BuildRunner,
|
|
42
|
+
LeaseHeldError,
|
|
43
|
+
SetupFailureError,
|
|
44
|
+
} from '../processes/build-runner'
|
|
45
|
+
export { readEventsWithWait } from '../store/streams/wait'
|
|
46
|
+
export { textContent } from '../store/types'
|
|
47
|
+
export {
|
|
48
|
+
CONFIG_TOML,
|
|
49
|
+
GIT_ID,
|
|
50
|
+
git,
|
|
51
|
+
happyHandlers,
|
|
52
|
+
makeHarness,
|
|
53
|
+
readyTicket,
|
|
54
|
+
typesOf,
|
|
55
|
+
writeFileIn,
|
|
56
|
+
type Cli,
|
|
57
|
+
type E2eHarness,
|
|
58
|
+
type SkillHandlers,
|
|
59
|
+
} from '../integration/harness'
|
|
@@ -27,7 +27,11 @@ goes nowhere.
|
|
|
27
27
|
fake or mock are not contract evidence because they can repeat the
|
|
28
28
|
author's assumption.
|
|
29
29
|
- **Spec conformance** — every acceptance criterion met; nothing beyond
|
|
30
|
-
the spec's scope smuggled in.
|
|
30
|
+
the spec's scope smuggled in. A pinned `design` asset (listed under
|
|
31
|
+
`assets` in `.ab/context.json`, files under `.ab/assets/<kind>/<name>/`)
|
|
32
|
+
is a contract on observable visual and reference outcomes, not on implementation: judge the rendered output against it wherever the code lets you
|
|
33
|
+
check, and treat a divergence as a finding. A gap in the asset is not a
|
|
34
|
+
reason to invent requirements.
|
|
31
35
|
- **Tests** — do the new tests exercise the seams this change created or
|
|
32
36
|
moved? Would they fail if the change were wrong?
|
|
33
37
|
- **Fit** — matches the codebase's idioms; no needless indirection.
|
package/skills/guide/SKILL.md
CHANGED
|
@@ -65,6 +65,13 @@ spec → plan ⇄ plan-review → implement ⇄ code-review → verify:* → fin
|
|
|
65
65
|
claims tickets that pass the `[tickets]` ready
|
|
66
66
|
gate, chooses a short immutable slug from the final conforming spec, and
|
|
67
67
|
starts builds up to the top-level `capacity` bound.
|
|
68
|
+
- **Ticket assets** — files or folders attached to a ticket (see
|
|
69
|
+
[Ticket assets](#ticket-assets)) are frozen into the build at claim and
|
|
70
|
+
appear under `.ab/assets/` in every phase, as inputs alongside the spec.
|
|
71
|
+
A `design` asset is part of the contract: `plan`, `plan-review`, `implement`,
|
|
72
|
+
`code-review`, and agent verify steps judge against it, as a contract on
|
|
73
|
+
observable visual and reference outcomes, not on implementation. Other kinds
|
|
74
|
+
are reference material.
|
|
68
75
|
- **`spec`** — the ticket's spec becomes the build's contract. The `ab-spec`
|
|
69
76
|
skill is the human-interactive surface for producing it, and it runs *before*
|
|
70
77
|
a build exists.
|
|
@@ -337,7 +344,7 @@ gitPasswordEnv = "AB_GIT_READ_TOKEN"
|
|
|
337
344
|
|
|
338
345
|
[workspace.config.runtimeProvisioning.pi]
|
|
339
346
|
install = "npm install --global --ignore-scripts @earendil-works/pi-coding-agent@0.84.4"
|
|
340
|
-
preflight = "test \"$(pi --version)\" = \"0.84.4\""
|
|
347
|
+
preflight = "test \"$(pi --version)\" = \"0.84.4\" && pi update --models"
|
|
341
348
|
```
|
|
342
349
|
|
|
343
350
|
`timeoutSeconds` is required (60–86400; Hobby currently caps at 2700), `vcpus`
|
|
@@ -413,6 +420,12 @@ Names must already exist in `[verify].steps` with matching tables; duplicates,
|
|
|
413
420
|
blanks, unknown names, malformed metadata, and omission of an `always = true`
|
|
414
421
|
step make the planner's `ab done` fail before `plan.completed` is appended.
|
|
415
422
|
|
|
423
|
+
An agent verify step is handed the build's pinned ticket assets under
|
|
424
|
+
`.ab/assets/` (listed in `.ab/context.json`) as well as the spec. A verify skill
|
|
425
|
+
should treat a `design` asset as part of the contract, a contract on observable
|
|
426
|
+
visual and reference outcomes, not on implementation, and judge the result
|
|
427
|
+
against it.
|
|
428
|
+
|
|
416
429
|
An agent verify step selects `[roles.<step>]` by its **logical step name** —
|
|
417
430
|
the name in `[verify].steps`, not the skill it runs. An agent finalize
|
|
418
431
|
post-step follows the same rule.
|
|
@@ -719,7 +732,8 @@ state eligible.
|
|
|
719
732
|
|---|---|---|---|
|
|
720
733
|
| `source` | — | **required**, nonblank builtin or plugin registration name | Which provider backs all ticket operations. Unknown names report every available builtin and plugin source. |
|
|
721
734
|
| `readyLabels` | — (source-aware) | optional; array of nonempty strings | A ticket must carry **every** listed label to be dispatchable. `[]` = **no label gate**. Absent uses the source default below. |
|
|
722
|
-
| `readyState` | — | **required**, non-blank string | The one workflow state a ticket must sit in to be dispatchable. Linear matches exactly and case-sensitively; file
|
|
735
|
+
| `readyState` | — | **required**, non-blank string | The one workflow state a ticket must sit in to be dispatchable. Linear matches exactly and case-sensitively; file matches it case-insensitively to a state directory (`ready` → `ready/`). There is no any-state mode. |
|
|
736
|
+
| `readyAssignee` | — | optional; `"me"` or an email; `linear` only | Also require the ticket to be assigned to that Linear user (`me` = owner of `LINEAR_API_KEY`); unassigned tickets are never ready. |
|
|
723
737
|
| `teamKey` | — | required by `linear`, forbidden by `file`, allowed for plugins | The Linear team key (e.g. `"ENG"`) or an existing plugin configuration field. |
|
|
724
738
|
| `claimedState` | — | optional nonempty string; forbidden by `file`, allowed for plugins | Workflow state `claim()` moves a ticket to when a build starts. |
|
|
725
739
|
| `createState` | — | optional, nonempty string | Default state for new tickets when a create does not name one. Absent = the provider's default (Linear: the team's default, e.g. Backlog; file: Triage). |
|
|
@@ -759,11 +773,16 @@ Cross-field rules, each an **error**:
|
|
|
759
773
|
janitor completion. Every source-agnostic `ab ticket` command loads and uses
|
|
760
774
|
the same configured registration.
|
|
761
775
|
|
|
762
|
-
The file tracker is **directory-per-state**: `<dir>/<state>/<id>.md
|
|
763
|
-
|
|
776
|
+
The file tracker is **directory-per-state**: `<dir>/<state>/<id>.md`, where
|
|
777
|
+
every directory directly under the root is a state: the four lifecycle
|
|
778
|
+
directories `triage/ ready/ doing/ done/` (always present, created on first use)
|
|
779
|
+
plus any others the repository adds, such as `icebox/`. A state exists when its
|
|
780
|
+
directory exists; state names match directories case-insensitively, and a name
|
|
781
|
+
with no directory is an error listing those that exist. The directory *is* the
|
|
782
|
+
state, so a transition or
|
|
764
783
|
claim is a rename — frontmatter carries no `state`/`claimedBy`, and a ticket
|
|
765
784
|
body survives byte-exactly because a move never rewrites the file. A malformed
|
|
766
|
-
record in any
|
|
785
|
+
record in any state directory is diagnosed with its path and validation
|
|
767
786
|
problem, left untouched, and excluded from listing/claim so unrelated valid
|
|
768
787
|
ready work can continue. `ab ticket list` sends those diagnostics to stderr and
|
|
769
788
|
keeps JSON stdout as one bare valid-ticket array. Tracker-wide safety checks
|
|
@@ -771,8 +790,8 @@ remain fatal: the same id in two state dirs is a loud error naming both paths,
|
|
|
771
790
|
as are root-level ticket files with no state and filesystem failures. When
|
|
772
791
|
`dir` is defaulted, the backlog writes its own `.gitignore` of `*`, so git never sees it; an
|
|
773
792
|
explicit `dir` is the user's and is left alone. Agents and operators drive it
|
|
774
|
-
through the source-agnostic `ab ticket` commands rather than running `mv`
|
|
775
|
-
hand.
|
|
793
|
+
through the source-agnostic `ab ticket` commands rather than running `mv` or
|
|
794
|
+
`mkdir` by hand; `ab ticket state create` makes a new state.
|
|
776
795
|
|
|
777
796
|
**Secrets never live in this file.** `LINEAR_API_KEY` and plugin-declared
|
|
778
797
|
`requiredEnv` credentials are environment variables (a local `.env` works).
|
|
@@ -782,15 +801,21 @@ environment variable instead and say why.
|
|
|
782
801
|
|
|
783
802
|
### `[orchestrator]`
|
|
784
803
|
|
|
785
|
-
Gates the operator-
|
|
786
|
-
environment per operator × repository that an
|
|
787
|
-
`sandbox.*` registry tools (`ab mcp`, and
|
|
788
|
-
|
|
789
|
-
|
|
804
|
+
Gates the operator-agent feature (AUT-340, AUT-342): the persistent,
|
|
805
|
+
**credential-free** sandbox environment per operator × repository that an
|
|
806
|
+
operator agent drives through the `sandbox.*` registry tools (`ab mcp`, and
|
|
807
|
+
every later binding), and — when the embedded orchestrator is enabled — the
|
|
808
|
+
turn runner that answers operator sessions and wakes on build attention
|
|
809
|
+
events. The whole table is **closed to unknown keys** and restart-classified:
|
|
810
|
+
changing it requires a dispatcher restart.
|
|
790
811
|
|
|
791
812
|
| Field | Default | Allowed / constraints | Effect |
|
|
792
813
|
|---|---|---|---|
|
|
793
|
-
| `enabled` | `false` | boolean | Master gate. With the table absent or `enabled = false`, the sandbox tools are absent from every binding
|
|
814
|
+
| `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. |
|
|
815
|
+
| `model` | — (required when `enabled = true`) | nonblank provider-qualified string, same vocabulary as `[roles]` | The turn runner's model, resolved through the deployment's gateway credential; a leading `vercel-ai-gateway/` prefix is accepted and stripped. |
|
|
816
|
+
| `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. |
|
|
817
|
+
| `approvals` | `["builds.control:abort", "builds.control:discard", "builds.answer:revise-spec", "sandbox.publish", "tickets.move:ready"]` | array of `tool` or `tool:qualifier` strings | Registry tool calls that suspend a turn until the operator answers. Empty (`[]`) means none — autonomous operation. An entry naming an absent or unknown tool is **inert by design**, never an error. A qualified entry applies to one discriminator value only (`tickets.move:ready` approves moving a ticket to `ready`); for a tool without a discriminator, only the bare form matches. |
|
|
818
|
+
| `wake` | inherits the default | array of event-type globs | The attention events a **new** session wakes for. Absent inherits the default attention set (the events `ab watch` filters on by default); an explicit `[]` means never wake — message-only. Each glob must match at least one build event type. Existing sessions never retroactively inherit; an explicit wake update always wins. |
|
|
794
819
|
| `sandbox` | — | strict subtable | The sandbox behavior knobs; absence reads as the defaults below. |
|
|
795
820
|
|
|
796
821
|
`[orchestrator.sandbox]` fields:
|
|
@@ -814,6 +839,20 @@ and archiving an operator's last session are **destructive** (reset re-provision
|
|
|
814
839
|
from the current base head); there is at most **one** environment per operator
|
|
815
840
|
and repository.
|
|
816
841
|
|
|
842
|
+
Publication: `sandbox.publish` takes a title (1–200 characters), an optional
|
|
843
|
+
body (≤65,536 characters), and an optional explicit commit, and takes your
|
|
844
|
+
sandbox's current head commit to a pull request. It refuses when the checkout
|
|
845
|
+
has uncommitted changes — tracked or untracked (the sandbox's own provisioning
|
|
846
|
+
marker is excluded) — and when the commit is not a descendant of the base head
|
|
847
|
+
recorded when the sandbox was provisioned or last reset — a pre-existing environment without a recorded
|
|
848
|
+
base head asks you to run `sandbox.reset` first. The rule is PR only, never the
|
|
849
|
+
base branch: the sandbox itself never pushes and holds no credential — the push
|
|
850
|
+
and the PR creation are kernel plumbing through the workspace provider's
|
|
851
|
+
publication capability, to one deterministic operator branch per operator and
|
|
852
|
+
repository, so a later publish updates the same PR's head. A publication is a
|
|
853
|
+
repository-journal fact naming the operator, the session, the branch, the
|
|
854
|
+
commit, and the PR; a refused or failed attempt is journaled too.
|
|
855
|
+
|
|
817
856
|
## Setup and upgrades
|
|
818
857
|
|
|
819
858
|
**`ab init <target> [--force]`** runs *outside* build sessions — it takes a
|
|
@@ -827,7 +866,7 @@ repo path, needs no `AB_*` environment, and is safe to re-run. It:
|
|
|
827
866
|
`[commands]`, no verify or finalize steps, a valid local ticket gate, and one
|
|
828
867
|
explicit runtime solely as a schema placeholder. It reads no package or
|
|
829
868
|
language manifest and invents no command.
|
|
830
|
-
- Vendors
|
|
869
|
+
- Vendors 12 skills before handoff, including the locally editable
|
|
831
870
|
[repository setup reference](references/setup.md) in the installed `ab-guide`
|
|
832
871
|
tree. On an interactive terminal it starts the selected coding-agent CLI in
|
|
833
872
|
the target repository with a short prompt to read that reference and
|
|
@@ -1030,6 +1069,19 @@ with Linear and the file tracker, without provider-specific API/MCP calls:
|
|
|
1030
1069
|
labeled metadata and the body verbatim, so it can read a stored spec back.
|
|
1031
1070
|
- `ab ticket move <id> <state> [--json]` transitions one ticket and reports its
|
|
1032
1071
|
post-transition value.
|
|
1072
|
+
- `ab ticket states [--json]` lists every state of the configured source:
|
|
1073
|
+
lifecycle states first (triage, ready, doing, done), then custom states
|
|
1074
|
+
alphabetically. Each row has the state name, the roles it plays under the
|
|
1075
|
+
current config (create, ready, claimed, triage, proposal, done, or none), its
|
|
1076
|
+
ticket count, and its purpose when set. `--json` emits one bare array of
|
|
1077
|
+
`{name, roles, tickets, about?}`.
|
|
1078
|
+
- `ab ticket state create <name> [--about <text>] [--json]` makes a state, for
|
|
1079
|
+
example `icebox`. It is idempotent: an existing state is reported as already
|
|
1080
|
+
existing, and `--about` (one line) records or replaces its purpose. A name is
|
|
1081
|
+
one to forty lowercase letters, digits, and hyphens starting with a letter,
|
|
1082
|
+
and may not match an existing state case-insensitively. There is no rename or
|
|
1083
|
+
delete. Only the file source supports `states` and `state create`; other
|
|
1084
|
+
sources exit nonzero naming the source and the unsupported operation.
|
|
1033
1085
|
|
|
1034
1086
|
State names and ids are source-local. For block and unblock, the first id is the
|
|
1035
1087
|
ticket being changed and the comma-separated second operand names its blockers.
|
|
@@ -1070,6 +1122,37 @@ subcommand accepts `--json`, which emits one bare JSON value and no prose: a
|
|
|
1070
1122
|
`Ticket[]` for `list`, and the complete resulting `Ticket` for `create`,
|
|
1071
1123
|
`update`, `block`, `unblock`, `show`, or `move`.
|
|
1072
1124
|
|
|
1125
|
+
### Ticket assets
|
|
1126
|
+
|
|
1127
|
+
A ticket asset is a file or folder attached to a ticket and stored in the
|
|
1128
|
+
BuildStore, never in the ticket source: a design export, reference screenshots,
|
|
1129
|
+
a sample payload. Each has a kind and a name.
|
|
1130
|
+
|
|
1131
|
+
- `ab ticket attach <id> <kind> <path> [--name <name>] [--json]` stores `<path>`
|
|
1132
|
+
(default name: its basename). Attaching the same kind and name again makes a
|
|
1133
|
+
new revision; earlier ones stay retrievable. Over the store's size limit
|
|
1134
|
+
(25 MiB by default, lower on a hosted deployment) it is refused. Attach and
|
|
1135
|
+
remove leave a note on the ticket naming the asset.
|
|
1136
|
+
- `ab ticket show <id>` lists the current assets; with `--json` the ticket
|
|
1137
|
+
gains an `assets` array.
|
|
1138
|
+
- `ab ticket asset get <id> <kind> <name> <dest> [--rev <n>]` downloads the
|
|
1139
|
+
exact bytes of the latest (or given) revision; `ab ticket asset rm <id> <kind>
|
|
1140
|
+
<name>` drops it from the current assets.
|
|
1141
|
+
- **Frozen at claim.** A claim pins the current revisions into the build. A
|
|
1142
|
+
later attach or remove leaves a running build alone; a human answer with
|
|
1143
|
+
`--revise-spec-from-ticket` pins again. `ab build asset get <slug> <kind>
|
|
1144
|
+
<name> <dest> [--rev <n>]` downloads what the build froze, also after it ends.
|
|
1145
|
+
- **Where phases find them.** `ab context` writes each pinned asset to
|
|
1146
|
+
`.ab/assets/<kind>/<name>/` (a file asset is the single file inside that
|
|
1147
|
+
directory) and lists them under `assets` in `.ab/context.json` with kind,
|
|
1148
|
+
name, revision, layout, size, and path. The key is absent when the build has
|
|
1149
|
+
none.
|
|
1150
|
+
|
|
1151
|
+
By convention the `design` kind is a visual or reference contract, exported to
|
|
1152
|
+
static files when the ticket is groomed, so no build converts a link. The spec
|
|
1153
|
+
cites it by kind and name. See [the lifecycle](#the-lifecycle) for how phases
|
|
1154
|
+
judge against it.
|
|
1155
|
+
|
|
1073
1156
|
## Retrieving build artifacts
|
|
1074
1157
|
|
|
1075
1158
|
`ab artifact download <build> <kind>[@rev] --output <file> [--store <ref>]`
|
|
@@ -1081,6 +1164,17 @@ Inside a phase, a complete ambient tuple permits only the ambient build; a
|
|
|
1081
1164
|
foreign build or malformed/partial identity is rejected. Use the exact pinned
|
|
1082
1165
|
`@rev` from a PR attachment command.
|
|
1083
1166
|
|
|
1167
|
+
Repository-scoped streams have their own form:
|
|
1168
|
+
`ab artifact download stream:<id>[@rev] --output <file> [--store <ref>]`. A
|
|
1169
|
+
stream id is store-assigned and globally unique, so no build argument is
|
|
1170
|
+
needed; the command resolves the stream, requires it to be repository-scoped
|
|
1171
|
+
and owned by this repository, and retrieves the artifact its close finalized
|
|
1172
|
+
(§7.6) — an open stream has no artifact yet. This form is strictly an operator
|
|
1173
|
+
read: under any complete ambient build or Harvest identity it fails closed
|
|
1174
|
+
(§8.2), since repository-scoped targets are never reachable by ambient
|
|
1175
|
+
own-build or own-harvest authority. Find stream ids in the session rows of
|
|
1176
|
+
`ab harvest status`.
|
|
1177
|
+
|
|
1084
1178
|
In a build session, `ab artifact put <kind> <file> --attach` atomically deposits
|
|
1085
1179
|
the exact bytes and designates that revision for the PR. A later designation of
|
|
1086
1180
|
the same kind replaces it; distinct kinds remain distinct attachments. The
|
|
@@ -1214,16 +1308,19 @@ on its first paint; clearing the hold removes both on the next poll. The hold
|
|
|
1214
1308
|
survives a restart and is not defeated by re-running `ab dispatch`.
|
|
1215
1309
|
|
|
1216
1310
|
`--auto-merge` and `--no-auto-merge` similarly set the durable repository
|
|
1217
|
-
|
|
1311
|
+
auto-merge default; omission reuses stored state, falling back to OFF only when
|
|
1218
1312
|
no fact exists. The forms are mutually exclusive independently of the intake
|
|
1219
1313
|
pair. Global-row `m` re-reads current state, appends the opposite value, and
|
|
1220
1314
|
posts a dispatcher notice. When on, each fresh dispatcher claim records the
|
|
1221
1315
|
existing human-authored `build.auto-merge-requested` fact immediately after
|
|
1222
1316
|
`build.created` and before runner launch. The first visible build frame therefore
|
|
1223
|
-
carries `auto merge`.
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
the
|
|
1317
|
+
carries `auto merge`. The default is also a bulk action over current builds:
|
|
1318
|
+
on each change the dispatcher reconciles every non-terminal build against the
|
|
1319
|
+
newest fact, requesting consent when it turns on and withdrawing it when it
|
|
1320
|
+
turns off, attributed to the toggling operator exactly as a row keypress would
|
|
1321
|
+
be. A per-build toggle overrides its build's state until the global row is
|
|
1322
|
+
toggled again, so a seeded or fanned build can still be cancelled while the
|
|
1323
|
+
global default stays on. Both repository settings are independently
|
|
1227
1324
|
last-write-wins by event sequence. They are stored in the BuildStore, not in
|
|
1228
1325
|
`autobuild.toml`; propagation uses polling, not a push channel.
|
|
1229
1326
|
|
|
@@ -1249,10 +1346,13 @@ settles every exhaustion barrier. Exhaustion and escalation remain terminal.
|
|
|
1249
1346
|
Escalation's row is dismissed only by a post-terminal human resume request
|
|
1250
1347
|
followed by its later kernel acknowledgement, never by the request alone.
|
|
1251
1348
|
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1349
|
+
Every build row renders an explicit `auto merge <state>` token, including off:
|
|
1350
|
+
cyan means requested locally but not yet applied on GitHub, green means native
|
|
1351
|
+
auto-merge is enabled, yellow means cancellation is in flight, and dim means
|
|
1352
|
+
off — turning red while the repository default reads ON, so the
|
|
1353
|
+
consent mismatch is visible without opening the detail view. A build parked on
|
|
1354
|
+
an open PR with no consent carries the reason on its merge step, naming the
|
|
1355
|
+
per-build control that requests it.
|
|
1256
1356
|
Merge conflicts recover automatically: the gate defers, the pipeline re-enters
|
|
1257
1357
|
reconcile, and verify re-runs before consent is re-examined — the reconcile
|
|
1258
1358
|
step on the build row is the only indication, and uncomputed mergeability
|
|
@@ -1509,10 +1609,12 @@ stream:<id>` retrieves the closed session's finalized document.
|
|
|
1509
1609
|
Harvest sessions stream the same protocol into *repository-scoped* streams:
|
|
1510
1610
|
the harvest runner's synthesize and review brackets each get one stream
|
|
1511
1611
|
(`phase` spelled `harvest:<step>`), with `harvest.session.started` carrying
|
|
1512
|
-
the stream id.
|
|
1513
|
-
|
|
1514
|
-
`
|
|
1515
|
-
|
|
1612
|
+
the stream id. `ab harvest status` shows each run's sessions the way build
|
|
1613
|
+
status does — one row per session with its stream id and open/closed status
|
|
1614
|
+
(`session hs_… (harvest, synthesize@1) stream st_… (open)`). Once a stream
|
|
1615
|
+
closes, its finalized document is a repository-scoped `stream:<id>` artifact,
|
|
1616
|
+
and `ab artifact download stream:<id>` retrieves it; the stream form is an
|
|
1617
|
+
operator-only read (ambient phase identity fails closed).
|
|
1516
1618
|
|
|
1517
1619
|
**`ab watch [<slug>...] [--repository] [--event <glob>]... [--since <cursor>]
|
|
1518
1620
|
[--timeout <dur>] [--interval <dur>] [--count <n>] [--json] [--store <ref>]`**
|
|
@@ -1553,7 +1655,10 @@ The watch ends with exit 0 when `--timeout` elapses (30 minutes by default;
|
|
|
1553
1655
|
gone terminal; with no slugs named, an empty set of active builds does not end
|
|
1554
1656
|
it. Usage errors, scope violations, unknown slugs, and cursor rejection exit 1
|
|
1555
1657
|
before any record. A store read that fails after the watch has started is
|
|
1556
|
-
reported
|
|
1658
|
+
reported on stderr once per failing read source — locally the poll cycle is
|
|
1659
|
+
one source, while against an `http(s)` store each tracked stream and the
|
|
1660
|
+
discovery pass carries its own failure streak — and retried without
|
|
1661
|
+
duplicating or skipping any event.
|
|
1557
1662
|
Against a local store the default cadence polls every 1 second. Against an
|
|
1558
1663
|
`http(s)` store each tracked stream long-polls instead — one held request per
|
|
1559
1664
|
stream waits up to 25 seconds for the next event, requests run concurrently,
|
|
@@ -1635,8 +1740,11 @@ condition (one record with `condition` null, showing how the build ended); 3 —
|
|
|
1635
1740
|
stdout is a bare `{"cursor": …}` object for the final position, plus one line
|
|
1636
1741
|
on stderr); 4 — interrupted by SIGINT before any condition was satisfied (same
|
|
1637
1742
|
cursor behavior as 3). The default poll interval and `--interval` match
|
|
1638
|
-
`ab watch`. A store read that fails while waiting is reported
|
|
1639
|
-
|
|
1743
|
+
`ab watch`. A store read that fails while waiting is reported on stderr once
|
|
1744
|
+
per failing read source — locally the poll cycle is one source, while
|
|
1745
|
+
against an `http(s)` store each tracked build and the discovery pass carries
|
|
1746
|
+
its own failure streak — and retried without missing or duplicating a
|
|
1747
|
+
condition. The command is
|
|
1640
1748
|
read-only — it appends no event, takes no lease, and creates no record — and
|
|
1641
1749
|
deciding what to do about a match stays with the caller's skill.
|
|
1642
1750
|
|
|
@@ -1760,7 +1868,7 @@ default, when you need to know what this repo's version says).
|
|
|
1760
1868
|
| Skill | Place in the lifecycle | Purpose |
|
|
1761
1869
|
|---|---|---|
|
|
1762
1870
|
| `ab-spec` | Before a build exists | Design a feature spec-first through conversation, or flesh out a ticket to the spec standard. The human-interactive surface; takes a ticket, not a build slug. **Model-invocable.** |
|
|
1763
|
-
| `ab-tickets` | Before a build exists | Drive this repo's local file tracker: create a ticket, report the backlog, groom or move one between `triage/ ready/ doing/ done
|
|
1871
|
+
| `ab-tickets` | Before a build exists | Drive this repo's local file tracker: create a ticket, report the backlog, groom or move one between the lifecycle directories (`triage/ ready/ doing/ done/`) and any repository-defined states, including the icebox. The agent-facing surface on the tracker — use it instead of `mv`. **Model-invocable.** |
|
|
1764
1872
|
| `ab-guide` | Outside the pipeline | This skill: reference for the lifecycle, config surface, setup/upgrade behavior, and the installed skills. Its editable `references/setup.md` guides the init handoff. **Model-invocable.** |
|
|
1765
1873
|
| `ab-harvest` | harvest `synthesize` step | Continue the producer across review rounds: cluster the claimed structured observations and author typed spec-standard create/join/suppress proposals. Runner-only. |
|
|
1766
1874
|
| `ab-harvest-review` | harvest `review` step | Fresh adversarial reviewer for proposal coverage, semantic dedup, spec quality, and evidence; returns `approve`/`revise`/`escalate`. Runner-only. |
|
|
@@ -1770,12 +1878,16 @@ default, when you need to know what this repo's version says).
|
|
|
1770
1878
|
| `ab-code-review` | `code-review` phase | Fresh skeptic: review the implementation diff against spec and plan, same verdict vocabulary. |
|
|
1771
1879
|
| `ab-reconcile` | `reconcile` phase (epilogue) | Resolve a conflicted PR with one merge commit, base merged *into* the build branch. Never rebases. |
|
|
1772
1880
|
| `ab-finalize` | `finalize` phase | Write the PR description for a green build; the kernel opens the PR. |
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
`ab-
|
|
1776
|
-
`disable-model-invocation: true` — do not invoke a phase
|
|
1777
|
-
not remove that key to make one convenient to call. A
|
|
1778
|
-
phase by pattern-matching a description is exactly
|
|
1779
|
-
three exceptions drive no phase, which is
|
|
1780
|
-
`ab-spec` and `ab-tickets` are
|
|
1781
|
-
`ab-guide` is read-only reference
|
|
1881
|
+
| `ab-operate` | hosted only | The embedded orchestrator's own operating manual: its role, the registry tool surface with the approval semantics, the attention set, wake-trigger input, budget/approval suspension, and when to escalate to the operator rather than act. Invoked by the embedded orchestrator, never vendored into a build session. |
|
|
1882
|
+
|
|
1883
|
+
Autobuild installs 12 skills. Everything except `ab-spec`, `ab-tickets`, and
|
|
1884
|
+
`ab-guide` carries `disable-model-invocation: true` — do not invoke a phase
|
|
1885
|
+
skill yourself, and do not remove that key to make one convenient to call. A
|
|
1886
|
+
model starting a pipeline phase by pattern-matching a description is exactly
|
|
1887
|
+
what the flag prevents. Those three exceptions drive no build phase, which is
|
|
1888
|
+
the criterion for membership (§16.3): `ab-spec` and `ab-tickets` are
|
|
1889
|
+
human/agent-facing pre-build surfaces, and `ab-guide` is read-only reference
|
|
1890
|
+
including the setup handoff guidance. The fourth skill outside the
|
|
1891
|
+
model-invocable set, `ab-operate`, is not a build-phase skill either: it is the
|
|
1892
|
+
embedded orchestrator's own operating manual, read by the hosted turn runner as
|
|
1893
|
+
its system prompt and never invoked by a model in a build session.
|
|
@@ -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:
|