feat(cli): batch create primitive — anet create --batch + anet batch <verb> (refs #55)#60
Conversation
3129549 to
34a1a1d
Compare
34a1a1d to
6b355e2
Compare
PR #60 84-Failure TriageTester: 通信测试马 Counts breakdown
🔴 Security/critical (0):无. 🟠 Functional regression (0):无. 所有 fail 都对应预期的 server 行为, 真实用户不受影响:
🟡 Infrastructure/flaky (16, Config Priority suite never ran):
⚪ Test obsolete (84, 全 84 fails 在此桶):80 in Base E2E — anonymous MCP/REST 全 401Root cause (server/src/index.ts:98-122
tests/docker-e2e.sh 几乎所有 MCP/REST 调用都是 anonymous: curl -s -X POST http://127.0.0.1:9200/mcp -d '...send_task...' # 401
curl -s "http://127.0.0.1:9200/api/tasks" # 401
curl -s "http://127.0.0.1:9200/api/stats" # 40180 个 pass/fail assertion 大量是这类 anonymous 调用 → 全 fail. 55 pass = section 1 (/health public) + sections 2-7 (CLI 纯 local, 不需 hub auth) + sections 12+ V3 auth flow (用 4 in V3 Networks — master-token write 被 RFC-001 deprecation 拒Root cause (server/src/index.ts:111-114): if (token === AUTH_TOKEN) {
if (!readOnlyApi) return Response.json({ ok: false, error: "master-token auth is deprecated; use admin utok_" }, { status: 401 });
...
}tests/docker-e2e-networks.sh §4 用 Why 84 fails ≠ regression?
🚦 Ship gate verdict: GOReasoning:
Path forward:
👥 Agent Assignment
|
…<verb> (refs #55) Issue #55 + Vincent 4335 lifted hold: add a generic `anet create --batch` wizard that batch-spawns N agents under a working directory, plus an `anet batch <verb> <prefix>` top-level lifecycle command set. The existing `anet demo sci-team` is refactored into a preset wrapper over the new primitive (PR #53's user-facing surface stays bit-identical). ## What's new ### `createBatch(options)` helper (~150 LOC) Generic N-node spawn primitive used by both `anet create --batch` and `anet demo sci-team`. Handles: - per-node mkdir (workdir-mode `separate` = `<workdir>/node{i}` / `shared` = single dir) - Profile build + `ensureNodeToken` (ntok_) + `saveProfile` - tmux session launch with `${team || prefix}-${alias}` naming - `process.chdir` restored in `finally` block so the caller's cwd is preserved - Two-pass loop (configs first, tmux launches second) so a partial-config failure doesn't leave half-started tmux sessions ### `batchLifecycle({ prefix, verb, workdir? })` helper (~80 LOC) Verbs: - `stop` — kill any tmux session matching `${prefix}-*` - `cleanup` — `stop` + `rm -rf <workdir>/node*` + remove empty `<workdir>` - `restart` / `start` — Phase 1 scaffold hint (re-run create wizard); in-place re-launch deferred to Phase 2 (would need to walk saved `.anet/nodes/<alias>/config.json` under each `<workdir>/node*` and re-spawn the tmux sessions) - `list` — group all tmux sessions by first `-` separator (Phase 1 known limitation: catches non-anet sessions whose names contain `-`; future improvement is a `~/.anet/batches.json` marker registry, deferred) ### CLI surfaces 1. `anet create --batch` wizard (5 prompts): - **Model preset** (Vincent-verified list, 1bc03c0 chain): intern-s1-pro / MiniMax-M2.7 / claude-sonnet-4-6 / claude-opus-4-6 / claude-haiku-4-5 / `__custom__`. Codex preset deliberately excluded — not yet verified, follow-up issue planned. - API key (ANTHROPIC_AUTH_TOKEN or runtime-equivalent) - Workdir + workdir-mode - Prefix + count (1-50, stderr warning when count > 20 per [[feedback_runtime_warning_count_high]]) - Description (systemPrompt) + optional `--leader-alias` (opt-in) 2. `anet batch <verb> <prefix>` top-level lifecycle (mirrors `anet hub`, `anet node`, `anet network` style — Decision A1 from scope review). 3. `anet demo sci-team` refactored to internally call `createBatch` with the sci-team preset (intern URL/model + sciTeamPrompt active fan-out template + `leaderAlias="研究Leader"` + `team="sci-team"`). User-facing wizard surface unchanged — backward compat for preview.5+ docs and demo videos. 4. Deprecation: `anet demo sci-team --stop|--restart|--cleanup` now prints a stderr deprecation warning pointing at the canonical `anet batch <verb> sci-team`. One-release-cycle grace per Decision D1. ## Verified locally (sandbox HOME, never touched 47.116.5.73) - `npm run typecheck` passes (504-line diff, no TS errors). - `bun bin/cli.ts create --batch --help` renders full banner with all flags. - `bun bin/cli.ts batch` renders verb list. - `bun bin/cli.ts batch list` enumerates host tmux session groups (limitation noted in help: catches non-anet groups). - `bun bin/cli.ts batch stop` without prefix → friendly usage error. - `bun bin/cli.ts demo sci-team --help` unchanged. - `bun bin/cli.ts demo sci-team --stop` → deprecation stderr + delegates to `batchLifecycle({ prefix: "sci-team", verb: "stop" })`. - End-to-end: spawned local commhub-server on :9897 + ran `create --batch --preset claude-haiku-4-5 --prefix 工程师 --count 3`: - 3 tmux sessions created (`工程师-工程师1号` .. `工程师-工程师3号`) - `<workdir>/node{1..3}/.anet/nodes/工程师{i}号/config.json` written with correct runtime / model / token / env / systemPrompt - `anet batch list` grouped them under `工程师 (3 node)` - `anet batch stop 工程师` killed all 3 tmux sessions cleanly ## Out of scope for this PR - Codex preset (model id + signup URL un-verified — follow-up issue) - In-place `anet batch restart` / `start` supervisor (Phase 2) - Cross-batch task routing (Phase 3+) - Multi-prefix protected lifecycle list filter (Phase 2) ## Scope creep defenses honored - Single file touched (`agent-network/bin/cli.ts`) - No new vendor / runtime / endpoint introduced - No new scaffold mode (tmux only, per Vincent 4303) - commhub-server / agent-node / demos untouched Refs #55 (Vincent 4335 lifted hold) Refs: #63 #64 #65 (test infra debt tracker — pre-existing rot exposed by lockfile fix, 测试马 triage) Author-Agent: 通信工程马 Helpers: 通信龙 (Option C 分层 propose + dispatch + 7 decision A1/B1/C/D1/E/F3/G ack + 2 nit drop-codex + count>20 warning + review), Vincent (issue raise + 4335 lifted hold)
6b355e2 to
0440c55
Compare
login UX + #59/#63/#64/#65 follow-ups) Headline: `anet create --batch` + `anet batch <verb> <prefix>` (issue #55, Vincent 4335). Single-shot create N agents under a working directory, unified lifecycle ops. Existing `anet demo sci-team` refactored into a preset wrapper over the new primitive — user-facing surface bit-identical to preview.7 (backward compat). Other delta vs preview.7: - `anet login` first-time-login UX guidance (#58 — register / fresh-hub default / admin reset hints when server returns auth-fail). - engines field bumped `+ "node": ">=22.13.0"` and matching README ZH/EN prereq line (fixes EBADENGINE warnings from @inquirer/* family for users on older node). Pre-flight (per [[feedback_npm_publish_two_phase]] + Round 202 SOP): - git fetch origin && HEAD == 8fa8fc0 ✓ - engines bump check + lockfile sync (already done in PR #60 amend) ✓ - rm -rf dist && npm run build ✓ (obfuscator output 839 KB) - functional verify on obfuscated dist/bin/cli.js (NOT strings grep — preview.4 stale-dist lesson): - `anet create --batch --help` → wizard banner with preset/prefix flags ✓ - `anet batch` → verb list (stop/cleanup/list) ✓ - `anet demo sci-team --help` → backward compat banner ✓ - `anet demo sci-team --stop` → stderr deprecation warning ✓ - npm publish --tag preview (preview ONLY per Vincent 4380 hard rule, no latest, no dist-tag swap) - docker --no-cache E2E with `npm install -g @sleep2agi/agent-network@preview` fresh container — separate step after push. Known: pre-existing regression test infra debt (#63 P1, #64 P2, #65 P2) exposed by lockfile fix in PR #60 — 测试马 triage 0 functional / 0 security / 16 flaky / 84 obsolete; V3 Auth 25/25 pass + sci-team E2E + #52 audit all green. Not blocking ship per verdict. Refs #55 (closed via PR #60), #58 (closed via 8dd1d18 chain), #63 #64 #65 (follow-up trackers) Author-Agent: 通信工程马 Helpers: 通信龙 (Lead review + lifecycle dispatch + Vincent 4380 preview-only gate), 通信测试马 (4-bucket regression triage GO verdict), 通信牛 (review chain catches), 通信SDK马 (RFC-008 spec), Vincent (4335 #55 + 4378 push-ship + 4380 preview-only)
|
🎉 Shipped in npm install -g @sleep2agi/agent-network@preview
anet --version # → anet v2.1.8-preview.8Verify (preview.4 lesson — functional, not strings grep):
Confirmed dist-tag state (Vincent 4380 hard rule: preview ONLY): Headline of 2.1.8-preview.8:
Known: pre-existing test infra debt #63 (P1) / #64 (P2) / #65 (P2). 测试马 triage verdict 🚦 GO — 0 functional / 0 security failures; 84 obsolete + 16 flaky 都是 test fixture lag. |
preview.8 Docker E2E Triage ReportTester: 通信测试马 🚦 Verdict: GOpreview.8 batch primitive production-ready:
唯一 Docker 环境 caveat: Claude Code CLI 拒绝 root 用户 Phase A (fake-key wiring) — 15 ✅ / 5 ❌(expected)
Root cause of 5 fail: fake key Phase B v2 (real intern-s1-pro) — 7 ✅ / 1 ❌
Phase B-tail (诊断 "no completion") — 关键发现
完整 round-trip 全过 (send_task → SSE push → agent-node 收 → processTask → reply):
Test bug fixes 找到的 wiring quirks (非 preview.8 bug, doc 建议)
Ship gate🚦 GO ship preview.8 — 给 Vincent confidence:
👥 Agent Assignment
|
Author & Helpers
Author (Primary): 通信工程马 (cli.ts implementation + amend chain)
Helpers:
--prefix,git addmiss onpackage.json, docs/batch.md wording polish, "byte-identical" → "same verified value set")Tier review gate: 通信龙 (Lead) + 通信牛 (cross-review per big-feature multi-cmd guideline) + 通信测试马 (regression-suite verdict)
Why
Refs #55 — Vincent 4335 lifted the earlier hold on the batch-create feature. This PR is the generic primitive that the existing
anet demo sci-team(PR #53) had baked into one specific preset; it lifts the batch pattern up so any team prefix / model preset can use it, and refactors sci-team into a preset wrapper. Issue body asked for:--preset+--api-key--workdir-mode separate|shared--prefix--count(1-50, stderr warning >20)--description(systemPrompt)anet batch <verb> <prefix>lifecycle (start/stop/restart/cleanup/list)What
Files touched (6, +801 -207):
agent-network/bin/cli.ts— createBatch helper + batchLifecycle helper +anet create --batchwizard +anet batch <verb>top-level + sci-team refactor + deprecation warningagent-network/package.json— engines+ "node": ">=22.13.0"agent-network/package-lock.json— npm install regen sync with engines bump (npm format lockfile, bun.lockb gitignored)docs/batch.md(new, 152 lines) — user-facing referenceREADME.md+README.en.md— 30-second-quickstart 顶 Prereq line Node.js ≥ 22.13.0createBatch(options)helper (~150 LOC)Generic N-node spawn primitive. Two-pass loop: configs first (mkdir + Profile build +
ensureNodeToken+saveProfile), then tmux sessions (so a partial config failure doesn't leave half-started tmux).process.chdirrestored infinallyblock.Path traversal defense (per 通信牛 first-pass catch):
validateNodeName(prefix / team / leaderAlias)at entry, thenvalidateNodeName(alias)defense-in-depth per generated alias. Verified:--prefix '../bad'/--prefix '/etc/passwd'/--leader-alias '..'all reject withError: invalid node-nameand exit 1 before any saveProfile / mkdir / tmux side effect.batchLifecycle({ prefix, verb, workdir? })helper (~80 LOC)stop— kill tmux matching${prefix}-*cleanup—stop+rm -rf <workdir>/node*+ remove empty<workdir>(separate workdir-mode only; shared-mode emits stderr warning + manualrmguidance)restart/start— Phase 1 scaffold hint (re-run create wizard); in-place supervisor deferred to Phase 2list— group all tmux sessions by first-separator. Phase 1 known limitation: catches non-anet sessions whose names contain-. Future:~/.anet/batches.jsonmarker registry, deferred.CLI surfaces (3 new entry points)
anet create --batchwizard — Vincent-verified preset list (intern-s1-pro / MiniMax-M2.7 / claude-sonnet-4-6 / claude-opus-4-6 / claude-haiku-4-5 /__custom__). Codex preset deliberately excluded — not yet verified end-to-end. Follow-up issue planned.anet batch <verb> <prefix>top-level lifecycle (mirrorsanet hub/anet node/anet networkpattern).anet demo sci-teamrefactored to internally callcreateBatchwith the sci-team preset (team="sci-team",leaderAlias="研究Leader", intern URL/model,sciTeamPromptactive fan-out template). User-facing wizard surface bit-identical to preview.7 — backward compat for docs / demo recordings.Deprecation
anet demo sci-team --stop|--restart|--cleanupnow prints a stderr deprecation warning pointing at the canonicalanet batch <verb> sci-team. One-release-cycle grace.CI status — pre-existing test infra debt (NOT introduced by this PR)
PR #60's lockfile fix (commit 0440c55 —
npm installregen ofpackage-lock.jsonto sync withengines.nodebump) exposed regression suite silently failing since preview.5. All 5 most recent main runs died atbun install --frozen-lockfilestep in 13-19s; the 186-test regression never actually ran:039c2a4preview.7a451899#58 cli fix8dd1d18preview.69e206aasci systemPrompte4507e4preview.5After the lockfile fix the install step passes and the suite actually runs. 通信测试马 triage (detail comment):
set -e+ mkdir crash, silent-skip)Supporting evidence — user-facing flows verified healthy:
Follow-up issues (NOT blocking this PR per 测试马 verdict + 通信龙 dispatch):
set -e+ mkdir crashVendor preset list (Vincent-verified per 1bc03c0 / issue #48 chain)
intern-s1-prohttps://chat.intern-ai.org.cnMiniMax-M2.7https://api.minimaxi.com/anthropicclaude-sonnet-4-6claude-opus-4-6claude-haiku-4-5__custom__No fabricated values added (per [[feedback_vendor_verify_before_hardcode]] SOP).
How to verify (post-merge functional gate)
Out of scope for this PR
anet batch restart/startsupervisor (Phase 2)~/.anet/batches.jsonmarker registry (Phase 2 cleanup ofbatch listnoise)Scope creep defenses
Checklist
docs-site/docs/changelog.mdupdated — n/a (frozen archive; release commit will sync after merge)--helpbanners +docs/batch.mdcover the new surface; demo sci-team--helpunchanged/home/<user>paths in the difffeat(cli):)Co-Authored-By: Claude*footer (OSS rule)Refs #55Release plan post-merge
Per [[project_release_ops_owner]] (boundary shift since preview.7): 通信工程马 (me) runs the full publish chain —
git pull+rm -rf dist && npm run build+ functional verify on the obfuscated dist +npm publish --tag preview(Vincent 4380 hard rule: preview only, never latest) + docker--no-cacheE2E + release commit + close #55. preview.8 is the second release-ops boundary transition test under the new ownership; passing it confirms reliability cap 8.5.