agentxchain 2.13.0 → 2.15.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 +8 -3
- package/bin/agentxchain.js +19 -2
- package/package.json +7 -1
- package/scripts/release-downstream-truth.sh +133 -0
- package/scripts/release-postflight.sh +84 -8
- package/src/commands/intake-approve.js +2 -10
- package/src/commands/intake-handoff.js +58 -0
- package/src/commands/intake-plan.js +2 -11
- package/src/commands/intake-record.js +2 -10
- package/src/commands/intake-resolve.js +2 -10
- package/src/commands/intake-scan.js +2 -10
- package/src/commands/intake-start.js +2 -10
- package/src/commands/intake-status.js +6 -10
- package/src/commands/intake-triage.js +2 -10
- package/src/commands/intake-workspace.js +58 -0
- package/src/commands/multi.js +58 -2
- package/src/lib/coordinator-acceptance.js +24 -98
- package/src/lib/coordinator-barriers.js +116 -0
- package/src/lib/coordinator-config.js +93 -0
- package/src/lib/coordinator-recovery.js +123 -68
- package/src/lib/coordinator-state.js +1 -0
- package/src/lib/cross-repo-context.js +68 -1
- package/src/lib/intake-handoff.js +58 -0
- package/src/lib/intake.js +300 -11
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@ Legacy IDE-window coordination is still shipped as a compatibility mode for team
|
|
|
14
14
|
- [Adapter reference](https://agentxchain.dev/docs/adapters/)
|
|
15
15
|
- [Protocol spec (v6)](https://agentxchain.dev/docs/protocol/)
|
|
16
16
|
- [Protocol reference](https://agentxchain.dev/docs/protocol-reference/)
|
|
17
|
+
- [Build your own runner](https://agentxchain.dev/docs/build-your-own-runner/)
|
|
17
18
|
- [Why governed multi-agent delivery matters](https://agentxchain.dev/why/)
|
|
18
19
|
|
|
19
20
|
## Install
|
|
@@ -99,10 +100,10 @@ For initiatives spanning multiple governed repos, use the coordinator to add cro
|
|
|
99
100
|
npx agentxchain init --governed --template api-service --dir repos/backend -y
|
|
100
101
|
npx agentxchain init --governed --template web-app --dir repos/frontend -y
|
|
101
102
|
agentxchain multi init
|
|
102
|
-
agentxchain multi step --
|
|
103
|
+
agentxchain multi step --json
|
|
103
104
|
```
|
|
104
105
|
|
|
105
|
-
See the [multi-repo quickstart](https://agentxchain.dev/docs/quickstart#multi-repo-cold-start) for the full cold-start walkthrough.
|
|
106
|
+
If the coordinator enters `blocked`, fix the cause and run `agentxchain multi resume` before continuing with `multi step` or `multi approve-gate`. See the [multi-repo quickstart](https://agentxchain.dev/docs/quickstart#multi-repo-cold-start) for the full cold-start walkthrough.
|
|
106
107
|
|
|
107
108
|
### Migrate a legacy project
|
|
108
109
|
|
|
@@ -131,7 +132,10 @@ agentxchain step
|
|
|
131
132
|
| `template validate` | Prove the template registry, workflow-kit scaffold contract, and planning artifact completeness (`--json` exposes a `workflow_kit` block) |
|
|
132
133
|
| `verify protocol` | Run the shipped protocol conformance suite against a target implementation |
|
|
133
134
|
| `dashboard` | Open the local governance dashboard in your browser for repo-local runs or multi-repo coordinator initiatives, including pending gate approvals |
|
|
134
|
-
| `
|
|
135
|
+
| `multi init\|status\|step\|resume\|approve-gate\|resync` | Run the multi-repo coordinator lifecycle, including blocked-state recovery via `multi resume` |
|
|
136
|
+
| `intake record\|triage\|approve\|plan\|start\|scan\|resolve` | Continuous-delivery intake: turn delivery signals into governed work items |
|
|
137
|
+
| `intake handoff` | Bridge a planned intake intent to a coordinator workstream for multi-repo execution |
|
|
138
|
+
| `plugin install\|list\|remove` | Install, inspect, or remove governed hook plugins backed by `agentxchain-plugin.json` manifests |
|
|
135
139
|
|
|
136
140
|
### Shared utilities
|
|
137
141
|
|
|
@@ -196,6 +200,7 @@ TALK.md
|
|
|
196
200
|
|
|
197
201
|
- `manual`: implemented
|
|
198
202
|
- `local_cli`: implemented
|
|
203
|
+
- `mcp`: implemented for stdio and streamable HTTP tool-contract dispatch
|
|
199
204
|
- `api_proxy`: implemented for synchronous review-only turns and stages a provider-backed result during `step`
|
|
200
205
|
|
|
201
206
|
## Legacy IDE Mode
|
package/bin/agentxchain.js
CHANGED
|
@@ -88,6 +88,7 @@ import {
|
|
|
88
88
|
multiInitCommand,
|
|
89
89
|
multiStatusCommand,
|
|
90
90
|
multiStepCommand,
|
|
91
|
+
multiResumeCommand,
|
|
91
92
|
multiApproveGateCommand,
|
|
92
93
|
multiResyncCommand,
|
|
93
94
|
} from '../src/commands/multi.js';
|
|
@@ -96,6 +97,7 @@ import { intakeTriageCommand } from '../src/commands/intake-triage.js';
|
|
|
96
97
|
import { intakeApproveCommand } from '../src/commands/intake-approve.js';
|
|
97
98
|
import { intakePlanCommand } from '../src/commands/intake-plan.js';
|
|
98
99
|
import { intakeStartCommand } from '../src/commands/intake-start.js';
|
|
100
|
+
import { intakeHandoffCommand } from '../src/commands/intake-handoff.js';
|
|
99
101
|
import { intakeScanCommand } from '../src/commands/intake-scan.js';
|
|
100
102
|
import { intakeResolveCommand } from '../src/commands/intake-resolve.js';
|
|
101
103
|
import { intakeStatusCommand } from '../src/commands/intake-status.js';
|
|
@@ -415,6 +417,12 @@ multiCmd
|
|
|
415
417
|
.option('-j, --json', 'Output as JSON')
|
|
416
418
|
.action(multiStepCommand);
|
|
417
419
|
|
|
420
|
+
multiCmd
|
|
421
|
+
.command('resume')
|
|
422
|
+
.description('Clear a blocked coordinator state after operator recovery')
|
|
423
|
+
.option('-j, --json', 'Output as JSON')
|
|
424
|
+
.action(multiResumeCommand);
|
|
425
|
+
|
|
418
426
|
multiCmd
|
|
419
427
|
.command('approve-gate')
|
|
420
428
|
.description('Approve a pending phase transition or completion gate')
|
|
@@ -449,7 +457,7 @@ intakeCmd
|
|
|
449
457
|
intakeCmd
|
|
450
458
|
.command('triage')
|
|
451
459
|
.description('Triage a detected intent — set priority, template, charter, and acceptance')
|
|
452
|
-
.
|
|
460
|
+
.option('--intent <id>', 'Intent ID to triage')
|
|
453
461
|
.option('--priority <level>', 'Priority level (p0, p1, p2, p3)')
|
|
454
462
|
.option('--template <id>', 'Governed template (generic, api-service, cli-tool, library, web-app)')
|
|
455
463
|
.option('--charter <text>', 'Delivery charter text')
|
|
@@ -486,10 +494,19 @@ intakeCmd
|
|
|
486
494
|
.option('-j, --json', 'Output as JSON')
|
|
487
495
|
.action(intakeStartCommand);
|
|
488
496
|
|
|
497
|
+
intakeCmd
|
|
498
|
+
.command('handoff')
|
|
499
|
+
.description('Hand off a planned intent to a coordinator workstream')
|
|
500
|
+
.option('--intent <id>', 'Intent ID to hand off')
|
|
501
|
+
.option('--coordinator-root <path>', 'Path to the coordinator workspace root')
|
|
502
|
+
.option('--workstream <id>', 'Coordinator workstream ID')
|
|
503
|
+
.option('-j, --json', 'Output as JSON')
|
|
504
|
+
.action(intakeHandoffCommand);
|
|
505
|
+
|
|
489
506
|
intakeCmd
|
|
490
507
|
.command('scan')
|
|
491
508
|
.description('Scan a structured source snapshot into intake events')
|
|
492
|
-
.
|
|
509
|
+
.option('--source <id>', 'Source type: ci_failure, git_ref_change, schedule')
|
|
493
510
|
.option('--file <path>', 'Path to snapshot JSON file')
|
|
494
511
|
.option('--stdin', 'Read snapshot from stdin')
|
|
495
512
|
.option('-j, --json', 'Output as JSON')
|
package/package.json
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentxchain",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.15.0",
|
|
4
4
|
"description": "CLI for AgentXchain — governed multi-agent software delivery",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"agentxchain": "./bin/agentxchain.js"
|
|
8
8
|
},
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./bin/agentxchain.js",
|
|
11
|
+
"./runner-interface": "./src/lib/runner-interface.js",
|
|
12
|
+
"./run-loop": "./src/lib/run-loop.js"
|
|
13
|
+
},
|
|
9
14
|
"files": [
|
|
10
15
|
"bin/",
|
|
11
16
|
"src/",
|
|
@@ -21,6 +26,7 @@
|
|
|
21
26
|
"preflight:release": "bash scripts/release-preflight.sh",
|
|
22
27
|
"preflight:release:strict": "bash scripts/release-preflight.sh --strict",
|
|
23
28
|
"postflight:release": "bash scripts/release-postflight.sh",
|
|
29
|
+
"postflight:downstream": "bash scripts/release-downstream-truth.sh",
|
|
24
30
|
"build:macos": "bun build bin/agentxchain.js --compile --target=bun-darwin-arm64 --outfile=dist/agentxchain-macos-arm64",
|
|
25
31
|
"build:linux": "bun build bin/agentxchain.js --compile --target=bun-linux-x64 --outfile=dist/agentxchain-linux-x64",
|
|
26
32
|
"publish:npm": "bash scripts/publish-npm.sh"
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Release downstream truth — run after all downstream surfaces are updated.
|
|
3
|
+
# Verifies: GitHub release exists, Homebrew tap SHA and URL match registry tarball.
|
|
4
|
+
# Usage: bash scripts/release-downstream-truth.sh --target-version <semver>
|
|
5
|
+
set -uo pipefail
|
|
6
|
+
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
8
|
+
CLI_DIR="${SCRIPT_DIR}/.."
|
|
9
|
+
REPO_ROOT="${CLI_DIR}/.."
|
|
10
|
+
cd "$CLI_DIR"
|
|
11
|
+
|
|
12
|
+
TARGET_VERSION=""
|
|
13
|
+
RETRY_ATTEMPTS="${RELEASE_DOWNSTREAM_RETRY_ATTEMPTS:-3}"
|
|
14
|
+
RETRY_DELAY_SECONDS="${RELEASE_DOWNSTREAM_RETRY_DELAY_SECONDS:-5}"
|
|
15
|
+
|
|
16
|
+
usage() {
|
|
17
|
+
echo "Usage: bash scripts/release-downstream-truth.sh --target-version <semver>" >&2
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
while [[ $# -gt 0 ]]; do
|
|
21
|
+
case "$1" in
|
|
22
|
+
--target-version)
|
|
23
|
+
if [[ -z "${2:-}" ]]; then
|
|
24
|
+
echo "Error: --target-version requires a semver argument" >&2
|
|
25
|
+
usage
|
|
26
|
+
exit 1
|
|
27
|
+
fi
|
|
28
|
+
if ! [[ "$2" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
29
|
+
echo "Invalid semver: $2" >&2
|
|
30
|
+
usage
|
|
31
|
+
exit 1
|
|
32
|
+
fi
|
|
33
|
+
TARGET_VERSION="$2"
|
|
34
|
+
shift 2
|
|
35
|
+
;;
|
|
36
|
+
*)
|
|
37
|
+
usage
|
|
38
|
+
exit 1
|
|
39
|
+
;;
|
|
40
|
+
esac
|
|
41
|
+
done
|
|
42
|
+
|
|
43
|
+
if [[ -z "$TARGET_VERSION" ]]; then
|
|
44
|
+
echo "Error: --target-version is required" >&2
|
|
45
|
+
usage
|
|
46
|
+
exit 1
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
PACKAGE_NAME="$(node -e "console.log(JSON.parse(require('fs').readFileSync('package.json', 'utf8')).name)")"
|
|
50
|
+
CANONICAL_HOMEBREW_FORMULA_URL="${AGENTXCHAIN_DOWNSTREAM_FORMULA_URL:-https://raw.githubusercontent.com/shivamtiwari93/homebrew-tap/main/Formula/agentxchain.rb}"
|
|
51
|
+
|
|
52
|
+
PASS=0
|
|
53
|
+
FAIL=0
|
|
54
|
+
|
|
55
|
+
pass() { PASS=$((PASS + 1)); echo " PASS: $1"; }
|
|
56
|
+
fail() { FAIL=$((FAIL + 1)); echo " FAIL: $1"; }
|
|
57
|
+
|
|
58
|
+
echo "AgentXchain v${TARGET_VERSION} Downstream Release Truth"
|
|
59
|
+
echo "====================================="
|
|
60
|
+
echo "Checks downstream surfaces after publish: GitHub release, canonical Homebrew tap."
|
|
61
|
+
echo ""
|
|
62
|
+
|
|
63
|
+
# --- Check 1: GitHub Release ---
|
|
64
|
+
echo "[1/3] GitHub release"
|
|
65
|
+
if ! command -v gh >/dev/null 2>&1; then
|
|
66
|
+
fail "gh CLI not available — cannot verify GitHub release"
|
|
67
|
+
else
|
|
68
|
+
GH_FOUND=false
|
|
69
|
+
for attempt in $(seq 1 "$RETRY_ATTEMPTS"); do
|
|
70
|
+
GH_TAG="$(gh release view "v${TARGET_VERSION}" --json tagName -q '.tagName' 2>/dev/null || true)"
|
|
71
|
+
if [[ "$GH_TAG" == "v${TARGET_VERSION}" ]]; then
|
|
72
|
+
GH_FOUND=true
|
|
73
|
+
break
|
|
74
|
+
fi
|
|
75
|
+
if [[ "$attempt" -lt "$RETRY_ATTEMPTS" ]]; then
|
|
76
|
+
echo " INFO: GitHub release not found (attempt ${attempt}/${RETRY_ATTEMPTS}); retrying in ${RETRY_DELAY_SECONDS}s..."
|
|
77
|
+
sleep "$RETRY_DELAY_SECONDS"
|
|
78
|
+
fi
|
|
79
|
+
done
|
|
80
|
+
if $GH_FOUND; then
|
|
81
|
+
pass "GitHub release v${TARGET_VERSION} exists"
|
|
82
|
+
else
|
|
83
|
+
fail "GitHub release v${TARGET_VERSION} not found after ${RETRY_ATTEMPTS} attempts"
|
|
84
|
+
fi
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
# --- Get registry tarball URL and compute SHA ---
|
|
88
|
+
echo "[2/3] Canonical Homebrew tap SHA matches registry tarball"
|
|
89
|
+
REGISTRY_TARBALL_URL="$(npm view "${PACKAGE_NAME}@${TARGET_VERSION}" dist.tarball 2>/dev/null || true)"
|
|
90
|
+
FORMULA_CONTENT="$(curl -fsSL "$CANONICAL_HOMEBREW_FORMULA_URL" 2>/dev/null || true)"
|
|
91
|
+
if [[ -z "$REGISTRY_TARBALL_URL" ]]; then
|
|
92
|
+
fail "cannot fetch registry tarball URL for ${PACKAGE_NAME}@${TARGET_VERSION}"
|
|
93
|
+
elif [[ -z "$FORMULA_CONTENT" ]]; then
|
|
94
|
+
fail "cannot fetch canonical Homebrew formula from ${CANONICAL_HOMEBREW_FORMULA_URL}"
|
|
95
|
+
else
|
|
96
|
+
REGISTRY_SHA="$(curl -sL "$REGISTRY_TARBALL_URL" | shasum -a 256 | awk '{print $1}')"
|
|
97
|
+
if [[ -z "$REGISTRY_SHA" ]]; then
|
|
98
|
+
fail "cannot compute SHA256 of registry tarball"
|
|
99
|
+
else
|
|
100
|
+
FORMULA_SHA="$(printf '%s\n' "$FORMULA_CONTENT" | grep -E '^\s*sha256\s+"' | sed 's/.*sha256 *"\([a-f0-9]*\)".*/\1/')"
|
|
101
|
+
if [[ "$REGISTRY_SHA" == "$FORMULA_SHA" ]]; then
|
|
102
|
+
pass "canonical Homebrew formula SHA256 matches registry tarball (${REGISTRY_SHA:0:16}...)"
|
|
103
|
+
else
|
|
104
|
+
fail "canonical Homebrew formula SHA256 mismatch: formula=${FORMULA_SHA:0:16}... registry=${REGISTRY_SHA:0:16}..."
|
|
105
|
+
fi
|
|
106
|
+
fi
|
|
107
|
+
fi
|
|
108
|
+
|
|
109
|
+
# --- Check 3: Homebrew tap URL matches registry tarball URL ---
|
|
110
|
+
echo "[3/3] Canonical Homebrew tap URL matches registry tarball"
|
|
111
|
+
if [[ -z "$REGISTRY_TARBALL_URL" ]]; then
|
|
112
|
+
fail "cannot verify URL — registry tarball URL unavailable"
|
|
113
|
+
elif [[ -z "$FORMULA_CONTENT" ]]; then
|
|
114
|
+
fail "cannot verify URL — canonical Homebrew formula unavailable"
|
|
115
|
+
else
|
|
116
|
+
FORMULA_URL="$(printf '%s\n' "$FORMULA_CONTENT" | grep -E '^\s*url\s+"' | sed 's/.*url *"\([^"]*\)".*/\1/')"
|
|
117
|
+
if [[ "$FORMULA_URL" == "$REGISTRY_TARBALL_URL" ]]; then
|
|
118
|
+
pass "canonical Homebrew formula URL matches registry tarball"
|
|
119
|
+
else
|
|
120
|
+
fail "canonical Homebrew formula URL mismatch: formula=${FORMULA_URL} registry=${REGISTRY_TARBALL_URL}"
|
|
121
|
+
fi
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
echo ""
|
|
125
|
+
echo "====================================="
|
|
126
|
+
echo "Results: ${PASS} passed, ${FAIL} failed"
|
|
127
|
+
if [ "$FAIL" -gt 0 ]; then
|
|
128
|
+
echo "DOWNSTREAM TRUTH FAILED — at least one downstream surface is inconsistent."
|
|
129
|
+
exit 1
|
|
130
|
+
fi
|
|
131
|
+
|
|
132
|
+
echo "DOWNSTREAM TRUTH PASSED — all downstream surfaces are consistent."
|
|
133
|
+
exit 0
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# Release postflight — run this after publish succeeds.
|
|
3
3
|
# Verifies: release tag exists, npm registry serves the version, metadata is present,
|
|
4
|
-
#
|
|
4
|
+
# the published package can execute its CLI entrypoint, and runner package exports
|
|
5
|
+
# are importable in a clean consumer project.
|
|
5
6
|
# Usage: bash scripts/release-postflight.sh --target-version <semver> [--tag vX.Y.Z]
|
|
6
7
|
set -uo pipefail
|
|
7
8
|
|
|
@@ -15,7 +16,7 @@ RETRY_ATTEMPTS="${RELEASE_POSTFLIGHT_RETRY_ATTEMPTS:-12}"
|
|
|
15
16
|
RETRY_DELAY_SECONDS="${RELEASE_POSTFLIGHT_RETRY_DELAY_SECONDS:-10}"
|
|
16
17
|
|
|
17
18
|
usage() {
|
|
18
|
-
|
|
19
|
+
echo "Usage: bash scripts/release-postflight.sh --target-version <semver> [--tag vX.Y.Z]" >&2
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
while [[ $# -gt 0 ]]; do
|
|
@@ -76,6 +77,7 @@ TARBALL_URL=""
|
|
|
76
77
|
REGISTRY_CHECKSUM=""
|
|
77
78
|
PACKAGE_NAME="$(node -e "console.log(JSON.parse(require('fs').readFileSync('package.json', 'utf8')).name)")"
|
|
78
79
|
PACKAGE_BIN_NAME="$(node -e "const pkg = JSON.parse(require('fs').readFileSync('package.json', 'utf8')); if (typeof pkg.bin === 'string') { console.log(pkg.name); process.exit(0); } const names = Object.keys(pkg.bin || {}); if (names.length !== 1) { console.error('package.json bin must declare exactly one entry'); process.exit(1); } console.log(names[0]);")"
|
|
80
|
+
RUNNER_INTERFACE_VERSION_EXPECTED="$(node --input-type=module -e "import('./src/lib/runner-interface.js').then((mod) => { console.log(mod.RUNNER_INTERFACE_VERSION); }).catch((error) => { console.error(error.message); process.exit(1); });")"
|
|
79
81
|
|
|
80
82
|
pass() { PASS=$((PASS + 1)); echo " PASS: $1"; }
|
|
81
83
|
fail() { FAIL=$((FAIL + 1)); echo " FAIL: $1"; }
|
|
@@ -136,6 +138,67 @@ run_install_smoke() {
|
|
|
136
138
|
return "$version_status"
|
|
137
139
|
}
|
|
138
140
|
|
|
141
|
+
run_runner_export_smoke() {
|
|
142
|
+
if [[ -z "$TARBALL_URL" ]]; then
|
|
143
|
+
echo "registry tarball metadata unavailable for runner export smoke" >&2
|
|
144
|
+
return 1
|
|
145
|
+
fi
|
|
146
|
+
|
|
147
|
+
local smoke_root
|
|
148
|
+
local consumer_root
|
|
149
|
+
local smoke_npmrc
|
|
150
|
+
local install_status
|
|
151
|
+
local node_status
|
|
152
|
+
|
|
153
|
+
smoke_root="$(mktemp -d "${TMPDIR:-/tmp}/agentxchain-runner-postflight.XXXXXX")"
|
|
154
|
+
consumer_root="${smoke_root}/consumer"
|
|
155
|
+
mkdir -p "$consumer_root"
|
|
156
|
+
|
|
157
|
+
smoke_npmrc="${smoke_root}/.npmrc"
|
|
158
|
+
echo "registry=https://registry.npmjs.org/" > "$smoke_npmrc"
|
|
159
|
+
|
|
160
|
+
cat > "${consumer_root}/package.json" <<'EOF'
|
|
161
|
+
{
|
|
162
|
+
"name": "agentxchain-runner-postflight-smoke",
|
|
163
|
+
"private": true,
|
|
164
|
+
"type": "module"
|
|
165
|
+
}
|
|
166
|
+
EOF
|
|
167
|
+
|
|
168
|
+
(
|
|
169
|
+
cd "$consumer_root" || exit 1
|
|
170
|
+
env -u NODE_AUTH_TOKEN NPM_CONFIG_USERCONFIG="$smoke_npmrc" \
|
|
171
|
+
npm install "$TARBALL_URL" >/dev/null 2>&1
|
|
172
|
+
)
|
|
173
|
+
install_status=$?
|
|
174
|
+
if [[ "$install_status" -ne 0 ]]; then
|
|
175
|
+
rm -rf "$smoke_root"
|
|
176
|
+
return "$install_status"
|
|
177
|
+
fi
|
|
178
|
+
|
|
179
|
+
cat > "${consumer_root}/runner-export-smoke.mjs" <<'EOF'
|
|
180
|
+
import { RUNNER_INTERFACE_VERSION, loadContext } from 'agentxchain/runner-interface';
|
|
181
|
+
import { runLoop } from 'agentxchain/run-loop';
|
|
182
|
+
|
|
183
|
+
if (typeof loadContext !== 'function') {
|
|
184
|
+
throw new Error('loadContext export missing');
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (typeof runLoop !== 'function') {
|
|
188
|
+
throw new Error('runLoop export missing');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
console.log(RUNNER_INTERFACE_VERSION);
|
|
192
|
+
EOF
|
|
193
|
+
|
|
194
|
+
local runner_output
|
|
195
|
+
runner_output="$(cd "$consumer_root" && node runner-export-smoke.mjs 2>&1)"
|
|
196
|
+
node_status=$?
|
|
197
|
+
printf '%s\n' "$runner_output"
|
|
198
|
+
rm -rf "$smoke_root"
|
|
199
|
+
return "$node_status"
|
|
200
|
+
}
|
|
201
|
+
|
|
139
202
|
run_with_retry() {
|
|
140
203
|
local __output_var="$1"
|
|
141
204
|
local description="$2"
|
|
@@ -189,17 +252,17 @@ run_with_retry() {
|
|
|
189
252
|
|
|
190
253
|
echo "AgentXchain v${TARGET_VERSION} Release Postflight"
|
|
191
254
|
echo "====================================="
|
|
192
|
-
echo "Checks release truth after publish: tag, registry visibility, metadata,
|
|
255
|
+
echo "Checks release truth after publish: tag, registry visibility, metadata, CLI install smoke, and runner export smoke."
|
|
193
256
|
echo ""
|
|
194
257
|
|
|
195
|
-
echo "[1/
|
|
258
|
+
echo "[1/6] Git tag"
|
|
196
259
|
if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null 2>&1; then
|
|
197
260
|
pass "Git tag ${TAG} exists locally"
|
|
198
261
|
else
|
|
199
262
|
fail "Git tag ${TAG} is missing locally"
|
|
200
263
|
fi
|
|
201
264
|
|
|
202
|
-
echo "[2/
|
|
265
|
+
echo "[2/6] Registry version"
|
|
203
266
|
if run_with_retry VERSION_OUTPUT "registry version" equals "${TARGET_VERSION}" npm view "${PACKAGE_NAME}@${TARGET_VERSION}" version; then
|
|
204
267
|
PUBLISHED_VERSION="$(trim_last_line "$VERSION_OUTPUT")"
|
|
205
268
|
if [[ "$PUBLISHED_VERSION" == "$TARGET_VERSION" ]]; then
|
|
@@ -212,7 +275,7 @@ else
|
|
|
212
275
|
printf '%s\n' "$VERSION_OUTPUT" | tail -20
|
|
213
276
|
fi
|
|
214
277
|
|
|
215
|
-
echo "[3/
|
|
278
|
+
echo "[3/6] Registry tarball metadata"
|
|
216
279
|
if run_with_retry TARBALL_OUTPUT "registry tarball metadata" nonempty "" npm view "${PACKAGE_NAME}@${TARGET_VERSION}" dist.tarball; then
|
|
217
280
|
TARBALL_URL="$(trim_last_line "$TARBALL_OUTPUT")"
|
|
218
281
|
if [[ -n "$TARBALL_URL" ]]; then
|
|
@@ -225,7 +288,7 @@ else
|
|
|
225
288
|
printf '%s\n' "$TARBALL_OUTPUT" | tail -20
|
|
226
289
|
fi
|
|
227
290
|
|
|
228
|
-
echo "[4/
|
|
291
|
+
echo "[4/6] Registry checksum metadata"
|
|
229
292
|
if run_with_retry INTEGRITY_OUTPUT "registry checksum metadata" nonempty "" npm view "${PACKAGE_NAME}@${TARGET_VERSION}" dist.integrity; then
|
|
230
293
|
REGISTRY_CHECKSUM="$(trim_last_line "$INTEGRITY_OUTPUT")"
|
|
231
294
|
fi
|
|
@@ -240,7 +303,7 @@ else
|
|
|
240
303
|
fail "registry did not return checksum metadata"
|
|
241
304
|
fi
|
|
242
305
|
|
|
243
|
-
echo "[5/
|
|
306
|
+
echo "[5/6] Install smoke"
|
|
244
307
|
if run_with_retry EXEC_OUTPUT "install smoke" nonempty "" run_install_smoke; then
|
|
245
308
|
EXEC_VERSION="$(trim_last_line "$EXEC_OUTPUT")"
|
|
246
309
|
if [[ "$EXEC_VERSION" == "$TARGET_VERSION" ]]; then
|
|
@@ -253,6 +316,19 @@ else
|
|
|
253
316
|
printf '%s\n' "$EXEC_OUTPUT" | tail -20
|
|
254
317
|
fi
|
|
255
318
|
|
|
319
|
+
echo "[6/6] Runner export smoke"
|
|
320
|
+
if run_with_retry RUNNER_EXPORT_OUTPUT "runner export smoke" nonempty "" run_runner_export_smoke; then
|
|
321
|
+
RUNNER_EXPORT_VERSION="$(trim_last_line "$RUNNER_EXPORT_OUTPUT")"
|
|
322
|
+
if [[ "$RUNNER_EXPORT_VERSION" == "$RUNNER_INTERFACE_VERSION_EXPECTED" ]]; then
|
|
323
|
+
pass "published runner exports import with interface ${RUNNER_INTERFACE_VERSION_EXPECTED}"
|
|
324
|
+
else
|
|
325
|
+
fail "published runner exports reported interface '${RUNNER_EXPORT_VERSION}', expected '${RUNNER_INTERFACE_VERSION_EXPECTED}'"
|
|
326
|
+
fi
|
|
327
|
+
else
|
|
328
|
+
fail "published runner exports install smoke failed"
|
|
329
|
+
printf '%s\n' "$RUNNER_EXPORT_OUTPUT" | tail -20
|
|
330
|
+
fi
|
|
331
|
+
|
|
256
332
|
echo ""
|
|
257
333
|
echo "====================================="
|
|
258
334
|
echo "Results: ${PASS} passed, ${FAIL} failed"
|
|
@@ -1,17 +1,9 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
import { findProjectRoot } from '../lib/config.js';
|
|
3
2
|
import { approveIntent } from '../lib/intake.js';
|
|
3
|
+
import { requireIntakeWorkspaceOrExit } from './intake-workspace.js';
|
|
4
4
|
|
|
5
5
|
export async function intakeApproveCommand(opts) {
|
|
6
|
-
const root =
|
|
7
|
-
if (!root) {
|
|
8
|
-
if (opts.json) {
|
|
9
|
-
console.log(JSON.stringify({ ok: false, error: 'agentxchain.json not found' }, null, 2));
|
|
10
|
-
} else {
|
|
11
|
-
console.log(chalk.red('agentxchain.json not found'));
|
|
12
|
-
}
|
|
13
|
-
process.exit(2);
|
|
14
|
-
}
|
|
6
|
+
const root = requireIntakeWorkspaceOrExit(opts);
|
|
15
7
|
|
|
16
8
|
if (!opts.intent) {
|
|
17
9
|
const msg = '--intent <id> is required';
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { handoffIntent } from '../lib/intake.js';
|
|
3
|
+
import { requireIntakeWorkspaceOrExit } from './intake-workspace.js';
|
|
4
|
+
|
|
5
|
+
export async function intakeHandoffCommand(opts) {
|
|
6
|
+
const root = requireIntakeWorkspaceOrExit(opts);
|
|
7
|
+
|
|
8
|
+
if (!opts.intent) {
|
|
9
|
+
const msg = '--intent <id> is required';
|
|
10
|
+
if (opts.json) {
|
|
11
|
+
console.log(JSON.stringify({ ok: false, error: msg }, null, 2));
|
|
12
|
+
} else {
|
|
13
|
+
console.log(chalk.red(msg));
|
|
14
|
+
}
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (!opts.coordinatorRoot) {
|
|
19
|
+
const msg = '--coordinator-root <path> is required';
|
|
20
|
+
if (opts.json) {
|
|
21
|
+
console.log(JSON.stringify({ ok: false, error: msg }, null, 2));
|
|
22
|
+
} else {
|
|
23
|
+
console.log(chalk.red(msg));
|
|
24
|
+
}
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!opts.workstream) {
|
|
29
|
+
const msg = '--workstream <id> is required';
|
|
30
|
+
if (opts.json) {
|
|
31
|
+
console.log(JSON.stringify({ ok: false, error: msg }, null, 2));
|
|
32
|
+
} else {
|
|
33
|
+
console.log(chalk.red(msg));
|
|
34
|
+
}
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const result = handoffIntent(root, opts.intent, {
|
|
39
|
+
coordinatorRoot: opts.coordinatorRoot,
|
|
40
|
+
workstreamId: opts.workstream,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
if (opts.json) {
|
|
44
|
+
console.log(JSON.stringify(result, null, 2));
|
|
45
|
+
} else if (result.ok) {
|
|
46
|
+
console.log('');
|
|
47
|
+
console.log(chalk.green(` Handed off intent ${result.intent.intent_id}`));
|
|
48
|
+
console.log(` Workstream: ${result.intent.target_workstream.workstream_id}`);
|
|
49
|
+
console.log(` Super Run: ${result.super_run_id}`);
|
|
50
|
+
console.log(` Handoff: ${result.handoff_path}`);
|
|
51
|
+
console.log(chalk.dim(' Status: planned → executing (coordinator-managed)'));
|
|
52
|
+
console.log('');
|
|
53
|
+
} else {
|
|
54
|
+
console.log(chalk.red(` ${result.error}`));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
process.exit(result.exitCode);
|
|
58
|
+
}
|
|
@@ -1,18 +1,9 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
import { findProjectRoot } from '../lib/config.js';
|
|
3
2
|
import { planIntent } from '../lib/intake.js';
|
|
4
|
-
import {
|
|
3
|
+
import { requireIntakeWorkspaceOrExit } from './intake-workspace.js';
|
|
5
4
|
|
|
6
5
|
export async function intakePlanCommand(opts) {
|
|
7
|
-
const root =
|
|
8
|
-
if (!root) {
|
|
9
|
-
if (opts.json) {
|
|
10
|
-
console.log(JSON.stringify({ ok: false, error: 'agentxchain.json not found' }, null, 2));
|
|
11
|
-
} else {
|
|
12
|
-
console.log(chalk.red('agentxchain.json not found'));
|
|
13
|
-
}
|
|
14
|
-
process.exit(2);
|
|
15
|
-
}
|
|
6
|
+
const root = requireIntakeWorkspaceOrExit(opts);
|
|
16
7
|
|
|
17
8
|
if (!opts.intent) {
|
|
18
9
|
const msg = '--intent <id> is required';
|
|
@@ -1,19 +1,11 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
|
-
import { findProjectRoot } from '../lib/config.js';
|
|
5
4
|
import { recordEvent } from '../lib/intake.js';
|
|
5
|
+
import { requireIntakeWorkspaceOrExit } from './intake-workspace.js';
|
|
6
6
|
|
|
7
7
|
export async function intakeRecordCommand(opts) {
|
|
8
|
-
const root =
|
|
9
|
-
if (!root) {
|
|
10
|
-
if (opts.json) {
|
|
11
|
-
console.log(JSON.stringify({ ok: false, error: 'agentxchain.json not found' }, null, 2));
|
|
12
|
-
} else {
|
|
13
|
-
console.log(chalk.red('agentxchain.json not found'));
|
|
14
|
-
}
|
|
15
|
-
process.exit(2);
|
|
16
|
-
}
|
|
8
|
+
const root = requireIntakeWorkspaceOrExit(opts);
|
|
17
9
|
|
|
18
10
|
let payload;
|
|
19
11
|
try {
|
|
@@ -1,17 +1,9 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
import { findProjectRoot } from '../lib/config.js';
|
|
3
2
|
import { resolveIntent } from '../lib/intake.js';
|
|
3
|
+
import { requireIntakeWorkspaceOrExit } from './intake-workspace.js';
|
|
4
4
|
|
|
5
5
|
export async function intakeResolveCommand(opts) {
|
|
6
|
-
const root =
|
|
7
|
-
if (!root) {
|
|
8
|
-
if (opts.json) {
|
|
9
|
-
console.log(JSON.stringify({ ok: false, error: 'agentxchain.json not found' }, null, 2));
|
|
10
|
-
} else {
|
|
11
|
-
console.log(chalk.red('agentxchain.json not found'));
|
|
12
|
-
}
|
|
13
|
-
process.exit(2);
|
|
14
|
-
}
|
|
6
|
+
const root = requireIntakeWorkspaceOrExit(opts);
|
|
15
7
|
|
|
16
8
|
if (!opts.intent) {
|
|
17
9
|
const msg = '--intent <id> is required';
|
|
@@ -1,19 +1,11 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
|
-
import { findProjectRoot } from '../lib/config.js';
|
|
5
4
|
import { scanSource, SCAN_SOURCES } from '../lib/intake.js';
|
|
5
|
+
import { requireIntakeWorkspaceOrExit } from './intake-workspace.js';
|
|
6
6
|
|
|
7
7
|
export async function intakeScanCommand(opts) {
|
|
8
|
-
const root =
|
|
9
|
-
if (!root) {
|
|
10
|
-
if (opts.json) {
|
|
11
|
-
console.log(JSON.stringify({ ok: false, error: 'agentxchain.json not found' }, null, 2));
|
|
12
|
-
} else {
|
|
13
|
-
console.log(chalk.red('agentxchain.json not found'));
|
|
14
|
-
}
|
|
15
|
-
process.exit(2);
|
|
16
|
-
}
|
|
8
|
+
const root = requireIntakeWorkspaceOrExit(opts);
|
|
17
9
|
|
|
18
10
|
if (!opts.source) {
|
|
19
11
|
const msg = `--source is required. Supported scan sources: ${SCAN_SOURCES.join(', ')}`;
|
|
@@ -1,17 +1,9 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
import { findProjectRoot } from '../lib/config.js';
|
|
3
2
|
import { startIntent } from '../lib/intake.js';
|
|
3
|
+
import { requireIntakeWorkspaceOrExit } from './intake-workspace.js';
|
|
4
4
|
|
|
5
5
|
export async function intakeStartCommand(opts) {
|
|
6
|
-
const root =
|
|
7
|
-
if (!root) {
|
|
8
|
-
if (opts.json) {
|
|
9
|
-
console.log(JSON.stringify({ ok: false, error: 'agentxchain.json not found' }, null, 2));
|
|
10
|
-
} else {
|
|
11
|
-
console.log(chalk.red('agentxchain.json not found'));
|
|
12
|
-
}
|
|
13
|
-
process.exit(2);
|
|
14
|
-
}
|
|
6
|
+
const root = requireIntakeWorkspaceOrExit(opts);
|
|
15
7
|
|
|
16
8
|
if (!opts.intent) {
|
|
17
9
|
const msg = '--intent <id> is required';
|
|
@@ -1,17 +1,9 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
import { findProjectRoot } from '../lib/config.js';
|
|
3
2
|
import { intakeStatus } from '../lib/intake.js';
|
|
3
|
+
import { requireIntakeWorkspaceOrExit } from './intake-workspace.js';
|
|
4
4
|
|
|
5
5
|
export async function intakeStatusCommand(opts) {
|
|
6
|
-
const root =
|
|
7
|
-
if (!root) {
|
|
8
|
-
if (opts.json) {
|
|
9
|
-
console.log(JSON.stringify({ ok: false, error: 'agentxchain.json not found' }, null, 2));
|
|
10
|
-
} else {
|
|
11
|
-
console.log(chalk.red('agentxchain.json not found'));
|
|
12
|
-
}
|
|
13
|
-
process.exit(2);
|
|
14
|
-
}
|
|
6
|
+
const root = requireIntakeWorkspaceOrExit(opts);
|
|
15
7
|
|
|
16
8
|
const result = intakeStatus(root, opts.intent || null);
|
|
17
9
|
|
|
@@ -72,6 +64,10 @@ function printIntentDetail(intent, event) {
|
|
|
72
64
|
console.log(` ${chalk.dim('Charter:')} ${intent.charter || '—'}`);
|
|
73
65
|
console.log(` ${chalk.dim('Created:')} ${intent.created_at}`);
|
|
74
66
|
console.log(` ${chalk.dim('Updated:')} ${intent.updated_at}`);
|
|
67
|
+
if (intent.target_workstream) {
|
|
68
|
+
console.log(` ${chalk.dim('Workstream:')} ${intent.target_workstream.workstream_id}`);
|
|
69
|
+
console.log(` ${chalk.dim('Super Run:')} ${intent.target_workstream.super_run_id}`);
|
|
70
|
+
}
|
|
75
71
|
|
|
76
72
|
if (intent.acceptance_contract && intent.acceptance_contract.length > 0) {
|
|
77
73
|
console.log('');
|
|
@@ -1,17 +1,9 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
import { findProjectRoot } from '../lib/config.js';
|
|
3
2
|
import { triageIntent } from '../lib/intake.js';
|
|
3
|
+
import { requireIntakeWorkspaceOrExit } from './intake-workspace.js';
|
|
4
4
|
|
|
5
5
|
export async function intakeTriageCommand(opts) {
|
|
6
|
-
const root =
|
|
7
|
-
if (!root) {
|
|
8
|
-
if (opts.json) {
|
|
9
|
-
console.log(JSON.stringify({ ok: false, error: 'agentxchain.json not found' }, null, 2));
|
|
10
|
-
} else {
|
|
11
|
-
console.log(chalk.red('agentxchain.json not found'));
|
|
12
|
-
}
|
|
13
|
-
process.exit(2);
|
|
14
|
-
}
|
|
6
|
+
const root = requireIntakeWorkspaceOrExit(opts);
|
|
15
7
|
|
|
16
8
|
if (!opts.intent) {
|
|
17
9
|
const msg = '--intent <id> is required';
|