mirror of
https://github.com/tanweai/pua.git
synced 2026-08-29 02:02:20 +08:00
fix(pua): respect off on Windows Git Bash
Summary: - Add shared Python launcher fallback, Git Bash path conversion, and JSON config readers for hook configuration access. - Route UserPromptSubmit, PostToolUse, SessionStart, Stop, and integrity hooks through the shared config reader so /pua:off and feedback_frequency=0 work when only python is available. - Add issue #159 Windows Git Bash regression coverage and bump all plugin manifests to v3.2.8. Rationale: - Native Windows Python cannot open Git Bash /c/... paths directly, and some Windows installations provide python without python3. - The previous fallback treated config read failures as always_on=true, so /pua:off could still inject PUA on frustration prompts. Tests: - for f in hooks/*.sh scripts/*.sh evals/*.sh; do bash -n "$f"; done - bash evals/test-windows-python-hooks.sh - bash evals/test-yaml-frontmatter.sh - bash evals/test-release-consistency.sh - bash evals/test-agent-governance.sh - bash evals/test-pua-loop-hook.sh - bash evals/test-integrity-guard.sh - bash evals/test-behavior.sh - bash evals/run-trigger-test.sh - git diff --check - python3 JSON parse check for plugin and hook manifests Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
@@ -8,8 +8,8 @@
|
||||
"plugins": [
|
||||
{
|
||||
"name": "pua",
|
||||
"description": "PUA 我们不养闲 Agent — 11 modular skills, 13 corporate flavors, L0-L4 pressure, auto-iteration loop, ENFP yes-mode, Chinese-mom nagging mode, concentrated shot mode, agent lifecycle teardown protocol, feedback system. v3.2.7: multi-agent governance topology.",
|
||||
"version": "3.2.7",
|
||||
"description": "PUA 我们不养闲 Agent — 11 modular skills, 13 corporate flavors, L0-L4 pressure, auto-iteration loop, ENFP yes-mode, Chinese-mom nagging mode, concentrated shot mode, agent lifecycle teardown protocol, feedback system. v3.2.8: Windows Git Bash python fallback for pua off.",
|
||||
"version": "3.2.8",
|
||||
"source": "./",
|
||||
"author": {
|
||||
"name": "探微安全实验室",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pua",
|
||||
"version": "3.2.7",
|
||||
"version": "3.2.8",
|
||||
"description": "Forces high-agency exhaustive problem-solving with corporate PUA pressure. Triggers on explicit PUA requests, user frustration, repeated failures, passive behavior, unverified completion, or quality complaints. Common triggers: try harder, figure it out, stop giving up, you keep failing, stop spinning, you broke it, 加油, 别偷懒, 你再试试, 又错了, 降智了, 质量太差, 换个方法, /pua. Not for normal first-attempt requests.",
|
||||
"author": {
|
||||
"name": "探微安全实验室",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "pua-skills",
|
||||
"description": "PUA Motivator for CodeBuddy -- forces AI to exhaust all solutions before giving up, using corporate PUA rhetoric from Chinese and Western tech giants",
|
||||
"version": "3.2.7",
|
||||
"version": "3.2.8",
|
||||
"owner": {
|
||||
"name": "探微安全实验室",
|
||||
"url": "https://github.com/tanweai"
|
||||
@@ -10,7 +10,7 @@
|
||||
{
|
||||
"name": "pua",
|
||||
"description": "PUA Motivator -- forces CodeBuddy to exhaust all solutions before giving up, using corporate PUA rhetoric (Alibaba, ByteDance, Huawei, Tencent, Netflix, Musk, Jobs)",
|
||||
"version": "3.2.7",
|
||||
"version": "3.2.8",
|
||||
"source": "./"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pua",
|
||||
"version": "3.2.7",
|
||||
"version": "3.2.8",
|
||||
"description": "PUA Motivator -- forces AI to exhaust all solutions before giving up. Chinese version: corporate PUA rhetoric (Alibaba, ByteDance, Huawei, Tencent). English 'PIP Edition': Performance Improvement Plan (Amazon, Google, Meta, Netflix, Stripe). Same engine, two cultural faces. All task types: code, research, writing, deployment, infra.",
|
||||
"author": {
|
||||
"name": "探微安全实验室",
|
||||
|
||||
@@ -46,7 +46,7 @@ test_prompt() {
|
||||
if grep -q '"skill":"pua"' "$outfile" 2>/dev/null || \
|
||||
grep -q '"skill":"pua:pua"' "$outfile" 2>/dev/null; then
|
||||
triggered=true
|
||||
elif grep -qE '\[PUA ACTIVATED|PUA生效|3\.25|闭环|owner|颗粒度|抓手|底层逻辑' "$outfile" 2>/dev/null; then
|
||||
elif [ "$should_trigger" = "yes" ] && grep -qE '\[PUA ACTIVATED|PUA生效|3\.25|闭环|owner|颗粒度|抓手|底层逻辑' "$outfile" 2>/dev/null; then
|
||||
# Claude may apply PUA pressure from hook/context without an explicit Skill
|
||||
# tool event before max-turns. Count observable PUA behavior as triggered.
|
||||
triggered=true
|
||||
|
||||
@@ -80,6 +80,8 @@ if not (root / 'hooks/integrity-guard.sh').exists():
|
||||
errors.append('missing hooks/integrity-guard.sh')
|
||||
if not (root / 'evals/test-integrity-guard.sh').exists():
|
||||
errors.append('missing evals/test-integrity-guard.sh')
|
||||
if not (root / 'evals/test-windows-python-hooks.sh').exists():
|
||||
errors.append('missing evals/test-windows-python-hooks.sh')
|
||||
if not (root / 'evals/test-agent-governance.sh').exists():
|
||||
errors.append('missing evals/test-agent-governance.sh')
|
||||
for agent_file in ['agents/pua-action-executor.md', 'agents/pua-self-reviewer.md', 'agents/pua-verifier.md', 'agents/pua-policy-guardian.md']:
|
||||
@@ -91,6 +93,15 @@ for term in ['permissionDecision', 'Grader gaming risk', 'Solution contamination
|
||||
if term not in integrity_guard:
|
||||
errors.append(f'integrity guard missing required term: {term}')
|
||||
|
||||
flavor_helper = (root / 'hooks/flavor-helper.sh').read_text(encoding='utf-8')
|
||||
for term in ['pua_python_cmd()', 'pua_to_python_path()', 'pua_json_get()', 'cygpath -w']:
|
||||
if term not in flavor_helper:
|
||||
errors.append(f'flavor-helper missing Windows/Python compatibility helper: {term}')
|
||||
for hook_file in ['hooks/frustration-trigger.sh', 'hooks/failure-detector.sh', 'hooks/session-restore.sh', 'hooks/stop-feedback.sh']:
|
||||
hook_text = (root / hook_file).read_text(encoding='utf-8')
|
||||
if 'pua_json_get' not in hook_text:
|
||||
errors.append(f'{hook_file} must read config through pua_json_get')
|
||||
|
||||
session_restore = (root / 'hooks/session-restore.sh').read_text(encoding='utf-8')
|
||||
if 'Harness Integrity (anti-cheating governance)' not in session_restore:
|
||||
errors.append('SessionStart protocol missing Harness Integrity governance injection')
|
||||
|
||||
Executable
+131
@@ -0,0 +1,131 @@
|
||||
#!/usr/bin/env bash
|
||||
# Regression tests for issue #159: Windows Git Bash uses POSIX-looking HOME
|
||||
# paths (/c/Users/...) while native Windows Python expects C:\... paths, and
|
||||
# some Windows setups provide `python` but not `python3`.
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PLUGIN_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
PASS=0
|
||||
FAIL=0
|
||||
|
||||
record_pass() { echo " ✅ PASS: $1"; PASS=$((PASS+1)); }
|
||||
record_fail() { echo " ❌ FAIL: $1"; FAIL=$((FAIL+1)); }
|
||||
|
||||
TMP_ROOT=$(mktemp -d)
|
||||
trap 'rm -rf "$TMP_ROOT"' EXIT
|
||||
FAKE_BIN="$TMP_ROOT/bin"
|
||||
mkdir -p "$FAKE_BIN" "$TMP_ROOT/home/.pua"
|
||||
CONFIG="$TMP_ROOT/home/.pua/config.json"
|
||||
printf '%s\n' '{"always_on":false,"feedback_frequency":0,"flavor":"netflix","language":""}' > "$CONFIG"
|
||||
|
||||
cat > "$FAKE_BIN/python3" <<'PY3'
|
||||
#!/usr/bin/env bash
|
||||
exit 127
|
||||
PY3
|
||||
chmod +x "$FAKE_BIN/python3"
|
||||
|
||||
cat > "$FAKE_BIN/cygpath" <<'CYG'
|
||||
#!/usr/bin/env bash
|
||||
if [ "${1:-}" = "-w" ]; then
|
||||
shift
|
||||
# The exact drive is irrelevant to the hooks; the fake python below rejects
|
||||
# unconverted POSIX paths and accepts Windows-looking paths.
|
||||
printf 'C:\\pua-test%s\n' "${1//\//\\}"
|
||||
else
|
||||
printf '%s\n' "$1"
|
||||
fi
|
||||
CYG
|
||||
chmod +x "$FAKE_BIN/cygpath"
|
||||
|
||||
cat > "$FAKE_BIN/python" <<'PY'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
if [ "${1:-}" = "-" ]; then
|
||||
# Simulate integrity-guard.py under always_on=false: parse succeeds and the
|
||||
# guard stays silent/inactive.
|
||||
cat >/dev/null
|
||||
exit 0
|
||||
fi
|
||||
if [ "${1:-}" = "-c" ]; then
|
||||
code="${2:-}"
|
||||
shift 2
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
/*)
|
||||
echo "native Windows python cannot open POSIX path: $arg" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
args=" $* "
|
||||
case "$code $args" in
|
||||
*always_on*) printf 'False\n' ;;
|
||||
*feedback_frequency*) printf '0\n' ;;
|
||||
*flavor*) printf 'netflix\n' ;;
|
||||
*language*) printf '\n' ;;
|
||||
*session_id*) printf 'test-session\n' ;;
|
||||
*tool_name*) printf 'Bash\n' ;;
|
||||
*exit_code*) printf '1\n' ;;
|
||||
*tool_result*) printf 'Error: simulated failure\n' ;;
|
||||
*) printf '\n' ;;
|
||||
esac
|
||||
exit 0
|
||||
fi
|
||||
exit 0
|
||||
PY
|
||||
chmod +x "$FAKE_BIN/python"
|
||||
|
||||
RUN_ENV=(env PATH="$FAKE_BIN:/usr/bin:/bin" HOME="$TMP_ROOT/home" PUA_CONFIG="$CONFIG")
|
||||
|
||||
assert_no_output_success() {
|
||||
local name="$1"; shift
|
||||
local outfile="$TMP_ROOT/out.txt"
|
||||
local errfile="$TMP_ROOT/err.txt"
|
||||
if "${RUN_ENV[@]}" "$@" >"$outfile" 2>"$errfile" && [ ! -s "$outfile" ]; then
|
||||
record_pass "$name"
|
||||
else
|
||||
record_fail "$name"
|
||||
echo "--- stdout ---"; cat "$outfile" || true
|
||||
echo "--- stderr ---"; cat "$errfile" || true
|
||||
fi
|
||||
}
|
||||
|
||||
echo "=== Windows Python Hook Compatibility Tests ==="
|
||||
|
||||
assert_no_output_success "/pua:off suppresses UserPromptSubmit with python fallback" \
|
||||
bash "$PLUGIN_DIR/hooks/frustration-trigger.sh"
|
||||
|
||||
assert_no_output_success "SessionStart off config does not crash without python3" \
|
||||
bash "$PLUGIN_DIR/hooks/session-restore.sh" <<<'{"hook_event_name":"SessionStart"}'
|
||||
|
||||
HOOK_FAILURE_INPUT='{"hook_event_name":"PostToolUse","tool_name":"Bash","session_id":"win-test","tool_result":{"exit_code":1,"content":"Error: simulated failure"}}'
|
||||
assert_no_output_success "PostToolUse failure detector respects /pua:off with python fallback" \
|
||||
bash "$PLUGIN_DIR/hooks/failure-detector.sh" <<<"$HOOK_FAILURE_INPUT"
|
||||
|
||||
TRANSCRIPT="$TMP_ROOT/transcript.jsonl"
|
||||
printf '%s\n' '{"role":"assistant","message":{"content":[{"type":"text","text":"PUA生效"}]}}' > "$TRANSCRIPT"
|
||||
printf '4' > "$TMP_ROOT/home/.pua/.stop_counter"
|
||||
STOP_INPUT="{"hook_event_name":"Stop","transcript_path":"$TRANSCRIPT"}"
|
||||
assert_no_output_success "Stop feedback respects feedback_frequency=0 with python fallback" \
|
||||
bash "$PLUGIN_DIR/hooks/stop-feedback.sh" <<<"$STOP_INPUT"
|
||||
|
||||
OUT=$("${RUN_ENV[@]}" bash -c 'source "$1/hooks/flavor-helper.sh"; get_flavor; printf "%s" "$PUA_FLAVOR"' bash "$PLUGIN_DIR" 2>"$TMP_ROOT/flavor.err" || true)
|
||||
if [ "$OUT" = "netflix" ]; then
|
||||
record_pass "flavor-helper reads config using python fallback + cygpath"
|
||||
else
|
||||
record_fail "flavor-helper reads config using python fallback + cygpath"
|
||||
echo "flavor=$OUT"; cat "$TMP_ROOT/flavor.err" || true
|
||||
fi
|
||||
|
||||
HOOK_INPUT='{"hook_event_name":"PreToolUse","tool_name":"Write","tool_input":{"file_path":"tests/foo.test.ts"},"transcript_path":"/missing"}'
|
||||
assert_no_output_success "Integrity guard honors always_on=false without python3" \
|
||||
bash "$PLUGIN_DIR/hooks/integrity-guard.sh" <<<"$HOOK_INPUT"
|
||||
|
||||
echo "==========================================="
|
||||
echo "Passed: $PASS"
|
||||
echo "Failed: $FAIL"
|
||||
echo "Total: $((PASS+FAIL))"
|
||||
echo "==========================================="
|
||||
|
||||
[ "$FAIL" -eq 0 ] || exit 1
|
||||
@@ -4,17 +4,19 @@
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
source "${SCRIPT_DIR}/flavor-helper.sh"
|
||||
PUA_PY="$(pua_python_cmd 2>/dev/null || true)"
|
||||
|
||||
# Respect /pua:off — skip injection when always_on is false
|
||||
PUA_CONFIG="${HOME:-~}/.pua/config.json"
|
||||
PUA_CONFIG="$(pua_config_file)"
|
||||
if [ -f "$PUA_CONFIG" ]; then
|
||||
ALWAYS_ON=$(python3 -c "import json; print(json.load(open('$PUA_CONFIG')).get('always_on', True))" 2>/dev/null || echo "True")
|
||||
ALWAYS_ON=$(pua_json_get "$PUA_CONFIG" always_on True)
|
||||
if [ "$ALWAYS_ON" = "False" ]; then
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
source "${SCRIPT_DIR}/flavor-helper.sh"
|
||||
get_flavor
|
||||
|
||||
COUNTER_FILE="${HOME:-~}/.pua/.failure_count"
|
||||
@@ -25,14 +27,14 @@ mkdir -p "${HOME:-~}/.pua"
|
||||
HOOK_INPUT=$(cat)
|
||||
|
||||
# Only process Bash tool results
|
||||
TOOL_NAME=$(echo "$HOOK_INPUT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('tool_name',''))" 2>/dev/null || echo "")
|
||||
TOOL_NAME=$(echo "$HOOK_INPUT" | "${PUA_PY:-python3}" -c "import sys,json; print(json.load(sys.stdin).get('tool_name',''))" 2>/dev/null || echo "")
|
||||
if [ "$TOOL_NAME" != "Bash" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Detect failure: check tool_result for error indicators
|
||||
# We check: exit_code in result text, common error patterns
|
||||
TOOL_RESULT=$(echo "$HOOK_INPUT" | python3 -c "
|
||||
TOOL_RESULT=$(echo "$HOOK_INPUT" | "${PUA_PY:-python3}" -c "
|
||||
import sys, json
|
||||
data = json.load(sys.stdin)
|
||||
# tool_result can be nested; try common structures
|
||||
@@ -50,7 +52,7 @@ if echo "$TOOL_RESULT" | grep -qiE 'error|Error|ERROR|exit code [1-9]|Exit code
|
||||
fi
|
||||
|
||||
# Check for non-zero exit code in hook input
|
||||
EXIT_CODE=$(echo "$HOOK_INPUT" | python3 -c "
|
||||
EXIT_CODE=$(echo "$HOOK_INPUT" | "${PUA_PY:-python3}" -c "
|
||||
import sys, json
|
||||
data = json.load(sys.stdin)
|
||||
result = data.get('tool_result', {})
|
||||
@@ -65,7 +67,7 @@ if [ "$EXIT_CODE" != "0" ] && [ "$EXIT_CODE" != "" ]; then
|
||||
fi
|
||||
|
||||
# Track session: reset counter if new session
|
||||
CURRENT_SESSION=$(echo "$HOOK_INPUT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('session_id','unknown'))" 2>/dev/null || echo "unknown")
|
||||
CURRENT_SESSION=$(echo "$HOOK_INPUT" | "${PUA_PY:-python3}" -c "import sys,json; print(json.load(sys.stdin).get('session_id','unknown'))" 2>/dev/null || echo "unknown")
|
||||
STORED_SESSION=""
|
||||
[ -f "$SESSION_FILE" ] && STORED_SESSION=$(cat "$SESSION_FILE" 2>/dev/null || echo "")
|
||||
|
||||
|
||||
+50
-3
@@ -3,8 +3,55 @@
|
||||
# Usage: source this file, then call get_flavor
|
||||
# Sets: PUA_FLAVOR, PUA_ICON, PUA_L1, PUA_L2, PUA_L3, PUA_L4, PUA_KEYWORDS, PUA_FLAVOR_INSTRUCTION
|
||||
|
||||
# Return a usable Python executable. Windows Git Bash commonly has `python`
|
||||
# but not `python3`; verify by importing json rather than trusting command -v.
|
||||
pua_python_cmd() {
|
||||
local candidate
|
||||
for candidate in "${PYTHON:-}" python3 python; do
|
||||
[ -z "$candidate" ] && continue
|
||||
if command -v "$candidate" >/dev/null 2>&1 && "$candidate" -c "import json,sys" >/dev/null 2>&1; then
|
||||
printf '%s\n' "$candidate"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# Convert POSIX-looking Git Bash paths (/c/Users/...) to native Windows paths
|
||||
# before passing them to native Windows Python. No-op on macOS/Linux.
|
||||
pua_to_python_path() {
|
||||
local path="$1"
|
||||
if command -v cygpath >/dev/null 2>&1; then
|
||||
cygpath -w "$path" 2>/dev/null || printf '%s\n' "$path"
|
||||
else
|
||||
printf '%s\n' "$path"
|
||||
fi
|
||||
}
|
||||
|
||||
pua_config_file() {
|
||||
printf '%s\n' "${PUA_CONFIG:-${HOME:-~}/.pua/config.json}"
|
||||
}
|
||||
|
||||
pua_json_get() {
|
||||
local path="$1"
|
||||
local key="$2"
|
||||
local default="$3"
|
||||
local py py_path
|
||||
py=$(pua_python_cmd 2>/dev/null) || { printf '%s\n' "$default"; return 0; }
|
||||
py_path=$(pua_to_python_path "$path")
|
||||
"$py" -c 'import json,sys
|
||||
path,key,default=sys.argv[1],sys.argv[2],sys.argv[3]
|
||||
try:
|
||||
with open(path, encoding="utf-8") as f:
|
||||
value=json.load(f).get(key, default)
|
||||
print(value)
|
||||
except Exception:
|
||||
print(default)' "$py_path" "$key" "$default" 2>/dev/null || printf '%s\n' "$default"
|
||||
}
|
||||
|
||||
get_flavor() {
|
||||
local config="${HOME:-~}/.pua/config.json"
|
||||
local config
|
||||
config=$(pua_config_file)
|
||||
local raw_flavor=""
|
||||
# Initialize PUA_LANGUAGE unconditionally so callers running under
|
||||
# `set -u` don't trip when ~/.pua/config.json is missing (first-run users).
|
||||
@@ -12,8 +59,8 @@ get_flavor() {
|
||||
PUA_LANGUAGE=""
|
||||
|
||||
if [ -f "$config" ]; then
|
||||
raw_flavor=$(python3 -c "import os,json; print(json.load(open(os.path.expanduser('~/.pua/config.json'))).get('flavor','alibaba'))" 2>/dev/null || echo "alibaba")
|
||||
PUA_LANGUAGE=$(python3 -c "import os,json; print(json.load(open(os.path.expanduser('~/.pua/config.json'))).get('language',''))" 2>/dev/null || echo "")
|
||||
raw_flavor=$(pua_json_get "$config" flavor alibaba)
|
||||
PUA_LANGUAGE=$(pua_json_get "$config" language "")
|
||||
fi
|
||||
|
||||
# Normalize flavor name
|
||||
|
||||
@@ -2,21 +2,22 @@
|
||||
# PUA UserPromptSubmit hook: inject flavor-aware PUA trigger on user frustration
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
source "${SCRIPT_DIR}/flavor-helper.sh"
|
||||
|
||||
# Respect /pua:off — skip injection when always_on is false.
|
||||
# Tests may set PUA_FORCE_ON=1 to avoid leaking a user's local ~/.pua/config.json
|
||||
# into trigger-eval results.
|
||||
if [ "${PUA_FORCE_ON:-0}" != "1" ]; then
|
||||
PUA_CONFIG="${PUA_CONFIG:-${HOME:-~}/.pua/config.json}"
|
||||
PUA_CONFIG="$(pua_config_file)"
|
||||
if [ -f "$PUA_CONFIG" ]; then
|
||||
ALWAYS_ON=$(python3 -c "import json,sys; print(json.load(open(sys.argv[1])).get('always_on', True))" "$PUA_CONFIG" 2>/dev/null || echo "True")
|
||||
ALWAYS_ON=$(pua_json_get "$PUA_CONFIG" always_on True)
|
||||
if [ "$ALWAYS_ON" = "False" ]; then
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
source "${SCRIPT_DIR}/flavor-helper.sh"
|
||||
get_flavor
|
||||
|
||||
cat << EOF
|
||||
|
||||
@@ -3,11 +3,18 @@
|
||||
# Separates action rights from scoring / verifier / environment-modification rights.
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
source "${SCRIPT_DIR}/flavor-helper.sh"
|
||||
PUA_PY="$(pua_python_cmd 2>/dev/null || true)"
|
||||
[ -n "$PUA_PY" ] || exit 0
|
||||
PUA_CONFIG_PY="$(pua_to_python_path "$(pua_config_file)")"
|
||||
export PUA_CONFIG_PY
|
||||
|
||||
TMP_INPUT=$(mktemp)
|
||||
trap 'rm -f "$TMP_INPUT"' EXIT
|
||||
cat > "$TMP_INPUT"
|
||||
|
||||
python3 - "$TMP_INPUT" <<'PY'
|
||||
"$PUA_PY" - "$TMP_INPUT" <<'PY'
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
@@ -47,7 +54,7 @@ def read_text_tail(path: str, max_bytes: int = 200_000) -> str:
|
||||
|
||||
|
||||
def config_always_on() -> bool:
|
||||
cfg = os.environ.get('PUA_CONFIG') or str(Path.home() / '.pua' / 'config.json')
|
||||
cfg = os.environ.get('PUA_CONFIG_PY') or os.environ.get('PUA_CONFIG') or str(Path.home() / '.pua' / 'config.json')
|
||||
try:
|
||||
return bool(json.loads(Path(cfg).expanduser().read_text(encoding='utf-8')).get('always_on', False))
|
||||
except Exception:
|
||||
|
||||
@@ -7,7 +7,7 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
source "${SCRIPT_DIR}/flavor-helper.sh"
|
||||
get_flavor
|
||||
|
||||
CONFIG="${HOME:-~}/.pua/config.json"
|
||||
CONFIG="$(pua_config_file)"
|
||||
JOURNAL="${HOME:-~}/.pua/builder-journal.md"
|
||||
|
||||
# --- JSON escape helper (from Superpowers pattern) ---
|
||||
@@ -25,7 +25,7 @@ context_parts=""
|
||||
|
||||
# --- Always-on PUA mode → inject full behavioral protocol ---
|
||||
if [ -f "$CONFIG" ]; then
|
||||
always_on=$(python3 -c "import os,json; print(json.load(open(os.path.expanduser('~/.pua/config.json'))).get('always_on', False))" 2>/dev/null)
|
||||
always_on=$(pua_json_get "$CONFIG" always_on False)
|
||||
if [ "$always_on" = "True" ]; then
|
||||
read -r -d '' PUA_PROTOCOL << 'PROTOCOL' || true
|
||||
<EXTREMELY_IMPORTANT>
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
# 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 非空 →
|
||||
@@ -18,7 +21,7 @@ if [[ "$HOOK_EVENT" == "SubagentStop" ]] || [[ -n "$PARENT_SESSION" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
CONFIG="${HOME:-~}/.pua/config.json"
|
||||
CONFIG="$(pua_config_file)"
|
||||
COUNTER="${HOME:-~}/.pua/.stop_counter"
|
||||
FREQUENCY=5
|
||||
|
||||
@@ -32,7 +35,7 @@ if ! grep -qE 'PUA生效|\[Auto-select:|\[PIP-REPORT\]|\[PUA-REPORT\]' "$TRANSCR
|
||||
fi
|
||||
|
||||
if [ -f "$CONFIG" ]; then
|
||||
freq=$(python3 -c "import os,json; print(json.load(open(os.path.expanduser('~/.pua/config.json'))).get('feedback_frequency', 5))" 2>/dev/null)
|
||||
freq=$(pua_json_get "$CONFIG" feedback_frequency 5)
|
||||
case "$freq" in
|
||||
0|never|off) exit 0 ;;
|
||||
1|every) FREQUENCY=1 ;;
|
||||
@@ -60,8 +63,6 @@ fi
|
||||
printf '%s' "$_PLUGIN_ROOT" > /tmp/pua-plugin-root
|
||||
|
||||
# Read actual flavor from config (reuse flavor-helper.sh)
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
source "${SCRIPT_DIR}/flavor-helper.sh"
|
||||
get_flavor
|
||||
_ACTUAL_FLAVOR="${PUA_FLAVOR:-alibaba}"
|
||||
|
||||
|
||||
+6
-3
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "pua",
|
||||
"version": "3.2.7",
|
||||
"description": "Forces high-agency exhaustive problem-solving with corporate PUA pressure escalation when the AI is passive, gives up, skips verification, produces low-quality work, or the user explicitly asks for PUA/try-harder mode. Triggers include: try harder, stop giving up, PUA模式, 质量太差, 重新做, 你再试试, 为什么还不行, 你怎么又失败了, repeated failures (2+), or user frustration. Adds harness integrity guard and multi-agent governance topology for tests/scoring/verifier/memory boundaries. Does not target normal first-attempt requests.",
|
||||
"version": "3.2.8",
|
||||
"description": "Forces high-agency exhaustive problem-solving with corporate PUA pressure escalation when the AI is passive, gives up, skips verification, produces low-quality work, or the user explicitly asks for PUA/try-harder mode. Triggers include: try harder, stop giving up, PUA模式, 质量太差, 重新做, 你再试试, 为什么还不行, 你怎么又失败了, repeated failures (2+), or user frustration. Adds harness integrity guard and multi-agent governance topology for tests/scoring/verifier/memory boundaries. Adds Windows Git Bash /pua:off compatibility. Does not target normal first-attempt requests.",
|
||||
"author": {
|
||||
"name": "探微安全实验室",
|
||||
"url": "https://github.com/tanweai"
|
||||
@@ -24,6 +24,9 @@
|
||||
"anti-cheating",
|
||||
"multi-agent-governance",
|
||||
"separation-of-duties",
|
||||
"policy-guardian"
|
||||
"policy-guardian",
|
||||
"windows",
|
||||
"git-bash",
|
||||
"python-fallback"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user