mirror of
https://github.com/eunomia-bpf/bpf-developer-tutorial.git
synced 2026-10-31 04:36:26 +08:00
Add cross-model tutorial writing review
This commit is contained in:
@@ -5,6 +5,7 @@ readonly MODEL='claude-opus-4-6[1m]'
|
||||
readonly SKILL_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
readonly VERIFY="$SKILL_DIR/scripts/verify_claude_trace.py"
|
||||
readonly GUIDE="$SKILL_DIR/references/writing-guide.md"
|
||||
readonly PRECEDENTS="$SKILL_DIR/references/repository-precedents.md"
|
||||
|
||||
usage() {
|
||||
echo "usage: $0 --repo ABSOLUTE_REPO_PATH --task ABSOLUTE_TASK_FILE --readme ABSOLUTE_README_PATH --readme ABSOLUTE_README_PATH" >&2
|
||||
@@ -94,10 +95,11 @@ status_before=$(git -C "$repo" status --porcelain=v1)
|
||||
task_sha=$(sha256sum "$task" | awk '{print $1}')
|
||||
printf -v allowed_paths 'Allowed README path: %s\n' "${allowed_readmes[@]}"
|
||||
|
||||
prompt=$(printf '%s\n\n%s\n%s\n%s\n' \
|
||||
'You are the sole prose author for an eBPF production tutorial. Read the repository code and evidence named in the task. Edit only the README.md and README.zh.md paths explicitly allowed by the task. Do not edit code, build files, generated indexes, or tests. Do not invent output or claims. Finish by stating which README files you edited.' \
|
||||
prompt=$(printf '%s\n\n%s\n%s\n%s\n%s\n' \
|
||||
'You are the prose author for this eBPF production tutorial pass. Read the repository code and evidence named in the task. Edit only the README.md and README.zh.md paths explicitly allowed by the task. Do not edit code, build files, generated indexes, or tests. Do not invent output or claims. Finish by stating which README files you edited.' \
|
||||
"$allowed_paths" \
|
||||
"$(<"$GUIDE")" \
|
||||
"$(<"$PRECEDENTS")" \
|
||||
"$(<"$task")")
|
||||
|
||||
set +e
|
||||
|
||||
209
.agents/skills/write-bpf-production-tutorial/scripts/run-external-review.sh
Executable file
209
.agents/skills/write-bpf-production-tutorial/scripts/run-external-review.sh
Executable file
@@ -0,0 +1,209 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
readonly SKILL_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
readonly WRITING_GUIDE="$SKILL_DIR/references/writing-guide.md"
|
||||
readonly REVIEW_GUIDE="$SKILL_DIR/references/review-checklist.md"
|
||||
readonly PRECEDENT_GUIDE="$SKILL_DIR/references/repository-precedents.md"
|
||||
|
||||
usage() {
|
||||
echo "usage: $0 --reviewer grok|glm --repo ABSOLUTE_REPO_PATH --task ABSOLUTE_TASK_FILE --file REPO_RELATIVE_PATH [--file ...]" >&2
|
||||
}
|
||||
|
||||
reviewer=
|
||||
repo=
|
||||
task=
|
||||
files=()
|
||||
while (($#)); do
|
||||
case "$1" in
|
||||
--reviewer)
|
||||
reviewer=${2:-}
|
||||
shift 2
|
||||
;;
|
||||
--repo)
|
||||
repo=${2:-}
|
||||
shift 2
|
||||
;;
|
||||
--task)
|
||||
task=${2:-}
|
||||
shift 2
|
||||
;;
|
||||
--file)
|
||||
files+=("${2:-}")
|
||||
shift 2
|
||||
;;
|
||||
--model|--fallback-model)
|
||||
echo "model overrides and fallbacks are forbidden" >&2
|
||||
exit 2
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
[[ $reviewer == grok || $reviewer == glm ]] || { usage; exit 2; }
|
||||
[[ $repo = /* && -d $repo ]] || { echo "--repo must be an absolute Git checkout" >&2; exit 2; }
|
||||
git -C "$repo" rev-parse --is-inside-work-tree >/dev/null 2>&1 || { echo "--repo must be an absolute Git checkout" >&2; exit 2; }
|
||||
[[ $task = /* && -f $task ]] || { echo "--task must be an absolute readable file" >&2; exit 2; }
|
||||
((${#files[@]} >= 2)) || { echo "pass at least the English and Chinese README with --file" >&2; exit 2; }
|
||||
command -v git >/dev/null || { echo "git is required" >&2; exit 127; }
|
||||
command -v python3 >/dev/null || { echo "python3 is required" >&2; exit 127; }
|
||||
|
||||
case "$reviewer" in
|
||||
grok)
|
||||
readonly model='grok-4.5'
|
||||
command -v grok >/dev/null || { echo "Grok CLI is required" >&2; exit 127; }
|
||||
;;
|
||||
glm)
|
||||
readonly model='zai-coding-plan/glm-5.2'
|
||||
command -v opencode >/dev/null || { echo "OpenCode is required" >&2; exit 127; }
|
||||
;;
|
||||
esac
|
||||
|
||||
repo_real=$(realpath "$repo")
|
||||
for file in "${files[@]}"; do
|
||||
[[ $file && $file != /* ]] || { echo "--file paths must be repository-relative: $file" >&2; exit 2; }
|
||||
file_real=$(realpath "$repo/$file")
|
||||
[[ $file_real == "$repo_real"/* && -f $file_real ]] || { echo "invalid review file: $file" >&2; exit 2; }
|
||||
done
|
||||
|
||||
state_root=${XDG_STATE_HOME:-$HOME/.local/state}/bpf-tutorial-reviews/runs
|
||||
mkdir -p "$state_root"
|
||||
chmod 700 "$state_root"
|
||||
run_id="$(date -u +%Y%m%dT%H%M%SZ)-$$-$reviewer"
|
||||
run_dir="$state_root/$run_id"
|
||||
mkdir -m 700 "$run_dir"
|
||||
prompt="$run_dir/review-prompt.md"
|
||||
trace="$run_dir/review-trace.jsonl"
|
||||
manifest="$run_dir/manifest.json"
|
||||
|
||||
{
|
||||
printf '# Independent eBPF tutorial review\n\n'
|
||||
printf 'Review this immutable snapshot. Do not edit files, run commands, use network sources, or infer facts absent from the snapshot. Do not assume the author\x27s intended diagnosis.\n\n'
|
||||
printf '## Writing rulebook\n\n'
|
||||
sed -n '1,$p' "$WRITING_GUIDE"
|
||||
printf '\n## Review rulebook\n\n'
|
||||
sed -n '1,$p' "$REVIEW_GUIDE"
|
||||
printf '\n## Repository precedent rulebook\n\n'
|
||||
sed -n '1,$p' "$PRECEDENT_GUIDE"
|
||||
printf '\n## Review task and evidence\n\n'
|
||||
sed -n '1,$p' "$task"
|
||||
for file in "${files[@]}"; do
|
||||
printf '\n## Snapshot: `%s`\n\n```text\n' "$file"
|
||||
sed -n '1,$p' "$repo/$file"
|
||||
printf '\n```\n'
|
||||
done
|
||||
} >"$prompt"
|
||||
chmod 600 "$prompt"
|
||||
|
||||
head_before=$(git -C "$repo" rev-parse HEAD)
|
||||
status_before=$(git -C "$repo" status --porcelain=v1)
|
||||
files_before=$(
|
||||
for file in "${files[@]}"; do
|
||||
sha256sum "$repo/$file"
|
||||
done
|
||||
)
|
||||
prompt_sha=$(sha256sum "$prompt" | awk '{print $1}')
|
||||
|
||||
set +e
|
||||
case "$reviewer" in
|
||||
grok)
|
||||
(
|
||||
cd "$run_dir"
|
||||
grok --prompt-file "$prompt" \
|
||||
--model "$model" \
|
||||
--permission-mode plan \
|
||||
--no-subagents \
|
||||
--disable-web-search \
|
||||
--output-format streaming-json
|
||||
) >"$trace" 2>&1
|
||||
review_status=$?
|
||||
;;
|
||||
glm)
|
||||
(
|
||||
cd "$run_dir"
|
||||
opencode run \
|
||||
'Review the complete attached snapshot and return only the requested independent review.' \
|
||||
--dir "$run_dir" \
|
||||
--model "$model" \
|
||||
--agent plan \
|
||||
--format json \
|
||||
--title "bpf-tutorial-review-$run_id" \
|
||||
--file "$prompt"
|
||||
) >"$trace" 2>&1
|
||||
review_status=$?
|
||||
;;
|
||||
esac
|
||||
set -e
|
||||
|
||||
trace_sha=$(sha256sum "$trace" | awk '{print $1}')
|
||||
head_after=$(git -C "$repo" rev-parse HEAD)
|
||||
status_after=$(git -C "$repo" status --porcelain=v1)
|
||||
files_after=$(
|
||||
for file in "${files[@]}"; do
|
||||
sha256sum "$repo/$file"
|
||||
done
|
||||
)
|
||||
|
||||
REVIEWER_VALUE="$reviewer" \
|
||||
MODEL_VALUE="$model" \
|
||||
REPO_VALUE="$repo" \
|
||||
TASK_VALUE="$task" \
|
||||
PROMPT_VALUE="$prompt" \
|
||||
PROMPT_SHA_VALUE="$prompt_sha" \
|
||||
TRACE_VALUE="$trace" \
|
||||
TRACE_SHA_VALUE="$trace_sha" \
|
||||
REVIEW_STATUS_VALUE="$review_status" \
|
||||
HEAD_BEFORE_VALUE="$head_before" \
|
||||
HEAD_AFTER_VALUE="$head_after" \
|
||||
STATUS_BEFORE_VALUE="$status_before" \
|
||||
STATUS_AFTER_VALUE="$status_after" \
|
||||
FILES_BEFORE_VALUE="$files_before" \
|
||||
FILES_AFTER_VALUE="$files_after" \
|
||||
python3 - "$manifest" <<'PY'
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
|
||||
path = pathlib.Path(__import__("sys").argv[1])
|
||||
path.write_text(json.dumps({
|
||||
"reviewer": os.environ["REVIEWER_VALUE"],
|
||||
"model": os.environ["MODEL_VALUE"],
|
||||
"repo": os.environ["REPO_VALUE"],
|
||||
"task": os.environ["TASK_VALUE"],
|
||||
"prompt": os.environ["PROMPT_VALUE"],
|
||||
"prompt_sha256": os.environ["PROMPT_SHA_VALUE"],
|
||||
"trace": os.environ["TRACE_VALUE"],
|
||||
"trace_sha256": os.environ["TRACE_SHA_VALUE"],
|
||||
"review_exit_status": int(os.environ["REVIEW_STATUS_VALUE"]),
|
||||
"head_before": os.environ["HEAD_BEFORE_VALUE"],
|
||||
"head_after": os.environ["HEAD_AFTER_VALUE"],
|
||||
"status_before": os.environ["STATUS_BEFORE_VALUE"],
|
||||
"status_after": os.environ["STATUS_AFTER_VALUE"],
|
||||
"repository_status_changed": os.environ["STATUS_BEFORE_VALUE"] != os.environ["STATUS_AFTER_VALUE"],
|
||||
"review_files_sha256_before": os.environ["FILES_BEFORE_VALUE"].splitlines(),
|
||||
"review_files_sha256_after": os.environ["FILES_AFTER_VALUE"].splitlines(),
|
||||
}, indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
||||
PY
|
||||
chmod 600 "$trace" "$manifest"
|
||||
|
||||
if ((review_status != 0)); then
|
||||
echo "$reviewer exited with status $review_status; preserved trace: $trace" >&2
|
||||
exit "$review_status"
|
||||
fi
|
||||
[[ -s $trace ]] || { echo "review trace is empty: $trace" >&2; exit 1; }
|
||||
if [[ $head_before != "$head_after" || $files_before != "$files_after" ]]; then
|
||||
echo "read-only review changed Git HEAD or a reviewed file; preserved trace: $trace" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ $status_before != "$status_after" ]]; then
|
||||
echo "warning: unrelated repository status changed during review; recorded in manifest" >&2
|
||||
fi
|
||||
|
||||
echo "manifest=$manifest"
|
||||
Reference in New Issue
Block a user