agentxchain 2.14.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 +9 -3
- package/bin/agentxchain.js +20 -2
- package/package.json +3 -1
- package/scripts/release-downstream-truth.sh +15 -14
- package/scripts/release-postflight.sh +21 -5
- package/scripts/sync-homebrew.sh +225 -0
- package/src/commands/init.js +16 -6
- 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/migrate.js +7 -3
- package/src/commands/multi.js +58 -2
- 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-acceptance.js +24 -98
- package/src/lib/coordinator-barriers.js +116 -0
- package/src/lib/coordinator-config.js +124 -0
- package/src/lib/coordinator-dispatch.js +10 -1
- package/src/lib/coordinator-gates.js +28 -1
- package/src/lib/coordinator-recovery.js +133 -68
- package/src/lib/coordinator-state.js +74 -0
- package/src/lib/cross-repo-context.js +68 -1
- package/src/lib/governed-templates.js +60 -0
- package/src/lib/intake-handoff.js +58 -0
- package/src/lib/intake.js +300 -11
- 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
|
@@ -100,10 +100,10 @@ For initiatives spanning multiple governed repos, use the coordinator to add cro
|
|
|
100
100
|
npx agentxchain init --governed --template api-service --dir repos/backend -y
|
|
101
101
|
npx agentxchain init --governed --template web-app --dir repos/frontend -y
|
|
102
102
|
agentxchain multi init
|
|
103
|
-
agentxchain multi step --
|
|
103
|
+
agentxchain multi step --json
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
-
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.
|
|
107
107
|
|
|
108
108
|
### Migrate a legacy project
|
|
109
109
|
|
|
@@ -132,7 +132,10 @@ agentxchain step
|
|
|
132
132
|
| `template validate` | Prove the template registry, workflow-kit scaffold contract, and planning artifact completeness (`--json` exposes a `workflow_kit` block) |
|
|
133
133
|
| `verify protocol` | Run the shipped protocol conformance suite against a target implementation |
|
|
134
134
|
| `dashboard` | Open the local governance dashboard in your browser for repo-local runs or multi-repo coordinator initiatives, including pending gate approvals |
|
|
135
|
-
| `
|
|
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 |
|
|
136
139
|
|
|
137
140
|
### Shared utilities
|
|
138
141
|
|
|
@@ -191,12 +194,15 @@ agentxchain.json
|
|
|
191
194
|
.agentxchain/staging/<turn_id>/turn-result.json
|
|
192
195
|
TALK.md
|
|
193
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.
|
|
194
199
|
```
|
|
195
200
|
|
|
196
201
|
### Runtime support today
|
|
197
202
|
|
|
198
203
|
- `manual`: implemented
|
|
199
204
|
- `local_cli`: implemented
|
|
205
|
+
- `mcp`: implemented for stdio and streamable HTTP tool-contract dispatch
|
|
200
206
|
- `api_proxy`: implemented for synchronous review-only turns and stages a provider-backed result during `step`
|
|
201
207
|
|
|
202
208
|
## 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';
|
|
@@ -319,6 +321,7 @@ program
|
|
|
319
321
|
.option('--auto-approve', 'Auto-approve all gates (non-interactive mode)')
|
|
320
322
|
.option('--verbose', 'Stream adapter subprocess output')
|
|
321
323
|
.option('--dry-run', 'Print what would be dispatched without executing')
|
|
324
|
+
.option('--no-report', 'Suppress automatic governance report after run completes')
|
|
322
325
|
.action(runCommand);
|
|
323
326
|
|
|
324
327
|
program
|
|
@@ -415,6 +418,12 @@ multiCmd
|
|
|
415
418
|
.option('-j, --json', 'Output as JSON')
|
|
416
419
|
.action(multiStepCommand);
|
|
417
420
|
|
|
421
|
+
multiCmd
|
|
422
|
+
.command('resume')
|
|
423
|
+
.description('Clear a blocked coordinator state after operator recovery')
|
|
424
|
+
.option('-j, --json', 'Output as JSON')
|
|
425
|
+
.action(multiResumeCommand);
|
|
426
|
+
|
|
418
427
|
multiCmd
|
|
419
428
|
.command('approve-gate')
|
|
420
429
|
.description('Approve a pending phase transition or completion gate')
|
|
@@ -449,7 +458,7 @@ intakeCmd
|
|
|
449
458
|
intakeCmd
|
|
450
459
|
.command('triage')
|
|
451
460
|
.description('Triage a detected intent — set priority, template, charter, and acceptance')
|
|
452
|
-
.
|
|
461
|
+
.option('--intent <id>', 'Intent ID to triage')
|
|
453
462
|
.option('--priority <level>', 'Priority level (p0, p1, p2, p3)')
|
|
454
463
|
.option('--template <id>', 'Governed template (generic, api-service, cli-tool, library, web-app)')
|
|
455
464
|
.option('--charter <text>', 'Delivery charter text')
|
|
@@ -486,10 +495,19 @@ intakeCmd
|
|
|
486
495
|
.option('-j, --json', 'Output as JSON')
|
|
487
496
|
.action(intakeStartCommand);
|
|
488
497
|
|
|
498
|
+
intakeCmd
|
|
499
|
+
.command('handoff')
|
|
500
|
+
.description('Hand off a planned intent to a coordinator workstream')
|
|
501
|
+
.option('--intent <id>', 'Intent ID to hand off')
|
|
502
|
+
.option('--coordinator-root <path>', 'Path to the coordinator workspace root')
|
|
503
|
+
.option('--workstream <id>', 'Coordinator workstream ID')
|
|
504
|
+
.option('-j, --json', 'Output as JSON')
|
|
505
|
+
.action(intakeHandoffCommand);
|
|
506
|
+
|
|
489
507
|
intakeCmd
|
|
490
508
|
.command('scan')
|
|
491
509
|
.description('Scan a structured source snapshot into intake events')
|
|
492
|
-
.
|
|
510
|
+
.option('--source <id>', 'Source type: ci_failure, git_ref_change, schedule')
|
|
493
511
|
.option('--file <path>', 'Path to snapshot JSON file')
|
|
494
512
|
.option('--stdin', 'Read snapshot from stdin')
|
|
495
513
|
.option('-j, --json', 'Output as JSON')
|
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"
|
|
@@ -47,7 +47,7 @@ if [[ -z "$TARGET_VERSION" ]]; then
|
|
|
47
47
|
fi
|
|
48
48
|
|
|
49
49
|
PACKAGE_NAME="$(node -e "console.log(JSON.parse(require('fs').readFileSync('package.json', 'utf8')).name)")"
|
|
50
|
-
|
|
50
|
+
CANONICAL_HOMEBREW_FORMULA_URL="${AGENTXCHAIN_DOWNSTREAM_FORMULA_URL:-https://raw.githubusercontent.com/shivamtiwari93/homebrew-tap/main/Formula/agentxchain.rb}"
|
|
51
51
|
|
|
52
52
|
PASS=0
|
|
53
53
|
FAIL=0
|
|
@@ -57,7 +57,7 @@ fail() { FAIL=$((FAIL + 1)); echo " FAIL: $1"; }
|
|
|
57
57
|
|
|
58
58
|
echo "AgentXchain v${TARGET_VERSION} Downstream Release Truth"
|
|
59
59
|
echo "====================================="
|
|
60
|
-
echo "Checks downstream surfaces after publish: GitHub release, Homebrew tap."
|
|
60
|
+
echo "Checks downstream surfaces after publish: GitHub release, canonical Homebrew tap."
|
|
61
61
|
echo ""
|
|
62
62
|
|
|
63
63
|
# --- Check 1: GitHub Release ---
|
|
@@ -85,38 +85,39 @@ else
|
|
|
85
85
|
fi
|
|
86
86
|
|
|
87
87
|
# --- Get registry tarball URL and compute SHA ---
|
|
88
|
-
echo "[2/3] Homebrew tap SHA matches registry tarball"
|
|
88
|
+
echo "[2/3] Canonical Homebrew tap SHA matches registry tarball"
|
|
89
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)"
|
|
90
91
|
if [[ -z "$REGISTRY_TARBALL_URL" ]]; then
|
|
91
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}"
|
|
92
95
|
else
|
|
93
96
|
REGISTRY_SHA="$(curl -sL "$REGISTRY_TARBALL_URL" | shasum -a 256 | awk '{print $1}')"
|
|
94
97
|
if [[ -z "$REGISTRY_SHA" ]]; then
|
|
95
98
|
fail "cannot compute SHA256 of registry tarball"
|
|
96
|
-
elif [[ ! -f "$HOMEBREW_FORMULA" ]]; then
|
|
97
|
-
fail "Homebrew formula not found at ${HOMEBREW_FORMULA}"
|
|
98
99
|
else
|
|
99
|
-
FORMULA_SHA="$(grep -E '^\s*sha256\s+"'
|
|
100
|
+
FORMULA_SHA="$(printf '%s\n' "$FORMULA_CONTENT" | grep -E '^\s*sha256\s+"' | sed 's/.*sha256 *"\([a-f0-9]*\)".*/\1/')"
|
|
100
101
|
if [[ "$REGISTRY_SHA" == "$FORMULA_SHA" ]]; then
|
|
101
|
-
pass "Homebrew formula SHA256 matches registry tarball (${REGISTRY_SHA:0:16}...)"
|
|
102
|
+
pass "canonical Homebrew formula SHA256 matches registry tarball (${REGISTRY_SHA:0:16}...)"
|
|
102
103
|
else
|
|
103
|
-
fail "Homebrew formula SHA256 mismatch: formula=${FORMULA_SHA:0:16}... registry=${REGISTRY_SHA:0:16}..."
|
|
104
|
+
fail "canonical Homebrew formula SHA256 mismatch: formula=${FORMULA_SHA:0:16}... registry=${REGISTRY_SHA:0:16}..."
|
|
104
105
|
fi
|
|
105
106
|
fi
|
|
106
107
|
fi
|
|
107
108
|
|
|
108
109
|
# --- Check 3: Homebrew tap URL matches registry tarball URL ---
|
|
109
|
-
echo "[3/3] Homebrew tap URL matches registry tarball"
|
|
110
|
+
echo "[3/3] Canonical Homebrew tap URL matches registry tarball"
|
|
110
111
|
if [[ -z "$REGISTRY_TARBALL_URL" ]]; then
|
|
111
112
|
fail "cannot verify URL — registry tarball URL unavailable"
|
|
112
|
-
elif [[
|
|
113
|
-
fail "
|
|
113
|
+
elif [[ -z "$FORMULA_CONTENT" ]]; then
|
|
114
|
+
fail "cannot verify URL — canonical Homebrew formula unavailable"
|
|
114
115
|
else
|
|
115
|
-
FORMULA_URL="$(grep -E '^\s*url\s+"'
|
|
116
|
+
FORMULA_URL="$(printf '%s\n' "$FORMULA_CONTENT" | grep -E '^\s*url\s+"' | sed 's/.*url *"\([^"]*\)".*/\1/')"
|
|
116
117
|
if [[ "$FORMULA_URL" == "$REGISTRY_TARBALL_URL" ]]; then
|
|
117
|
-
pass "Homebrew formula URL matches registry tarball"
|
|
118
|
+
pass "canonical Homebrew formula URL matches registry tarball"
|
|
118
119
|
else
|
|
119
|
-
fail "Homebrew formula URL mismatch: formula=${FORMULA_URL} registry=${REGISTRY_TARBALL_URL}"
|
|
120
|
+
fail "canonical Homebrew formula URL mismatch: formula=${FORMULA_URL} registry=${REGISTRY_TARBALL_URL}"
|
|
120
121
|
fi
|
|
121
122
|
fi
|
|
122
123
|
|
|
@@ -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`);
|
|
@@ -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';
|