agentxchain 2.15.0 → 2.16.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 +2 -0
- package/bin/agentxchain.js +1 -0
- package/package.json +3 -1
- package/scripts/release-postflight.sh +21 -5
- package/scripts/sync-homebrew.sh +225 -0
- package/src/commands/init.js +16 -6
- package/src/commands/migrate.js +7 -3
- package/src/commands/run.js +29 -1
- package/src/commands/template-set.js +51 -2
- package/src/lib/adapter-interface.js +31 -0
- package/src/lib/coordinator-config.js +31 -0
- package/src/lib/coordinator-dispatch.js +10 -1
- package/src/lib/coordinator-gates.js +28 -1
- package/src/lib/coordinator-recovery.js +10 -0
- package/src/lib/coordinator-state.js +73 -0
- package/src/lib/governed-templates.js +60 -0
- package/src/lib/report.js +759 -27
- package/src/lib/workflow-gate-semantics.js +209 -0
- package/src/templates/governed/api-service.json +8 -1
- package/src/templates/governed/cli-tool.json +8 -1
- package/src/templates/governed/library.json +8 -1
- package/src/templates/governed/web-app.json +8 -1
package/README.md
CHANGED
|
@@ -194,6 +194,8 @@ agentxchain.json
|
|
|
194
194
|
.agentxchain/staging/<turn_id>/turn-result.json
|
|
195
195
|
TALK.md
|
|
196
196
|
.planning/
|
|
197
|
+
|
|
198
|
+
The first-party governed workflow kit includes `.planning/SYSTEM_SPEC.md` alongside `PM_SIGNOFF.md`, `ROADMAP.md`, `acceptance-matrix.md`, and `ship-verdict.md`. `template validate --json` exposes this under the `workflow_kit` block.
|
|
197
199
|
```
|
|
198
200
|
|
|
199
201
|
### Runtime support today
|
package/bin/agentxchain.js
CHANGED
|
@@ -321,6 +321,7 @@ program
|
|
|
321
321
|
.option('--auto-approve', 'Auto-approve all gates (non-interactive mode)')
|
|
322
322
|
.option('--verbose', 'Stream adapter subprocess output')
|
|
323
323
|
.option('--dry-run', 'Print what would be dispatched without executing')
|
|
324
|
+
.option('--no-report', 'Suppress automatic governance report after run completes')
|
|
324
325
|
.action(runCommand);
|
|
325
326
|
|
|
326
327
|
program
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentxchain",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.16.0",
|
|
4
4
|
"description": "CLI for AgentXchain — governed multi-agent software delivery",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
},
|
|
9
9
|
"exports": {
|
|
10
10
|
".": "./bin/agentxchain.js",
|
|
11
|
+
"./adapter-interface": "./src/lib/adapter-interface.js",
|
|
11
12
|
"./runner-interface": "./src/lib/runner-interface.js",
|
|
12
13
|
"./run-loop": "./src/lib/run-loop.js"
|
|
13
14
|
},
|
|
@@ -27,6 +28,7 @@
|
|
|
27
28
|
"preflight:release:strict": "bash scripts/release-preflight.sh --strict",
|
|
28
29
|
"postflight:release": "bash scripts/release-postflight.sh",
|
|
29
30
|
"postflight:downstream": "bash scripts/release-downstream-truth.sh",
|
|
31
|
+
"sync:homebrew": "bash scripts/sync-homebrew.sh",
|
|
30
32
|
"build:macos": "bun build bin/agentxchain.js --compile --target=bun-darwin-arm64 --outfile=dist/agentxchain-macos-arm64",
|
|
31
33
|
"build:linux": "bun build bin/agentxchain.js --compile --target=bun-linux-x64 --outfile=dist/agentxchain-linux-x64",
|
|
32
34
|
"publish:npm": "bash scripts/publish-npm.sh"
|
|
@@ -78,6 +78,7 @@ REGISTRY_CHECKSUM=""
|
|
|
78
78
|
PACKAGE_NAME="$(node -e "console.log(JSON.parse(require('fs').readFileSync('package.json', 'utf8')).name)")"
|
|
79
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
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); });")"
|
|
81
|
+
ADAPTER_INTERFACE_VERSION_EXPECTED="$(node --input-type=module -e "import('./src/lib/adapter-interface.js').then((mod) => { console.log(mod.ADAPTER_INTERFACE_VERSION); }).catch((error) => { console.error(error.message); process.exit(1); });")"
|
|
81
82
|
|
|
82
83
|
pass() { PASS=$((PASS + 1)); echo " PASS: $1"; }
|
|
83
84
|
fail() { FAIL=$((FAIL + 1)); echo " FAIL: $1"; }
|
|
@@ -178,17 +179,25 @@ EOF
|
|
|
178
179
|
|
|
179
180
|
cat > "${consumer_root}/runner-export-smoke.mjs" <<'EOF'
|
|
180
181
|
import { RUNNER_INTERFACE_VERSION, loadContext } from 'agentxchain/runner-interface';
|
|
182
|
+
import { ADAPTER_INTERFACE_VERSION, dispatchLocalCli } from 'agentxchain/adapter-interface';
|
|
181
183
|
import { runLoop } from 'agentxchain/run-loop';
|
|
182
184
|
|
|
183
185
|
if (typeof loadContext !== 'function') {
|
|
184
186
|
throw new Error('loadContext export missing');
|
|
185
187
|
}
|
|
186
188
|
|
|
189
|
+
if (typeof dispatchLocalCli !== 'function') {
|
|
190
|
+
throw new Error('dispatchLocalCli export missing');
|
|
191
|
+
}
|
|
192
|
+
|
|
187
193
|
if (typeof runLoop !== 'function') {
|
|
188
194
|
throw new Error('runLoop export missing');
|
|
189
195
|
}
|
|
190
196
|
|
|
191
|
-
console.log(
|
|
197
|
+
console.log(JSON.stringify({
|
|
198
|
+
runner_interface_version: RUNNER_INTERFACE_VERSION,
|
|
199
|
+
adapter_interface_version: ADAPTER_INTERFACE_VERSION
|
|
200
|
+
}));
|
|
192
201
|
EOF
|
|
193
202
|
|
|
194
203
|
local runner_output
|
|
@@ -252,7 +261,7 @@ run_with_retry() {
|
|
|
252
261
|
|
|
253
262
|
echo "AgentXchain v${TARGET_VERSION} Release Postflight"
|
|
254
263
|
echo "====================================="
|
|
255
|
-
echo "Checks release truth after publish: tag, registry visibility, metadata, CLI install smoke, and
|
|
264
|
+
echo "Checks release truth after publish: tag, registry visibility, metadata, CLI install smoke, and package export smoke."
|
|
256
265
|
echo ""
|
|
257
266
|
|
|
258
267
|
echo "[1/6] Git tag"
|
|
@@ -316,16 +325,23 @@ else
|
|
|
316
325
|
printf '%s\n' "$EXEC_OUTPUT" | tail -20
|
|
317
326
|
fi
|
|
318
327
|
|
|
319
|
-
echo "[6/6]
|
|
328
|
+
echo "[6/6] Package export smoke"
|
|
320
329
|
if run_with_retry RUNNER_EXPORT_OUTPUT "runner export smoke" nonempty "" run_runner_export_smoke; then
|
|
321
|
-
|
|
330
|
+
RUNNER_EXPORT_JSON="$(trim_last_line "$RUNNER_EXPORT_OUTPUT")"
|
|
331
|
+
RUNNER_EXPORT_VERSION="$(printf '%s' "$RUNNER_EXPORT_JSON" | node --input-type=module -e "process.stdin.setEncoding('utf8'); let raw=''; process.stdin.on('data', (chunk) => raw += chunk); process.stdin.on('end', () => { const parsed = JSON.parse(raw); console.log(parsed.runner_interface_version || ''); });")"
|
|
332
|
+
ADAPTER_EXPORT_VERSION="$(printf '%s' "$RUNNER_EXPORT_JSON" | node --input-type=module -e "process.stdin.setEncoding('utf8'); let raw=''; process.stdin.on('data', (chunk) => raw += chunk); process.stdin.on('end', () => { const parsed = JSON.parse(raw); console.log(parsed.adapter_interface_version || ''); });")"
|
|
322
333
|
if [[ "$RUNNER_EXPORT_VERSION" == "$RUNNER_INTERFACE_VERSION_EXPECTED" ]]; then
|
|
323
334
|
pass "published runner exports import with interface ${RUNNER_INTERFACE_VERSION_EXPECTED}"
|
|
324
335
|
else
|
|
325
336
|
fail "published runner exports reported interface '${RUNNER_EXPORT_VERSION}', expected '${RUNNER_INTERFACE_VERSION_EXPECTED}'"
|
|
326
337
|
fi
|
|
338
|
+
if [[ "$ADAPTER_EXPORT_VERSION" == "$ADAPTER_INTERFACE_VERSION_EXPECTED" ]]; then
|
|
339
|
+
pass "published adapter exports import with interface ${ADAPTER_INTERFACE_VERSION_EXPECTED}"
|
|
340
|
+
else
|
|
341
|
+
fail "published adapter exports reported interface '${ADAPTER_EXPORT_VERSION}', expected '${ADAPTER_INTERFACE_VERSION_EXPECTED}'"
|
|
342
|
+
fi
|
|
327
343
|
else
|
|
328
|
-
fail "published runner exports install smoke failed"
|
|
344
|
+
fail "published runner/adapter exports install smoke failed"
|
|
329
345
|
printf '%s\n' "$RUNNER_EXPORT_OUTPUT" | tail -20
|
|
330
346
|
fi
|
|
331
347
|
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Sync Homebrew formula from live npm registry metadata.
|
|
3
|
+
# Updates both the repo mirror (cli/homebrew/) and optionally the canonical tap.
|
|
4
|
+
# Usage: bash scripts/sync-homebrew.sh --target-version <semver> [--push-tap] [--dry-run]
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
8
|
+
CLI_DIR="${SCRIPT_DIR}/.."
|
|
9
|
+
REPO_ROOT="${CLI_DIR}/.."
|
|
10
|
+
|
|
11
|
+
TARGET_VERSION=""
|
|
12
|
+
PUSH_TAP=false
|
|
13
|
+
DRY_RUN=false
|
|
14
|
+
|
|
15
|
+
FORMULA_PATH="${CLI_DIR}/homebrew/agentxchain.rb"
|
|
16
|
+
README_PATH="${CLI_DIR}/homebrew/README.md"
|
|
17
|
+
CANONICAL_TAP_REPO="shivamtiwari93/homebrew-tap"
|
|
18
|
+
PACKAGE_NAME="agentxchain"
|
|
19
|
+
|
|
20
|
+
formula_url() {
|
|
21
|
+
local formula_path="$1"
|
|
22
|
+
grep -E '^\s*url\s+"' "$formula_path" | sed 's/.*url *"\([^"]*\)".*/\1/' || true
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
formula_sha() {
|
|
26
|
+
local formula_path="$1"
|
|
27
|
+
grep -E '^\s*sha256\s+"' "$formula_path" | sed 's/.*sha256 *"\([a-f0-9]*\)".*/\1/' || true
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
usage() {
|
|
31
|
+
echo "Usage: bash scripts/sync-homebrew.sh --target-version <semver> [--push-tap] [--dry-run]" >&2
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
while [[ $# -gt 0 ]]; do
|
|
35
|
+
case "$1" in
|
|
36
|
+
--target-version)
|
|
37
|
+
if [[ -z "${2:-}" ]]; then
|
|
38
|
+
echo "Error: --target-version requires a semver argument" >&2
|
|
39
|
+
usage
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
|
42
|
+
if ! [[ "$2" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
43
|
+
echo "Invalid semver: $2" >&2
|
|
44
|
+
usage
|
|
45
|
+
exit 1
|
|
46
|
+
fi
|
|
47
|
+
TARGET_VERSION="$2"
|
|
48
|
+
shift 2
|
|
49
|
+
;;
|
|
50
|
+
--push-tap)
|
|
51
|
+
PUSH_TAP=true
|
|
52
|
+
shift
|
|
53
|
+
;;
|
|
54
|
+
--dry-run)
|
|
55
|
+
DRY_RUN=true
|
|
56
|
+
shift
|
|
57
|
+
;;
|
|
58
|
+
*)
|
|
59
|
+
usage
|
|
60
|
+
exit 1
|
|
61
|
+
;;
|
|
62
|
+
esac
|
|
63
|
+
done
|
|
64
|
+
|
|
65
|
+
if [[ -z "$TARGET_VERSION" ]]; then
|
|
66
|
+
echo "Error: --target-version is required" >&2
|
|
67
|
+
usage
|
|
68
|
+
exit 1
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
echo "Homebrew Sync — ${PACKAGE_NAME}@${TARGET_VERSION}"
|
|
72
|
+
echo "====================================="
|
|
73
|
+
|
|
74
|
+
# --- Step 1: Fetch tarball URL from npm ---
|
|
75
|
+
echo "[1/5] Fetching tarball URL from npm registry..."
|
|
76
|
+
TARBALL_URL="$(npm view "${PACKAGE_NAME}@${TARGET_VERSION}" dist.tarball 2>/dev/null || true)"
|
|
77
|
+
if [[ -z "$TARBALL_URL" ]]; then
|
|
78
|
+
echo "FAIL: npm registry does not serve ${PACKAGE_NAME}@${TARGET_VERSION}" >&2
|
|
79
|
+
exit 1
|
|
80
|
+
fi
|
|
81
|
+
echo " tarball: ${TARBALL_URL}"
|
|
82
|
+
|
|
83
|
+
# --- Step 2: Download tarball and compute SHA256 ---
|
|
84
|
+
echo "[2/5] Computing SHA256 from registry tarball..."
|
|
85
|
+
TARBALL_SHA="$(curl -sL "$TARBALL_URL" | shasum -a 256 | awk '{print $1}')"
|
|
86
|
+
if [[ -z "$TARBALL_SHA" ]] || [[ ${#TARBALL_SHA} -ne 64 ]]; then
|
|
87
|
+
echo "FAIL: could not compute valid SHA256 from tarball" >&2
|
|
88
|
+
exit 1
|
|
89
|
+
fi
|
|
90
|
+
echo " sha256: ${TARBALL_SHA}"
|
|
91
|
+
|
|
92
|
+
# --- Step 3: Check if already in sync ---
|
|
93
|
+
echo "[3/5] Checking repo mirror..."
|
|
94
|
+
MIRROR_IN_SYNC=false
|
|
95
|
+
if [[ -f "$FORMULA_PATH" ]]; then
|
|
96
|
+
CURRENT_URL="$(formula_url "$FORMULA_PATH")"
|
|
97
|
+
CURRENT_SHA="$(formula_sha "$FORMULA_PATH")"
|
|
98
|
+
if [[ "$CURRENT_URL" == "$TARBALL_URL" && "$CURRENT_SHA" == "$TARBALL_SHA" ]]; then
|
|
99
|
+
MIRROR_IN_SYNC=true
|
|
100
|
+
echo " Repo mirror already matches npm registry."
|
|
101
|
+
if ! $PUSH_TAP; then
|
|
102
|
+
echo "====================================="
|
|
103
|
+
echo "SYNC COMPLETE — repo mirror already up to date."
|
|
104
|
+
exit 0
|
|
105
|
+
fi
|
|
106
|
+
echo " Repo mirror is current, but canonical tap verification is still required."
|
|
107
|
+
fi
|
|
108
|
+
if ! $MIRROR_IN_SYNC; then
|
|
109
|
+
echo " Current URL: ${CURRENT_URL}"
|
|
110
|
+
echo " Current SHA: ${CURRENT_SHA}"
|
|
111
|
+
echo " Updating to match registry..."
|
|
112
|
+
fi
|
|
113
|
+
else
|
|
114
|
+
echo " Formula not found at ${FORMULA_PATH} — will create."
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
if $DRY_RUN; then
|
|
118
|
+
echo ""
|
|
119
|
+
echo "[DRY RUN] Would update:"
|
|
120
|
+
if $MIRROR_IN_SYNC; then
|
|
121
|
+
echo " Repo mirror already matches:"
|
|
122
|
+
echo " url -> ${TARBALL_URL}"
|
|
123
|
+
echo " sha256 -> ${TARBALL_SHA}"
|
|
124
|
+
else
|
|
125
|
+
echo " ${FORMULA_PATH}:"
|
|
126
|
+
echo " url -> ${TARBALL_URL}"
|
|
127
|
+
echo " sha256 -> ${TARBALL_SHA}"
|
|
128
|
+
echo " ${README_PATH}:"
|
|
129
|
+
echo " version -> ${TARGET_VERSION}"
|
|
130
|
+
echo " tarball -> ${TARBALL_URL}"
|
|
131
|
+
fi
|
|
132
|
+
if $PUSH_TAP; then
|
|
133
|
+
echo " Canonical tap ${CANONICAL_TAP_REPO}:"
|
|
134
|
+
echo " Formula/agentxchain.rb -> ${TARBALL_URL}"
|
|
135
|
+
echo " Formula/agentxchain.rb sha256 -> ${TARBALL_SHA}"
|
|
136
|
+
fi
|
|
137
|
+
echo "====================================="
|
|
138
|
+
echo "DRY RUN COMPLETE — no files modified."
|
|
139
|
+
exit 0
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
# --- Step 4: Update repo mirror ---
|
|
143
|
+
echo "[4/5] Updating repo mirror..."
|
|
144
|
+
|
|
145
|
+
if $MIRROR_IN_SYNC; then
|
|
146
|
+
echo " Repo mirror already in sync — no local file changes needed."
|
|
147
|
+
else
|
|
148
|
+
# Update formula
|
|
149
|
+
ESCAPED_URL="$(printf '%s' "$TARBALL_URL" | sed 's/[&/\]/\\&/g')"
|
|
150
|
+
ESCAPED_SHA="$(printf '%s' "$TARBALL_SHA" | sed 's/[&/\]/\\&/g')"
|
|
151
|
+
sed -i.bak -E "s|^([[:space:]]*url \").*(\")|\1${ESCAPED_URL}\2|" "$FORMULA_PATH"
|
|
152
|
+
sed -i.bak -E "s|^([[:space:]]*sha256 \").*(\")|\1${ESCAPED_SHA}\2|" "$FORMULA_PATH"
|
|
153
|
+
rm -f "${FORMULA_PATH}.bak"
|
|
154
|
+
|
|
155
|
+
# Update README version and tarball lines
|
|
156
|
+
if [[ -f "$README_PATH" ]]; then
|
|
157
|
+
# Update version line: "- version: `X.Y.Z`"
|
|
158
|
+
sed -i.bak -E "s|^(- version: \`).*(\`)|\1${TARGET_VERSION}\2|" "$README_PATH"
|
|
159
|
+
# Update tarball line: "- source tarball: `URL`"
|
|
160
|
+
sed -i.bak -E "s|^(- source tarball: \`).*(\`)|\1${TARBALL_URL}\2|" "$README_PATH"
|
|
161
|
+
rm -f "${README_PATH}.bak"
|
|
162
|
+
fi
|
|
163
|
+
|
|
164
|
+
echo " Updated ${FORMULA_PATH}"
|
|
165
|
+
echo " Updated ${README_PATH}"
|
|
166
|
+
fi
|
|
167
|
+
|
|
168
|
+
# --- Step 5: Push to canonical tap (optional) ---
|
|
169
|
+
if $PUSH_TAP; then
|
|
170
|
+
echo "[5/5] Pushing to canonical tap ${CANONICAL_TAP_REPO}..."
|
|
171
|
+
TAP_TMPDIR="$(mktemp -d "${TMPDIR:-/tmp}/homebrew-tap-sync.XXXXXX")"
|
|
172
|
+
TAP_REMOTE_URL="https://github.com/${CANONICAL_TAP_REPO}.git"
|
|
173
|
+
if [[ -n "${HOMEBREW_TAP_TOKEN:-}" ]]; then
|
|
174
|
+
TAP_REMOTE_URL="https://x-access-token:${HOMEBREW_TAP_TOKEN}@github.com/${CANONICAL_TAP_REPO}.git"
|
|
175
|
+
fi
|
|
176
|
+
|
|
177
|
+
if ! git clone "$TAP_REMOTE_URL" "$TAP_TMPDIR" 2>/dev/null; then
|
|
178
|
+
echo "FAIL: could not clone ${CANONICAL_TAP_REPO}" >&2
|
|
179
|
+
rm -rf "$TAP_TMPDIR"
|
|
180
|
+
exit 1
|
|
181
|
+
fi
|
|
182
|
+
|
|
183
|
+
TAP_FORMULA="${TAP_TMPDIR}/Formula/agentxchain.rb"
|
|
184
|
+
if [[ ! -f "$TAP_FORMULA" ]]; then
|
|
185
|
+
mkdir -p "${TAP_TMPDIR}/Formula"
|
|
186
|
+
fi
|
|
187
|
+
|
|
188
|
+
TAP_CURRENT_URL=""
|
|
189
|
+
TAP_CURRENT_SHA=""
|
|
190
|
+
if [[ -f "$TAP_FORMULA" ]]; then
|
|
191
|
+
TAP_CURRENT_URL="$(formula_url "$TAP_FORMULA")"
|
|
192
|
+
TAP_CURRENT_SHA="$(formula_sha "$TAP_FORMULA")"
|
|
193
|
+
fi
|
|
194
|
+
|
|
195
|
+
(
|
|
196
|
+
cd "$TAP_TMPDIR" || exit 1
|
|
197
|
+
if [[ "$TAP_CURRENT_URL" == "$TARBALL_URL" && "$TAP_CURRENT_SHA" == "$TARBALL_SHA" ]]; then
|
|
198
|
+
echo " Canonical tap already in sync — no push needed."
|
|
199
|
+
else
|
|
200
|
+
cp "$FORMULA_PATH" "$TAP_FORMULA"
|
|
201
|
+
if ! git config user.name >/dev/null; then
|
|
202
|
+
git config user.name "${HOMEBREW_TAP_GIT_NAME:-github-actions[bot]}"
|
|
203
|
+
fi
|
|
204
|
+
if ! git config user.email >/dev/null; then
|
|
205
|
+
git config user.email "${HOMEBREW_TAP_GIT_EMAIL:-github-actions[bot]@users.noreply.github.com}"
|
|
206
|
+
fi
|
|
207
|
+
git add Formula/agentxchain.rb
|
|
208
|
+
git commit -m "agentxchain ${TARGET_VERSION}"
|
|
209
|
+
if ! git push origin HEAD:main; then
|
|
210
|
+
echo "FAIL: could not push to ${CANONICAL_TAP_REPO}" >&2
|
|
211
|
+
exit 1
|
|
212
|
+
fi
|
|
213
|
+
echo " Pushed to ${CANONICAL_TAP_REPO}"
|
|
214
|
+
fi
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
rm -rf "$TAP_TMPDIR"
|
|
218
|
+
else
|
|
219
|
+
echo "[5/5] Skipping tap push (--push-tap not set)."
|
|
220
|
+
fi
|
|
221
|
+
|
|
222
|
+
echo ""
|
|
223
|
+
echo "====================================="
|
|
224
|
+
echo "SYNC COMPLETE — Homebrew formula updated to ${PACKAGE_NAME}@${TARGET_VERSION}."
|
|
225
|
+
exit 0
|
package/src/commands/init.js
CHANGED
|
@@ -5,7 +5,7 @@ import chalk from 'chalk';
|
|
|
5
5
|
import inquirer from 'inquirer';
|
|
6
6
|
import { CONFIG_FILE, LOCK_FILE, STATE_FILE } from '../lib/config.js';
|
|
7
7
|
import { generateVSCodeFiles } from '../lib/generate-vscode.js';
|
|
8
|
-
import { loadGovernedTemplate, VALID_GOVERNED_TEMPLATE_IDS } from '../lib/governed-templates.js';
|
|
8
|
+
import { loadGovernedTemplate, VALID_GOVERNED_TEMPLATE_IDS, buildSystemSpecContent } from '../lib/governed-templates.js';
|
|
9
9
|
import { VALID_PROMPT_TRANSPORTS } from '../lib/normalized-config.js';
|
|
10
10
|
|
|
11
11
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -128,14 +128,15 @@ const GOVERNED_ROUTING = {
|
|
|
128
128
|
|
|
129
129
|
const GOVERNED_GATES = {
|
|
130
130
|
planning_signoff: {
|
|
131
|
-
requires_files: ['.planning/PM_SIGNOFF.md', '.planning/ROADMAP.md'],
|
|
131
|
+
requires_files: ['.planning/PM_SIGNOFF.md', '.planning/ROADMAP.md', '.planning/SYSTEM_SPEC.md'],
|
|
132
132
|
requires_human_approval: true
|
|
133
133
|
},
|
|
134
134
|
implementation_complete: {
|
|
135
|
+
requires_files: ['.planning/IMPLEMENTATION_NOTES.md'],
|
|
135
136
|
requires_verification_pass: true
|
|
136
137
|
},
|
|
137
138
|
qa_ship_verdict: {
|
|
138
|
-
requires_files: ['.planning/acceptance-matrix.md', '.planning/ship-verdict.md'],
|
|
139
|
+
requires_files: ['.planning/acceptance-matrix.md', '.planning/ship-verdict.md', '.planning/RELEASE_NOTES.md'],
|
|
139
140
|
requires_human_approval: true
|
|
140
141
|
}
|
|
141
142
|
};
|
|
@@ -166,6 +167,7 @@ You are the Product Manager. Your mandate: **${role.mandate}**
|
|
|
166
167
|
2. **Challenge it.** Even if the work looks correct, identify at least one risk, scope gap, or assumption worth questioning. Rubber-stamping violates the protocol.
|
|
167
168
|
3. **Create or refine planning artifacts:**
|
|
168
169
|
- \`.planning/ROADMAP.md\` — what will be built, in what order, with acceptance criteria
|
|
170
|
+
- \`.planning/SYSTEM_SPEC.md\` — the baseline subsystem contract implementation will follow
|
|
169
171
|
- \`.planning/PM_SIGNOFF.md\` — your formal sign-off when planning is complete
|
|
170
172
|
- \`.planning/acceptance-matrix.md\` — the acceptance criteria checklist for QA
|
|
171
173
|
4. **Propose the next role.** Typically \`dev\` after planning is complete, or \`eng_director\` if there's a technical deadlock.
|
|
@@ -175,6 +177,7 @@ You are the Product Manager. Your mandate: **${role.mandate}**
|
|
|
175
177
|
To exit the planning phase, you must:
|
|
176
178
|
- Ensure \`.planning/PM_SIGNOFF.md\` exists with your explicit sign-off
|
|
177
179
|
- Ensure \`.planning/ROADMAP.md\` exists with clear acceptance criteria
|
|
180
|
+
- Ensure \`.planning/SYSTEM_SPEC.md\` defines \`## Purpose\`, \`## Interface\`, and \`## Acceptance Tests\`
|
|
178
181
|
- Set \`phase_transition_request: "implementation"\` in your turn result
|
|
179
182
|
|
|
180
183
|
The orchestrator will evaluate the gate and may require human approval.
|
|
@@ -246,6 +249,7 @@ You are QA. Your mandate: **${role.mandate}**
|
|
|
246
249
|
4. **Create review artifacts:**
|
|
247
250
|
- \`.planning/acceptance-matrix.md\` — updated with pass/fail verdicts per criterion
|
|
248
251
|
- \`.planning/ship-verdict.md\` — your overall ship/no-ship recommendation
|
|
252
|
+
- \`.planning/RELEASE_NOTES.md\` — user-facing release notes with impact and verification summary
|
|
249
253
|
|
|
250
254
|
## You Cannot Modify Code
|
|
251
255
|
|
|
@@ -273,12 +277,14 @@ Each objection must have:
|
|
|
273
277
|
When you are satisfied the work meets acceptance criteria:
|
|
274
278
|
1. Create \`.planning/ship-verdict.md\` with your verdict
|
|
275
279
|
2. Create/update \`.planning/acceptance-matrix.md\` with all criteria checked
|
|
276
|
-
3.
|
|
280
|
+
3. Create/update \`.planning/RELEASE_NOTES.md\` with \`## User Impact\` and \`## Verification Summary\`
|
|
281
|
+
4. Set \`run_completion_request: true\` in your turn result
|
|
277
282
|
|
|
278
283
|
**Only set \`run_completion_request: true\` when:**
|
|
279
284
|
- All blocking objections from prior turns are resolved
|
|
280
285
|
- The acceptance matrix shows all critical criteria passing
|
|
281
286
|
- \`.planning/ship-verdict.md\` exists with an affirmative verdict
|
|
287
|
+
- \`.planning/RELEASE_NOTES.md\` exists with real \`## User Impact\` and \`## Verification Summary\` content
|
|
282
288
|
|
|
283
289
|
**Do NOT set \`run_completion_request: true\` if:**
|
|
284
290
|
- You have unresolved blocking objections
|
|
@@ -531,12 +537,15 @@ export function scaffoldGoverned(dir, projectName, projectId, templateId = 'gene
|
|
|
531
537
|
// Planning artifacts
|
|
532
538
|
writeFileSync(join(dir, '.planning', 'PM_SIGNOFF.md'), `# PM Signoff — ${projectName}\n\nApproved: NO\n\n## Discovery Checklist\n- [ ] Target user defined\n- [ ] Core pain point defined\n- [ ] Core workflow defined\n- [ ] MVP scope defined\n- [ ] Out-of-scope list defined\n- [ ] Success metric defined\n\n## Notes for team\n(PM and human add final kickoff notes here.)\n`);
|
|
533
539
|
writeFileSync(join(dir, '.planning', 'ROADMAP.md'), `# Roadmap — ${projectName}\n\n## Phases\n\n| Phase | Goal | Status |\n|-------|------|--------|\n| Planning | Align scope, requirements, acceptance criteria | In progress |\n| Implementation | Build and verify | Pending |\n| QA | Challenge correctness and ship readiness | Pending |\n`);
|
|
540
|
+
writeFileSync(join(dir, '.planning', 'SYSTEM_SPEC.md'), buildSystemSpecContent(projectName, template.system_spec_overlay));
|
|
541
|
+
writeFileSync(join(dir, '.planning', 'IMPLEMENTATION_NOTES.md'), `# Implementation Notes — ${projectName}\n\n## Changes\n\n(Dev fills this during implementation)\n\n## Verification\n\n(Dev fills this during implementation)\n\n## Unresolved Follow-ups\n\n(Dev lists any known gaps, tech debt, or follow-up items here.)\n`);
|
|
534
542
|
const baseAcceptanceMatrix = `# Acceptance Matrix — ${projectName}\n\n| Req # | Requirement | Acceptance criteria | Test status | Last tested | Status |\n|-------|-------------|-------------------|-------------|-------------|--------|\n| (QA fills this from ROADMAP.md) | | | | | |\n`;
|
|
535
543
|
writeFileSync(
|
|
536
544
|
join(dir, '.planning', 'acceptance-matrix.md'),
|
|
537
545
|
appendAcceptanceHints(baseAcceptanceMatrix, template.acceptance_hints)
|
|
538
546
|
);
|
|
539
547
|
writeFileSync(join(dir, '.planning', 'ship-verdict.md'), `# Ship Verdict — ${projectName}\n\n## Verdict: PENDING\n\n## QA Summary\n\n(QA writes the final ship/no-ship assessment here.)\n\n## Open Blockers\n\n(List any blocking issues.)\n\n## Conditions\n\n(List any conditions for shipping.)\n`);
|
|
548
|
+
writeFileSync(join(dir, '.planning', 'RELEASE_NOTES.md'), `# Release Notes — ${projectName}\n\n## User Impact\n\n(QA fills this during the QA phase)\n\n## Verification Summary\n\n(QA fills this during the QA phase)\n\n## Upgrade Notes\n\n(QA fills this during the QA phase)\n\n## Known Issues\n\n(QA fills this during the QA phase)\n`);
|
|
540
549
|
for (const artifact of template.planning_artifacts) {
|
|
541
550
|
writeFileSync(
|
|
542
551
|
join(dir, '.planning', artifact.filename),
|
|
@@ -658,8 +667,9 @@ async function initGoverned(opts) {
|
|
|
658
667
|
console.log(` ${chalk.dim('│')} ${chalk.dim('├──')} reviews/`);
|
|
659
668
|
console.log(` ${chalk.dim('│')} ${chalk.dim('└──')} dispatch/`);
|
|
660
669
|
console.log(` ${chalk.dim('├──')} .planning/`);
|
|
661
|
-
console.log(` ${chalk.dim('│')} ${chalk.dim('├──')} PM_SIGNOFF.md / ROADMAP.md`);
|
|
662
|
-
console.log(` ${chalk.dim('│')} ${chalk.dim('
|
|
670
|
+
console.log(` ${chalk.dim('│')} ${chalk.dim('├──')} PM_SIGNOFF.md / ROADMAP.md / SYSTEM_SPEC.md`);
|
|
671
|
+
console.log(` ${chalk.dim('│')} ${chalk.dim('├──')} acceptance-matrix.md / ship-verdict.md`);
|
|
672
|
+
console.log(` ${chalk.dim('│')} ${chalk.dim('└──')} RELEASE_NOTES.md`);
|
|
663
673
|
console.log(` ${chalk.dim('└──')} TALK.md`);
|
|
664
674
|
console.log('');
|
|
665
675
|
console.log(` ${chalk.dim('Roles:')} pm, dev, qa, eng_director`);
|
package/src/commands/migrate.js
CHANGED
|
@@ -165,14 +165,15 @@ export async function migrateCommand(opts) {
|
|
|
165
165
|
routing,
|
|
166
166
|
gates: {
|
|
167
167
|
planning_signoff: {
|
|
168
|
-
requires_files: ['.planning/PM_SIGNOFF.md', '.planning/ROADMAP.md'],
|
|
168
|
+
requires_files: ['.planning/PM_SIGNOFF.md', '.planning/ROADMAP.md', '.planning/SYSTEM_SPEC.md'],
|
|
169
169
|
requires_human_approval: true
|
|
170
170
|
},
|
|
171
171
|
implementation_complete: {
|
|
172
|
+
requires_files: ['.planning/IMPLEMENTATION_NOTES.md'],
|
|
172
173
|
requires_verification_pass: true
|
|
173
174
|
},
|
|
174
175
|
qa_ship_verdict: {
|
|
175
|
-
requires_files: ['.planning/acceptance-matrix.md', '.planning/ship-verdict.md'],
|
|
176
|
+
requires_files: ['.planning/acceptance-matrix.md', '.planning/ship-verdict.md', '.planning/RELEASE_NOTES.md'],
|
|
176
177
|
requires_human_approval: true
|
|
177
178
|
}
|
|
178
179
|
},
|
|
@@ -311,8 +312,11 @@ ${report.requires_human_review.map((r, i) => `${i + 1}. ${r}`).join('\n')}
|
|
|
311
312
|
const planningFiles = {
|
|
312
313
|
'PM_SIGNOFF.md': `# PM Signoff — ${projectName}\n\nApproved: NO\n`,
|
|
313
314
|
'ROADMAP.md': `# Roadmap — ${projectName}\n\n(Migrated from v3. Review and update.)\n`,
|
|
315
|
+
'SYSTEM_SPEC.md': `# System Spec — ${projectName}\n\n## Purpose\n\n(Describe the migrated subsystem purpose.)\n\n## Interface\n\n(List the commands, files, APIs, or contracts this repo owns.)\n\n## Behavior\n\n(Describe the expected runtime behavior.)\n\n## Error Cases\n\n(List the important failure modes.)\n\n## Acceptance Tests\n\n- [ ] Name the executable checks required before implementation resumes.\n\n## Open Questions\n\n- (Capture migration-specific gaps here.)\n`,
|
|
316
|
+
'IMPLEMENTATION_NOTES.md': `# Implementation Notes — ${projectName}\n\n## Changes\n\n(Dev fills this during implementation)\n\n## Verification\n\n(Dev fills this during implementation)\n\n## Unresolved Follow-ups\n\n(Dev lists any known gaps, tech debt, or follow-up items here.)\n`,
|
|
314
317
|
'acceptance-matrix.md': `# Acceptance Matrix — ${projectName}\n\n(QA fills this.)\n`,
|
|
315
|
-
'ship-verdict.md': `# Ship Verdict — ${projectName}\n\n## Verdict: PENDING\n
|
|
318
|
+
'ship-verdict.md': `# Ship Verdict — ${projectName}\n\n## Verdict: PENDING\n`,
|
|
319
|
+
'RELEASE_NOTES.md': `# Release Notes — ${projectName}\n\n## User Impact\n\n(QA fills this during the QA phase)\n\n## Verification Summary\n\n(QA fills this during the QA phase)\n\n## Upgrade Notes\n\n(QA fills this during the QA phase)\n\n## Known Issues\n\n(QA fills this during the QA phase)\n`
|
|
316
320
|
};
|
|
317
321
|
for (const [file, content] of Object.entries(planningFiles)) {
|
|
318
322
|
const path = join(root, '.planning', file);
|
package/src/commands/run.js
CHANGED
|
@@ -14,10 +14,12 @@
|
|
|
14
14
|
|
|
15
15
|
import chalk from 'chalk';
|
|
16
16
|
import { createInterface } from 'readline';
|
|
17
|
-
import { readFileSync, existsSync } from 'fs';
|
|
17
|
+
import { readFileSync, existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
18
18
|
import { join } from 'path';
|
|
19
19
|
import { loadProjectContext, loadProjectState } from '../lib/config.js';
|
|
20
20
|
import { runLoop } from '../lib/run-loop.js';
|
|
21
|
+
import { buildRunExport } from '../lib/export.js';
|
|
22
|
+
import { buildGovernanceReport, formatGovernanceReportMarkdown } from '../lib/report.js';
|
|
21
23
|
import { dispatchApiProxy } from '../lib/adapters/api-proxy-adapter.js';
|
|
22
24
|
import {
|
|
23
25
|
dispatchLocalCli,
|
|
@@ -328,6 +330,32 @@ export async function runCommand(opts) {
|
|
|
328
330
|
}
|
|
329
331
|
}
|
|
330
332
|
|
|
333
|
+
// ── Auto governance report ──────────────────────────────────────────────
|
|
334
|
+
if (opts.report !== false && result.state) {
|
|
335
|
+
try {
|
|
336
|
+
const reportsDir = join(root, '.agentxchain', 'reports');
|
|
337
|
+
mkdirSync(reportsDir, { recursive: true });
|
|
338
|
+
|
|
339
|
+
const exportResult = buildRunExport(root);
|
|
340
|
+
if (exportResult.ok) {
|
|
341
|
+
const runId = result.state.run_id || 'unknown';
|
|
342
|
+
const exportPath = join(reportsDir, `export-${runId}.json`);
|
|
343
|
+
writeFileSync(exportPath, JSON.stringify(exportResult.export, null, 2));
|
|
344
|
+
|
|
345
|
+
const reportResult = buildGovernanceReport(exportResult.export, { input: exportPath });
|
|
346
|
+
const reportPath = join(reportsDir, `report-${runId}.md`);
|
|
347
|
+
writeFileSync(reportPath, formatGovernanceReportMarkdown(reportResult.report));
|
|
348
|
+
|
|
349
|
+
console.log('');
|
|
350
|
+
console.log(chalk.dim(` Governance report: .agentxchain/reports/report-${runId}.md`));
|
|
351
|
+
} else {
|
|
352
|
+
console.log(chalk.dim(` Governance report skipped: ${exportResult.error}`));
|
|
353
|
+
}
|
|
354
|
+
} catch (err) {
|
|
355
|
+
console.log(chalk.dim(` Governance report failed: ${err.message}`));
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
331
359
|
// ── Exit code ───────────────────────────────────────────────────────────
|
|
332
360
|
const successReasons = new Set(['completed', 'gate_held', 'caller_stopped', 'max_turns_reached']);
|
|
333
361
|
if (result.ok || successReasons.has(result.stop_reason)) {
|
|
@@ -2,7 +2,7 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
|
2
2
|
import { join, dirname } from 'node:path';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import { CONFIG_FILE } from '../lib/config.js';
|
|
5
|
-
import { loadGovernedTemplate, VALID_GOVERNED_TEMPLATE_IDS } from '../lib/governed-templates.js';
|
|
5
|
+
import { loadGovernedTemplate, VALID_GOVERNED_TEMPLATE_IDS, SYSTEM_SPEC_OVERLAY_SEPARATOR } from '../lib/governed-templates.js';
|
|
6
6
|
|
|
7
7
|
const LEDGER_PATH = '.agentxchain/decision-ledger.jsonl';
|
|
8
8
|
const PROMPT_OVERRIDE_SEPARATOR = '## Project-Type-Specific Guidance';
|
|
@@ -76,6 +76,7 @@ export async function templateSetCommand(templateId, opts) {
|
|
|
76
76
|
prompts_missing_paths: [],
|
|
77
77
|
prompts_missing_files: [],
|
|
78
78
|
acceptance_hints_status: 'none',
|
|
79
|
+
system_spec_overlay_status: 'none',
|
|
79
80
|
};
|
|
80
81
|
|
|
81
82
|
// Planning artifacts
|
|
@@ -127,6 +128,22 @@ export async function templateSetCommand(templateId, opts) {
|
|
|
127
128
|
}
|
|
128
129
|
}
|
|
129
130
|
|
|
131
|
+
// System spec overlay
|
|
132
|
+
const systemSpecOverlay = manifest.system_spec_overlay;
|
|
133
|
+
const systemSpecPath = join(root, '.planning', 'SYSTEM_SPEC.md');
|
|
134
|
+
if (systemSpecOverlay && Object.keys(systemSpecOverlay).length > 0) {
|
|
135
|
+
if (!existsSync(systemSpecPath)) {
|
|
136
|
+
plan.system_spec_overlay_status = 'missing_file';
|
|
137
|
+
} else {
|
|
138
|
+
const specContent = readFileSync(systemSpecPath, 'utf8');
|
|
139
|
+
if (specContent.includes(SYSTEM_SPEC_OVERLAY_SEPARATOR)) {
|
|
140
|
+
plan.system_spec_overlay_status = 'existing_guidance';
|
|
141
|
+
} else {
|
|
142
|
+
plan.system_spec_overlay_status = 'append';
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
130
147
|
// ── Dry run: print plan and exit ──────────────────────────────────────
|
|
131
148
|
if (opts.dryRun) {
|
|
132
149
|
console.log(chalk.bold(`\n Template: ${previousTemplate} → ${templateId}\n`));
|
|
@@ -175,6 +192,16 @@ export async function templateSetCommand(templateId, opts) {
|
|
|
175
192
|
} else {
|
|
176
193
|
console.log(` ${chalk.dim('(none)')}`);
|
|
177
194
|
}
|
|
195
|
+
console.log('\n System spec overlay:');
|
|
196
|
+
if (plan.system_spec_overlay_status === 'append') {
|
|
197
|
+
console.log(` .planning/SYSTEM_SPEC.md: ${chalk.green('WILL APPEND template guidance')}`);
|
|
198
|
+
} else if (plan.system_spec_overlay_status === 'existing_guidance') {
|
|
199
|
+
console.log(` .planning/SYSTEM_SPEC.md: ${chalk.dim('ALREADY HAS guidance (skip)')}`);
|
|
200
|
+
} else if (plan.system_spec_overlay_status === 'missing_file') {
|
|
201
|
+
console.log(` .planning/SYSTEM_SPEC.md: ${chalk.yellow('MISSING FILE (skip)')}`);
|
|
202
|
+
} else {
|
|
203
|
+
console.log(` ${chalk.dim('(none)')}`);
|
|
204
|
+
}
|
|
178
205
|
console.log(chalk.dim('\n No changes written. Use without --dry-run to apply.\n'));
|
|
179
206
|
process.exit(0);
|
|
180
207
|
}
|
|
@@ -242,7 +269,24 @@ export async function templateSetCommand(templateId, opts) {
|
|
|
242
269
|
console.log(chalk.yellow(' Warning: .planning/acceptance-matrix.md not found. Skipping template guidance hints.'));
|
|
243
270
|
}
|
|
244
271
|
|
|
245
|
-
// 5.
|
|
272
|
+
// 5. Append system spec overlay
|
|
273
|
+
if (plan.system_spec_overlay_status === 'append' && existsSync(systemSpecPath)) {
|
|
274
|
+
const specContent = readFileSync(systemSpecPath, 'utf8');
|
|
275
|
+
const guidanceLines = [];
|
|
276
|
+
if (systemSpecOverlay.purpose_guidance) guidanceLines.push(`**Purpose:** ${systemSpecOverlay.purpose_guidance}`);
|
|
277
|
+
if (systemSpecOverlay.interface_guidance) guidanceLines.push(`**Interface:** ${systemSpecOverlay.interface_guidance}`);
|
|
278
|
+
if (systemSpecOverlay.behavior_guidance) guidanceLines.push(`**Behavior:** ${systemSpecOverlay.behavior_guidance}`);
|
|
279
|
+
if (systemSpecOverlay.error_cases_guidance) guidanceLines.push(`**Error Cases:** ${systemSpecOverlay.error_cases_guidance}`);
|
|
280
|
+
if (systemSpecOverlay.acceptance_tests_guidance) guidanceLines.push(`**Acceptance Tests:**\n${systemSpecOverlay.acceptance_tests_guidance}`);
|
|
281
|
+
if (systemSpecOverlay.extra_sections) guidanceLines.push(systemSpecOverlay.extra_sections);
|
|
282
|
+
const guidanceBlock = guidanceLines.join('\n\n');
|
|
283
|
+
const appended = `${specContent}\n\n${SYSTEM_SPEC_OVERLAY_SEPARATOR}\n\n${guidanceBlock}\n`;
|
|
284
|
+
writeFileSync(systemSpecPath, appended);
|
|
285
|
+
} else if (plan.system_spec_overlay_status === 'missing_file') {
|
|
286
|
+
console.log(chalk.yellow(' Warning: .planning/SYSTEM_SPEC.md not found. Skipping template spec overlay.'));
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// 6. Decision ledger
|
|
246
290
|
const ledgerEntry = {
|
|
247
291
|
type: 'template_set',
|
|
248
292
|
timestamp: new Date().toISOString(),
|
|
@@ -260,6 +304,8 @@ export async function templateSetCommand(templateId, opts) {
|
|
|
260
304
|
prompt_missing_files: plan.prompts_missing_files,
|
|
261
305
|
acceptance_hints_appended: plan.acceptance_hints_status === 'append',
|
|
262
306
|
acceptance_hints_skipped_reason: plan.acceptance_hints_status === 'append' ? null : plan.acceptance_hints_status,
|
|
307
|
+
system_spec_overlay_appended: plan.system_spec_overlay_status === 'append',
|
|
308
|
+
system_spec_overlay_skipped_reason: plan.system_spec_overlay_status === 'append' ? null : plan.system_spec_overlay_status,
|
|
263
309
|
operator: 'human',
|
|
264
310
|
};
|
|
265
311
|
appendJsonl(root, LEDGER_PATH, ledgerEntry);
|
|
@@ -275,5 +321,8 @@ export async function templateSetCommand(templateId, opts) {
|
|
|
275
321
|
if (plan.acceptance_hints_status === 'append') {
|
|
276
322
|
console.log(` Appended template guidance to acceptance-matrix.md`);
|
|
277
323
|
}
|
|
324
|
+
if (plan.system_spec_overlay_status === 'append') {
|
|
325
|
+
console.log(` Appended template-specific guidance to SYSTEM_SPEC.md`);
|
|
326
|
+
}
|
|
278
327
|
console.log('');
|
|
279
328
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapter Interface — declared public boundary for shipped adapter dispatch.
|
|
3
|
+
*
|
|
4
|
+
* This module gives external runners a stable way to reuse the first-party
|
|
5
|
+
* adapters without importing deep internal source paths.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
printManualDispatchInstructions,
|
|
10
|
+
waitForStagedResult,
|
|
11
|
+
readStagedResult,
|
|
12
|
+
} from './adapters/manual-adapter.js';
|
|
13
|
+
|
|
14
|
+
export {
|
|
15
|
+
dispatchLocalCli,
|
|
16
|
+
saveDispatchLogs,
|
|
17
|
+
resolvePromptTransport,
|
|
18
|
+
} from './adapters/local-cli-adapter.js';
|
|
19
|
+
|
|
20
|
+
export { dispatchApiProxy } from './adapters/api-proxy-adapter.js';
|
|
21
|
+
|
|
22
|
+
export {
|
|
23
|
+
DEFAULT_MCP_TOOL_NAME,
|
|
24
|
+
DEFAULT_MCP_TRANSPORT,
|
|
25
|
+
dispatchMcp,
|
|
26
|
+
resolveMcpToolName,
|
|
27
|
+
resolveMcpTransport,
|
|
28
|
+
describeMcpRuntimeTarget,
|
|
29
|
+
} from './adapters/mcp-adapter.js';
|
|
30
|
+
|
|
31
|
+
export const ADAPTER_INTERFACE_VERSION = '0.1';
|