Compare commits
2
Commits
08f138d30d
...
b18e0ae0bc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b18e0ae0bc | ||
|
|
050baed640 |
@@ -0,0 +1,100 @@
|
||||
# Deploy / install verification — v3.0.0
|
||||
|
||||
- **Date**: 2026-08-26
|
||||
- **Verifier**: `creator-grok-01` (jobs `c9275b44`, `16201e43`, `61299e40`)
|
||||
- **Source tree**: `/Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux` (working copy used as `MAM_REPO_URL`)
|
||||
- **Installer under test**: `deploy/install.sh` (same path as `tests/test_deploy_*.py` and `update.sh`)
|
||||
- **Sandbox (first)**: `/tmp/mam-v3-verify.o0ocAX`
|
||||
- **Sandbox (re-run 16201e43)**: `/tmp/mam-v3-verify2.7RCtR7` (clean dir, `MAM_SKIP_VENV=1`; removed after hash check)
|
||||
|
||||
---
|
||||
|
||||
## 1. Installer surface
|
||||
|
||||
| Artifact | Role |
|
||||
| :--- | :--- |
|
||||
| `deploy/INSTALL.md` | User guide. Documents `deploy/install_mam.sh --target …`. Installed copy is `.agents/INSTALL.md`. |
|
||||
| `deploy/install.sh` | Production installer used by tests, `update.sh`, and `MAM_REPO_URL` staging. Copies `.agents/**` (except reports/references), `AGENTS.md`, hooks, skills. |
|
||||
| `deploy/update.sh` | Installed as `.mam_deploy/update.sh`. Backs up `.mam.env` / `.mam` then re-runs install. |
|
||||
| `deploy/install_mam.sh` | Alternate rsync installer from a local clone (`SRC_DIR` = parent of `deploy/`). Same ownership rules. |
|
||||
|
||||
Both installers pull from the clone they are run from when `MAM_REPO_URL` is a directory (`install.sh`) or when invoked as `install_mam.sh` from that clone. This verification used `install.sh` against the working tree so the installed bits are this v3.0.0 checkout, not `main` on the remote.
|
||||
|
||||
---
|
||||
|
||||
## 2. Sandbox install — skill versions
|
||||
|
||||
`bash deploy/install.sh <sandbox>` completed 0.
|
||||
|
||||
All **8** `SKILL.md` files in the sandbox:
|
||||
|
||||
| Skill | Installed `version` |
|
||||
| :--- | :--- |
|
||||
| `multi-agent-mux-create` | `3.0.0` |
|
||||
| `multi-agent-mux-stop` | `3.0.0` |
|
||||
| `multi-agent-mux-resume` | `3.0.0` |
|
||||
| `multi-agent-mux-status` | `3.0.0` |
|
||||
| `multi-agent-mux-monitor` | `3.0.0` |
|
||||
| `multi-agent-mux-delegate-job` | `3.0.0` |
|
||||
| `multi-agent-mux-loop` | `3.0.0` |
|
||||
| `multi-agent-mux-orc-onboard` | `3.0.0` |
|
||||
|
||||
Matches `VERSIONS.md` skill matrix (`v3.0.0`).
|
||||
|
||||
---
|
||||
|
||||
## 3. Framework assets and v3 payloads
|
||||
|
||||
Present in the sandbox and **SHA-256 identical** to the source tree:
|
||||
|
||||
| Installed path | Source | SHA prefix |
|
||||
| :--- | :--- | :--- |
|
||||
| `.agents/hooks.json` | same | `fc730f18fd9ecc53` |
|
||||
| `.agents/hooks/loop_delegation_guard.sh` | same | `9896c63ffbd6fb00` |
|
||||
| `.agents/MULTI_AGENT_RULES.md` | same | `a5e31712c5cadaac` |
|
||||
| `.agents/INSTALL.md` | `deploy/INSTALL.md` | `26ec7eaf2cc050a7` |
|
||||
| `AGENTS.md` | same | `91acdf00a537e326` |
|
||||
| `.agents/skills/lib.sh` | same | `d884bb839e0a6336` |
|
||||
| `.agents/skills/lib_py/layout.py` | same | `a06d25e660c65084` |
|
||||
| `.agents/skills/lib_py/agents/adapters/grok.py` | same | `33113671c456437e` |
|
||||
| `.agents/skills/lib_py/agents/registry.py` | same | `ec2d169e0a0e6690` |
|
||||
| `.agents/skills/multi-agent-mux-loop/scripts/run_loop.sh` | same | `25c405cd88f1fc19` |
|
||||
|
||||
Also present: `.agents/MULTI_AGENT_RULES.ko.md`. Adapters dir: `claude.py`, `agy.py`, `hermes.py`, `cline.py`, `grok.py`.
|
||||
|
||||
v3 behavior on the installed copies:
|
||||
|
||||
- **Loop CLI**: `--creator)` parser; `--target-agent` only as the removal error. `SKILL.md` and `.agents/INSTALL.md` examples use `--creator`. No leftover `--target-agent` in installed skills except that error handler.
|
||||
- **Layout 2.0**: `_decide` / `_decide_headless`, `new_column_right`, `max_rows` default 2.
|
||||
- **Grok**: `GrokAgentAdapter` registered in `registry.py`.
|
||||
|
||||
---
|
||||
|
||||
## 4. Automated tests
|
||||
|
||||
```text
|
||||
pytest tests/test_deploy_freshness.py tests/test_deploy_layout.py tests/test_loop_cli.py
|
||||
45 passed in 40.56s
|
||||
```
|
||||
|
||||
- `test_deploy_freshness.py`: non-skill assets refresh, ownership, NATS/docs guards.
|
||||
- `test_deploy_layout.py`: install layout, `.mam_deploy`, gitignore block.
|
||||
- `test_loop_cli.py`: `--creator` / `--planner` / `--target-agent` rejection.
|
||||
|
||||
---
|
||||
|
||||
## 5. Gaps / notes (not install failures)
|
||||
|
||||
1. **Two installers.** User-facing `INSTALL.md` tells people to run `install_mam.sh`. CI and `update.sh` use `install.sh`. Both installed v3.0.0 from this tree; operators should know which command they ran.
|
||||
2. **Remote vs working tree.** Default `MAM_REPO_URL` is `https://git.godopu.com/tmpl/multi-agent-mux.git`. This check used the local working copy. A clean install from the remote is v3.0.0 only after that remote is tagged/pushed.
|
||||
3. **`--target-agent` string** remains in `run_loop.sh` as the dedicated rejection path (Rev.4). That is required, not a leak.
|
||||
|
||||
---
|
||||
|
||||
## 6. Verdict
|
||||
|
||||
**PASS.** A clean `deploy/install.sh` into an empty directory installs all eight skills at `version: 3.0.0`, copies hooks / MULTI_AGENT_RULES / INSTALL / lib_py (Grok + layout 2.0) byte-identical to this tree, and the three requested test modules are green.
|
||||
|
||||
Re-run job `16201e43`: second clean install still 8× `version: 3.0.0`, all listed assets MATCH, `pytest` **45 passed in 44.34s**. Verdict unchanged.
|
||||
|
||||
Re-run job `61299e40`: third clean install 8× `3.0.0`, listed assets MATCH, `pytest` **45 passed in 43.76s**. Verdict unchanged.
|
||||
+52
-12
@@ -246,22 +246,58 @@ case "$cmd" in
|
||||
agent)
|
||||
sub="${1:-}"
|
||||
shift || true
|
||||
_resolve_herdr_target() {
|
||||
local raw="$1"
|
||||
local sat
|
||||
sat=$(_sanitize_herdr_agent_name "$raw")
|
||||
if _real_herdr agent get "$sat" >/dev/null 2>&1; then
|
||||
echo "$sat"
|
||||
return 0
|
||||
fi
|
||||
if _real_herdr agent get "$raw" >/dev/null 2>&1; then
|
||||
echo "$raw"
|
||||
return 0
|
||||
fi
|
||||
local from_list
|
||||
from_list=$(_real_herdr agent list 2>/dev/null | TARGET_NAME="$raw" python3 -c '
|
||||
import sys, json, os
|
||||
tn = os.environ.get("TARGET_NAME", "")
|
||||
try:
|
||||
d = json.loads(sys.stdin.read())
|
||||
for a in d.get("result", {}).get("agents", []):
|
||||
name = a.get("name", "")
|
||||
agent = a.get("agent", "")
|
||||
pane_id = a.get("pane_id", "")
|
||||
if name == tn or (not name and agent and agent in tn):
|
||||
print(pane_id or agent)
|
||||
sys.exit(0)
|
||||
except Exception:
|
||||
pass
|
||||
sys.exit(1)
|
||||
' 2>/dev/null || echo "")
|
||||
if [ -n "$from_list" ]; then
|
||||
echo "$from_list"
|
||||
return 0
|
||||
fi
|
||||
echo "$raw"
|
||||
}
|
||||
|
||||
if [ "$sub" = "prompt" ] && [ $# -ge 2 ]; then
|
||||
t="$1"
|
||||
txt="$2"
|
||||
shift 2
|
||||
at=$(_sanitize_herdr_agent_name "$t")
|
||||
_real_herdr agent prompt "$at" "$txt" "$@" 2>/dev/null || _real_herdr agent prompt "$t" "$txt" "$@"
|
||||
tgt=$(_resolve_herdr_target "$t")
|
||||
_real_herdr agent prompt "$tgt" "$txt" "$@"
|
||||
elif [ "$sub" = "get" ] && [ $# -ge 1 ]; then
|
||||
t="$1"
|
||||
shift
|
||||
at=$(_sanitize_herdr_agent_name "$t")
|
||||
_real_herdr agent get "$at" "$@" 2>/dev/null || _real_herdr agent get "$t" "$@"
|
||||
tgt=$(_resolve_herdr_target "$t")
|
||||
_real_herdr agent get "$tgt" "$@"
|
||||
elif [ "$sub" = "read" ] && [ $# -ge 1 ]; then
|
||||
t="$1"
|
||||
shift
|
||||
at=$(_sanitize_herdr_agent_name "$t")
|
||||
_real_herdr agent read "$at" "$@" 2>/dev/null || _real_herdr agent read "$t" "$@"
|
||||
tgt=$(_resolve_herdr_target "$t")
|
||||
_real_herdr agent read "$tgt" "$@"
|
||||
else
|
||||
_real_herdr agent "$sub" "$@"
|
||||
fi
|
||||
@@ -284,22 +320,26 @@ case "$cmd" in
|
||||
if _real_herdr agent get "$(_sanitize_herdr_agent_name "$sess")" >/dev/null 2>&1 || _real_herdr agent get "$sess" >/dev/null 2>&1; then
|
||||
exit 0
|
||||
fi
|
||||
if _real_herdr agent list 2>/dev/null | TARGET_NAME="$sess" python3 -c "
|
||||
if _real_herdr agent list 2>/dev/null | TARGET_NAME="$sess" python3 -c '
|
||||
import sys, json, os
|
||||
try:
|
||||
sys.path.insert(0, os.path.abspath(".agents/skills"))
|
||||
from lib_py.agents.sanitize import sanitize_herdr_agent_name
|
||||
tn = os.environ.get('TARGET_NAME', '')
|
||||
except Exception:
|
||||
sanitize_herdr_agent_name = lambda s: s.lower()[:32] if s else "agent"
|
||||
tn = os.environ.get("TARGET_NAME", "")
|
||||
stn = sanitize_herdr_agent_name(tn)
|
||||
try:
|
||||
d = json.loads(sys.stdin.read())
|
||||
agents = d.get('result', {}).get('agents', [])
|
||||
agents = d.get("result", {}).get("agents", [])
|
||||
for a in agents:
|
||||
an = a.get('name', '')
|
||||
if an == tn or an == stn:
|
||||
an = a.get("name", "")
|
||||
if (an and (an == tn or an == stn)) or (not an and a.get("agent") and a.get("agent") in tn):
|
||||
sys.exit(0)
|
||||
except Exception:
|
||||
pass
|
||||
sys.exit(1)
|
||||
"; then
|
||||
'; then
|
||||
exit 0
|
||||
fi
|
||||
exit 1
|
||||
|
||||
Reference in New Issue
Block a user