@defrex/autobuild 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +192 -0
- package/SPEC.md +2269 -0
- package/bin/ab-build-runner.ts +47 -0
- package/bin/ab-dev.ts +27 -0
- package/bin/ab-dispatch-kernel.ts +92 -0
- package/bin/ab-harvest-runner.ts +29 -0
- package/bin/ab-init-probe.ts +19 -0
- package/bin/ab-process-group-reaper.ts +32 -0
- package/bin/ab.ts +6 -0
- package/bin/agent/ab +3 -0
- package/docs/answering-blocked-builds.md +89 -0
- package/docs/architecture.md +726 -0
- package/docs/assets/headline-wide.png +0 -0
- package/docs/configuration.md +1623 -0
- package/docs/hosted-dispatcher-cutover-validation.md +178 -0
- package/docs/hosted-dispatcher.md +204 -0
- package/docs/mcp.md +119 -0
- package/docs/operator-api.md +186 -0
- package/docs/remote-store-protocol.md +972 -0
- package/docs/remote-ticket-protocol.md +79 -0
- package/docs/setup.md +289 -0
- package/docs/spec-standard.md +63 -0
- package/docs/ticket-dependencies.md +59 -0
- package/docs/vercel-sandbox-rollout-probe.md +7 -0
- package/package.json +135 -0
- package/packages/core/src/cli/args.ts +74 -0
- package/packages/core/src/cli/artifact.ts +182 -0
- package/packages/core/src/cli/binary.ts +198 -0
- package/packages/core/src/cli/build-control.ts +789 -0
- package/packages/core/src/cli/build-progress.ts +55 -0
- package/packages/core/src/cli/bulk-control.ts +385 -0
- package/packages/core/src/cli/context.ts +470 -0
- package/packages/core/src/cli/dashboard/actions.ts +59 -0
- package/packages/core/src/cli/dashboard/cells.ts +92 -0
- package/packages/core/src/cli/dashboard/composer.ts +230 -0
- package/packages/core/src/cli/dashboard/detail.ts +100 -0
- package/packages/core/src/cli/dashboard/frame-image.ts +373 -0
- package/packages/core/src/cli/dashboard/live.ts +152 -0
- package/packages/core/src/cli/dashboard/model.ts +1173 -0
- package/packages/core/src/cli/dashboard/poll.ts +196 -0
- package/packages/core/src/cli/dashboard/render.ts +1568 -0
- package/packages/core/src/cli/dashboard/selection.ts +66 -0
- package/packages/core/src/cli/dashboard/session-feed.ts +244 -0
- package/packages/core/src/cli/dashboard/session-view.ts +506 -0
- package/packages/core/src/cli/dashboard/transcript.ts +108 -0
- package/packages/core/src/cli/dev.ts +46 -0
- package/packages/core/src/cli/dispatch-frontend.ts +1045 -0
- package/packages/core/src/cli/dispatch-process.ts +259 -0
- package/packages/core/src/cli/dispatch.ts +3692 -0
- package/packages/core/src/cli/dotenv.ts +48 -0
- package/packages/core/src/cli/env.ts +206 -0
- package/packages/core/src/cli/harvest.ts +698 -0
- package/packages/core/src/cli/help.ts +713 -0
- package/packages/core/src/cli/init-agent.ts +106 -0
- package/packages/core/src/cli/init-validation.ts +583 -0
- package/packages/core/src/cli/init.ts +756 -0
- package/packages/core/src/cli/installation.ts +333 -0
- package/packages/core/src/cli/keyboard.ts +261 -0
- package/packages/core/src/cli/main.ts +1399 -0
- package/packages/core/src/cli/mcp.ts +279 -0
- package/packages/core/src/cli/models.ts +65 -0
- package/packages/core/src/cli/observe.ts +55 -0
- package/packages/core/src/cli/plugin.ts +227 -0
- package/packages/core/src/cli/pr-attachments.ts +138 -0
- package/packages/core/src/cli/pr-summary.ts +124 -0
- package/packages/core/src/cli/publication-settlement.ts +188 -0
- package/packages/core/src/cli/repo-state.ts +213 -0
- package/packages/core/src/cli/repository-status.ts +80 -0
- package/packages/core/src/cli/self-update.ts +443 -0
- package/packages/core/src/cli/status.ts +895 -0
- package/packages/core/src/cli/store-opening.contract.ts +289 -0
- package/packages/core/src/cli/store-opening.ts +167 -0
- package/packages/core/src/cli/store-ref.ts +33 -0
- package/packages/core/src/cli/terminal-restore.ts +174 -0
- package/packages/core/src/cli/terminal.ts +361 -0
- package/packages/core/src/cli/terminals.ts +995 -0
- package/packages/core/src/cli/testkit.ts +194 -0
- package/packages/core/src/cli/ticket.ts +484 -0
- package/packages/core/src/cli/upgrade-agent.ts +180 -0
- package/packages/core/src/cli/upgrade-commit.ts +468 -0
- package/packages/core/src/cli/upgrade-notice.ts +91 -0
- package/packages/core/src/cli/upgrade-progress.ts +110 -0
- package/packages/core/src/cli/upgrade.ts +888 -0
- package/packages/core/src/cli/wait.ts +587 -0
- package/packages/core/src/cli/watch.ts +932 -0
- package/packages/core/src/config/live.ts +255 -0
- package/packages/core/src/config/load.ts +98 -0
- package/packages/core/src/config/roles.ts +438 -0
- package/packages/core/src/config/schema.ts +774 -0
- package/packages/core/src/distribution.ts +24 -0
- package/packages/core/src/events/catalog.ts +201 -0
- package/packages/core/src/events/envelope.ts +59 -0
- package/packages/core/src/events/payloads.ts +618 -0
- package/packages/core/src/events/repository.ts +559 -0
- package/packages/core/src/events/sessions.ts +180 -0
- package/packages/core/src/harvest/schema.ts +147 -0
- package/packages/core/src/ids.ts +45 -0
- package/packages/core/src/integration/harness.ts +681 -0
- package/packages/core/src/kernel/auto-merge.ts +259 -0
- package/packages/core/src/kernel/converge.ts +117 -0
- package/packages/core/src/kernel/dispatch-settings.ts +60 -0
- package/packages/core/src/kernel/dispatch-status.ts +141 -0
- package/packages/core/src/kernel/engine.ts +1047 -0
- package/packages/core/src/kernel/harvest.ts +823 -0
- package/packages/core/src/kernel/origin.ts +69 -0
- package/packages/core/src/kernel/phases.ts +196 -0
- package/packages/core/src/kernel/plan-verify-selection.ts +105 -0
- package/packages/core/src/kernel/pr-attachments.ts +82 -0
- package/packages/core/src/kernel/reducer.ts +752 -0
- package/packages/core/src/kernel/stall.ts +155 -0
- package/packages/core/src/kernel/verify-applicability.ts +52 -0
- package/packages/core/src/markdown.ts +67 -0
- package/packages/core/src/ontology.ts +288 -0
- package/packages/core/src/open-map.ts +203 -0
- package/packages/core/src/operator/annotations.ts +187 -0
- package/packages/core/src/operator/client.ts +311 -0
- package/packages/core/src/operator/control.ts +117 -0
- package/packages/core/src/operator/index.ts +62 -0
- package/packages/core/src/operator/presentation.ts +22 -0
- package/packages/core/src/operator/protocol.ts +98 -0
- package/packages/core/src/operator/query.ts +201 -0
- package/packages/core/src/operator/registry.ts +1043 -0
- package/packages/core/src/operator/requests.ts +138 -0
- package/packages/core/src/operator/sandbox.ts +458 -0
- package/packages/core/src/operator/server.ts +616 -0
- package/packages/core/src/operator/sessions.ts +223 -0
- package/packages/core/src/operator/tickets.ts +177 -0
- package/packages/core/src/plugin-sdk/index.ts +174 -0
- package/packages/core/src/plugins/contract-entry.ts +74 -0
- package/packages/core/src/plugins/contract-env.ts +3 -0
- package/packages/core/src/plugins/load.ts +259 -0
- package/packages/core/src/plugins/manifest.ts +236 -0
- package/packages/core/src/plugins/registry.ts +274 -0
- package/packages/core/src/plugins/runtimes.ts +75 -0
- package/packages/core/src/ports/forge/contract.ts +258 -0
- package/packages/core/src/ports/forge/create.ts +74 -0
- package/packages/core/src/ports/forge/fake.ts +488 -0
- package/packages/core/src/ports/forge/github-pr-attachments.ts +351 -0
- package/packages/core/src/ports/forge/github-transport.ts +352 -0
- package/packages/core/src/ports/forge/github.ts +1162 -0
- package/packages/core/src/ports/forge/local-git.ts +568 -0
- package/packages/core/src/ports/runner/claude.ts +873 -0
- package/packages/core/src/ports/runner/cli-stream.ts +90 -0
- package/packages/core/src/ports/runner/codex.ts +873 -0
- package/packages/core/src/ports/runner/contract.ts +492 -0
- package/packages/core/src/ports/runner/fake.ts +213 -0
- package/packages/core/src/ports/runner/json-record.ts +2 -0
- package/packages/core/src/ports/runner/live-contract-fixture.ts +176 -0
- package/packages/core/src/ports/runner/one-shot.ts +29 -0
- package/packages/core/src/ports/runner/pi-bridge-core.ts +136 -0
- package/packages/core/src/ports/runner/pi-bridge.js +6 -0
- package/packages/core/src/ports/runner/pi-rpc.ts +454 -0
- package/packages/core/src/ports/runner/pi.ts +617 -0
- package/packages/core/src/ports/runner/production.ts +74 -0
- package/packages/core/src/ports/runner/provider-error.ts +121 -0
- package/packages/core/src/ports/runner/routing.ts +234 -0
- package/packages/core/src/ports/runner/runtime.ts +214 -0
- package/packages/core/src/ports/runner/session-env.ts +34 -0
- package/packages/core/src/ports/runner/stream-parts.ts +103 -0
- package/packages/core/src/ports/tickets/contract.ts +570 -0
- package/packages/core/src/ports/tickets/create.ts +135 -0
- package/packages/core/src/ports/tickets/fake.ts +215 -0
- package/packages/core/src/ports/tickets/file.ts +559 -0
- package/packages/core/src/ports/tickets/linear.ts +811 -0
- package/packages/core/src/ports/tickets/operations.ts +161 -0
- package/packages/core/src/ports/tickets/remote-index.ts +13 -0
- package/packages/core/src/ports/tickets/remote-protocol.ts +80 -0
- package/packages/core/src/ports/tickets/remote-server.ts +185 -0
- package/packages/core/src/ports/tickets/remote.ts +130 -0
- package/packages/core/src/ports/tickets/update.ts +51 -0
- package/packages/core/src/ports/types.ts +528 -0
- package/packages/core/src/ports/workspace/build-execution.ts +123 -0
- package/packages/core/src/ports/workspace/contract.ts +136 -0
- package/packages/core/src/ports/workspace/create.ts +132 -0
- package/packages/core/src/ports/workspace/distribution-archive.ts +317 -0
- package/packages/core/src/ports/workspace/fake.ts +432 -0
- package/packages/core/src/ports/workspace/git-worktree.ts +848 -0
- package/packages/core/src/ports/workspace/harvest-execution.ts +111 -0
- package/packages/core/src/ports/workspace/in-process-build-execution.ts +30 -0
- package/packages/core/src/ports/workspace/local-build-execution.ts +88 -0
- package/packages/core/src/ports/workspace/operator-sandbox.ts +142 -0
- package/packages/core/src/ports/workspace/phase-scratch.ts +156 -0
- package/packages/core/src/ports/workspace/vercel-sandbox.ts +2541 -0
- package/packages/core/src/processes/build-child-exit.ts +78 -0
- package/packages/core/src/processes/build-child.ts +119 -0
- package/packages/core/src/processes/build-execution-state.ts +95 -0
- package/packages/core/src/processes/build-parent-watch.ts +35 -0
- package/packages/core/src/processes/build-runner.ts +2614 -0
- package/packages/core/src/processes/dispatcher.ts +2825 -0
- package/packages/core/src/processes/execution-settlement.ts +171 -0
- package/packages/core/src/processes/harvest-child.ts +115 -0
- package/packages/core/src/processes/harvest-execution-state.ts +121 -0
- package/packages/core/src/processes/harvest-runner.ts +1656 -0
- package/packages/core/src/processes/harvest.ts +595 -0
- package/packages/core/src/processes/infrastructure-failure-budget.ts +146 -0
- package/packages/core/src/processes/phase-failure-budget.ts +52 -0
- package/packages/core/src/processes/process-group-reaper.ts +35 -0
- package/packages/core/src/processes/process-group.ts +65 -0
- package/packages/core/src/processes/publication-loss.ts +62 -0
- package/packages/core/src/processes/publication-state.ts +93 -0
- package/packages/core/src/processes/sandbox-state.ts +101 -0
- package/packages/core/src/registry.ts +24 -0
- package/packages/core/src/sessions/reducer.ts +185 -0
- package/packages/core/src/skills.ts +7 -0
- package/packages/core/src/spec-standard.ts +47 -0
- package/packages/core/src/store/adapter.ts +80 -0
- package/packages/core/src/store/build-scope.ts +272 -0
- package/packages/core/src/store/contract.ts +2581 -0
- package/packages/core/src/store/local/blobs.ts +38 -0
- package/packages/core/src/store/local/schema.ts +180 -0
- package/packages/core/src/store/local/store.ts +1713 -0
- package/packages/core/src/store/memory.ts +1138 -0
- package/packages/core/src/store/phase-session.ts +425 -0
- package/packages/core/src/store/remote/client.ts +780 -0
- package/packages/core/src/store/remote/index.ts +12 -0
- package/packages/core/src/store/remote/protocol.ts +348 -0
- package/packages/core/src/store/remote/server.ts +923 -0
- package/packages/core/src/store/remote/token.ts +137 -0
- package/packages/core/src/store/remote/version.ts +10 -0
- package/packages/core/src/store/retention.ts +91 -0
- package/packages/core/src/store/session-handle.ts +265 -0
- package/packages/core/src/store/streams/assemble.ts +79 -0
- package/packages/core/src/store/streams/lock.ts +42 -0
- package/packages/core/src/store/streams/session-writer.ts +306 -0
- package/packages/core/src/store/streams/types.ts +171 -0
- package/packages/core/src/store/streams/wait.ts +127 -0
- package/packages/core/src/store/subscribe.ts +105 -0
- package/packages/core/src/store/types.ts +466 -0
- package/packages/core/src/testing/fixed.ts +44 -0
- package/packages/core/src/testing/store-failures.ts +32 -0
- package/packages/core/src/zod-issues.ts +91 -0
- package/skills/code-review/SKILL.md +100 -0
- package/skills/finalize/SKILL.md +44 -0
- package/skills/guide/SKILL.md +1781 -0
- package/skills/guide/references/operator-api.md +164 -0
- package/skills/guide/references/plugin-authoring.md +354 -0
- package/skills/guide/references/remote-store-protocol.md +972 -0
- package/skills/guide/references/remote-ticket-protocol.md +79 -0
- package/skills/guide/references/setup.md +289 -0
- package/skills/guide/references/spec-standard.md +63 -0
- package/skills/guide/references/ticket-dependencies.md +59 -0
- package/skills/harvest/SKILL.md +66 -0
- package/skills/harvest-review/SKILL.md +63 -0
- package/skills/implement/SKILL.md +82 -0
- package/skills/plan/SKILL.md +123 -0
- package/skills/plan-review/SKILL.md +121 -0
- package/skills/reconcile/SKILL.md +65 -0
- package/skills/spec/SKILL.md +132 -0
- package/skills/tickets/SKILL.md +139 -0
- package/templates/autobuild.toml +36 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { expect } from 'bun:test'
|
|
2
|
+
import { chmod, copyFile, mkdir, mkdtemp, readFile, rm, symlink, writeFile } from 'node:fs/promises'
|
|
3
|
+
import { tmpdir } from 'node:os'
|
|
4
|
+
import { join } from 'node:path'
|
|
5
|
+
import type { AgentRunner, AgentTurnResult, Transcript } from '../types'
|
|
6
|
+
import type { OneShotCompletion } from './one-shot'
|
|
7
|
+
import { AGENT_BIN_DIR } from './session-env'
|
|
8
|
+
|
|
9
|
+
interface LiveFixture {
|
|
10
|
+
cwd: string
|
|
11
|
+
evidencePath: string
|
|
12
|
+
cleanup: () => Promise<void>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface ProbeEvidence {
|
|
16
|
+
phase: string
|
|
17
|
+
retained: string
|
|
18
|
+
collide: string
|
|
19
|
+
abPath: string
|
|
20
|
+
helpStatus: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function createLiveFixture(): Promise<LiveFixture> {
|
|
24
|
+
const cwd = await mkdtemp(join(tmpdir(), 'ab-runner-live-contract-'))
|
|
25
|
+
const skillDir = join(cwd, '.agents', 'skills', 'ab-runner-contract')
|
|
26
|
+
const claudeSkills = join(cwd, '.claude', 'skills')
|
|
27
|
+
await mkdir(skillDir, { recursive: true })
|
|
28
|
+
await mkdir(claudeSkills, { recursive: true })
|
|
29
|
+
const skillPath = join(skillDir, 'SKILL.md')
|
|
30
|
+
await writeFile(
|
|
31
|
+
skillPath,
|
|
32
|
+
`---\nname: ab-runner-contract\ndescription: Live AgentRunner contract probe.\ndisable-model-invocation: true\n---\n\n# Runner contract probe\n\nImmediately use the bash tool to execute \`./contract-probe\` exactly once.\nWait for it to finish, then reply with the single word \`probed\`.\n`,
|
|
33
|
+
)
|
|
34
|
+
const claudeSkill = join(claudeSkills, 'ab-runner-contract')
|
|
35
|
+
try {
|
|
36
|
+
await symlink(skillDir, claudeSkill, 'dir')
|
|
37
|
+
} catch {
|
|
38
|
+
await mkdir(claudeSkill, { recursive: true })
|
|
39
|
+
await copyFile(skillPath, join(claudeSkill, 'SKILL.md'))
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const evidencePath = join(cwd, 'contract-evidence.tsv')
|
|
43
|
+
const probePath = join(cwd, 'contract-probe')
|
|
44
|
+
await writeFile(
|
|
45
|
+
probePath,
|
|
46
|
+
`#!/bin/sh\nset -eu\nab_path="$(command -v ab)"\nif ab --help >/dev/null 2>&1; then help=0; else help=$?; fi\nprintf '%s\\t%s\\t%s\\t%s\\t%s\\n' "\${AB_CONTRACT_PHASE:-}" "\${AB_CONTRACT_RETAINED:-}" "\${AB_CONTRACT_COLLIDE:-}" "$ab_path" "$help" >> ${JSON.stringify(evidencePath)}\n`,
|
|
47
|
+
)
|
|
48
|
+
await chmod(probePath, 0o755)
|
|
49
|
+
return {
|
|
50
|
+
cwd,
|
|
51
|
+
evidencePath,
|
|
52
|
+
cleanup: () => rm(cwd, { recursive: true, force: true }),
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function evidence(path: string): Promise<ProbeEvidence[]> {
|
|
57
|
+
const content = await readFile(path, 'utf8')
|
|
58
|
+
return content
|
|
59
|
+
.trim()
|
|
60
|
+
.split('\n')
|
|
61
|
+
.filter((line) => line !== '')
|
|
62
|
+
.map((line) => {
|
|
63
|
+
const [phase = '', retained = '', collide = '', abPath = '', helpStatus = ''] =
|
|
64
|
+
line.split('\t')
|
|
65
|
+
return { phase, retained, collide, abPath, helpStatus }
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function expectCompleted(result: AgentTurnResult): void {
|
|
70
|
+
expect(result.kind).toBe('completed')
|
|
71
|
+
expect(Number.isInteger(result.usage.inputTokens)).toBe(true)
|
|
72
|
+
expect(Number.isInteger(result.usage.outputTokens)).toBe(true)
|
|
73
|
+
expect(result.usage.turns).toBeGreaterThan(0)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function expectTranscript(transcript: Transcript, runner: AgentRunner, model: string): void {
|
|
77
|
+
expect(transcript.content.trim()).not.toBe('')
|
|
78
|
+
expect(transcript.metadata.runner).toBe(runner.name)
|
|
79
|
+
expect(transcript.metadata.model).toBe(model)
|
|
80
|
+
expect(transcript.metadata.usage.turns).toBeGreaterThanOrEqual(2)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Successful real-provider smoke coverage. Deterministic failure taxonomy is
|
|
84
|
+
* deliberately covered by the full injected adapter contract instead. */
|
|
85
|
+
export async function runLiveAgentRunnerContract(
|
|
86
|
+
runner: AgentRunner & OneShotCompletion,
|
|
87
|
+
model: string,
|
|
88
|
+
): Promise<void> {
|
|
89
|
+
const fixture = await createLiveFixture()
|
|
90
|
+
let failure: unknown
|
|
91
|
+
try {
|
|
92
|
+
const started = await runner.start({
|
|
93
|
+
skill: 'ab-runner-contract',
|
|
94
|
+
invocation: 'live-contract',
|
|
95
|
+
workspacePath: fixture.cwd,
|
|
96
|
+
model,
|
|
97
|
+
env: {
|
|
98
|
+
AB_CONTRACT_PHASE: 'start',
|
|
99
|
+
AB_CONTRACT_RETAINED: 'retained',
|
|
100
|
+
AB_CONTRACT_COLLIDE: 'start-value',
|
|
101
|
+
},
|
|
102
|
+
})
|
|
103
|
+
let transcript: Transcript | undefined
|
|
104
|
+
try {
|
|
105
|
+
expect(started.session.id.trim()).not.toBe('')
|
|
106
|
+
expect(started.session.runner).toBe(runner.name)
|
|
107
|
+
expect(started.session.model).toBe(model)
|
|
108
|
+
expectCompleted(started.result)
|
|
109
|
+
expect(await evidence(fixture.evidencePath)).toEqual([
|
|
110
|
+
{
|
|
111
|
+
phase: 'start',
|
|
112
|
+
retained: 'retained',
|
|
113
|
+
collide: 'start-value',
|
|
114
|
+
abPath: join(AGENT_BIN_DIR, 'ab'),
|
|
115
|
+
helpStatus: '0',
|
|
116
|
+
},
|
|
117
|
+
])
|
|
118
|
+
|
|
119
|
+
const continued = await runner.continue(
|
|
120
|
+
started.session,
|
|
121
|
+
'Use the bash tool to execute `./contract-probe` exactly once, wait for it, then reply with exactly the same single word as your previous response.',
|
|
122
|
+
{
|
|
123
|
+
env: {
|
|
124
|
+
AB_CONTRACT_PHASE: 'continue',
|
|
125
|
+
AB_CONTRACT_COLLIDE: 'continue-value',
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
)
|
|
129
|
+
expectCompleted(continued)
|
|
130
|
+
expect(continued.text.trim()).toBe('probed')
|
|
131
|
+
expect(await evidence(fixture.evidencePath)).toEqual([
|
|
132
|
+
{
|
|
133
|
+
phase: 'start',
|
|
134
|
+
retained: 'retained',
|
|
135
|
+
collide: 'start-value',
|
|
136
|
+
abPath: join(AGENT_BIN_DIR, 'ab'),
|
|
137
|
+
helpStatus: '0',
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
phase: 'continue',
|
|
141
|
+
retained: 'retained',
|
|
142
|
+
collide: 'continue-value',
|
|
143
|
+
abPath: join(AGENT_BIN_DIR, 'ab'),
|
|
144
|
+
helpStatus: '0',
|
|
145
|
+
},
|
|
146
|
+
])
|
|
147
|
+
} catch (error) {
|
|
148
|
+
failure = error
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
transcript = await runner.end(started.session)
|
|
153
|
+
} catch (endError) {
|
|
154
|
+
if (failure !== undefined) {
|
|
155
|
+
throw new AggregateError(
|
|
156
|
+
[failure, endError],
|
|
157
|
+
'live AgentRunner assertion and session end both failed',
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
throw endError
|
|
161
|
+
}
|
|
162
|
+
if (failure !== undefined) throw failure
|
|
163
|
+
expectTranscript(transcript, runner, model)
|
|
164
|
+
|
|
165
|
+
const nonce = crypto.randomUUID()
|
|
166
|
+
const oneShot = await runner.complete({
|
|
167
|
+
prompt: `Reply with exactly this token and no other text: ${nonce}`,
|
|
168
|
+
cwd: fixture.cwd,
|
|
169
|
+
env: { AB_CONTRACT_ONE_SHOT: nonce },
|
|
170
|
+
model,
|
|
171
|
+
})
|
|
172
|
+
expect(oneShot.text.trim()).toContain(nonce)
|
|
173
|
+
} finally {
|
|
174
|
+
await fixture.cleanup()
|
|
175
|
+
}
|
|
176
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A narrow, tool-free, non-phase judgment capability. Unlike AgentRunner,
|
|
3
|
+
* one-shot completions have no resumable session, skill invocation,
|
|
4
|
+
* transcript, or typed terminal: callers provide one prompt and consume text
|
|
5
|
+
* as an untrusted proposal behind deterministic validation.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface OneShotCompletionInput {
|
|
9
|
+
prompt: string
|
|
10
|
+
/** Working directory used for project context and runtime resolution. */
|
|
11
|
+
cwd: string
|
|
12
|
+
/** Runtime environment (credentials, provider settings, and so on). */
|
|
13
|
+
env: Record<string, string>
|
|
14
|
+
/** Absent means the runtime's own default model. */
|
|
15
|
+
model?: string
|
|
16
|
+
/** Extra CLI argv tokens for the selected runtime, in declared order. */
|
|
17
|
+
args?: readonly string[]
|
|
18
|
+
/** Caller-owned cancellation, normally a deterministic deadline. */
|
|
19
|
+
signal?: AbortSignal
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface OneShotCompletionResult {
|
|
23
|
+
text: string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Optional capability carried by a runtime registration. */
|
|
27
|
+
export interface OneShotCompletion {
|
|
28
|
+
complete(input: OneShotCompletionInput): Promise<OneShotCompletionResult>
|
|
29
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
export interface BridgeToolSourceInfo {
|
|
2
|
+
origin?: string
|
|
3
|
+
source?: string
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface BridgeTool {
|
|
7
|
+
name: string
|
|
8
|
+
sourceInfo?: BridgeToolSourceInfo
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface BridgeApi {
|
|
12
|
+
getAllTools(): BridgeTool[]
|
|
13
|
+
setActiveTools(names: string[]): void
|
|
14
|
+
registerTool(tool: unknown): void
|
|
15
|
+
on(event: 'session_start', handler: (event: unknown, context: { cwd: string }) => void): void
|
|
16
|
+
registerCommand(
|
|
17
|
+
name: string,
|
|
18
|
+
command: {
|
|
19
|
+
description: string
|
|
20
|
+
handler: (args: string, context: BridgeCommandContext) => Promise<void>
|
|
21
|
+
},
|
|
22
|
+
): void
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface BridgeCommandContext {
|
|
26
|
+
modelRegistry: {
|
|
27
|
+
getAll(): Array<{ provider: string; id: string }>
|
|
28
|
+
getAvailable(): Array<{ provider: string; id: string }>
|
|
29
|
+
}
|
|
30
|
+
ui: { notify(message: string, type: 'info'): void }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type BridgeBashToolFactory = (
|
|
34
|
+
cwd: string,
|
|
35
|
+
options: {
|
|
36
|
+
spawnHook: (input: { env?: Record<string, string>; [key: string]: unknown }) => {
|
|
37
|
+
env: Record<string, string>
|
|
38
|
+
[key: string]: unknown
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
) => unknown
|
|
42
|
+
|
|
43
|
+
const BUILTIN_TOOL_NAMES = new Set(['read', 'bash', 'edit', 'write', 'grep', 'find', 'ls'])
|
|
44
|
+
const CATALOG_PREFIX = 'autobuild-pi-catalog:'
|
|
45
|
+
|
|
46
|
+
export function selectActiveToolNames(
|
|
47
|
+
tools: readonly BridgeTool[],
|
|
48
|
+
baseTools: readonly string[],
|
|
49
|
+
): string[] {
|
|
50
|
+
const allowedBase = new Set(baseTools)
|
|
51
|
+
return [
|
|
52
|
+
...new Set(
|
|
53
|
+
tools
|
|
54
|
+
.filter((tool) => {
|
|
55
|
+
if (BUILTIN_TOOL_NAMES.has(tool.name)) return allowedBase.has(tool.name)
|
|
56
|
+
// Ambient discovery is disabled by the adapter. Every remaining
|
|
57
|
+
// non-builtin tool came from an explicitly loaded extension. An
|
|
58
|
+
// empty builtin allowlist marks a tool-free one-shot invocation.
|
|
59
|
+
return baseTools.length > 0
|
|
60
|
+
})
|
|
61
|
+
.map((tool) => tool.name),
|
|
62
|
+
),
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function installAutobuildBridge(pi: BridgeApi, createBashTool: BridgeBashToolFactory): void {
|
|
67
|
+
let environment: Record<string, string> = {}
|
|
68
|
+
let baseTools: string[] = []
|
|
69
|
+
|
|
70
|
+
const activateTools = (): void => {
|
|
71
|
+
pi.setActiveTools(selectActiveToolNames(pi.getAllTools(), baseTools))
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
pi.on('session_start', (_event, context) => {
|
|
75
|
+
pi.registerTool(
|
|
76
|
+
createBashTool(context.cwd, {
|
|
77
|
+
spawnHook: (input) => ({
|
|
78
|
+
...input,
|
|
79
|
+
env: { ...input.env, ...environment },
|
|
80
|
+
}),
|
|
81
|
+
}),
|
|
82
|
+
)
|
|
83
|
+
activateTools()
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
pi.registerCommand('autobuild-configure', {
|
|
87
|
+
description: 'Configure an Autobuild-managed headless session',
|
|
88
|
+
handler: async (args) => {
|
|
89
|
+
const payload = decode(args)
|
|
90
|
+
if (!isRecord(payload)) throw new Error('invalid Autobuild bridge configuration')
|
|
91
|
+
environment = stringRecord(payload.environment)
|
|
92
|
+
baseTools = stringArray(payload.tools)
|
|
93
|
+
activateTools()
|
|
94
|
+
},
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
pi.registerCommand('autobuild-models', {
|
|
98
|
+
description: 'Return the local Pi model catalog to Autobuild',
|
|
99
|
+
handler: async (args, context) => {
|
|
100
|
+
const payload = decode(args)
|
|
101
|
+
if (!isRecord(payload) || typeof payload.nonce !== 'string' || payload.nonce.length < 8) {
|
|
102
|
+
throw new Error('invalid Autobuild model-catalog nonce')
|
|
103
|
+
}
|
|
104
|
+
const models = payload.availableOnly
|
|
105
|
+
? context.modelRegistry.getAvailable()
|
|
106
|
+
: context.modelRegistry.getAll()
|
|
107
|
+
const entries = models.map((model) => ({ provider: model.provider, id: model.id }))
|
|
108
|
+
context.ui.notify(`${CATALOG_PREFIX}${payload.nonce}:${encode(entries)}`, 'info')
|
|
109
|
+
},
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function decode(value: string): unknown {
|
|
114
|
+
return JSON.parse(Buffer.from(value, 'base64url').toString('utf8'))
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function encode(value: unknown): string {
|
|
118
|
+
return Buffer.from(JSON.stringify(value), 'utf8').toString('base64url')
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function stringArray(value: unknown): string[] {
|
|
122
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === 'string') ? value : []
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function stringRecord(value: unknown): Record<string, string> {
|
|
126
|
+
if (!isRecord(value)) return {}
|
|
127
|
+
return Object.fromEntries(
|
|
128
|
+
Object.entries(value).filter(
|
|
129
|
+
(entry): entry is [string, string] => typeof entry[1] === 'string',
|
|
130
|
+
),
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
135
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
136
|
+
}
|