@ssheleg/agent-sync 1.18.5 → 1.18.7
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/CHANGELOG.md +69 -0
- package/package.json +1 -1
- package/plugins/agent-sync/.claude-plugin/plugin.json +2 -1
- package/plugins/agent-sync/hooks/_lib.sh +5 -0
- package/plugins/agent-sync/hooks/guard.sh +17 -3
- package/plugins/agent-sync/hooks/hooks.json +1 -1
- package/plugins/agent-sync/skills/agent-sync/SKILL.md +1 -1
- package/plugins/agent-sync/skills/agent-sync/scripts/agent_sync.py +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,72 @@
|
|
|
1
|
+
## v1.18.7 — the evals stop being a claim, and the manifests say what shapes them
|
|
2
|
+
|
|
3
|
+
Wave-3 close-out of the 2026-08-29 family audit (ASY-03, ASY-09). No behavior
|
|
4
|
+
changes; a measurement that did not exist now does, and two manifests declare
|
|
5
|
+
their schemas.
|
|
6
|
+
|
|
7
|
+
- **ASY-03 — the behavioral evals were executed, dated, and the numbers are worse
|
|
8
|
+
than silence pretended.** `test/evals/RESULTS.md` had one row: "no run yet".
|
|
9
|
+
It now carries two dated rows (2026-08-31, haiku and sonnet): 24 blind
|
|
10
|
+
fresh-context trigger probes — one per query per model, the query verbatim plus
|
|
11
|
+
the installed family list, nothing else — and all six scenario lines driven as
|
|
12
|
+
real agent sessions against scratch repositories, end states verified on disk.
|
|
13
|
+
Both models score 11/12 on triggers (train 6/6, validation 5/6) and fail the
|
|
14
|
+
SAME query: **q06, the submodule-finish positive, 0/3 samples on each model** —
|
|
15
|
+
the description has no submodule vocabulary to catch it. That gap is filed as
|
|
16
|
+
ASY-10 (a description change is a minor release, not this patch). The Method
|
|
17
|
+
section states the harness limits out loud: n=1 sampling except the failing
|
|
18
|
+
query, the operator's routing doctrine present in probe context, fs-backend
|
|
19
|
+
`reserve` refusing by design in s02, model aliases rather than pinned snapshot
|
|
20
|
+
ids. SKILL-CARD.md's "never executed" line now points at the dated rows.
|
|
21
|
+
- **ASY-09 — both plugin manifests declare `$schema`.**
|
|
22
|
+
`.claude-plugin/marketplace.json` names
|
|
23
|
+
`https://json.schemastore.org/claude-code-marketplace.json` and
|
|
24
|
+
`plugins/agent-sync/.claude-plugin/plugin.json` names
|
|
25
|
+
`https://json.schemastore.org/claude-code-plugin-manifest.json`; both files
|
|
26
|
+
validate against the schemas those addresses serve (fetched and checked at
|
|
27
|
+
edit time), and `claude plugin validate --strict` stays green on both. The
|
|
28
|
+
repo's own no-host-address rule refused the plugin manifest — correctly, by
|
|
29
|
+
its letter — so `json.schemastore.org` joined `ALLOWED_HOSTS` beside
|
|
30
|
+
`json-schema.org`: a vendor-neutral public schema registry, not an instance
|
|
31
|
+
address. The planted `leaked host` self-test still proves the check can fail.
|
|
32
|
+
|
|
33
|
+
## v1.18.6 — the guard keeps its own header's promise, and /clear gets its own identity
|
|
34
|
+
|
|
35
|
+
Wave-2 hardening from the 2026-08-29 family audit (ASY-07, ASY-08, ASY-06, ASY-01).
|
|
36
|
+
Same shape as v1.18.5: text that claimed more than the code did.
|
|
37
|
+
|
|
38
|
+
- **ASY-07 — a machine without python3 had no guard, and said nothing.** `guard.sh`'s
|
|
39
|
+
header promises that every internal failure exits 2, because any other outcome is
|
|
40
|
+
non-blocking in Claude Code — and the python3-absent path broke it: both parser
|
|
41
|
+
substitutions failed under `2>/dev/null`, `path` came back empty, `is_commit`
|
|
42
|
+
defaulted to 0 and the hook exited 0. Fail OPEN, exactly where the header says it
|
|
43
|
+
must not, and nothing upstream compensates — hooks.json's `if` filter is best-effort
|
|
44
|
+
by doctrine, so the parser IS the guard. Both substitutions now report through
|
|
45
|
+
`parser_or_die`, which exits 2 and names the remedy (install python3 / fix PATH, or
|
|
46
|
+
remove `.claude/agent-sync.json` to switch coordination off).
|
|
47
|
+
`check_guard_fails_closed_without_python3` drives the real hook through a shim PATH
|
|
48
|
+
holding bash and cat but no interpreter — watched failing against the shipped guard
|
|
49
|
+
(`the guard exited 0`) — and the self-test plants the fail-open back
|
|
50
|
+
(`an absent interpreter fails open`).
|
|
51
|
+
- **ASY-08 — a post-/clear session inherited the ended run's identity.** The
|
|
52
|
+
SessionStart matcher read `startup|resume`, and `/clear` ends the run while keeping
|
|
53
|
+
the CLI process — so the stamp keyed by that process survived into the next session:
|
|
54
|
+
"two sessions, one identity", the case SKILL.md itself names, and `release` then
|
|
55
|
+
takes a lease the caller never had. The matcher now carries `clear`; `compact` stays
|
|
56
|
+
excluded deliberately, because a compaction continues the SAME session.
|
|
57
|
+
`hooks_session_test.py` gained the case (matcher parts asserted both directions, and
|
|
58
|
+
the hook re-stamps on a clear payload) — watched failing against the shipped matcher.
|
|
59
|
+
- **ASY-06 — the guard's internal-failure refusal named no next step.** A refusal with
|
|
60
|
+
no remedy is how an operator learns to switch a hook off. The message now says:
|
|
61
|
+
diagnose with `python3 <script> check`, or acquire a lease first.
|
|
62
|
+
- **ASY-01 — `scripts/__pycache__` regenerated forever.** Hooks now export
|
|
63
|
+
`PYTHONDONTWRITEBYTECODE=1` in `_lib.sh` (sourced by all four), and the test files
|
|
64
|
+
that import `agent_sync.py` set `sys.dont_write_bytecode` — the shipped `scripts/`
|
|
65
|
+
directory stays source, not build products.
|
|
66
|
+
- ASY-04 (this test class missing from CI) was already closed in v1.18.5:
|
|
67
|
+
`validate.yml` runs `hooks_session_test.py` since commit `5446990`. Verified, not
|
|
68
|
+
re-done. ASY-02 (command rename) closed by operator decision 2026-08-30: names stay.
|
|
69
|
+
|
|
1
70
|
## v1.18.5 — a pipe reaches the guard, and the installers stop deleting blind
|
|
2
71
|
|
|
3
72
|
Two enforcement holes, each of the same shape: a mechanism whose own text claimed more
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ssheleg/agent-sync",
|
|
3
|
-
"version": "1.18.
|
|
3
|
+
"version": "1.18.7",
|
|
4
4
|
"description": "Let concurrent coding agents share one project without colliding — leases with TTL, race-free id reservation, a run journal and a generated board, over a pluggable knowledge cloud.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"agent-sync": "bin/agent-sync.js"
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
2
3
|
"name": "agent-sync",
|
|
3
4
|
"displayName": "Agent Sync",
|
|
4
|
-
"version": "1.18.
|
|
5
|
+
"version": "1.18.7",
|
|
5
6
|
"description": "Coordination layer for multi-agent repositories — leases with TTL, race-free ID reservation, a run journal, a cross-repo signal feed and a generated board, over a pluggable knowledge cloud.",
|
|
6
7
|
"author": {
|
|
7
8
|
"name": "ssheleg",
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# Shared helpers for the agent-sync hooks. Sourced, never executed.
|
|
3
3
|
|
|
4
|
+
# Every hook runs python3 against the shipped scripts/ directory, which people read
|
|
5
|
+
# as source, not as a build product. Bytecode caching buys nothing at this call rate
|
|
6
|
+
# and left scripts/__pycache__ regenerating forever (ASY-01).
|
|
7
|
+
export PYTHONDONTWRITEBYTECODE=1
|
|
8
|
+
|
|
4
9
|
# Run a command under a time limit, portably.
|
|
5
10
|
#
|
|
6
11
|
# `timeout` is GNU coreutils and is NOT on a stock macOS. Calling it directly made
|
|
@@ -8,6 +8,17 @@ S="$AGENT_SYNC_PY"
|
|
|
8
8
|
agent_sync_configured || exit 0
|
|
9
9
|
input=$(cat)
|
|
10
10
|
|
|
11
|
+
# The parser IS the guard: hooks.json's `if` filter is best-effort and fails open by
|
|
12
|
+
# doctrine, so nothing upstream compensates for a parser that cannot run. A python3
|
|
13
|
+
# missing from PATH used to leave `path` empty, default `is_commit` to 0 and exit 0 —
|
|
14
|
+
# the one machine state that disables the parser silently disabled the guard (ASY-07).
|
|
15
|
+
parser_or_die() {
|
|
16
|
+
local rc="$1"
|
|
17
|
+
[ "$rc" -eq 0 ] && return 0
|
|
18
|
+
echo "agent-sync: the guard could not run its parser (python3 exit $rc — likely missing from PATH). Failing closed. Install python3 or fix PATH and retry, or remove .claude/agent-sync.json to switch coordination off here." >&2
|
|
19
|
+
exit 2
|
|
20
|
+
}
|
|
21
|
+
|
|
11
22
|
path=$(python3 -c '
|
|
12
23
|
import json,sys
|
|
13
24
|
try:
|
|
@@ -17,6 +28,7 @@ except Exception:
|
|
|
17
28
|
ti=d.get("tool_input") or {}
|
|
18
29
|
print(ti.get("file_path") or ti.get("path") or ti.get("notebook_path") or "")
|
|
19
30
|
' <<<"$input" 2>/dev/null)
|
|
31
|
+
parser_or_die $?
|
|
20
32
|
|
|
21
33
|
# git commit: check every staged path instead of a single file argument.
|
|
22
34
|
if [ -z "$path" ]; then
|
|
@@ -30,7 +42,7 @@ if [ -z "$path" ]; then
|
|
|
30
42
|
#
|
|
31
43
|
# Tokenised in python rather than globbed in shell: `git log --grep=commit` must not match, and
|
|
32
44
|
# `git -c user.name=x -C dir commit` must.
|
|
33
|
-
|
|
45
|
+
parsed=$(python3 -c '
|
|
34
46
|
import json, shlex, sys
|
|
35
47
|
try:
|
|
36
48
|
d = json.load(sys.stdin)
|
|
@@ -71,7 +83,9 @@ for seg in cmd.replace("&&", "\n").replace("||", "\n").replace("|&", "\n").repla
|
|
|
71
83
|
repo = r
|
|
72
84
|
break
|
|
73
85
|
print(is_commit, repo)
|
|
74
|
-
' <<<"$input" 2>/dev/null)
|
|
86
|
+
' <<<"$input" 2>/dev/null)
|
|
87
|
+
parser_or_die $?
|
|
88
|
+
read -r is_commit repo <<<"$parsed"
|
|
75
89
|
[ -n "${is_commit:-}" ] || is_commit=0
|
|
76
90
|
[ -n "${repo:-}" ] || repo="."
|
|
77
91
|
[ -d "$repo" ] || repo="${CLAUDE_PROJECT_DIR:-$PWD}"
|
|
@@ -100,6 +114,6 @@ else
|
|
|
100
114
|
echo "$out" >&2
|
|
101
115
|
exit 2
|
|
102
116
|
fi
|
|
103
|
-
echo "agent-sync guard failed to run ($code): $out" >&2
|
|
117
|
+
echo "agent-sync guard failed to run ($code): $out — diagnose with \`python3 $S check\`, or acquire a lease first: \`python3 $S acquire <TASK-ID>\`" >&2
|
|
104
118
|
exit 2
|
|
105
119
|
fi
|
|
@@ -4,7 +4,7 @@ description: "Use when several coding agents work one repository at the same tim
|
|
|
4
4
|
compatibility: "Requires the task-pipeline skill for its stages (npx sshlg-skills install). Needs python3 3.9+ (stdlib only, HTTP included - nothing to pip install) and bash for the hooks. The knowledge backend is configured per project; with none configured it degrades to git-file leases. Enforcement hooks are Claude Code only - on other agents the same checks run as a self-check."
|
|
5
5
|
license: MIT
|
|
6
6
|
metadata:
|
|
7
|
-
version: "1.18.
|
|
7
|
+
version: "1.18.7"
|
|
8
8
|
author: ssheleg
|
|
9
9
|
---
|
|
10
10
|
|