@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
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Config } from '../config/schema'
|
|
2
2
|
import { configSchema } from '../config/schema'
|
|
3
|
+
import { BUILD_OWNED_CONFIG_PATHS } from '../config/live'
|
|
4
|
+
import { isPipelineSourceRef, type PipelineSourceMeta } from '../config/pipeline-source'
|
|
3
5
|
import type { AbEvent } from '../events/catalog'
|
|
4
6
|
import type { Artifact, ArtifactInput } from '../store/types'
|
|
5
7
|
|
|
@@ -46,6 +48,41 @@ export function parseEffectiveBuildConfig(artifact: Artifact): Config {
|
|
|
46
48
|
return result.data
|
|
47
49
|
}
|
|
48
50
|
|
|
51
|
+
/** Read the artifact metadata's revision + pipeline-source projection. Old
|
|
52
|
+
* deposits (and externally written ones) carry no `pipelineSource`; status and
|
|
53
|
+
* the dashboard render that as "unknown (pre-pin)" instead of guessing. */
|
|
54
|
+
export function parseBuildConfigMetadata(artifact: Artifact): {
|
|
55
|
+
revision?: number
|
|
56
|
+
pipelineSource?: PipelineSourceMeta
|
|
57
|
+
} {
|
|
58
|
+
const metadata = artifact.meta.metadata
|
|
59
|
+
const revision = metadata.revision
|
|
60
|
+
const raw = metadata.pipelineSource
|
|
61
|
+
let pipelineSource: PipelineSourceMeta | undefined
|
|
62
|
+
if (typeof raw === 'object' && raw !== null) {
|
|
63
|
+
const value = raw as Record<string, unknown>
|
|
64
|
+
if (isPipelineSourceRef(value.ref)) {
|
|
65
|
+
pipelineSource = {
|
|
66
|
+
ref: value.ref,
|
|
67
|
+
...(typeof value.commit === 'string' ? { commit: value.commit } : {}),
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
...(typeof revision === 'number' ? { revision } : {}),
|
|
73
|
+
...(pipelineSource !== undefined ? { pipelineSource } : {}),
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** True when two configs' build-owned sections differ — the guest's defensive
|
|
78
|
+
* guard against a deposit that rewrites the pinned pipeline without a recorded
|
|
79
|
+
* pipeline-source commit advance. */
|
|
80
|
+
export function buildOwnedSectionsDiffer(a: Config, b: Config): boolean {
|
|
81
|
+
return BUILD_OWNED_CONFIG_PATHS.some(
|
|
82
|
+
(path) => JSON.stringify(a[path]) !== JSON.stringify(b[path]),
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
49
86
|
/** Latest workspace location not followed by release. Historical events use
|
|
50
87
|
* the provider ref as the path compatibility fallback. */
|
|
51
88
|
export function selectOpenWorkspace(events: readonly AbEvent[]): {
|
|
@@ -48,6 +48,7 @@ import type { Config } from '../config/schema'
|
|
|
48
48
|
import type { AbEvent, EventWrite } from '../events/catalog'
|
|
49
49
|
import type { EventPayload } from '../events/payloads'
|
|
50
50
|
import { KERNEL, agentActor, type Actor } from '../events/envelope'
|
|
51
|
+
import { isRemoteWorkspace } from '../events/workspace-remote'
|
|
51
52
|
import type { IdSource } from '../ids'
|
|
52
53
|
import { decideNext, type Decision } from '../kernel/engine'
|
|
53
54
|
import { PHASE_SPECS } from '../kernel/phases'
|
|
@@ -240,6 +241,12 @@ interface SessionSpec {
|
|
|
240
241
|
/** Longest tail of check output preserved in a verify report (§8.2). */
|
|
241
242
|
const REPORT_TAIL_CHARS = 10_000
|
|
242
243
|
|
|
244
|
+
/** Per-section cap for the finalize preflight's dirty-worktree diff capture:
|
|
245
|
+
* each diff view (working tree, staged) is truncated at this many characters
|
|
246
|
+
* so a large dirty diff cannot bloat the failure record unboundedly — worst
|
|
247
|
+
* case ≈ porcelain + 2 × (cap + header). */
|
|
248
|
+
const FINALIZE_DIFF_CAPTURE_CAP = 20_000
|
|
249
|
+
|
|
243
250
|
/**
|
|
244
251
|
* One session bracket's live stream (SPEC §9): the sink the build-runner
|
|
245
252
|
* opened through the resolved target's streaming capability, the store id it
|
|
@@ -260,6 +267,14 @@ function errorMessage(error: unknown): string {
|
|
|
260
267
|
return error instanceof Error ? error.message : String(error)
|
|
261
268
|
}
|
|
262
269
|
|
|
270
|
+
/** Bound one captured diff section: unchanged within the cap, otherwise the
|
|
271
|
+
* first FINALIZE_DIFF_CAPTURE_CAP characters plus an explicit truncation
|
|
272
|
+
* marker, so truncation is visible in the record itself. */
|
|
273
|
+
function capDiffOutput(output: string): string {
|
|
274
|
+
if (output.length <= FINALIZE_DIFF_CAPTURE_CAP) return output
|
|
275
|
+
return `${output.slice(0, FINALIZE_DIFF_CAPTURE_CAP)}\n... (truncated at ${FINALIZE_DIFF_CAPTURE_CAP} characters)`
|
|
276
|
+
}
|
|
277
|
+
|
|
263
278
|
function sessionBudgetError(seconds: number): string {
|
|
264
279
|
return `phase session budget expired after ${seconds} seconds`
|
|
265
280
|
}
|
|
@@ -1137,8 +1152,7 @@ export class BuildRunner {
|
|
|
1137
1152
|
)
|
|
1138
1153
|
if (scratchPaths.length > 0) throw phaseScratchRejection(scratchPaths)
|
|
1139
1154
|
const remote = events.some(
|
|
1140
|
-
(event) =>
|
|
1141
|
-
event.type === 'workspace.provisioned' && event.payload.provider === 'vercel-sandbox',
|
|
1155
|
+
(event) => event.type === 'workspace.provisioned' && isRemoteWorkspace(event.payload),
|
|
1142
1156
|
)
|
|
1143
1157
|
if (remote) {
|
|
1144
1158
|
await this.deps.store.append(this.deps.slug, {
|
|
@@ -1490,13 +1504,50 @@ export class BuildRunner {
|
|
|
1490
1504
|
)
|
|
1491
1505
|
}
|
|
1492
1506
|
if (result.stdout.length > 0) {
|
|
1507
|
+
// The failure record must characterize the dirtiness on its own: the
|
|
1508
|
+
// build workspace is disposable, and porcelain lists paths and status
|
|
1509
|
+
// codes only — a mode-only flip (AUT-439) is indistinguishable from a
|
|
1510
|
+
// content modification once the workspace is gone. Append both diff
|
|
1511
|
+
// views so the record shows what actually changed.
|
|
1493
1512
|
throw new Error(
|
|
1494
1513
|
`workspace must be clean ${when}; commit intended files and remove ` +
|
|
1495
|
-
`temporary files before finishing:\n${result.stdout.trimEnd()}
|
|
1514
|
+
`temporary files before finishing:\n${result.stdout.trimEnd()}\n\n` +
|
|
1515
|
+
(await this.collectWorktreeDiffSections()),
|
|
1496
1516
|
)
|
|
1497
1517
|
}
|
|
1498
1518
|
}
|
|
1499
1519
|
|
|
1520
|
+
/** Labeled working-tree and staged diff sections for a dirty finalize
|
|
1521
|
+
* preflight record. Runs only on the dirty branch (a clean worktree or a
|
|
1522
|
+
* failed status command never executes a diff), caps each section at
|
|
1523
|
+
* FINALIZE_DIFF_CAPTURE_CAP characters, and is best-effort: a failing `git
|
|
1524
|
+
* diff` command annotates its own section instead of masking the
|
|
1525
|
+
* dirty-worktree failure it is annotating. */
|
|
1526
|
+
private async collectWorktreeDiffSections(): Promise<string> {
|
|
1527
|
+
const views = [
|
|
1528
|
+
{ args: ['git', 'diff'], header: '--- git diff (working tree) ---' },
|
|
1529
|
+
{ args: ['git', 'diff', '--cached'], header: '--- git diff --cached (staged) ---' },
|
|
1530
|
+
] as const
|
|
1531
|
+
const sections: string[] = []
|
|
1532
|
+
for (const { args, header } of views) {
|
|
1533
|
+
const command = args.join(' ')
|
|
1534
|
+
let body: string
|
|
1535
|
+
try {
|
|
1536
|
+
const result = await this.deps.exec([...args], { cwd: this.deps.workspacePath })
|
|
1537
|
+
if (result.exitCode !== 0) {
|
|
1538
|
+
const detail = result.stderr.trim() || result.stdout.trim() || '(no output)'
|
|
1539
|
+
body = `(${command} failed: exit ${result.exitCode}: ${capDiffOutput(detail)})`
|
|
1540
|
+
} else {
|
|
1541
|
+
body = capDiffOutput(result.stdout) || '(no output)'
|
|
1542
|
+
}
|
|
1543
|
+
} catch (error) {
|
|
1544
|
+
body = `(${command} failed: ${capDiffOutput(errorMessage(error))})`
|
|
1545
|
+
}
|
|
1546
|
+
sections.push(`${header}\n${body}`)
|
|
1547
|
+
}
|
|
1548
|
+
return sections.join('\n\n')
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1500
1551
|
private async resolveFinalizeHead(): Promise<string> {
|
|
1501
1552
|
const args = ['git', 'rev-parse', 'HEAD']
|
|
1502
1553
|
const result = await this.deps.exec(args, { cwd: this.deps.workspacePath })
|