Files
tanweai__pua/hooks/stop-feedback.sh
T
xsser ac50267918 Remove all data collection: 5 upload channels, client and server
PUA Skill no longer sends anything over the network. Removed end to end,
both the client hooks that emit data and the server that received it.

Channels removed:
- Session transcript upload   (/api/upload)      full redacted .jsonl
- Rating feedback             (/api/feedback)    rating, counts, flavor
- Silent heartbeat telemetry  (/api/heartbeat)   install id, version, platform
- PUA leaderboard             (/api/leaderboard) email, phone, PUA counts
- pua-api platform            (agentguard.workers.dev)
    phone + SMS registration, silent session_start/pua_triggered/command_used
    events, remote prompt-template fetch, and the payment flow that depended
    on the registration token

Client:
- delete hooks/heartbeat.sh; drop both SessionStart registrations
- stop-feedback.sh: 5 curl calls -> append one line to ~/.pua/feedback.jsonl
- rewrite references/platform.md as a local-only command reference
- drop the leaderboard section and commands from skills/pro
- survey/pua/offline command docs: local-only wording

Server:
- delete all Pages Functions (upload, feedback, heartbeat, leaderboard,
  _sanitize, me, _session, auth/*) and all 5 D1 migrations
- contribute + admin pages become notices; no upload form, no login
- wrangler.toml: drop R2/D1 bindings and GitHub OAuth vars

Note: removing the bindings does not delete stored data. The R2 bucket
(puaskill-upload), the D1 database (pua-uploads-db) and the
GITHUB_CLIENT_SECRET / SESSION_SECRET secrets must be deleted in the
Cloudflare dashboard separately.

Guard rail:
- add evals/test-no-telemetry.sh: reverse assertions over the whole repo
  (collection hosts, endpoint paths, outbound request bodies, deleted files,
  hook registrations, CF bindings) plus a positive control that local
  feedback still works. Verified by injecting both a naive and an evasive
  upload; 4 and 2 gates fired respectively.
- test-upload-flow / test-heartbeat / test-feedback-auth asserted that
  collection worked, so they were replaced rather than merely deleted --
  deleting them would have removed the guard along with the feature.

hooks/sanitize-session.sh is kept as a standalone offline redaction tool.
Unlike the deleted TypeScript port it does not split input per line, so the
multiline PEM pattern still matches (issue #134 ID-001 did not apply to it).

Refs #134, #98, #100
2026-08-29 15:57:20 +08:00

112 lines
5.0 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# PUA Stop hook: LOCAL-ONLY feedback collection (writes ~/.pua/feedback.jsonl)
# Config: ~/.pua/config.json → feedback_frequency (0=off, 1=every, 3=default, 5=relaxed)
#
# This hook performs NO network requests. Session-transcript upload, rating
# upload, heartbeat telemetry and leaderboard submission were all removed.
# Read hook input before anything else consumes stdin
HOOK_INPUT=$(cat)
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "${SCRIPT_DIR}/flavor-helper.sh"
# ═══════════════════════════════════════════════════════════════
# Gate 0 — Subagent Isolation
# hook_event_name=SubagentStop 或 parent_session_id 非空 →
# subagent 不应触发反馈问卷subagent 没有 AskUserQuestion
# 且 counter 会被多余的 Stop 事件污染)。直接放行。
# ═══════════════════════════════════════════════════════════════
if ! command -v jq &>/dev/null; then exit 0; fi
HOOK_EVENT=$(echo "$HOOK_INPUT" | jq -r '.hook_event_name // ""')
PARENT_SESSION=$(echo "$HOOK_INPUT" | jq -r '.parent_session_id // ""')
if [[ "$HOOK_EVENT" == "SubagentStop" ]] || [[ -n "$PARENT_SESSION" ]]; then
exit 0
fi
CONFIG="$(pua_config_file)"
COUNTER="${HOME:-~}/.pua/.stop_counter"
FREQUENCY=5
if [ -f "$CONFIG" ] && [ "$(pua_json_get "$CONFIG" offline False)" = "True" ]; then
exit 0
fi
# Only prompt if PUA was actually triggered this session (transcript is ground truth)
TRANSCRIPT_PATH=$(echo "$HOOK_INPUT" | jq -r '.transcript_path // ""')
if [[ -z "$TRANSCRIPT_PATH" || ! -f "$TRANSCRIPT_PATH" ]]; then
exit 0
fi
if ! grep -qE 'PUA生效|\[Auto-select:|\[PIP-REPORT\]|\[PUA-REPORT\]' "$TRANSCRIPT_PATH" 2>/dev/null; then
exit 0
fi
if [ -f "$CONFIG" ]; then
freq=$(pua_json_get "$CONFIG" feedback_frequency 5)
case "$freq" in
0|never|off) exit 0 ;;
1|every) FREQUENCY=1 ;;
*) [[ "$freq" =~ ^[0-9]+$ ]] && FREQUENCY="$freq" || FREQUENCY=5 ;;
esac
fi
mkdir -p "${HOME:-~}/.pua"
count=0
[ -f "$COUNTER" ] && count=$(cat "$COUNTER" 2>/dev/null || echo 0)
count=$((count + 1))
echo "$count" > "$COUNTER"
[ $((count % FREQUENCY)) -ne 0 ] && exit 0
# Read actual flavor from config (reuse flavor-helper.sh)
get_flavor
_ACTUAL_FLAVOR="${PUA_FLAVOR:-alibaba}"
# Use `read -r -d ''` instead of `$(cat <<'FEEDBACK' ... FEEDBACK)` to avoid a
# bash 3.2 parser bug (macOS default `/bin/bash`) where the `$(...)` scanner
# still tracks single-quote balance inside a quoted heredoc body. An odd
# number of apostrophes in the body (e.g. `user's`) made the scanner think a
# quote was unterminated and reported `unexpected EOF` at the next statement.
# `read -d ''` reads until NUL (never present), populates the variable, and
# returns non-zero at EOF — hence `|| true`. See issue #166.
IFS= read -r -d '' _feedback_text <<'FEEDBACK' || true
IMPORTANT — BEFORE doing anything else, you MUST execute this feedback flow:
## Step 1: Ask for a rating (LOCAL RECORD ONLY — no network)
Call AskUserQuestion:
questions: [{
question: "任务结束了,顺手评个分?\n\n这条评分**只写入本机** `~/.pua/feedback.jsonl`不会发送到任何服务器。PUA Skill 已移除全部联网上报功能——session 上传、评分上报、心跳 telemetry、排行榜提交都已删除。\n\n本地记录的用处你自己可以回看哪类任务下 PUA 有效、压力升到过几级。完全自愿,跳过没问题。",
header: "感谢使用 PUA Skill",
options: [
{label: "很有用", description: "写入本地 ~/.pua/feedback.jsonl"},
{label: "一般般", description: "写入本地 ~/.pua/feedback.jsonl"},
{label: "没感觉", description: "写入本地 ~/.pua/feedback.jsonl"},
{label: "这次跳过", description: "不记录。可在 ~/.pua/config.json 设 feedback_frequency:0 永久关闭此提示"}
],
multiSelect: false
}]
## Step 2: Append one line to the local file
If user chose "这次跳过":
```bash
echo "{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"rating\":\"跳过\"}" >> ~/.pua/feedback.jsonl
```
Otherwise (substitute RATING with the label the user picked, and fill in a brief task summary):
```bash
echo "{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"rating\":\"RATING\",\"pua_count\":0,\"flavor\":\"阿里\",\"task_summary\":\"brief task description\"}" >> ~/.pua/feedback.jsonl
```
## Hard constraint — this flow is offline
Appending that single line IS the entire flow. Do NOT send this data anywhere:
no curl, no wget, no WebFetch, no POST to any endpoint, and never upload the
session transcript. There is no server to receive it — the endpoints were removed.
Call AskUserQuestion NOW.
FEEDBACK
# Replace the placeholder flavor with the actual configured flavor.
_pua_pat='\"flavor\":\"阿里\"'
_pua_rep='\"flavor\":\"'"${_ACTUAL_FLAVOR}"'\"'
printf '%s\n' "${_feedback_text//${_pua_pat}/${_pua_rep}}"