From 69e3b8d9a2eba009a7e29ff43cb7aa7c8e050356 Mon Sep 17 00:00:00 2001 From: Luke Parke <5702154+LukasParke@users.noreply.github.com> Date: Tue, 28 Jul 2026 17:23:17 -0500 Subject: [PATCH 1/2] fix: address both review suggestions from #1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - scripts/upstream: clone upstream --single-branch (ephemeral CI clone, full ref namespace doubles clone time), with a fetch fallback so a --ref outside the default branch still resolves. - verify.sh / contract: the HooksManager check grepped for the exact TS spelling while its comment claimed the name was loose — a future Go-idiomatic rename would falsely fail the gate. The 0.8.0 port chose the upstream spelling verbatim, so pin it explicitly: the contract now names HooksManager as the required Go type and the verify.sh comment says a rename is a contract change, not a drift to tolerate. Co-Authored-By: Claude Fable 5 --- .upstreamer/scripts/verify.sh | 7 +++++-- .upstreamer/upstreamer.md | 4 +++- scripts/upstream | 12 ++++++++++-- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/.upstreamer/scripts/verify.sh b/.upstreamer/scripts/verify.sh index 3627e86..fd096e4 100755 --- a/.upstreamer/scripts/verify.sh +++ b/.upstreamer/scripts/verify.sh @@ -59,8 +59,11 @@ if command -v go >/dev/null 2>&1; then fi echo -# Hooks and versioned state are the 0.8.0 parity floor. Named loosely because -# the Go equivalents may not match TS spelling exactly; the eval checks behavior. +# Hooks and versioned state are the 0.8.0 parity floor. The 0.8.0 port chose +# the upstream spelling `HooksManager` verbatim, so this check pins that exact +# name; the contract's required-API list is the source of truth. If a future +# port renames it, that is a contract change — update the contract's naming map +# and this check together, not just the code. echo "-- 0.8.0 parity surface present" grep -rqE '\bHooksManager\b' --include='*.go' . 2>/dev/null \ && pass "hooks manager present" \ diff --git a/.upstreamer/upstreamer.md b/.upstreamer/upstreamer.md index cc4174f..c85acfe 100644 --- a/.upstreamer/upstreamer.md +++ b/.upstreamer/upstreamer.md @@ -80,7 +80,9 @@ Stop conditions: - `StepCountIs`, `HasToolCall`, `MaxTokensUsed`, `MaxCost`, `FinishReasonIs` Lifecycle hooks (upstream #7, #67 — the 0.8.0 headline): -- A `HooksManager` equivalent with options, hook name constants, hook +- A `HooksManager` type — pinned to the upstream spelling, which is already + idiomatic Go (the 0.8.0 port adopted it verbatim; `verify.sh` checks the + exact name) — with options, hook name constants, hook definition/entry/handler/registry types, tool matchers, `PostModelCall` telemetry, `SessionEnd` usage totals - Session-id threading per emit so a shared manager is concurrency-safe diff --git a/scripts/upstream b/scripts/upstream index ce561de..f67206e 100755 --- a/scripts/upstream +++ b/scripts/upstream @@ -124,11 +124,19 @@ if [ -d "$upstream_dir/.git" ]; then git -C "$upstream_dir" fetch --tags --force origin else rm -rf "$upstream_dir" - git clone "$upstream_url" "$upstream_dir" + # --single-branch: CI recreates this clone every run, and fetching the whole + # ref namespace roughly doubles clone time for nothing — the script targets + # origin/HEAD or a release tag (reachable from the default branch, so still + # fetched). Refs outside that (e.g. a manual run against a feature branch) + # are handled by the fallback fetch below. + git clone --single-branch "$upstream_url" "$upstream_dir" fi if [ -n "$ref" ]; then - target_commit="$(git -C "$upstream_dir" rev-parse "$ref^{commit}")" + if ! target_commit="$(git -C "$upstream_dir" rev-parse --quiet --verify "$ref^{commit}")"; then + git -C "$upstream_dir" fetch origin "$ref" + target_commit="$(git -C "$upstream_dir" rev-parse FETCH_HEAD^{commit})" + fi else target_commit="$(git -C "$upstream_dir" rev-parse origin/HEAD 2>/dev/null || git -C "$upstream_dir" rev-parse origin/main)" fi From ade75b04463b29779617afbbf968d07c10085e0e Mon Sep 17 00:00:00 2001 From: Luke Parke <5702154+LukasParke@users.noreply.github.com> Date: Wed, 29 Jul 2026 11:00:30 -0500 Subject: [PATCH 2/2] fix(upstream): guard ref arguments against option injection Review nit on #2: separate the ref from options in the fallback fetch (-- terminator) and rev-parse (--end-of-options) so a manually supplied --ref value starting with '-' cannot be parsed as an option. CI refs always start with '@'; this hardens the manual path. Co-Authored-By: Claude Fable 5 --- scripts/upstream | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/upstream b/scripts/upstream index f67206e..e110791 100755 --- a/scripts/upstream +++ b/scripts/upstream @@ -133,8 +133,10 @@ else fi if [ -n "$ref" ]; then - if ! target_commit="$(git -C "$upstream_dir" rev-parse --quiet --verify "$ref^{commit}")"; then - git -C "$upstream_dir" fetch origin "$ref" + # --end-of-options / --: a ref value starting with "-" must not be parsed as + # an option (CI refs always start with "@", but manual runs take anything). + if ! target_commit="$(git -C "$upstream_dir" rev-parse --quiet --verify --end-of-options "$ref^{commit}")"; then + git -C "$upstream_dir" fetch origin -- "$ref" target_commit="$(git -C "$upstream_dir" rev-parse FETCH_HEAD^{commit})" fi else