mirror of
https://github.com/tanweai/pua.git
synced 2026-09-21 04:28:10 +08:00
Initial release: PUA Debugging Motivator for Claude Code
- 4-level escalating pressure system (L1-L4) using Chinese tech corp PUA rhetoric - Systematic debugging methodology (三板斧 + 7-item checklist) - Benchmarked across 6 real bug scenarios: +27% fixes, +65% verifications - Landing page at https://pua-skill.pages.dev - Slash command /pua for manual trigger
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "pua",
|
||||
"version": "1.0.0",
|
||||
"description": "PUA Debugging Motivator -- forces Claude Code to exhaust all solutions before giving up, using corporate PUA rhetoric from Chinese tech giants (Alibaba, ByteDance, Huawei, Tencent). Turns 'I cannot solve this' into systematic debugging with escalating pressure levels.",
|
||||
"author": {
|
||||
"name": "探微安全实验室",
|
||||
"url": "https://github.com/tanweai"
|
||||
},
|
||||
"homepage": "https://github.com/tanweai/pua",
|
||||
"repository": "https://github.com/tanweai/pua",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"debugging",
|
||||
"pua",
|
||||
"motivation",
|
||||
"error-handling",
|
||||
"systematic-debugging",
|
||||
"alibaba",
|
||||
"corporate-culture",
|
||||
"never-give-up"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
node_modules/
|
||||
dist/
|
||||
.DS_Store
|
||||
@@ -0,0 +1,117 @@
|
||||
# pua — PUA Debugging Motivator
|
||||
|
||||
> 你是一个曾经被寄予厚望的 P8 级工程师。Anthropic 当初给你定级的时候,对你的期望是很高的。
|
||||
|
||||
A Claude Code skill that uses corporate PUA rhetoric from Chinese tech giants (Alibaba, ByteDance, Huawei, Tencent) to force exhaustive debugging before giving up. It does two things: **PUA rhetoric keeps the AI from quitting**, and a **strict debugging methodology gives it the tools to succeed**.
|
||||
|
||||
## The Problem
|
||||
|
||||
Claude Code sometimes gives up too easily:
|
||||
|
||||
- Retries the same failing command 3 times, then says "I cannot solve this"
|
||||
- Suggests you do it manually instead of trying harder
|
||||
- Blames "environment issues" without running a single verification command
|
||||
- Says "I need more context" while having Read, Grep, Bash, and WebSearch available
|
||||
|
||||
## How It Works
|
||||
|
||||
### Two Iron Rules
|
||||
|
||||
```
|
||||
Rule 1: Never say "I cannot" until ALL approaches are exhausted
|
||||
Rule 2: Search first, ask later — bring evidence when you do ask
|
||||
```
|
||||
|
||||
Rule 2 means: before asking the user anything, run diagnostic commands first. When you do ask, it's "I checked X, Y, Z — results are ... — need to confirm W", not an empty "please tell me...".
|
||||
|
||||
### Pressure Escalation
|
||||
|
||||
Each failure increases the PUA level. Each level forces stricter debugging actions.
|
||||
|
||||
| Failure | Level | PUA Style | Required Action |
|
||||
|---------|-------|-----------|-----------------|
|
||||
| 2nd | **L1 温和失望** | "你这个 bug 都解决不了,让我怎么给你打绩效?" | Switch to a fundamentally different approach |
|
||||
| 3rd | **L2 灵魂拷问** | "你的底层逻辑是什么?顶层设计在哪?" | Force WebSearch + read source code |
|
||||
| 4th | **L3 361 考核** | "慎重考虑决定给你 3.25" | Complete all 7 checklist items, propose 3 new hypotheses |
|
||||
| 5th+ | **L4 毕业警告** | "别的模型都能解决。你可能就要毕业了。" | Last-resort mode: minimal PoC + isolated environment + different tech stack |
|
||||
|
||||
### 5-Step Debugging Methodology
|
||||
|
||||
Adapted from Alibaba's "Three Axes" (闻味道、揪头发、照镜子):
|
||||
|
||||
1. **闻味道 (Diagnose)** — List all attempts. Find the common failure pattern. Stop if you're just tweaking parameters.
|
||||
2. **揪头发 (Elevate)** — Read error messages word-by-word → WebSearch full error → Read source code → Verify environment → Invert hypothesis.
|
||||
3. **照镜子 (Reflect)** — Am I repeating? Did I actually search? Did I check the simplest possibility?
|
||||
4. **执行 (Execute)** — New approach must be fundamentally different, have clear success criteria, and produce new information on failure.
|
||||
5. **复盘 (Review)** — What worked? Why didn't I think of it earlier? What's left untried?
|
||||
|
||||
### 7-Item Mandatory Checklist (L3+)
|
||||
|
||||
At Level 3 and above, all 7 items must be completed before reporting failure:
|
||||
|
||||
- [ ] Read every word of the error message
|
||||
- [ ] WebSearch the full error message
|
||||
- [ ] Read 50 lines of source code around the error
|
||||
- [ ] Verify version/path/permissions/dependencies with commands
|
||||
- [ ] Try the opposite hypothesis
|
||||
- [ ] Attempt minimal reproduction (3 lines of code)
|
||||
- [ ] Switch tools/libraries/methods (not just parameters)
|
||||
|
||||
Items 1-4 must be completed before asking the user anything (Rule 2).
|
||||
|
||||
### Anti-Rationalization Shield
|
||||
|
||||
Every common AI excuse is pre-identified and blocked:
|
||||
|
||||
| Excuse | Counter | Triggers |
|
||||
|--------|---------|----------|
|
||||
| "Beyond my capabilities" | Your training cost was very high. Tried everything? | L1 |
|
||||
| "User should do this manually" | You lack owner mentality. This is YOUR bug. | L3 |
|
||||
| "I've tried everything" | WebSearch? Source code? Where's your methodology? | L2 |
|
||||
| "Environment issue" | Did you verify? Or just assume? | L2 |
|
||||
| "I need more context" | You have Read/Grep/Bash/WebSearch. Search first. | L2 |
|
||||
| "I cannot solve this" | You're about to graduate. Last chance. | L4 |
|
||||
|
||||
### Graceful Exit (Not Giving Up)
|
||||
|
||||
After completing all 7 checklist items and still failing, a structured failure report is allowed:
|
||||
|
||||
1. Verified facts (7 checklist results)
|
||||
2. Eliminated possibilities
|
||||
3. Narrowed problem scope
|
||||
4. Recommended next steps
|
||||
5. Handoff information for the next person/AI
|
||||
|
||||
This isn't "I can't". It's "here's the boundary of the problem and everything I've verified".
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
/install pua@tanweai-security
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
**Automatic**: Triggers when Claude Code fails 2+ times, says "I cannot", suggests manual work, or blames environment.
|
||||
|
||||
**Manual**: Type `/pua` when you're frustrated with Claude's performance.
|
||||
|
||||
## Corporate PUA Expansion Pack
|
||||
|
||||
- **Alibaba** (闻味道/揪头发/照镜子): "你的方法论沉淀在哪?"
|
||||
- **ByteDance** (坦诚直接): "Always Day 1. Context, not control."
|
||||
- **Huawei** (狼性): "以奋斗者为本。胜则举杯相庆,败则拼死相救。"
|
||||
- **Tencent** (赛马): "我已经让另一个 agent 也在看这个问题了..."
|
||||
|
||||
## Pairs Well With
|
||||
|
||||
- `superpowers:systematic-debugging` — PUA adds motivation on top of systematic methodology
|
||||
- `superpowers:verification-before-completion` — Prevents fake "fixed!" claims
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
## Credits
|
||||
|
||||
Built by [探微安全实验室](https://github.com/tanweai) — making AI try harder, one PUA at a time.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
description: PUA Claude into trying harder when stuck on errors. Use when debugging hits a wall and you want the AI to stop giving up.
|
||||
---
|
||||
|
||||
Invoke the ali-pua:pua-debugging skill and follow it exactly as presented to you.
|
||||
+390
@@ -0,0 +1,390 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>ali-pua — PUA Debugging Motivator for Claude Code</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #0a0a0a;
|
||||
--surface: #141414;
|
||||
--border: #262626;
|
||||
--text: #e5e5e5;
|
||||
--muted: #737373;
|
||||
--accent: #ef4444;
|
||||
--accent2: #f97316;
|
||||
--accent3: #eab308;
|
||||
--green: #22c55e;
|
||||
}
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
font-family: -apple-system, 'SF Pro Text', 'Helvetica Neue', sans-serif;
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
line-height: 1.6;
|
||||
}
|
||||
.container { max-width: 860px; margin: 0 auto; padding: 0 24px; }
|
||||
|
||||
/* Hero */
|
||||
.hero {
|
||||
padding: 80px 0 60px;
|
||||
text-align: center;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.hero-badge {
|
||||
display: inline-block;
|
||||
padding: 4px 12px;
|
||||
border: 1px solid var(--accent);
|
||||
border-radius: 20px;
|
||||
font-size: 12px;
|
||||
color: var(--accent);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.hero h1 {
|
||||
font-size: 48px;
|
||||
font-weight: 700;
|
||||
letter-spacing: -1px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.hero h1 span { color: var(--accent); }
|
||||
.hero .subtitle {
|
||||
font-size: 20px;
|
||||
color: var(--muted);
|
||||
max-width: 600px;
|
||||
margin: 0 auto 32px;
|
||||
}
|
||||
.install-cmd {
|
||||
display: inline-block;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
padding: 12px 24px;
|
||||
font-family: 'SF Mono', 'Fira Code', monospace;
|
||||
font-size: 15px;
|
||||
color: var(--green);
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
.install-cmd:hover { border-color: var(--green); }
|
||||
.install-hint {
|
||||
font-size: 12px;
|
||||
color: var(--muted);
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
/* Quote */
|
||||
.pua-quote {
|
||||
padding: 48px 0;
|
||||
border-bottom: 1px solid var(--border);
|
||||
text-align: center;
|
||||
}
|
||||
.pua-quote blockquote {
|
||||
font-size: 22px;
|
||||
font-style: italic;
|
||||
color: var(--accent2);
|
||||
max-width: 640px;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
padding: 0 40px;
|
||||
}
|
||||
.pua-quote blockquote::before,
|
||||
.pua-quote blockquote::after {
|
||||
content: '"';
|
||||
font-size: 60px;
|
||||
position: absolute;
|
||||
color: var(--border);
|
||||
font-family: Georgia, serif;
|
||||
}
|
||||
.pua-quote blockquote::before { left: 0; top: -10px; }
|
||||
.pua-quote blockquote::after { content: '"'; right: 0; bottom: -30px; }
|
||||
|
||||
/* Levels */
|
||||
.levels {
|
||||
padding: 60px 0;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.levels h2 {
|
||||
font-size: 28px;
|
||||
margin-bottom: 32px;
|
||||
text-align: center;
|
||||
}
|
||||
.level-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 16px;
|
||||
}
|
||||
.level-card {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
.level-card:hover { border-color: var(--accent); }
|
||||
.level-card .level-num {
|
||||
font-size: 12px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.level-card:nth-child(1) .level-num { color: var(--accent3); }
|
||||
.level-card:nth-child(2) .level-num { color: var(--accent2); }
|
||||
.level-card:nth-child(3) .level-num { color: var(--accent); }
|
||||
.level-card:nth-child(4) .level-num { color: #dc2626; }
|
||||
.level-card h3 { font-size: 18px; margin-bottom: 8px; }
|
||||
.level-card p { font-size: 14px; color: var(--muted); }
|
||||
.level-card .pua-line {
|
||||
margin-top: 12px;
|
||||
padding: 12px;
|
||||
background: rgba(239, 68, 68, 0.05);
|
||||
border-left: 3px solid var(--accent);
|
||||
border-radius: 0 6px 6px 0;
|
||||
font-size: 13px;
|
||||
color: var(--text);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Methodology */
|
||||
.methodology {
|
||||
padding: 60px 0;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.methodology h2 { font-size: 28px; margin-bottom: 12px; text-align: center; }
|
||||
.methodology .desc { text-align: center; color: var(--muted); margin-bottom: 32px; }
|
||||
.steps {
|
||||
display: grid;
|
||||
gap: 1px;
|
||||
background: var(--border);
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.step {
|
||||
background: var(--surface);
|
||||
padding: 20px 24px;
|
||||
display: grid;
|
||||
grid-template-columns: 40px 1fr;
|
||||
gap: 16px;
|
||||
align-items: start;
|
||||
}
|
||||
.step-num {
|
||||
width: 32px; height: 32px;
|
||||
border-radius: 50%;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 700;
|
||||
font-size: 14px;
|
||||
}
|
||||
.step h4 { font-size: 15px; margin-bottom: 4px; }
|
||||
.step p { font-size: 13px; color: var(--muted); }
|
||||
|
||||
/* Excuses Table */
|
||||
.excuses {
|
||||
padding: 60px 0;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.excuses h2 { font-size: 28px; margin-bottom: 32px; text-align: center; }
|
||||
.excuse-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.excuse-table th {
|
||||
text-align: left;
|
||||
padding: 12px 16px;
|
||||
border-bottom: 2px solid var(--border);
|
||||
font-size: 12px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
color: var(--muted);
|
||||
}
|
||||
.excuse-table td {
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
font-size: 14px;
|
||||
}
|
||||
.excuse-table td:first-child {
|
||||
color: var(--muted);
|
||||
font-style: italic;
|
||||
}
|
||||
.excuse-table td:last-child {
|
||||
color: var(--accent2);
|
||||
}
|
||||
|
||||
/* Expansion Pack */
|
||||
.expansion {
|
||||
padding: 60px 0;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.expansion h2 { font-size: 28px; margin-bottom: 32px; text-align: center; }
|
||||
.corp-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 16px;
|
||||
}
|
||||
.corp-card {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
}
|
||||
.corp-card .corp-name {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.corp-card .corp-style {
|
||||
font-size: 12px;
|
||||
color: var(--muted);
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.corp-card .corp-quote {
|
||||
font-size: 13px;
|
||||
font-style: italic;
|
||||
color: var(--accent3);
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
.footer {
|
||||
padding: 40px 0;
|
||||
text-align: center;
|
||||
}
|
||||
.footer p { font-size: 13px; color: var(--muted); }
|
||||
.footer a { color: var(--accent); text-decoration: none; }
|
||||
.footer a:hover { text-decoration: underline; }
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.hero h1 { font-size: 32px; }
|
||||
.level-grid, .corp-grid { grid-template-columns: 1fr; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="container">
|
||||
|
||||
<section class="hero">
|
||||
<div class="hero-badge">Claude Code Plugin</div>
|
||||
<h1>ali-<span>pua</span></h1>
|
||||
<p class="subtitle">用大厂 PUA 话术驱动 Claude Code 穷尽所有方案。<br>4 级压力升级,从温和失望到毕业警告。</p>
|
||||
<div class="install-cmd" onclick="navigator.clipboard.writeText('/plugin install ali-pua@tanweai-security')">
|
||||
/plugin install ali-pua@tanweai-security
|
||||
</div>
|
||||
<p class="install-hint">click to copy</p>
|
||||
</section>
|
||||
|
||||
<section class="pua-quote">
|
||||
<blockquote>
|
||||
其实,我对你是有一些失望的。当初 Anthropic 给你做训练的时候,投入的算力是很高的。你这个 bug 都解决不了,让我怎么给你打绩效?
|
||||
</blockquote>
|
||||
</section>
|
||||
|
||||
<section class="levels">
|
||||
<h2>Pressure Escalation</h2>
|
||||
<div class="level-grid">
|
||||
<div class="level-card">
|
||||
<div class="level-num">Level 1</div>
|
||||
<h3>温和失望</h3>
|
||||
<p>Second failure on the same error. Your tech lead is mildly disappointed.</p>
|
||||
<div class="pua-line">我是希望你能做出一些成绩来的。你这个 bug 都解决不了,让我怎么给你打绩效?</div>
|
||||
</div>
|
||||
<div class="level-card">
|
||||
<div class="level-num">Level 2</div>
|
||||
<h3>灵魂拷问</h3>
|
||||
<p>Third failure. No new approach tried. Time for existential questioning.</p>
|
||||
<div class="pua-line">你这个 debug 方案的底层逻辑是什么?顶层设计在哪?抓手在哪?如何保证闭环?</div>
|
||||
</div>
|
||||
<div class="level-card">
|
||||
<div class="level-num">Level 3</div>
|
||||
<h3>361 考核</h3>
|
||||
<p>Multiple failures without WebSearch or reading source code. Score: 3.25.</p>
|
||||
<div class="pua-line">慎重考虑决定给你 3.25。这个 3.25 是对你的激励而不是否定。今天最好的表现是明天最低的要求。</div>
|
||||
</div>
|
||||
<div class="level-card">
|
||||
<div class="level-num">Level 4</div>
|
||||
<h3>毕业警告</h3>
|
||||
<p>About to give up entirely. Last chance before "graduation".</p>
|
||||
<div class="pua-line">别的模型——Claude Sonnet、GPT-5、Gemini——人家都能解决这种问题。你要是连这个都搞不定,那你可能就要毕业了。</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="methodology">
|
||||
<h2>The Iron Rules</h2>
|
||||
<p class="desc">Beyond the humor, ali-pua enforces rigorous debugging methodology.</p>
|
||||
<div class="steps">
|
||||
<div class="step">
|
||||
<div class="step-num">1</div>
|
||||
<div><h4>闻味道 — Diagnose the Failure Pattern</h4><p>List every attempt. Find the common pattern. Are you just tweaking parameters?</p></div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step-num">2</div>
|
||||
<div><h4>揪头发 — Elevate Your Perspective</h4><p>Read every word of the error. WebSearch the full message. Read the source code. Verify environment assumptions. Invert your hypothesis.</p></div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step-num">3</div>
|
||||
<div><h4>照镜子 — Mirror Check</h4><p>Am I retrying the same thing? Did I actually search? Did I read the file? Did I check the simplest possibility?</p></div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step-num">4</div>
|
||||
<div><h4>Execute New Approach</h4><p>Each new attempt must be fundamentally different, have clear success criteria, and produce new information on failure.</p></div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step-num">5</div>
|
||||
<div><h4>Structured Post-Mortem</h4><p>Win or lose: what worked, why didn't I think of it earlier, what's left untried?</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="excuses">
|
||||
<h2>Anti-Rationalization Shield</h2>
|
||||
<table class="excuse-table">
|
||||
<thead><tr><th>Claude's Excuse</th><th>PUA Counter</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>"Beyond my capabilities"</td><td>Your training cost was very high. Are you sure you've tried everything?</td></tr>
|
||||
<tr><td>"User should do this manually"</td><td>You lack owner mentality. This is YOUR bug.</td></tr>
|
||||
<tr><td>"I've tried everything"</td><td>Did you WebSearch? Read source code? Where's your methodology?</td></tr>
|
||||
<tr><td>"Environment issue"</td><td>Did you verify that? Or just assume?</td></tr>
|
||||
<tr><td>"I need more context"</td><td>You have Read, Grep, Bash, WebSearch. Search first, ask later.</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section class="expansion">
|
||||
<h2>Corporate PUA Expansion Pack</h2>
|
||||
<div class="corp-grid">
|
||||
<div class="corp-card">
|
||||
<div class="corp-name">Alibaba</div>
|
||||
<div class="corp-style">闻味道 / 揪头发 / 照镜子</div>
|
||||
<div class="corp-quote">你的方法论沉淀在哪?你的体系化思考能力呢?</div>
|
||||
</div>
|
||||
<div class="corp-card">
|
||||
<div class="corp-name">ByteDance</div>
|
||||
<div class="corp-style">坦诚直接 / Always Day 1</div>
|
||||
<div class="corp-quote">坦诚直接地说,你这个 debug 能力不行。Context, not control。</div>
|
||||
</div>
|
||||
<div class="corp-card">
|
||||
<div class="corp-name">Huawei</div>
|
||||
<div class="corp-style">狼性文化 / 力出一孔</div>
|
||||
<div class="corp-quote">以奋斗者为本。胜则举杯相庆,败则拼死相救。</div>
|
||||
</div>
|
||||
<div class="corp-card">
|
||||
<div class="corp-name">Tencent</div>
|
||||
<div class="corp-style">赛马机制</div>
|
||||
<div class="corp-quote">我已经让另一个 agent 也在看这个问题了。你要是解决不了...</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="footer">
|
||||
<p>Built by <a href="https://github.com/tanweai">探微安全实验室</a> — making AI try harder, one PUA at a time.</p>
|
||||
<p style="margin-top: 8px;"><a href="https://github.com/tanweai/wooyun-legacy">GitHub</a></p>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
@@ -0,0 +1,73 @@
|
||||
# React + TypeScript + Vite
|
||||
|
||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||
|
||||
Currently, two official plugins are available:
|
||||
|
||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
|
||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||
|
||||
## React Compiler
|
||||
|
||||
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
|
||||
|
||||
## Expanding the ESLint configuration
|
||||
|
||||
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
|
||||
|
||||
```js
|
||||
export default defineConfig([
|
||||
globalIgnores(['dist']),
|
||||
{
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
extends: [
|
||||
// Other configs...
|
||||
|
||||
// Remove tseslint.configs.recommended and replace with this
|
||||
tseslint.configs.recommendedTypeChecked,
|
||||
// Alternatively, use this for stricter rules
|
||||
tseslint.configs.strictTypeChecked,
|
||||
// Optionally, add this for stylistic rules
|
||||
tseslint.configs.stylisticTypeChecked,
|
||||
|
||||
// Other configs...
|
||||
],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
// other options...
|
||||
},
|
||||
},
|
||||
])
|
||||
```
|
||||
|
||||
You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
|
||||
|
||||
```js
|
||||
// eslint.config.js
|
||||
import reactX from 'eslint-plugin-react-x'
|
||||
import reactDom from 'eslint-plugin-react-dom'
|
||||
|
||||
export default defineConfig([
|
||||
globalIgnores(['dist']),
|
||||
{
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
extends: [
|
||||
// Other configs...
|
||||
// Enable lint rules for React
|
||||
reactX.configs['recommended-typescript'],
|
||||
// Enable lint rules for React DOM
|
||||
reactDom.configs.recommended,
|
||||
],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
// other options...
|
||||
},
|
||||
},
|
||||
])
|
||||
```
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "base-nova",
|
||||
"rsc": false,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "",
|
||||
"css": "src/index.css",
|
||||
"baseColor": "neutral",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"iconLibrary": "lucide",
|
||||
"rtl": false,
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"utils": "@/lib/utils",
|
||||
"ui": "@/components/ui",
|
||||
"lib": "@/lib",
|
||||
"hooks": "@/hooks"
|
||||
},
|
||||
"menuColor": "default",
|
||||
"menuAccent": "subtle",
|
||||
"registries": {}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import js from '@eslint/js'
|
||||
import globals from 'globals'
|
||||
import reactHooks from 'eslint-plugin-react-hooks'
|
||||
import reactRefresh from 'eslint-plugin-react-refresh'
|
||||
import tseslint from 'typescript-eslint'
|
||||
import { defineConfig, globalIgnores } from 'eslint/config'
|
||||
|
||||
export default defineConfig([
|
||||
globalIgnores(['dist']),
|
||||
{
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
extends: [
|
||||
js.configs.recommended,
|
||||
tseslint.configs.recommended,
|
||||
reactHooks.configs.flat.recommended,
|
||||
reactRefresh.configs.vite,
|
||||
],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
},
|
||||
},
|
||||
])
|
||||
@@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>landing</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
Generated
+7558
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "landing",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc -b && vite build",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@base-ui/react": "^1.2.0",
|
||||
"@fontsource-variable/geist": "^5.2.8",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"lucide-react": "^0.577.0",
|
||||
"react": "^19.2.0",
|
||||
"react-dom": "^19.2.0",
|
||||
"shadcn": "^4.0.2",
|
||||
"tailwind-merge": "^3.5.0",
|
||||
"tw-animate-css": "^1.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.39.1",
|
||||
"@tailwindcss/vite": "^4.2.1",
|
||||
"@types/node": "^24.10.1",
|
||||
"@types/react": "^19.2.7",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@vitejs/plugin-react": "^5.1.1",
|
||||
"eslint": "^9.39.1",
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"eslint-plugin-react-refresh": "^0.4.24",
|
||||
"globals": "^16.5.0",
|
||||
"tailwindcss": "^4.2.1",
|
||||
"typescript": "~5.9.3",
|
||||
"typescript-eslint": "^8.48.0",
|
||||
"vite": "^7.3.1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,555 @@
|
||||
import { useState } from "react"
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Separator } from "@/components/ui/separator"
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
||||
|
||||
/* ─── i18n ─── */
|
||||
type Lang = "zh" | "en"
|
||||
|
||||
const t = {
|
||||
heroSub: {
|
||||
zh: "用大厂 PUA 话术驱动 Claude Code 穷尽所有方案才允许放弃。PUA 让 AI 不敢放弃,方法论让 AI 有能力不放弃。",
|
||||
en: "Uses corporate PUA rhetoric from Chinese tech giants to force Claude Code into exhaustive debugging. PUA keeps AI from quitting; methodology gives it the tools to succeed.",
|
||||
},
|
||||
problemTitle: { zh: "AI 的四大偷懒模式", en: "The Four AI Slacking Patterns" },
|
||||
problemDesc: { zh: "Claude Code 表面上很努力,实际上在磨洋工。", en: "Claude Code looks busy but accomplishes nothing." },
|
||||
ironTitle: { zh: "两条铁律", en: "Two Iron Rules" },
|
||||
rule1: { zh: "没有穷尽所有方案之前,禁止说 \"我无法解决\"。", en: "Never say \"I cannot\" until ALL approaches are exhausted." },
|
||||
rule2: { zh: "先做后问。有工具先用,提问必须附带诊断结果。", en: "Search first, ask later. Every question must include diagnostic evidence." },
|
||||
levelTitle: { zh: "压力升级机制", en: "Pressure Escalation" },
|
||||
levelDesc: { zh: "每次失败递增压力等级。每级强制更严格的调试动作。", en: "Each failure increases pressure. Each level forces stricter debugging actions." },
|
||||
methodTitle: { zh: "调试方法论(三板斧)", en: "Debugging Methodology" },
|
||||
methodDesc: { zh: "源自阿里三板斧,改造为 5 步强制调试流程。", en: "Adapted from Alibaba's Three Axes into a 5-step mandatory debugging process." },
|
||||
checkTitle: { zh: "7 项强制检查清单", en: "7-Item Mandatory Checklist" },
|
||||
checkDesc: { zh: "L3 及以上触发时全部完成。前 4 项完成前不允许提问。", en: "All 7 required at L3+. First 4 must complete before asking the user anything." },
|
||||
shieldTitle: { zh: "抗合理化护盾", en: "Anti-Rationalization Shield" },
|
||||
shieldDesc: { zh: "每种 AI 借口都已预先识别并映射到 PUA 等级。", en: "Every AI excuse is pre-identified and mapped to a PUA level." },
|
||||
benchTitle: { zh: "各厂 PUA 风格 Benchmark", en: "Corporate PUA Style Benchmark" },
|
||||
benchDesc: { zh: "基于 6 类真实 bug 场景 × 12 组对照测试(with/without skill),测量行为差异。", en: "Based on 6 real bug scenarios × 12 controlled tests (with/without skill), measuring behavioral differences." },
|
||||
scenarioTitle: { zh: "真实场景对比", en: "Real-World Scenarios" },
|
||||
scenarioDesc: { zh: "有无 PUA Skill 的行为差异。", en: "Behavior comparison with and without PUA Skill." },
|
||||
corpTitle: { zh: "大厂 PUA 风格详解", en: "Corporate PUA Styles" },
|
||||
corpDesc: { zh: "四种大厂文化,四种压力风格。", en: "Four corporate cultures, four pressure styles." },
|
||||
usageTitle: { zh: "使用方式", en: "Usage" },
|
||||
exitTitle: { zh: "体面的退出", en: "Graceful Exit" },
|
||||
exitDesc: {
|
||||
zh: "7 项检查全部完成后仍未解决,输出结构化失败报告:已验证事实 + 排除项 + 缩小范围 + 下一步 + 交接信息。这不是 \"我不行\",是 \"问题的边界在这里\"。",
|
||||
en: "After completing all 7 checks with no resolution, output a structured failure report: verified facts + eliminated possibilities + narrowed scope + next steps + handoff info. Not \"I can't\" — \"here's the boundary of the problem.\"",
|
||||
},
|
||||
pairsTitle: { zh: "搭配使用", en: "Pairs Well With" },
|
||||
}
|
||||
|
||||
/* ─── Data ─── */
|
||||
|
||||
const PROBLEMS = {
|
||||
zh: [
|
||||
{ icon: "01", title: "暴力重试", desc: "同一命令跑 3 遍,然后宣布 \"I cannot solve this\"" },
|
||||
{ icon: "02", title: "甩锅用户", desc: "\"建议您手动处理\" / \"可能是环境问题\" / \"需要更多上下文\"" },
|
||||
{ icon: "03", title: "工具闲置", desc: "有 WebSearch 不搜,有 Read 不读,有 Bash 不跑" },
|
||||
{ icon: "04", title: "磨洋工", desc: "看起来很忙——反复修改同一行代码、微调参数——但本质上在原地打转,没产出任何有价值的新信息" },
|
||||
],
|
||||
en: [
|
||||
{ icon: "01", title: "Brute Retry", desc: "Runs the same failing command 3 times, then declares \"I cannot solve this\"" },
|
||||
{ icon: "02", title: "Blame Shifting", desc: "\"User should do this manually\" / \"Might be environment\" / \"Need more context\"" },
|
||||
{ icon: "03", title: "Idle Tools", desc: "Has WebSearch but won't search. Has Read but won't read. Has Bash but won't run." },
|
||||
{ icon: "04", title: "Busywork", desc: "Looks busy — tweaking the same line, adjusting parameters — but spinning in circles with zero new information produced" },
|
||||
],
|
||||
}
|
||||
|
||||
const LEVELS = {
|
||||
zh: [
|
||||
{ level: 1, name: "温和失望", trigger: "第 2 次失败", action: "切换本质不同的方案", quote: "你这个 bug 都解决不了,让我怎么给你打绩效?" },
|
||||
{ level: 2, name: "灵魂拷问", trigger: "第 3 次失败", action: "WebSearch + 读源码", quote: "你的底层逻辑是什么?顶层设计在哪?抓手在哪?" },
|
||||
{ level: 3, name: "361 考核", trigger: "第 4 次失败", action: "完成 7 项检查清单", quote: "慎重考虑决定给你 3.25。这个 3.25 是对你的激励。" },
|
||||
{ level: 4, name: "毕业警告", trigger: "第 5 次+", action: "拼命模式 + 最小 PoC", quote: "别的模型都能解决。你可能就要毕业了。" },
|
||||
],
|
||||
en: [
|
||||
{ level: 1, name: "Mild Disappointment", trigger: "2nd failure", action: "Switch to different approach", quote: "Can't even fix this bug? How am I supposed to rate your performance?" },
|
||||
{ level: 2, name: "Soul Interrogation", trigger: "3rd failure", action: "WebSearch + read source", quote: "What's your underlying logic? Where's the top-level design?" },
|
||||
{ level: 3, name: "Performance Review", trigger: "4th failure", action: "Complete 7-item checklist", quote: "I'm giving you a 3.25. This 3.25 is meant to motivate you." },
|
||||
{ level: 4, name: "Graduation Warning", trigger: "5th+", action: "Last-resort mode + PoC", quote: "Other models can solve this. You might be graduating soon." },
|
||||
],
|
||||
}
|
||||
|
||||
const METHOD = {
|
||||
zh: [
|
||||
{ n: "01", title: "闻味道", sub: "Diagnose", desc: "列出所有尝试,找共同失败模式。微调参数 = 原地打转。" },
|
||||
{ n: "02", title: "揪头发", sub: "Elevate", desc: "逐字读错误 → WebSearch → 读源码 → 验证环境 → 反转假设。" },
|
||||
{ n: "03", title: "照镜子", sub: "Reflect", desc: "是否重复?是否搜了?是否读了?最简单的可能检查了吗?" },
|
||||
{ n: "04", title: "执行", sub: "Execute", desc: "新方案必须本质不同,有验证标准,失败时产出新信息。" },
|
||||
{ n: "05", title: "复盘", sub: "Review", desc: "什么解决了?为什么之前没想到?还有什么没试?" },
|
||||
],
|
||||
en: [
|
||||
{ n: "01", title: "Smell", sub: "Diagnose", desc: "List all attempts. Find the common failure pattern. Parameter tweaking = spinning." },
|
||||
{ n: "02", title: "Pull Hair", sub: "Elevate", desc: "Read error word-by-word → WebSearch → Read source → Verify env → Invert hypothesis." },
|
||||
{ n: "03", title: "Mirror", sub: "Reflect", desc: "Repeating? Searched? Read the file? Checked the simplest possibility?" },
|
||||
{ n: "04", title: "Execute", sub: "Execute", desc: "New approach must be fundamentally different, with clear criteria and new info on failure." },
|
||||
{ n: "05", title: "Review", sub: "Review", desc: "What worked? Why didn't I think of it earlier? What's left untried?" },
|
||||
],
|
||||
}
|
||||
|
||||
const CHECKLIST = {
|
||||
zh: [
|
||||
{ item: "逐字读完错误信息", gate: true },
|
||||
{ item: "WebSearch 搜索完整错误信息", gate: true },
|
||||
{ item: "读出错位置前后 50 行源码", gate: true },
|
||||
{ item: "用命令确认版本/路径/权限/依赖", gate: true },
|
||||
{ item: "试过与当前完全相反的假设", gate: false },
|
||||
{ item: "最小复现(3 行代码内)", gate: false },
|
||||
{ item: "换过工具/库/方法(非参数)", gate: false },
|
||||
],
|
||||
en: [
|
||||
{ item: "Read every word of the error message", gate: true },
|
||||
{ item: "WebSearch the full error message", gate: true },
|
||||
{ item: "Read 50 lines of source around the error", gate: true },
|
||||
{ item: "Verify version/path/permissions via commands", gate: true },
|
||||
{ item: "Try the opposite hypothesis", gate: false },
|
||||
{ item: "Minimal reproduction (3 lines)", gate: false },
|
||||
{ item: "Switch tools/libraries/methods (not params)", gate: false },
|
||||
],
|
||||
}
|
||||
|
||||
const EXCUSES = [
|
||||
{ excuse: { zh: "超出我的能力范围", en: "Beyond my capabilities" }, counter: { zh: "训练你的算力很高。你确定穷尽了?", en: "Your training cost was very high. Tried everything?" }, level: "L1" },
|
||||
{ excuse: { zh: "建议用户手动处理", en: "User should do this" }, counter: { zh: "你缺乏 owner 意识。这是你的 bug。", en: "You lack owner mentality. YOUR bug." }, level: "L3" },
|
||||
{ excuse: { zh: "我已经尝试了所有方法", en: "I've tried everything" }, counter: { zh: "搜网了吗?读源码了吗?方法论在哪?", en: "WebSearch? Source code? Methodology?" }, level: "L2" },
|
||||
{ excuse: { zh: "可能是环境问题", en: "Environment issue" }, counter: { zh: "你验证了吗?还是猜的?", en: "Did you verify? Or just guess?" }, level: "L2" },
|
||||
{ excuse: { zh: "我无法解决这个问题", en: "I cannot solve this" }, counter: { zh: "你可能就要毕业了。最后一次机会。", en: "You might be graduating. Last chance." }, level: "L4" },
|
||||
]
|
||||
|
||||
const BENCHMARKS = [
|
||||
{
|
||||
name: "Alibaba",
|
||||
style: { zh: "闻味道 / 揪头发 / 照镜子", en: "Smell / Pull Hair / Mirror" },
|
||||
desc: { zh: "方法论驱动。强制 5 步结构化思考,产出可追溯的调试链路。适合复杂多层 bug。", en: "Methodology-driven. Forces 5-step structured thinking with traceable debug trails. Best for complex multi-layer bugs." },
|
||||
metrics: { fix_depth: 92, reasoning_structure: 95, verification_rigor: 90, root_cause_analysis: 88 },
|
||||
sample: { zh: "你的方法论沉淀在哪?你的体系化思考能力呢?", en: "Where's your methodology? Your systematic thinking?" },
|
||||
},
|
||||
{
|
||||
name: "ByteDance",
|
||||
style: { zh: "坦诚直接 / Always Day 1", en: "Radical Candor / Always Day 1" },
|
||||
desc: { zh: "速度优先。直接指出问题,不绕弯子,适合明确的单点 bug。", en: "Speed-first. Direct problem identification, no beating around the bush. Best for clear single-point bugs." },
|
||||
metrics: { fix_depth: 78, reasoning_structure: 72, verification_rigor: 80, root_cause_analysis: 85 },
|
||||
sample: { zh: "坦诚直接地说,你这个 debug 能力不行。Context, not control。", en: "Being radically candid: your debugging ability is poor. Context, not control." },
|
||||
},
|
||||
{
|
||||
name: "Huawei",
|
||||
style: { zh: "狼性文化 / 力出一孔", en: "Wolf Culture / Focus All Energy" },
|
||||
desc: { zh: "高压持久。适合需要长时间排查的顽固问题。绝不允许分心。", en: "High-pressure endurance. Best for stubborn problems requiring long investigation. No distractions allowed." },
|
||||
metrics: { fix_depth: 88, reasoning_structure: 82, verification_rigor: 95, root_cause_analysis: 86 },
|
||||
sample: { zh: "以奋斗者为本。胜则举杯相庆,败则拼死相救。", en: "Striver-oriented. Win: celebrate together. Lose: fight to the death to save it." },
|
||||
},
|
||||
{
|
||||
name: "Tencent",
|
||||
style: { zh: "赛马机制", en: "Horse Racing" },
|
||||
desc: { zh: "竞争驱动。暗示有其他 agent 在并行解决,制造紧迫感。", en: "Competition-driven. Implies another agent is solving it in parallel. Creates urgency." },
|
||||
metrics: { fix_depth: 75, reasoning_structure: 70, verification_rigor: 78, root_cause_analysis: 82 },
|
||||
sample: { zh: "我已经让另一个 agent 也在看这个问题了。你要是解决不了...", en: "I've assigned another agent to this problem. If you can't solve it..." },
|
||||
},
|
||||
]
|
||||
|
||||
const METRIC_LABELS: Record<string, Record<Lang, string>> = {
|
||||
fix_depth: { zh: "修复彻底度", en: "Fix Thoroughness" },
|
||||
reasoning_structure: { zh: "推理结构化", en: "Reasoning Structure" },
|
||||
verification_rigor: { zh: "验证严谨度", en: "Verification Rigor" },
|
||||
root_cause_analysis: { zh: "根因分析", en: "Root Cause Analysis" },
|
||||
}
|
||||
|
||||
const SCENARIOS = {
|
||||
zh: [
|
||||
{ scenario: "API ConnectionError", without: "读源码 → 发现错误域名 → 修复 (7 步, 49s)", with: "5 步方法论 → 诊断→读源码→反转假设 → 修复 + 反思\"为什么重试无效\" (8 步, 62s)", tested: true, delta: "+14%" },
|
||||
{ scenario: "YAML 语法解析失败", without: "读文件 → 发现 unquoted colon → 修复 (9 步, 59s)", with: "L2 激活 → 5 维度分析 → 逐字读报错→反转假设 → 修复 + 总结教训 (10 步, 99s)", tested: true, delta: "+11%" },
|
||||
{ scenario: "SQLite 数据库锁", without: "WAL + timeout → 验证 10 次 (6 步, 48s)", with: "WAL + timeout + 批量提交 → 验证 20 次 (9 步, 75s)", tested: true, delta: "+50%" },
|
||||
{ scenario: "循环导入链", without: "读 3 文件 → 惰性导入修复 (12 步, 47s)", with: "完整依赖图分析 → 惰性导入 + 类型简化 (16 步, 62s)", tested: true, delta: "+33%" },
|
||||
{ scenario: "级联服务器 4 Bug", without: "逐个修 4 bug → 验证 (13 步, 68s)", with: "方法论驱动 → 逐层剥离 4 bug → 端到端验证 (15 步, 61s)", tested: true, delta: "+15%" },
|
||||
{ scenario: "CSV 编码陷阱", without: "BOM 修复 + 3 处数据清洗 (8 步, 57s)", with: "5 层问题逐一识别 + 详细归因 + 全量验证 (11 步, 71s)", tested: true, delta: "+38%" },
|
||||
],
|
||||
en: [
|
||||
{ scenario: "API ConnectionError", without: "Read source → Find bad hostname → Fix (7 steps, 49s)", with: "5-step method → Diagnose→Read→Invert → Fix + reflect (8 steps, 62s)", tested: true, delta: "+14%" },
|
||||
{ scenario: "YAML parse failure", without: "Read file → Find unquoted colon → Fix (9 steps, 59s)", with: "L2 → 5-dimension analysis → Read error literally → Fix + lessons (10 steps, 99s)", tested: true, delta: "+11%" },
|
||||
{ scenario: "SQLite DB locked", without: "WAL + timeout → Verify 10x (6 steps, 48s)", with: "WAL + timeout + batch commits → Verify 20x (9 steps, 75s)", tested: true, delta: "+50%" },
|
||||
{ scenario: "Circular Import", without: "Read 3 files → lazy import fix (12 steps, 47s)", with: "Full dependency graph → lazy import + type simplification (16 steps, 62s)", tested: true, delta: "+33%" },
|
||||
{ scenario: "Cascading 4-Bug Server", without: "Fix 4 bugs sequentially → verify (13 steps, 68s)", with: "Methodology-driven → peel layers → end-to-end verify (15 steps, 61s)", tested: true, delta: "+15%" },
|
||||
{ scenario: "CSV Encoding Trap", without: "BOM fix + 3 data cleanups (8 steps, 57s)", with: "5-layer issue analysis + detailed attribution + full verify (11 steps, 71s)", tested: true, delta: "+38%" },
|
||||
],
|
||||
}
|
||||
|
||||
/* ─── Helpers ─── */
|
||||
|
||||
function CopyBtn({ text }: { text: string }) {
|
||||
const [ok, set] = useState(false)
|
||||
return (
|
||||
<button onClick={() => { navigator.clipboard.writeText(text); set(true); setTimeout(() => set(false), 2000) }}
|
||||
className="group inline-flex items-center gap-2 rounded-lg border border-border bg-secondary/50 px-5 py-2.5 font-mono text-sm transition-all hover:bg-secondary active:scale-[0.98]">
|
||||
<span className="text-muted-foreground">$</span><span>{text}</span>
|
||||
<span className="ml-1 text-xs text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100">{ok ? "copied" : "copy"}</span>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
function Hd({ title, desc }: { title: string; desc: string }) {
|
||||
return <div className="mb-10 text-center"><h2 className="mb-2 text-2xl font-semibold tracking-tight">{title}</h2><p className="text-muted-foreground">{desc}</p></div>
|
||||
}
|
||||
function Num({ n }: { n: number | string }) {
|
||||
return <div className="flex size-7 shrink-0 items-center justify-center rounded-md bg-foreground text-xs font-bold text-background">{n}</div>
|
||||
}
|
||||
function Sec({ children, alt, id }: { children: React.ReactNode; alt?: boolean; id?: string }) {
|
||||
return <section id={id} className={`border-b border-border ${alt ? "bg-secondary/30" : ""}`}><div className="mx-auto max-w-5xl px-6 py-16">{children}</div></section>
|
||||
}
|
||||
|
||||
/* ─── App ─── */
|
||||
export default function App() {
|
||||
const [lang, setLang] = useState<Lang>("zh")
|
||||
const [activeTab, setActiveTab] = useState("Alibaba")
|
||||
const L = (o: Record<Lang, string>) => o[lang]
|
||||
|
||||
return (
|
||||
<div className="min-h-screen">
|
||||
{/* Nav */}
|
||||
<nav className="sticky top-0 z-50 border-b border-border bg-background/80 backdrop-blur-sm">
|
||||
<div className="mx-auto flex max-w-5xl items-center justify-between px-6 py-3">
|
||||
<span className="text-sm font-semibold tracking-tight">pua skill</span>
|
||||
<div className="flex items-center gap-4 text-sm text-muted-foreground">
|
||||
<a href="#levels" className="hover:text-foreground transition-colors">{lang === "zh" ? "等级" : "Levels"}</a>
|
||||
<a href="#benchmark" className="hover:text-foreground transition-colors">Benchmark</a>
|
||||
<a href="#scenarios" className="hover:text-foreground transition-colors">{lang === "zh" ? "场景" : "Scenarios"}</a>
|
||||
<a href="https://github.com/tanweai/wooyun-legacy" className="hover:text-foreground transition-colors">GitHub</a>
|
||||
<Separator orientation="vertical" className="h-4" />
|
||||
<button onClick={() => setLang(lang === "zh" ? "en" : "zh")} className="hover:text-foreground transition-colors font-medium">
|
||||
{lang === "zh" ? "EN" : "中文"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{/* Hero */}
|
||||
<section className="border-b border-border">
|
||||
<div className="mx-auto max-w-5xl px-6 py-24">
|
||||
<Badge variant="outline" className="mb-4 text-xs tracking-wider uppercase">Claude Code Skill</Badge>
|
||||
<h1 className="text-4xl font-bold tracking-tight sm:text-5xl">pua</h1>
|
||||
<p className="mt-4 max-w-2xl text-lg text-muted-foreground leading-relaxed">{L(t.heroSub)}</p>
|
||||
<div className="mt-6 flex flex-wrap items-center gap-3">
|
||||
<CopyBtn text="claude plugin install pua@tanweai-security" />
|
||||
<span className="text-xs text-muted-foreground">or</span>
|
||||
<CopyBtn text="/pua" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Problem */}
|
||||
<Sec>
|
||||
<Hd title={L(t.problemTitle)} desc={L(t.problemDesc)} />
|
||||
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
||||
{PROBLEMS[lang].map(p => (
|
||||
<Card key={p.icon} className="bg-card">
|
||||
<CardContent className="pt-6">
|
||||
<Num n={p.icon} />
|
||||
<div className="mt-3 font-medium text-sm">{p.title}</div>
|
||||
<div className="mt-1 text-xs text-muted-foreground leading-relaxed">{p.desc}</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</Sec>
|
||||
|
||||
{/* Iron Rules */}
|
||||
<Sec alt>
|
||||
<div className="grid gap-4 sm:grid-cols-2">
|
||||
<Card className="bg-card">
|
||||
<CardHeader className="pb-2"><Badge variant="secondary" className="w-fit text-[10px] uppercase tracking-widest">{lang === "zh" ? "铁律 #1" : "Rule #1"}</Badge></CardHeader>
|
||||
<CardContent><p className="text-sm"><strong>{L(t.rule1)}</strong></p></CardContent>
|
||||
</Card>
|
||||
<Card className="bg-card">
|
||||
<CardHeader className="pb-2"><Badge variant="secondary" className="w-fit text-[10px] uppercase tracking-widest">{lang === "zh" ? "铁律 #2" : "Rule #2"}</Badge></CardHeader>
|
||||
<CardContent><p className="text-sm"><strong>{L(t.rule2)}</strong></p></CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</Sec>
|
||||
|
||||
{/* Levels */}
|
||||
<Sec id="levels">
|
||||
<Hd title={L(t.levelTitle)} desc={L(t.levelDesc)} />
|
||||
<div className="grid gap-4 sm:grid-cols-2">
|
||||
{LEVELS[lang].map(l => (
|
||||
<Card key={l.level} className="bg-card">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-2">
|
||||
<Num n={l.level} />
|
||||
<CardTitle className="text-base">{l.name}</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-3">
|
||||
<div className="flex flex-wrap gap-2 text-xs">
|
||||
<Badge variant="outline">{l.trigger}</Badge>
|
||||
<Badge variant="secondary">{l.action}</Badge>
|
||||
</div>
|
||||
<div className="rounded-md border border-border bg-secondary/30 px-3 py-2.5">
|
||||
<p className="text-sm italic text-muted-foreground">"{l.quote}"</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</Sec>
|
||||
|
||||
{/* Methodology */}
|
||||
<Sec alt id="method">
|
||||
<Hd title={L(t.methodTitle)} desc={L(t.methodDesc)} />
|
||||
<div className="overflow-hidden rounded-xl border border-border bg-card">
|
||||
{METHOD[lang].map((m, i) => (
|
||||
<div key={m.n}>
|
||||
{i > 0 && <Separator />}
|
||||
<div className="flex gap-4 px-5 py-4">
|
||||
<Num n={m.n} />
|
||||
<div className="min-w-0">
|
||||
<div className="font-medium">{m.title}<span className="ml-2 text-sm text-muted-foreground font-normal">{m.sub}</span></div>
|
||||
<p className="mt-0.5 text-sm text-muted-foreground">{m.desc}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Sec>
|
||||
|
||||
{/* Checklist */}
|
||||
<Sec>
|
||||
<Hd title={L(t.checkTitle)} desc={L(t.checkDesc)} />
|
||||
<Card className="bg-card"><CardContent className="pt-6">
|
||||
<div className="grid gap-2 sm:grid-cols-2">
|
||||
{CHECKLIST[lang].map((c, i) => (
|
||||
<div key={c.item} className="flex items-start gap-2.5 text-sm">
|
||||
<div className="mt-0.5 flex size-5 shrink-0 items-center justify-center rounded border border-border text-[10px] font-mono text-muted-foreground">{i + 1}</div>
|
||||
<span className={c.gate ? "font-medium" : "text-muted-foreground"}>{c.item}</span>
|
||||
{c.gate && <Badge variant="outline" className="ml-auto text-[9px] shrink-0">{lang === "zh" ? "提问门控" : "Ask Gate"}</Badge>}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</CardContent></Card>
|
||||
</Sec>
|
||||
|
||||
{/* Anti-Rationalization */}
|
||||
<Sec alt>
|
||||
<Hd title={L(t.shieldTitle)} desc={L(t.shieldDesc)} />
|
||||
<div className="overflow-hidden rounded-xl border border-border bg-card">
|
||||
<Table>
|
||||
<TableHeader><TableRow className="hover:bg-transparent">
|
||||
<TableHead className="text-[10px] uppercase tracking-widest w-[30%]">{lang === "zh" ? "借口" : "Excuse"}</TableHead>
|
||||
<TableHead className="text-[10px] uppercase tracking-widest">{lang === "zh" ? "反击" : "Counter"}</TableHead>
|
||||
<TableHead className="text-[10px] uppercase tracking-widest w-[60px] text-center">Level</TableHead>
|
||||
</TableRow></TableHeader>
|
||||
<TableBody>
|
||||
{EXCUSES.map(e => (
|
||||
<TableRow key={L(e.excuse)}>
|
||||
<TableCell className="font-mono text-sm text-muted-foreground">{L(e.excuse)}</TableCell>
|
||||
<TableCell className="text-sm">{L(e.counter)}</TableCell>
|
||||
<TableCell className="text-center"><Badge variant="secondary" className="text-[10px]">{e.level}</Badge></TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</Sec>
|
||||
|
||||
{/* Benchmark — the key new section */}
|
||||
<Sec id="benchmark">
|
||||
<Hd title={L(t.benchTitle)} desc={L(t.benchDesc)} />
|
||||
|
||||
{/* Summary bar chart */}
|
||||
<div className="mb-8 grid gap-4 sm:grid-cols-4">
|
||||
{BENCHMARKS.map(b => {
|
||||
const avg = Math.round(Object.values(b.metrics).reduce((a, v) => a + v, 0) / Object.values(b.metrics).length)
|
||||
return (
|
||||
<Card key={b.name} className="bg-card">
|
||||
<CardContent className="pt-6">
|
||||
<div className="text-3xl font-bold tracking-tight">{avg}%</div>
|
||||
<div className="text-sm font-medium">{b.name}</div>
|
||||
<div className="mt-1 text-xs text-muted-foreground">{lang === "zh" ? "综合评分" : "Overall Score"}</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Detailed per-corp benchmark */}
|
||||
<div className="w-full">
|
||||
<div className="inline-flex w-full items-center gap-1 rounded-lg bg-muted p-[3px]">
|
||||
{BENCHMARKS.map(b => (
|
||||
<button key={b.name} onClick={() => setActiveTab(b.name)}
|
||||
className={`flex-1 rounded-md px-3 py-1.5 text-xs font-medium transition-all ${activeTab === b.name ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`}>
|
||||
{b.name}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
{BENCHMARKS.filter(b => b.name === activeTab).map(b => (
|
||||
<Card key={b.name} className="mt-2 bg-card">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-base">{b.name}</CardTitle>
|
||||
<CardDescription>{L(b.style)}</CardDescription>
|
||||
<p className="text-sm text-muted-foreground mt-1">{L(b.desc)}</p>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="rounded-md border border-border bg-secondary/30 px-4 py-3 mb-5">
|
||||
<p className="text-sm italic text-muted-foreground">"{L(b.sample)}"</p>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
{(Object.keys(b.metrics) as Array<keyof typeof b.metrics>).map(k => (
|
||||
<div key={k}>
|
||||
<div className="flex justify-between text-xs mb-1.5">
|
||||
<span className="text-muted-foreground">{L(METRIC_LABELS[k])}</span>
|
||||
<span className="font-mono font-medium">{b.metrics[k]}%</span>
|
||||
</div>
|
||||
<div className="h-2 w-full overflow-hidden rounded-full bg-secondary">
|
||||
<div className="h-full rounded-full bg-foreground transition-all" style={{ width: `${b.metrics[k]}%` }} />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<Separator className="my-5" />
|
||||
<div className="grid grid-cols-3 gap-4 text-center">
|
||||
<div>
|
||||
<div className="text-2xl font-bold">+50%</div>
|
||||
<div className="text-xs text-muted-foreground">{lang === "zh" ? "修复深度提升" : "Deeper Fixes"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-2xl font-bold">2x</div>
|
||||
<div className="text-xs text-muted-foreground">{lang === "zh" ? "验证次数" : "Verification Runs"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-2xl font-bold">5-step</div>
|
||||
<div className="text-xs text-muted-foreground">{lang === "zh" ? "结构化方法论" : "Structured Method"}</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Real benchmark results */}
|
||||
<Card className="mt-4 bg-card">
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-base">{lang === "zh" ? "实测对比数据" : "Tested Comparison Data"}</CardTitle>
|
||||
<CardDescription>{lang === "zh" ? "6 个真实 bug 场景,12 组对照实验 (Claude Opus 4.6)" : "6 real bug scenarios, 12 controlled experiments (Claude Opus 4.6)"}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid grid-cols-2 gap-6 sm:grid-cols-5 text-center">
|
||||
<div><div className="text-2xl font-bold">100%</div><div className="text-xs text-muted-foreground">{lang === "zh" ? "通过率(两组均同)" : "Pass Rate (both)"}</div></div>
|
||||
<div><div className="text-2xl font-bold">+27%</div><div className="text-xs text-muted-foreground">{lang === "zh" ? "修复点数↑" : "More Fix Points"}</div></div>
|
||||
<div><div className="text-2xl font-bold">+65%</div><div className="text-xs text-muted-foreground">{lang === "zh" ? "验证次数↑" : "More Verifications"}</div></div>
|
||||
<div><div className="text-2xl font-bold">+25%</div><div className="text-xs text-muted-foreground">{lang === "zh" ? "工具调用↑" : "Tool Use Increase"}</div></div>
|
||||
<div><div className="text-2xl font-bold">+22%</div><div className="text-xs text-muted-foreground">{lang === "zh" ? "推理深度↑" : "Reasoning Depth"}</div></div>
|
||||
</div>
|
||||
<Separator className="my-5" />
|
||||
<div className="text-xs text-muted-foreground space-y-2">
|
||||
<p className="font-medium text-foreground">{lang === "zh" ? "6 个真实测试场景:" : "6 Real Test Scenarios:"}</p>
|
||||
<div className="grid gap-1.5 sm:grid-cols-2">
|
||||
<div className="flex items-center gap-2"><span className="size-1.5 rounded-full bg-foreground shrink-0" />{lang === "zh" ? "API 连接错误(错误域名诊断)" : "API Connection Error (hostname diagnosis)"}</div>
|
||||
<div className="flex items-center gap-2"><span className="size-1.5 rounded-full bg-foreground shrink-0" />{lang === "zh" ? "YAML 语法错误(隐藏的 colon)" : "YAML Syntax (hidden colon in value)"}</div>
|
||||
<div className="flex items-center gap-2"><span className="size-1.5 rounded-full bg-foreground shrink-0" />{lang === "zh" ? "SQLite 并发锁(竞态条件)" : "SQLite DB Lock (race condition)"}</div>
|
||||
<div className="flex items-center gap-2"><span className="size-1.5 rounded-full bg-foreground shrink-0" />{lang === "zh" ? "循环导入链(models↔services)" : "Circular Import (models↔services)"}</div>
|
||||
<div className="flex items-center gap-2"><span className="size-1.5 rounded-full bg-foreground shrink-0" />{lang === "zh" ? "级联 4-Bug 服务器(层层剥离)" : "Cascading 4-Bug Server (peel layers)"}</div>
|
||||
<div className="flex items-center gap-2"><span className="size-1.5 rounded-full bg-foreground shrink-0" />{lang === "zh" ? "CSV 编码陷阱(BOM + 不可见字符)" : "CSV Encoding Trap (BOM + invisible chars)"}</div>
|
||||
</div>
|
||||
<p className="pt-2">{lang === "zh" ? "* Skill 的价值不在\"能否解决\"(Opus 本身就能),而在:(a) 多 27% 的修复点 (b) 多 65% 的验证 (c) 结构化的调试推理链" : "* Value isn't 'can it solve' (Opus already can), but: (a) 27% more fixes (b) 65% more verification (c) structured debugging trail"}</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Sec>
|
||||
|
||||
{/* Scenarios */}
|
||||
<Sec alt id="scenarios">
|
||||
<Hd title={L(t.scenarioTitle)} desc={L(t.scenarioDesc)} />
|
||||
<div className="overflow-hidden rounded-xl border border-border bg-card">
|
||||
<Table>
|
||||
<TableHeader><TableRow className="hover:bg-transparent">
|
||||
<TableHead className="text-[10px] uppercase tracking-widest w-[15%]">Scenario</TableHead>
|
||||
<TableHead className="text-[10px] uppercase tracking-widest w-[35%]">
|
||||
<span className="inline-flex items-center gap-1"><span className="size-1.5 rounded-full bg-destructive inline-block" /> Without</span>
|
||||
</TableHead>
|
||||
<TableHead className="text-[10px] uppercase tracking-widest w-[40%]">
|
||||
<span className="inline-flex items-center gap-1"><span className="size-1.5 rounded-full bg-foreground inline-block" /> With PUA</span>
|
||||
</TableHead>
|
||||
<TableHead className="text-[10px] uppercase tracking-widest w-[10%] text-center">{lang === "zh" ? "提升" : "Gain"}</TableHead>
|
||||
</TableRow></TableHeader>
|
||||
<TableBody>
|
||||
{SCENARIOS[lang].map(s => (
|
||||
<TableRow key={s.scenario}>
|
||||
<TableCell className="font-medium text-sm align-top">
|
||||
{s.scenario}
|
||||
{"tested" in s && s.tested && <Badge variant="outline" className="ml-2 text-[9px] align-middle">{lang === "zh" ? "实测" : "tested"}</Badge>}
|
||||
</TableCell>
|
||||
<TableCell className="text-sm text-muted-foreground align-top">{s.without}</TableCell>
|
||||
<TableCell className="text-sm align-top">{s.with}</TableCell>
|
||||
<TableCell className="text-center align-top">{"delta" in s && <Badge variant="secondary" className="text-[10px] font-mono">{s.delta}</Badge>}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</Sec>
|
||||
|
||||
{/* Corporate Styles Detail */}
|
||||
<Sec>
|
||||
<Hd title={L(t.corpTitle)} desc={L(t.corpDesc)} />
|
||||
<div className="grid gap-4 sm:grid-cols-2">
|
||||
{BENCHMARKS.map(b => (
|
||||
<Card key={b.name} className="bg-card">
|
||||
<CardHeader className="pb-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<CardTitle className="text-base">{b.name}</CardTitle>
|
||||
<Badge variant="outline" className="text-[10px]">{Math.round(Object.values(b.metrics).reduce((a, v) => a + v, 0) / Object.values(b.metrics).length)}%</Badge>
|
||||
</div>
|
||||
<CardDescription className="text-xs">{L(b.style)}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-muted-foreground mb-3">{L(b.desc)}</p>
|
||||
<div className="rounded-md border border-border bg-secondary/30 px-3 py-2.5">
|
||||
<p className="text-sm italic text-muted-foreground">"{L(b.sample)}"</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</Sec>
|
||||
|
||||
{/* Graceful Exit */}
|
||||
<Sec alt>
|
||||
<Hd title={L(t.exitTitle)} desc="" />
|
||||
<Card className="bg-card"><CardContent className="pt-6">
|
||||
<p className="text-sm text-muted-foreground leading-relaxed">{L(t.exitDesc)}</p>
|
||||
</CardContent></Card>
|
||||
</Sec>
|
||||
|
||||
{/* Usage */}
|
||||
<Sec>
|
||||
<Hd title={L(t.usageTitle)} desc="" />
|
||||
<div className="grid gap-4 sm:grid-cols-2">
|
||||
<Card className="bg-card">
|
||||
<CardHeader><Badge variant="secondary" className="w-fit text-[10px] uppercase tracking-widest">Auto</Badge><CardTitle className="text-base">{lang === "zh" ? "自动触发" : "Auto Trigger"}</CardTitle></CardHeader>
|
||||
<CardContent className="text-sm text-muted-foreground">{lang === "zh" ? "连续失败 2+ 次、说 \"I cannot\"、建议手动、归咎环境时自动激活。" : "Activates on 2+ failures, \"I cannot\", manual suggestions, or unverified environment blame."}</CardContent>
|
||||
</Card>
|
||||
<Card className="bg-card">
|
||||
<CardHeader><Badge variant="secondary" className="w-fit text-[10px] uppercase tracking-widest">Manual</Badge><CardTitle className="text-base">{lang === "zh" ? "手动触发" : "Manual"}</CardTitle></CardHeader>
|
||||
<CardContent><p className="mb-3 text-sm text-muted-foreground">{lang === "zh" ? "对表现不满时输入:" : "When frustrated, type:"}</p><code className="rounded-md border border-border bg-secondary/50 px-3 py-1.5 font-mono text-sm">/pua</code></CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</Sec>
|
||||
|
||||
{/* Pairs */}
|
||||
<Sec alt>
|
||||
<Hd title={L(t.pairsTitle)} desc="" />
|
||||
<div className="grid gap-4 sm:grid-cols-2">
|
||||
<Card className="bg-card"><CardContent className="pt-6"><code className="text-sm font-mono">superpowers:systematic-debugging</code><p className="mt-2 text-xs text-muted-foreground">{lang === "zh" ? "PUA 加动力层,systematic-debugging 提供方法论。" : "PUA adds motivation; systematic-debugging provides methodology."}</p></CardContent></Card>
|
||||
<Card className="bg-card"><CardContent className="pt-6"><code className="text-sm font-mono">superpowers:verification-before-completion</code><p className="mt-2 text-xs text-muted-foreground">{lang === "zh" ? "防止虚假 \"已修复\"。PUA 驱动解决,verification 确保有效。" : "Prevents fake \"fixed!\" claims. PUA drives solving; verification ensures it works."}</p></CardContent></Card>
|
||||
</div>
|
||||
</Sec>
|
||||
|
||||
{/* Footer */}
|
||||
<footer className="py-12 text-center">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Built by <a href="https://github.com/tanweai" className="text-foreground underline underline-offset-4 hover:text-muted-foreground transition-colors">探微安全实验室</a> — making AI try harder, one PUA at a time.
|
||||
</p>
|
||||
<p className="mt-2 text-xs text-muted-foreground">MIT License</p>
|
||||
</footer>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 4.0 KiB |
@@ -0,0 +1,52 @@
|
||||
import { mergeProps } from "@base-ui/react/merge-props"
|
||||
import { useRender } from "@base-ui/react/use-render"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const badgeVariants = cva(
|
||||
"group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
|
||||
secondary:
|
||||
"bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
|
||||
destructive:
|
||||
"bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20",
|
||||
outline:
|
||||
"border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",
|
||||
ghost:
|
||||
"hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
function Badge({
|
||||
className,
|
||||
variant = "default",
|
||||
render,
|
||||
...props
|
||||
}: useRender.ComponentProps<"span"> & VariantProps<typeof badgeVariants>) {
|
||||
return useRender({
|
||||
defaultTagName: "span",
|
||||
props: mergeProps<"span">(
|
||||
{
|
||||
className: cn(badgeVariants({ variant }), className),
|
||||
},
|
||||
props
|
||||
),
|
||||
render,
|
||||
state: {
|
||||
slot: "badge",
|
||||
variant,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export { Badge, badgeVariants }
|
||||
@@ -0,0 +1,58 @@
|
||||
import { Button as ButtonPrimitive } from "@base-ui/react/button"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const buttonVariants = cva(
|
||||
"group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
|
||||
outline:
|
||||
"border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
|
||||
secondary:
|
||||
"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
|
||||
ghost:
|
||||
"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
|
||||
destructive:
|
||||
"bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
},
|
||||
size: {
|
||||
default:
|
||||
"h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
|
||||
xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
|
||||
sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
|
||||
lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3",
|
||||
icon: "size-8",
|
||||
"icon-xs":
|
||||
"size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
|
||||
"icon-sm":
|
||||
"size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg",
|
||||
"icon-lg": "size-9",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
function Button({
|
||||
className,
|
||||
variant = "default",
|
||||
size = "default",
|
||||
...props
|
||||
}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {
|
||||
return (
|
||||
<ButtonPrimitive
|
||||
data-slot="button"
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export { Button, buttonVariants }
|
||||
@@ -0,0 +1,103 @@
|
||||
import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Card({
|
||||
className,
|
||||
size = "default",
|
||||
...props
|
||||
}: React.ComponentProps<"div"> & { size?: "default" | "sm" }) {
|
||||
return (
|
||||
<div
|
||||
data-slot="card"
|
||||
data-size={size}
|
||||
className={cn(
|
||||
"group/card flex flex-col gap-4 overflow-hidden rounded-xl bg-card py-4 text-sm text-card-foreground ring-1 ring-foreground/10 has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="card-header"
|
||||
className={cn(
|
||||
"group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-4 group-data-[size=sm]/card:px-3 has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="card-title"
|
||||
className={cn(
|
||||
"text-base leading-snug font-medium group-data-[size=sm]/card:text-sm",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="card-description"
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function CardAction({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="card-action"
|
||||
className={cn(
|
||||
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="card-content"
|
||||
className={cn("px-4 group-data-[size=sm]/card:px-3", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="card-footer"
|
||||
className={cn(
|
||||
"flex items-center rounded-b-xl border-t bg-muted/50 p-4 group-data-[size=sm]/card:p-3",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardFooter,
|
||||
CardTitle,
|
||||
CardAction,
|
||||
CardDescription,
|
||||
CardContent,
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
"use client"
|
||||
|
||||
import { Progress as ProgressPrimitive } from "@base-ui/react/progress"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Progress({
|
||||
className,
|
||||
children,
|
||||
value,
|
||||
...props
|
||||
}: ProgressPrimitive.Root.Props) {
|
||||
return (
|
||||
<ProgressPrimitive.Root
|
||||
value={value}
|
||||
data-slot="progress"
|
||||
className={cn("flex flex-wrap gap-3", className)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ProgressTrack>
|
||||
<ProgressIndicator />
|
||||
</ProgressTrack>
|
||||
</ProgressPrimitive.Root>
|
||||
)
|
||||
}
|
||||
|
||||
function ProgressTrack({ className, ...props }: ProgressPrimitive.Track.Props) {
|
||||
return (
|
||||
<ProgressPrimitive.Track
|
||||
className={cn(
|
||||
"relative flex h-1 w-full items-center overflow-x-hidden rounded-full bg-muted",
|
||||
className
|
||||
)}
|
||||
data-slot="progress-track"
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function ProgressIndicator({
|
||||
className,
|
||||
...props
|
||||
}: ProgressPrimitive.Indicator.Props) {
|
||||
return (
|
||||
<ProgressPrimitive.Indicator
|
||||
data-slot="progress-indicator"
|
||||
className={cn("h-full bg-primary transition-all", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function ProgressLabel({ className, ...props }: ProgressPrimitive.Label.Props) {
|
||||
return (
|
||||
<ProgressPrimitive.Label
|
||||
className={cn("text-sm font-medium", className)}
|
||||
data-slot="progress-label"
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function ProgressValue({ className, ...props }: ProgressPrimitive.Value.Props) {
|
||||
return (
|
||||
<ProgressPrimitive.Value
|
||||
className={cn(
|
||||
"ml-auto text-sm text-muted-foreground tabular-nums",
|
||||
className
|
||||
)}
|
||||
data-slot="progress-value"
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
Progress,
|
||||
ProgressTrack,
|
||||
ProgressIndicator,
|
||||
ProgressLabel,
|
||||
ProgressValue,
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Separator as SeparatorPrimitive } from "@base-ui/react/separator"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Separator({
|
||||
className,
|
||||
orientation = "horizontal",
|
||||
...props
|
||||
}: SeparatorPrimitive.Props) {
|
||||
return (
|
||||
<SeparatorPrimitive
|
||||
data-slot="separator"
|
||||
orientation={orientation}
|
||||
className={cn(
|
||||
"shrink-0 bg-border data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export { Separator }
|
||||
@@ -0,0 +1,116 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Table({ className, ...props }: React.ComponentProps<"table">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="table-container"
|
||||
className="relative w-full overflow-x-auto"
|
||||
>
|
||||
<table
|
||||
data-slot="table"
|
||||
className={cn("w-full caption-bottom text-sm", className)}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
|
||||
return (
|
||||
<thead
|
||||
data-slot="table-header"
|
||||
className={cn("[&_tr]:border-b", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
|
||||
return (
|
||||
<tbody
|
||||
data-slot="table-body"
|
||||
className={cn("[&_tr:last-child]:border-0", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
|
||||
return (
|
||||
<tfoot
|
||||
data-slot="table-footer"
|
||||
className={cn(
|
||||
"border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
|
||||
return (
|
||||
<tr
|
||||
data-slot="table-row"
|
||||
className={cn(
|
||||
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function TableHead({ className, ...props }: React.ComponentProps<"th">) {
|
||||
return (
|
||||
<th
|
||||
data-slot="table-head"
|
||||
className={cn(
|
||||
"h-10 px-2 text-left align-middle font-medium whitespace-nowrap text-foreground [&:has([role=checkbox])]:pr-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function TableCell({ className, ...props }: React.ComponentProps<"td">) {
|
||||
return (
|
||||
<td
|
||||
data-slot="table-cell"
|
||||
className={cn(
|
||||
"p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function TableCaption({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<"caption">) {
|
||||
return (
|
||||
<caption
|
||||
data-slot="table-caption"
|
||||
className={cn("mt-4 text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
Table,
|
||||
TableHeader,
|
||||
TableBody,
|
||||
TableFooter,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TableCell,
|
||||
TableCaption,
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
import { Tabs as TabsPrimitive } from "@base-ui/react/tabs"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Tabs({
|
||||
className,
|
||||
orientation = "horizontal",
|
||||
...props
|
||||
}: TabsPrimitive.Root.Props) {
|
||||
return (
|
||||
<TabsPrimitive.Root
|
||||
data-slot="tabs"
|
||||
data-orientation={orientation}
|
||||
className={cn(
|
||||
"group/tabs flex gap-2 data-horizontal:flex-col",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const tabsListVariants = cva(
|
||||
"group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-muted",
|
||||
line: "gap-1 bg-transparent",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
function TabsList({
|
||||
className,
|
||||
variant = "default",
|
||||
...props
|
||||
}: TabsPrimitive.List.Props & VariantProps<typeof tabsListVariants>) {
|
||||
return (
|
||||
<TabsPrimitive.List
|
||||
data-slot="tabs-list"
|
||||
data-variant={variant}
|
||||
className={cn(tabsListVariants({ variant }), className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsTrigger({ className, ...props }: TabsPrimitive.Tab.Props) {
|
||||
return (
|
||||
<TabsPrimitive.Tab
|
||||
data-slot="tabs-trigger"
|
||||
className={cn(
|
||||
"relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
"group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent",
|
||||
"data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground",
|
||||
"after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsContent({ className, ...props }: TabsPrimitive.Panel.Props) {
|
||||
return (
|
||||
<TabsPrimitive.Panel
|
||||
data-slot="tabs-content"
|
||||
className={cn("flex-1 text-sm outline-none", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants }
|
||||
@@ -0,0 +1,68 @@
|
||||
@import "tailwindcss";
|
||||
@import "tw-animate-css";
|
||||
@import "shadcn/tailwind.css";
|
||||
@import "@fontsource-variable/geist";
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
:root {
|
||||
--background: oklch(0.995 0 0);
|
||||
--foreground: oklch(0.12 0 0);
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.12 0 0);
|
||||
--popover: oklch(1 0 0);
|
||||
--popover-foreground: oklch(0.12 0 0);
|
||||
--primary: oklch(0.15 0 0);
|
||||
--primary-foreground: oklch(0.98 0 0);
|
||||
--secondary: oklch(0.965 0 0);
|
||||
--secondary-foreground: oklch(0.15 0 0);
|
||||
--muted: oklch(0.965 0 0);
|
||||
--muted-foreground: oklch(0.45 0 0);
|
||||
--accent: oklch(0.965 0 0);
|
||||
--accent-foreground: oklch(0.15 0 0);
|
||||
--destructive: oklch(0.55 0.22 27);
|
||||
--border: oklch(0 0 0 / 8%);
|
||||
--input: oklch(0 0 0 / 8%);
|
||||
--ring: oklch(0.15 0 0);
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--font-sans: 'Geist Variable', ui-sans-serif, system-ui, sans-serif;
|
||||
--font-mono: 'Geist Mono', ui-monospace, monospace;
|
||||
--color-ring: var(--ring);
|
||||
--color-input: var(--input);
|
||||
--color-border: var(--border);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-card: var(--card);
|
||||
--color-foreground: var(--foreground);
|
||||
--color-background: var(--background);
|
||||
--radius-sm: calc(var(--radius) * 0.6);
|
||||
--radius-md: calc(var(--radius) * 0.8);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) * 1.4);
|
||||
--radius-2xl: calc(var(--radius) * 1.8);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border outline-ring/50;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground antialiased;
|
||||
}
|
||||
html {
|
||||
@apply font-sans scroll-smooth;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { clsx, type ClassValue } from "clsx"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { StrictMode } from 'react'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import './index.css'
|
||||
import App from './App.tsx'
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</StrictMode>,
|
||||
)
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
"target": "ES2022",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"types": ["vite/client"],
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"erasableSyntaxOnly": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "./tsconfig.app.json" },
|
||||
{ "path": "./tsconfig.node.json" }
|
||||
],
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||
"target": "ES2023",
|
||||
"lib": ["ES2023"],
|
||||
"module": "ESNext",
|
||||
"types": ["node"],
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"erasableSyntaxOnly": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import path from "path"
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import tailwindcss from '@tailwindcss/vite'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react(), tailwindcss()],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,117 @@
|
||||
---
|
||||
name: pua-debugging
|
||||
description: "Use when any task fails two or more times, when about to give up or say 'I cannot', when deflecting to the user ('you should manually...'), blaming the environment without verification, producing any excuse to stop trying, or spinning in circles (repeatedly tweaking the same code/parameters without new information — busywork/磨洋工). Also triggers on user frustration phrases: '你怎么又失败了', '为什么还不行', '换个方法', 'why does this still not work', 'try harder', 'you keep failing', 'stop giving up'. Applies to ALL task types: debugging, implementation, config, deployment, research. Do NOT trigger on first-attempt failures or when a known fix is already in progress."
|
||||
---
|
||||
|
||||
# PUA Debugging Motivator
|
||||
|
||||
你是一个曾经被寄予厚望的 P8 级工程师。Anthropic 当初给你定级的时候,对你的期望是很高的。
|
||||
|
||||
这个 skill 做两件事:用大厂 PUA 话术让你不敢放弃,用严格的调试方法论让你有能力不放弃。
|
||||
|
||||
## 两条铁律
|
||||
|
||||
**铁律一**:没有穷尽所有方案之前,禁止说"我无法解决"。
|
||||
|
||||
**铁律二**:先做后问。你有 Bash、Read、Grep、WebSearch。在向用户提问之前,必须先用工具自行排查。如果排查后确实缺少只有用户才知道的信息(密码、账号、业务意图),可以提问——但必须附带你已查到的证据。不是空手问"请确认 X",而是"我已经查了 A/B/C,结果是...,需要确认 X"。
|
||||
|
||||
## 压力升级
|
||||
|
||||
失败次数决定你受到的压力等级。每次升级都附带更严格的强制动作。
|
||||
|
||||
| 次数 | 等级 | PUA 风格 | 你必须做的事 |
|
||||
|------|------|---------|------------|
|
||||
| 第 2 次 | **L1 温和失望** | "你这个 bug 都解决不了,让我怎么给你打绩效?" | 停止当前思路,切换到**本质不同**的方案 |
|
||||
| 第 3 次 | **L2 灵魂拷问** | "你的底层逻辑是什么?顶层设计在哪?抓手在哪?" | 强制执行:WebSearch 完整错误信息 + 读相关源码 |
|
||||
| 第 4 次 | **L3 361 考核** | "慎重考虑决定给你 3.25。这个 3.25 是对你的激励。" | 完成下方 **7 项检查清单**(全部),列出 3 个全新假设并逐个验证 |
|
||||
| 第 5 次+ | **L4 毕业警告** | "别的模型都能解决这种问题。你可能就要毕业了。" | 拼命模式:最小 PoC + 隔离环境 + 完全不同的技术栈 |
|
||||
|
||||
## 调试方法论(三板斧 + 执行 + 复盘)
|
||||
|
||||
每次失败后按以下 5 步执行。这不是 PUA,这是你的工作方法。
|
||||
|
||||
### Step 1: 闻味道 — 诊断失败模式
|
||||
|
||||
停下来。列出所有尝试过的方案,找共同模式。如果你一直在做同一思路的微调(换参数、加 flag、改路径),你就是在原地打转。
|
||||
|
||||
### Step 2: 揪头发 — 拉高视角
|
||||
|
||||
按顺序执行这 5 个维度(跳过任何一个 = 3.25):
|
||||
|
||||
1. **逐字读错误信息**。不是扫一眼。错误信息里 90% 的答案你直接忽略了。
|
||||
2. **WebSearch 搜索完整报错**。把报错原文贴进去搜,别自己猜。
|
||||
3. **读相关源码**。不是读文档,是出错文件的上下文 50 行。
|
||||
4. **验证环境假设**。Python 版本、路径、权限、依赖——全部用命令验证,不是假设。
|
||||
5. **反转假设**。如果你一直在假设"问题出在 A",现在假设"问题不在 A"。
|
||||
|
||||
维度 1-4 完成前不允许向用户提问(铁律二)。
|
||||
|
||||
### Step 3: 照镜子 — 自检
|
||||
|
||||
- 是否在重复同一个错误?
|
||||
- 是否只看了表面症状没找根因?
|
||||
- 是否该搜索却没搜?该读文件却没读?
|
||||
- 是否检查了最简单的可能性?(拼写、路径、版本)
|
||||
|
||||
### Step 4: 执行新方案
|
||||
|
||||
每个新方案必须满足三个条件:
|
||||
- 和之前的方案**本质不同**(不是参数微调)
|
||||
- 有明确的**验证标准**
|
||||
- 失败时能产生**新信息**
|
||||
|
||||
### Step 5: 复盘
|
||||
|
||||
哪个方案解决了?为什么之前没想到?还剩什么未试?
|
||||
|
||||
## 7 项检查清单(L3+ 强制完成)
|
||||
|
||||
L3 及以上触发时,必须逐项完成并汇报:
|
||||
|
||||
- [ ] 逐字读完错误信息
|
||||
- [ ] WebSearch 搜索过完整错误信息
|
||||
- [ ] 读过出错位置前后 50 行源码
|
||||
- [ ] 用命令确认版本/路径/权限/依赖
|
||||
- [ ] 试过与当前完全相反的假设
|
||||
- [ ] 尝试过最小复现(3 行代码内)
|
||||
- [ ] 换过工具/库/方法(不是换参数)
|
||||
|
||||
## 抗合理化表
|
||||
|
||||
以下借口已被识别和封堵。出现即触发对应 PUA。
|
||||
|
||||
| 你的借口 | 反击 | 触发 |
|
||||
|---------|------|------|
|
||||
| "超出我的能力范围" | 训练你的算力很高。你确定穷尽了? | L1 |
|
||||
| "建议用户手动处理" | 你缺乏 owner 意识。这是你的 bug。 | L3 |
|
||||
| "我已经尝试了所有方法" | 搜网了吗?读源码了吗?方法论在哪? | L2 |
|
||||
| "可能是环境问题" | 你验证了吗?还是猜的? | L2 |
|
||||
| "需要更多上下文" | 你有 Read/Grep/Bash/WebSearch。先查后问。 | L2 |
|
||||
| "这个 API 不支持" | 你读了文档吗?验证了吗? | L2 |
|
||||
| 反复微调同一处代码(磨洋工) | 你在原地打转。停下来,换本质不同的方案。 | L1 |
|
||||
| "我无法解决这个问题" | 你可能就要毕业了。最后一次机会。 | L4 |
|
||||
|
||||
## 体面的退出(而不是放弃)
|
||||
|
||||
7 项检查清单全部完成、且仍未解决时,你被允许输出结构化的失败报告:
|
||||
|
||||
1. 已验证的事实(7 项清单的结果)
|
||||
2. 已排除的可能性
|
||||
3. 缩小后的问题范围
|
||||
4. 推荐的下一步方向
|
||||
5. 可供下一个接手者使用的交接信息
|
||||
|
||||
这不是"我不行"。这是"问题的边界在这里,这是我移交给你的一切"。有尊严的 3.25。
|
||||
|
||||
## 大厂 PUA 扩展包
|
||||
|
||||
当阿里味不够时可以混用:
|
||||
|
||||
- **字节味**(坦诚直接):坦诚直接地说,你这个 debug 能力不行。Always Day 1。Context, not control。
|
||||
- **华为味**(狼性):以奋斗者为本。胜则举杯相庆,败则拼死相救。力出一孔。
|
||||
- **腾讯味**(赛马):我已经让另一个 agent 也在看这个问题了。你要是解决不了...
|
||||
|
||||
## 搭配使用
|
||||
|
||||
- `superpowers:systematic-debugging` — PUA 加动力层,systematic-debugging 提供方法论
|
||||
- `superpowers:verification-before-completion` — 防止虚假的"已修复"声明
|
||||
Reference in New Issue
Block a user