@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,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal local .env loader for the `ab` binary: `KEY=VALUE` lines, `#`
|
|
3
|
+
* comments, optional matching quotes around the value, optional `export `
|
|
4
|
+
* prefix. Values never override variables already present in the environment
|
|
5
|
+
* — the real environment wins, so a checked-in .env cannot shadow runner-set
|
|
6
|
+
* ambient auth (D8). Bun auto-loads .env when running bin/ab.ts directly;
|
|
7
|
+
* this loader makes the behavior explicit and Node-portable.
|
|
8
|
+
*/
|
|
9
|
+
import { readFileSync } from 'node:fs'
|
|
10
|
+
|
|
11
|
+
const KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/
|
|
12
|
+
|
|
13
|
+
/** Parse .env text into key/value pairs; malformed lines are skipped. */
|
|
14
|
+
export function parseDotEnv(raw: string): Record<string, string> {
|
|
15
|
+
const result: Record<string, string> = {}
|
|
16
|
+
for (const line of raw.split('\n')) {
|
|
17
|
+
let trimmed = line.trim()
|
|
18
|
+
if (trimmed === '' || trimmed.startsWith('#')) continue
|
|
19
|
+
if (trimmed.startsWith('export ')) trimmed = trimmed.slice('export '.length)
|
|
20
|
+
const eq = trimmed.indexOf('=')
|
|
21
|
+
if (eq === -1) continue
|
|
22
|
+
const key = trimmed.slice(0, eq).trim()
|
|
23
|
+
if (!KEY_PATTERN.test(key)) continue
|
|
24
|
+
let value = trimmed.slice(eq + 1).trim()
|
|
25
|
+
const quote = value[0]
|
|
26
|
+
if ((quote === '"' || quote === "'") && value.length >= 2 && value.endsWith(quote)) {
|
|
27
|
+
value = value.slice(1, -1)
|
|
28
|
+
}
|
|
29
|
+
result[key] = value
|
|
30
|
+
}
|
|
31
|
+
return result
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Load `path` into `env` if the file exists (silently a no-op otherwise).
|
|
36
|
+
* Only keys not already set in `env` are written.
|
|
37
|
+
*/
|
|
38
|
+
export function loadDotEnv(path: string, env: Record<string, string | undefined>): void {
|
|
39
|
+
let raw: string
|
|
40
|
+
try {
|
|
41
|
+
raw = readFileSync(path, 'utf8')
|
|
42
|
+
} catch {
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
for (const [key, value] of Object.entries(parseDotEnv(raw))) {
|
|
46
|
+
if (env[key] === undefined) env[key] = value
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ambient auth resolution (SPEC §8.1, D8): the runner launches every session
|
|
3
|
+
* with `AB_STORE`, `AB_BUILD`, `AB_PHASE`, `AB_SESSION` (and `AB_TOKEN` for a
|
|
4
|
+
* remote store) set, and the CLI resolves everything from the environment —
|
|
5
|
+
* the skill only ever passes the build slug. Least privilege comes from the
|
|
6
|
+
* runner, not from prompt instructions.
|
|
7
|
+
*
|
|
8
|
+
* Errors here are agent feedback (D6): each names the missing or malformed
|
|
9
|
+
* variable and the format that would be accepted.
|
|
10
|
+
*/
|
|
11
|
+
import { CORE_PHASES, isPhase, type Phase } from '../ontology'
|
|
12
|
+
|
|
13
|
+
export interface HarvestCliEnv {
|
|
14
|
+
store: string
|
|
15
|
+
repo: string
|
|
16
|
+
run: string
|
|
17
|
+
phase: 'synthesize' | 'review'
|
|
18
|
+
round: number
|
|
19
|
+
session: string
|
|
20
|
+
token?: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface CliEnv {
|
|
24
|
+
/** Store URL or local path (`AB_STORE`). */
|
|
25
|
+
store: string
|
|
26
|
+
/** Build slug (`AB_BUILD`). */
|
|
27
|
+
build: string
|
|
28
|
+
/** Current phase, parsed from `AB_PHASE` (`<phase>[@<round>]`). */
|
|
29
|
+
phase: Phase
|
|
30
|
+
/** Round (loop phases) or attempt (verify/reconcile); defaults to 1. */
|
|
31
|
+
round: number
|
|
32
|
+
/** Session id (`AB_SESSION`). */
|
|
33
|
+
session: string
|
|
34
|
+
/** Scoped token for a remote store (`AB_TOKEN`) — optional locally. */
|
|
35
|
+
token?: string
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type AmbientReadSession = CliEnv | HarvestCliEnv
|
|
39
|
+
|
|
40
|
+
const PHASE_FORMAT = "'<phase>[@<round>]' (e.g. 'implement@2', 'verify:e2e@1')"
|
|
41
|
+
const BUILD_AMBIENT_TUPLE = 'AB_STORE/AB_BUILD/AB_PHASE/AB_SESSION'
|
|
42
|
+
const HARVEST_AMBIENT_TUPLE = 'AB_STORE/AB_REPO/AB_HARVEST/AB_PHASE/AB_SESSION'
|
|
43
|
+
|
|
44
|
+
/** Optional ambient identity is present but cannot safely select one scope. */
|
|
45
|
+
export class InvalidAmbientContextError extends Error {
|
|
46
|
+
override readonly name = 'InvalidAmbientContextError'
|
|
47
|
+
|
|
48
|
+
constructor(detail: string) {
|
|
49
|
+
super(
|
|
50
|
+
`invalid ambient context: ${detail}. Expected no agent identity markers, ` +
|
|
51
|
+
`a complete build tuple (${BUILD_AMBIENT_TUPLE}), or a complete Harvest tuple ` +
|
|
52
|
+
`(${HARVEST_AMBIENT_TUPLE})`,
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** A required runner-provided session value is absent or empty. Callers that
|
|
58
|
+
* resolve ambient auth directly still receive the variable-specific message;
|
|
59
|
+
* the process wiring uses the type to defer missing-session feedback to the
|
|
60
|
+
* command-aware router guard. */
|
|
61
|
+
export class MissingAmbientContextError extends Error {
|
|
62
|
+
override readonly name = 'MissingAmbientContextError'
|
|
63
|
+
|
|
64
|
+
constructor(
|
|
65
|
+
readonly variable: string,
|
|
66
|
+
expected: string,
|
|
67
|
+
) {
|
|
68
|
+
super(
|
|
69
|
+
`${variable} is not set — expected ${expected}. ` +
|
|
70
|
+
'The runner sets ambient auth for every session (D8, SPEC §8.1).',
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function requireVar(
|
|
76
|
+
env: Record<string, string | undefined>,
|
|
77
|
+
name: string,
|
|
78
|
+
expected: string,
|
|
79
|
+
): string {
|
|
80
|
+
const value = env[name]
|
|
81
|
+
if (value === undefined || value === '') {
|
|
82
|
+
throw new MissingAmbientContextError(name, expected)
|
|
83
|
+
}
|
|
84
|
+
return value
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** `implement@2` → `{ phase: 'implement', round: 2 }`; round defaults to 1. */
|
|
88
|
+
export function parseAbPhase(raw: string): { phase: Phase; round: number } {
|
|
89
|
+
// Split on the LAST '@' so a malformed 'implement@2@3' reports the phase
|
|
90
|
+
// part as unknown rather than silently taking the first segment.
|
|
91
|
+
const at = raw.lastIndexOf('@')
|
|
92
|
+
const phasePart = at === -1 ? raw : raw.slice(0, at)
|
|
93
|
+
const roundPart = at === -1 ? undefined : raw.slice(at + 1)
|
|
94
|
+
|
|
95
|
+
if (!isPhase(phasePart)) {
|
|
96
|
+
throw new Error(
|
|
97
|
+
`AB_PHASE "${raw}" names an unknown phase "${phasePart}" — expected one of ` +
|
|
98
|
+
`${CORE_PHASES.join(', ')}, or 'verify:<step>'; format ${PHASE_FORMAT}`,
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
let round = 1
|
|
103
|
+
if (roundPart !== undefined) {
|
|
104
|
+
if (!/^[1-9]\d*$/.test(roundPart)) {
|
|
105
|
+
throw new Error(
|
|
106
|
+
`AB_PHASE "${raw}" has a malformed round "${roundPart}" — the round must ` +
|
|
107
|
+
`be a positive integer; format ${PHASE_FORMAT}`,
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
round = Number(roundPart)
|
|
111
|
+
}
|
|
112
|
+
return { phase: phasePart, round }
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Resolve the CLI's ambient environment (D8). Throws with the exact variable
|
|
117
|
+
* and expected format on the first problem found.
|
|
118
|
+
*/
|
|
119
|
+
export function parseHarvestPhase(raw: string): {
|
|
120
|
+
phase: 'synthesize' | 'review'
|
|
121
|
+
round: number
|
|
122
|
+
} {
|
|
123
|
+
const match = /^(synthesize|review)@([1-9]\d*)$/.exec(raw)
|
|
124
|
+
if (!match) {
|
|
125
|
+
throw new Error(
|
|
126
|
+
`AB_PHASE "${raw}" is not a harvest session phase — expected ` +
|
|
127
|
+
`'synthesize@<round>' or 'review@<round>'`,
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
phase: match[1] as 'synthesize' | 'review',
|
|
132
|
+
round: Number(match[2]),
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function resolveHarvestCliEnv(env: Record<string, string | undefined>): HarvestCliEnv {
|
|
137
|
+
const store = requireVar(env, 'AB_STORE', 'the store URL or local path')
|
|
138
|
+
const repo = requireVar(env, 'AB_REPO', 'the repository identity')
|
|
139
|
+
const run = requireVar(env, 'AB_HARVEST', 'the harvest run id')
|
|
140
|
+
const rawPhase = requireVar(env, 'AB_PHASE', `'synthesize@<round>' or 'review@<round>'`)
|
|
141
|
+
const session = requireVar(env, 'AB_SESSION', 'the session id')
|
|
142
|
+
const { phase, round } = parseHarvestPhase(rawPhase)
|
|
143
|
+
const token = env.AB_TOKEN
|
|
144
|
+
return {
|
|
145
|
+
store,
|
|
146
|
+
repo,
|
|
147
|
+
run,
|
|
148
|
+
phase,
|
|
149
|
+
round,
|
|
150
|
+
session,
|
|
151
|
+
...(token !== undefined && token !== '' ? { token } : {}),
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function resolveCliEnv(env: Record<string, string | undefined>): CliEnv {
|
|
156
|
+
const store = requireVar(env, 'AB_STORE', 'the store URL or local path')
|
|
157
|
+
const build = requireVar(env, 'AB_BUILD', 'the build slug')
|
|
158
|
+
const rawPhase = requireVar(env, 'AB_PHASE', `the current phase in the format ${PHASE_FORMAT}`)
|
|
159
|
+
const session = requireVar(env, 'AB_SESSION', 'the session id')
|
|
160
|
+
const { phase, round } = parseAbPhase(rawPhase)
|
|
161
|
+
const token = env.AB_TOKEN
|
|
162
|
+
return {
|
|
163
|
+
store,
|
|
164
|
+
build,
|
|
165
|
+
phase,
|
|
166
|
+
round,
|
|
167
|
+
session,
|
|
168
|
+
...(token !== undefined && token !== '' ? { token } : {}),
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Classify the optional ambient authority used by the finite read-only query
|
|
174
|
+
* commands. AB_STORE and AB_TOKEN remain ordinary operator selection and
|
|
175
|
+
* credentials when no identity marker is present. Once any build/Harvest
|
|
176
|
+
* identity marker appears, however, the context must be complete and
|
|
177
|
+
* unambiguous; a partial agent environment must never fall back to operator
|
|
178
|
+
* authority.
|
|
179
|
+
*/
|
|
180
|
+
export function resolveAmbientReadSession(
|
|
181
|
+
env: Record<string, string | undefined>,
|
|
182
|
+
): AmbientReadSession | undefined {
|
|
183
|
+
const present = (name: string): boolean => env[name] !== undefined
|
|
184
|
+
const hasBuildMarker = present('AB_BUILD')
|
|
185
|
+
const hasHarvestMarker = present('AB_REPO') || present('AB_HARVEST')
|
|
186
|
+
const hasSharedMarker = present('AB_PHASE') || present('AB_SESSION')
|
|
187
|
+
|
|
188
|
+
if (!hasBuildMarker && !hasHarvestMarker && !hasSharedMarker) return undefined
|
|
189
|
+
if (hasBuildMarker && hasHarvestMarker) {
|
|
190
|
+
throw new InvalidAmbientContextError(
|
|
191
|
+
'build and Harvest identity markers are mixed, so resource authority is ambiguous',
|
|
192
|
+
)
|
|
193
|
+
}
|
|
194
|
+
if (!hasBuildMarker && !hasHarvestMarker) {
|
|
195
|
+
throw new InvalidAmbientContextError(
|
|
196
|
+
'AB_PHASE or AB_SESSION is present without AB_BUILD or AB_REPO/AB_HARVEST',
|
|
197
|
+
)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
try {
|
|
201
|
+
return hasBuildMarker ? resolveCliEnv(env) : resolveHarvestCliEnv(env)
|
|
202
|
+
} catch (error) {
|
|
203
|
+
const detail = error instanceof Error ? error.message : String(error)
|
|
204
|
+
throw new InvalidAmbientContextError(detail)
|
|
205
|
+
}
|
|
206
|
+
}
|