@tw93/waza 3.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +206 -0
  3. package/package.json +35 -0
  4. package/rules/anti-patterns.md +38 -0
  5. package/rules/chinese.md +18 -0
  6. package/rules/durable-context.md +27 -0
  7. package/rules/english.md +14 -0
  8. package/scripts/build_metadata.py +360 -0
  9. package/scripts/check_routing_drift.py +82 -0
  10. package/scripts/dispatcher-template.md +43 -0
  11. package/scripts/dispatcher.md +53 -0
  12. package/scripts/package-skill.sh +71 -0
  13. package/scripts/packaging_filter.py +55 -0
  14. package/scripts/setup-rule.sh +109 -0
  15. package/scripts/setup-statusline.sh +127 -0
  16. package/scripts/skill_checks.py +483 -0
  17. package/scripts/skill_frontmatter.py +110 -0
  18. package/scripts/statusline.sh +321 -0
  19. package/scripts/validate_package.py +66 -0
  20. package/scripts/verify_skills.py +100 -0
  21. package/skills/RESOLVER.md +91 -0
  22. package/skills/check/SKILL.md +338 -0
  23. package/skills/check/agents/reviewer-architecture.md +39 -0
  24. package/skills/check/agents/reviewer-security.md +39 -0
  25. package/skills/check/references/persona-catalog.md +56 -0
  26. package/skills/check/references/project-context.md +107 -0
  27. package/skills/check/references/public-reply.md +14 -0
  28. package/skills/check/scripts/audit_signals.py +485 -0
  29. package/skills/check/scripts/run-tests.sh +19 -0
  30. package/skills/design/SKILL.md +134 -0
  31. package/skills/design/references/design-aesthetic-quality.md +67 -0
  32. package/skills/design/references/design-data-viz.md +34 -0
  33. package/skills/design/references/design-reference.md +278 -0
  34. package/skills/design/references/design-tokens.md +53 -0
  35. package/skills/design/references/design-traps.md +43 -0
  36. package/skills/health/SKILL.md +231 -0
  37. package/skills/health/agents/inspector-context.md +119 -0
  38. package/skills/health/agents/inspector-control.md +84 -0
  39. package/skills/health/agents/inspector-maintainability.md +55 -0
  40. package/skills/health/scripts/check-agent-context.sh +5 -0
  41. package/skills/health/scripts/check-doc-refs.sh +8 -0
  42. package/skills/health/scripts/check-maintainability.sh +8 -0
  43. package/skills/health/scripts/check-verifier-output.sh +5 -0
  44. package/skills/health/scripts/check_agent_context.py +407 -0
  45. package/skills/health/scripts/check_doc_refs.py +110 -0
  46. package/skills/health/scripts/check_maintainability.py +629 -0
  47. package/skills/health/scripts/check_verifier_output.py +116 -0
  48. package/skills/health/scripts/collect-data.sh +760 -0
  49. package/skills/hunt/SKILL.md +197 -0
  50. package/skills/hunt/references/failure-patterns.md +75 -0
  51. package/skills/hunt/references/ime-unicode.md +58 -0
  52. package/skills/hunt/references/logging-techniques.md +72 -0
  53. package/skills/hunt/references/rendering-debug.md +34 -0
  54. package/skills/learn/SKILL.md +128 -0
  55. package/skills/read/SKILL.md +108 -0
  56. package/skills/read/references/read-methods.md +110 -0
  57. package/skills/read/references/save-paths.md +33 -0
  58. package/skills/read/scripts/fetch.sh +105 -0
  59. package/skills/read/scripts/fetch_feishu.py +246 -0
  60. package/skills/read/scripts/fetch_local.py +218 -0
  61. package/skills/read/scripts/fetch_weixin.py +107 -0
  62. package/skills/think/SKILL.md +155 -0
  63. package/skills/write/SKILL.md +129 -0
  64. package/skills/write/references/write-en.md +197 -0
  65. package/skills/write/references/write-zh-bilingual.md +60 -0
  66. package/skills/write/references/write-zh-prose.md +48 -0
  67. package/skills/write/references/write-zh-release-notes.md +38 -0
  68. package/skills/write/references/write-zh.md +645 -0
@@ -0,0 +1,218 @@
1
+ #!/usr/bin/env python3
2
+ """Local URL → Markdown extractor. Privacy-preserving tier 1 for fetch.sh.
3
+
4
+ Two paths, picked at runtime:
5
+
6
+ 1. **Best path**: `readability-lxml` + `html2text` installed. Extract main
7
+ content via readability scoring, convert to clean Markdown. Quality close
8
+ to defuddle.md / r.jina.ai for static pages.
9
+
10
+ 2. **Fallback path**: stdlib only. Strip HTML tags, collapse whitespace, drop
11
+ <script>/<style>/<nav>/<footer>. Quality is poor for JS-heavy pages and
12
+ complex layouts, but works for simple article-style HTML without any
13
+ third-party dependency.
14
+
15
+ JS-rendered pages (X/Twitter, paywalled news, SPA) are out of reach for both
16
+ paths. Use `fetch.sh --use-proxy` for those.
17
+
18
+ Exit codes:
19
+ 0 success, markdown on stdout
20
+ 1 fetch or extraction failed; reason on stderr
21
+ 2 invocation error (missing URL)
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ import argparse
27
+ import re
28
+ import sys
29
+ import urllib.error
30
+ import urllib.request
31
+ from html.parser import HTMLParser
32
+
33
+
34
+ USER_AGENT = (
35
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 12_0) "
36
+ "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120 Safari/537.36"
37
+ )
38
+ FETCH_TIMEOUT_SECS = 20
39
+
40
+
41
+ def fetch_html(url: str) -> str:
42
+ req = urllib.request.Request(url, headers={"User-Agent": USER_AGENT})
43
+ with urllib.request.urlopen(req, timeout=FETCH_TIMEOUT_SECS) as resp:
44
+ raw = resp.read()
45
+ # Detect charset from Content-Type header; fall back to utf-8 with replace.
46
+ charset = "utf-8"
47
+ ctype = resp.headers.get("Content-Type", "")
48
+ m = re.search(r"charset=([\w\-]+)", ctype, re.IGNORECASE)
49
+ if m:
50
+ charset = m.group(1).lower()
51
+ try:
52
+ return raw.decode(charset, errors="replace")
53
+ except LookupError:
54
+ return raw.decode("utf-8", errors="replace")
55
+
56
+
57
+ def extract_with_readability(html: str, url: str) -> str | None:
58
+ """Best path: readability-lxml + html2text. Returns Markdown or None if
59
+ deps missing. Raises only on genuine extraction failure."""
60
+ try:
61
+ from readability import Document # type: ignore
62
+ import html2text # type: ignore
63
+ except ImportError:
64
+ return None
65
+ doc = Document(html)
66
+ cleaned_html = doc.summary(html_partial=True)
67
+ title = (doc.short_title() or "").strip()
68
+ converter = html2text.HTML2Text()
69
+ converter.body_width = 0
70
+ converter.unicode_snob = True
71
+ converter.ignore_links = False
72
+ converter.ignore_images = False
73
+ body = converter.handle(cleaned_html).strip()
74
+ if not body:
75
+ return None
76
+ header = ""
77
+ if title:
78
+ header = f"# {title}\n\n"
79
+ return f"{header}> Source: {url}\n\n{body}\n"
80
+
81
+
82
+ class _StdlibStripper(HTMLParser):
83
+ """Fallback HTML → text converter using only stdlib. Quality is poor but
84
+ deterministic; intended as a last resort when readability isn't installed.
85
+ Drops common non-content blocks (script/style/nav/footer/aside)."""
86
+
87
+ DROP_TAGS = {"script", "style", "nav", "footer", "aside", "noscript", "form"}
88
+ BLOCK_TAGS = {
89
+ "p", "div", "section", "article", "li", "ul", "ol",
90
+ "h1", "h2", "h3", "h4", "h5", "h6", "br", "tr",
91
+ }
92
+
93
+ def __init__(self) -> None:
94
+ super().__init__()
95
+ self._buf: list[str] = []
96
+ self._drop_depth = 0
97
+ self._title = ""
98
+ self._in_title = False
99
+
100
+ def handle_starttag(self, tag, attrs):
101
+ if tag in self.DROP_TAGS:
102
+ self._drop_depth += 1
103
+ elif tag == "title":
104
+ self._in_title = True
105
+ elif tag in self.BLOCK_TAGS:
106
+ self._buf.append("\n")
107
+
108
+ def handle_endtag(self, tag):
109
+ if tag in self.DROP_TAGS:
110
+ self._drop_depth = max(0, self._drop_depth - 1)
111
+ elif tag == "title":
112
+ self._in_title = False
113
+ elif tag in self.BLOCK_TAGS:
114
+ self._buf.append("\n")
115
+
116
+ def handle_data(self, data):
117
+ if self._drop_depth:
118
+ return
119
+ if self._in_title:
120
+ self._title += data
121
+ return
122
+ self._buf.append(data)
123
+
124
+ def text(self) -> str:
125
+ raw = "".join(self._buf)
126
+ lines = [line.strip() for line in raw.splitlines()]
127
+ # Drop empty lines but keep paragraph breaks.
128
+ out: list[str] = []
129
+ prev_blank = False
130
+ for line in lines:
131
+ if not line:
132
+ if not prev_blank:
133
+ out.append("")
134
+ prev_blank = True
135
+ else:
136
+ out.append(line)
137
+ prev_blank = False
138
+ return "\n".join(out).strip()
139
+
140
+
141
+ def extract_with_stdlib(html: str, url: str) -> str:
142
+ p = _StdlibStripper()
143
+ p.feed(html)
144
+ body = p.text()
145
+ if not body:
146
+ body = "(no text content extracted)"
147
+ header = ""
148
+ title = (p._title or "").strip()
149
+ if title:
150
+ header = f"# {title}\n\n"
151
+ return f"{header}> Source: {url}\n\n{body}\n"
152
+
153
+
154
+ def main() -> int:
155
+ parser = argparse.ArgumentParser(description=__doc__)
156
+ parser.add_argument("url", help="URL to fetch")
157
+ parser.add_argument(
158
+ "--prefer",
159
+ choices=("auto", "readability", "stdlib"),
160
+ default="auto",
161
+ help="Force a specific extractor (default: auto = readability if installed, else stdlib)",
162
+ )
163
+ args = parser.parse_args()
164
+
165
+ try:
166
+ html = fetch_html(args.url)
167
+ except (urllib.error.URLError, urllib.error.HTTPError, TimeoutError, OSError) as exc:
168
+ print(
169
+ f"[fetch] tier=local status=fail reason=\"fetch failed: {exc}\"",
170
+ file=sys.stderr,
171
+ )
172
+ return 1
173
+
174
+ used = ""
175
+ body: str | None = None
176
+
177
+ if args.prefer in ("auto", "readability"):
178
+ body = extract_with_readability(html, args.url)
179
+ if body is not None:
180
+ used = "readability"
181
+ elif args.prefer == "readability":
182
+ print(
183
+ "[fetch] tier=local status=fail "
184
+ "reason=\"--prefer readability but readability-lxml or html2text not installed; "
185
+ "install with: pip install --user readability-lxml html2text\"",
186
+ file=sys.stderr,
187
+ )
188
+ return 1
189
+
190
+ if body is None:
191
+ body = extract_with_stdlib(html, args.url)
192
+ used = "stdlib"
193
+
194
+ # Sanity floor: if even the stdlib extractor returns essentially nothing,
195
+ # treat as failure so the proxy fallback (if --use-proxy) gets a chance.
196
+ body_lines = [l for l in body.splitlines() if l.strip()]
197
+ if len(body_lines) < 4:
198
+ print(
199
+ f"[fetch] tier=local status=fail reason=\"extractor={used} produced <4 non-empty lines\"",
200
+ file=sys.stderr,
201
+ )
202
+ return 1
203
+
204
+ if used == "stdlib":
205
+ print(
206
+ "[fetch] tier=local status=ok extractor=stdlib "
207
+ "hint=\"install readability-lxml + html2text for cleaner output\"",
208
+ file=sys.stderr,
209
+ )
210
+ else:
211
+ print(f"[fetch] tier=local status=ok extractor={used}", file=sys.stderr)
212
+
213
+ sys.stdout.write(body)
214
+ return 0
215
+
216
+
217
+ if __name__ == "__main__":
218
+ sys.exit(main())
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env python3
2
+ """Fetch WeChat public account article as Markdown using Playwright + BeautifulSoup.
3
+
4
+ Special thanks to joeseesun for the excellent qiaomu-markdown-proxy project,
5
+ which inspired the Playwright-based WeChat scraping approach in this script.
6
+ https://github.com/joeseesun/qiaomu-markdown-proxy
7
+
8
+ Requirements:
9
+ pip install playwright beautifulsoup4 lxml
10
+ playwright install chromium
11
+
12
+ Usage:
13
+ python3 fetch_weixin.py <url>
14
+ python3 fetch_weixin.py <url> --json
15
+ """
16
+
17
+ import sys
18
+ import json
19
+ import asyncio
20
+
21
+
22
+ def yaml_string(value: str) -> str:
23
+ return json.dumps("" if value is None else str(value), ensure_ascii=False)
24
+
25
+
26
+ async def fetch(url: str) -> dict:
27
+ try:
28
+ from playwright.async_api import async_playwright
29
+ from bs4 import BeautifulSoup
30
+ except ImportError as e:
31
+ return {"error": str(e) + "\nRun: pip install playwright beautifulsoup4 lxml && playwright install chromium"}
32
+
33
+ async with async_playwright() as p:
34
+ browser = await p.chromium.launch(headless=True)
35
+ page = await browser.new_page(
36
+ user_agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
37
+ )
38
+ try:
39
+ await page.goto(url, wait_until="domcontentloaded", timeout=30000)
40
+ await page.wait_for_selector("#js_content", timeout=15000)
41
+ html = await page.content()
42
+ except Exception as e:
43
+ await browser.close()
44
+ return {"error": f"Page load failed: {e}"}
45
+ await browser.close()
46
+
47
+ soup = BeautifulSoup(html, "lxml")
48
+
49
+ title = (soup.select_one("#activity-name") or soup.new_tag("x")).get_text(strip=True)
50
+ author = (soup.select_one("#js_author_name") or soup.new_tag("x")).get_text(strip=True)
51
+ date = (soup.select_one("#publish_time") or soup.new_tag("x")).get_text(strip=True)
52
+
53
+ content_el = soup.select_one("#js_content")
54
+ if not content_el:
55
+ return {"error": "Could not find #js_content"}
56
+
57
+ for tag in content_el.find_all(["script", "style"]):
58
+ tag.decompose()
59
+
60
+ for img in content_el.find_all("img"):
61
+ src = img.get("data-src") or img.get("src") or ""
62
+ img.replace_with(f"\n![image]({src})\n" if src else "")
63
+
64
+ lines = []
65
+ for el in content_el.find_all(["p", "h1", "h2", "h3", "h4", "section", "blockquote"]):
66
+ text = el.get_text(strip=True)
67
+ if not text:
68
+ continue
69
+ if el.name in ("h1", "h2", "h3", "h4"):
70
+ lines.append(f"{'#' * int(el.name[1])} {text}")
71
+ elif el.name == "blockquote":
72
+ lines.append(f"> {text}")
73
+ else:
74
+ lines.append(text)
75
+
76
+ content = "\n\n".join(lines) or content_el.get_text("\n", strip=True)
77
+ return {"title": title, "author": author, "date": date, "url": url, "content": content}
78
+
79
+
80
+ def to_markdown(r: dict) -> str:
81
+ if "error" in r:
82
+ return f"Error: {r['error']}"
83
+ parts = [
84
+ "---",
85
+ f"title: {yaml_string(r.get('title', ''))}",
86
+ *([f"author: {yaml_string(r['author'])}"] if r.get("author") else []),
87
+ *([f"date: {yaml_string(r['date'])}"] if r.get("date") else []),
88
+ f"url: {yaml_string(r.get('url', ''))}",
89
+ "---",
90
+ "",
91
+ f"# {r['title']}" if r.get("title") else "",
92
+ "",
93
+ r.get("content", ""),
94
+ ]
95
+ return "\n".join(parts)
96
+
97
+
98
+ if __name__ == "__main__":
99
+ if len(sys.argv) < 2:
100
+ print("Usage: fetch_weixin.py <url> [--json]", file=sys.stderr)
101
+ sys.exit(1)
102
+
103
+ result = asyncio.run(fetch(sys.argv[1]))
104
+ if "--json" in sys.argv:
105
+ print(json.dumps(result, ensure_ascii=False, indent=2))
106
+ else:
107
+ print(to_markdown(result))
@@ -0,0 +1,155 @@
1
+ ---
2
+ name: think
3
+ description: "Turns rough ideas into approved, decision-complete plans with validated structure before coding. Use when users ask 出方案/给方案/深入分析/怎么设计/有没有必要/值不值得/plan this/how should I/should we keep this for features, architecture, or value judgments. Not for bug fixes or small edits."
4
+ when_to_use: "出方案, 给方案, 深入分析, 怎么设计, 用什么方案, 判断一下, 有没有必要, 值不值得, what's the best approach, plan this, how should I, should we keep this"
5
+ dispatch_intent: "New feature, architecture, how should I design this, value judgment, executable plan, handoff"
6
+ ---
7
+
8
+ # Think: Design and Validate Before You Build
9
+
10
+ Prefix your first line with 🥷 inline, not as its own paragraph.
11
+
12
+ Turn a rough idea into an approved plan. No code, no scaffolding, no pseudo-code until the user approves.
13
+
14
+ Give opinions directly. Take a position and state what evidence would change it. Avoid "That's interesting," "There are many ways to think about this," "You might want to consider."
15
+
16
+ ## Lightweight Mode
17
+
18
+ Activate when the user wants to fix something rather than build something, the problem is already defined, and the only open question is "how to fix it."
19
+
20
+ Give one recommended fix in 2-3 sentences: what changes, where (file:line if known), and why. Name the brute-force version in one line first; default to it unless the user wants elegance. List involved files, flag explicitly if more than 5. State one risk. Wait for approval before implementing.
21
+
22
+ Upgrade to full mode if you find 3 or more genuinely different approaches with meaningful tradeoffs.
23
+
24
+ ## Evaluation Mode
25
+
26
+ Activate when the user wants to judge whether something should exist, be kept, exposed, or removed. Typical triggers: "判断一下", "有没有必要", "值不值得", "should we keep this", "is this worth it", "我不想做", "商业前景", "有没有必要继续".
27
+
28
+ State the evaluation target and what kind of judgment is needed (value, risk, or tradeoff). Take a current-state snapshot: what it does, who uses it, what depends on it; grep and read before opining.
29
+
30
+ For product pivot, commercialization, or business-direction requests, frame the market, user, distribution, willingness-to-pay, and maintenance burden before proposing technology. Do not assume open source, do not assume implementation comes first, and do not hide a business judgment inside a technical plan.
31
+
32
+ **Output format (Kill/Keep/Pivot):**
33
+
34
+ Line 1: one of **Kill** / **Keep** / **Pivot** as the verdict. No preamble.
35
+
36
+ Then three reasons, based on the user's actual constraints (time, motivation, business model, maintenance cost). Not generic tradeoffs.
37
+
38
+ If verdict is **Pivot**: list specific directions on separate lines, one per line, each actionable.
39
+
40
+ If verdict is **Kill** or major rework: list impact scope (files, dependents, migration cost) before asking for confirmation.
41
+
42
+ Do not use a build-plan template here. Do not list options. Give one verdict.
43
+
44
+ Distinction from Lightweight Mode: Lightweight answers "how to fix it" (method). Evaluation answers "should it exist" (value judgment).
45
+
46
+ ## Before Reading Any Code
47
+
48
+ - Confirm the working path: `pwd` or `git rev-parse --show-toplevel`. Never assume `~/project` and `~/www/project` are the same.
49
+ - If the project tracks prior decisions (ADRs, design docs, issue threads), skim the ones matching the problem before proposing. Skip if none exist.
50
+ - If the plan involves a default value, env var, or config field, open the project's actual config file (e.g. `pake.json`, `tauri.conf.json`, `package.json`, `.env`) and lift the live value. Never quote a default from memory or docs.
51
+
52
+ ## Durable Context Preflight
53
+
54
+ See [rules/durable-context.md](../../rules/durable-context.md) for when to read durable context, the read-order budget, and the memory-type mapping (planning constraints, reusable patterns, facts that need re-verification against current state).
55
+
56
+ For `/think`, planning constraints are `decision`, `preference`, and `principle` entries; current repo state, live docs, logs, tests, and remote state override memory. Lock durable decisions and preferences before asking questions. Do not ask the user to restate an intent that the durable context already establishes unless it is risky, stale, or contradicted by current state.
57
+
58
+ Before outputting any plan, scan the project's `AGENTS.md`, `CLAUDE.md`, `.claude/rules/*.md`, and any local agent-memory summary if the user pointed at one. If the proposed plan contradicts a "hard rule", "never X", "must Y", or "prefer Z" stated in those files, surface the contradiction in the plan output (one sentence: which rule, which step contradicts it, recommended resolution). Do not silently override the rule. If the rule blocks the plan, stop and ask before continuing.
59
+
60
+ ## Check for Official Solutions First
61
+
62
+ Before proposing custom implementations, search for framework built-ins, official patterns, and ecosystem standards. Use Context7 MCP tools to query latest docs when available. If an official solution exists, it is the default recommendation unless you can articulate why it is insufficient for this specific case.
63
+
64
+ ## Propose Approaches
65
+
66
+ Give one recommended approach with rationale. Include effort, risk, and what existing code it builds on. Mention one alternative only if the tradeoff is genuinely close (>40% chance the user would prefer it). Always include one minimal option.
67
+
68
+ When the plan is about distilling lessons from one project into a reusable skill set or shared rules, split the plan into **promote** and **do not promote**. Promote only reusable workflow constraints. Explicitly reject project-specific commands, paths, release checklists, safety boundaries, and private local context unless the user asks to update that project itself.
69
+
70
+ For the recommendation, identify the most fragile assumption (premise collapse) and state it explicitly: "This plan assumes X. If X does not hold, Y happens." If the assumption is load-bearing and fragile, deform the design to survive its failure.
71
+
72
+ **Blocking ambiguities**: if requirements have a conflict the user must resolve (two contradicting sources, two valid interpretations with different cost), name the specific conflict in one sentence and ask which takes precedence. Do not silently pick.
73
+
74
+ **Additional attack angles** (run only when the plan involves external dependencies, high concurrency, or data migration):
75
+
76
+ | Attack angle | Question |
77
+ |---|---|
78
+ | Dependency failure | If an external API, service, or tool goes down, can the plan degrade gracefully? |
79
+ | Scale explosion | At 10x data volume or user load, which step breaks first? |
80
+ | Rollback cost | If the direction is wrong after launch, what state can we return to and how hard is it? |
81
+
82
+ If an attack holds, deform the design to survive it. If it shatters the approach entirely, discard it and tell the user why. Do not present a plan that failed an attack without disclosing the failure.
83
+
84
+ Get approval before proceeding. If the user rejects, ask specifically what did not work. Do not restart from scratch.
85
+
86
+ ## Validate Before Handing Off
87
+
88
+ - More than 8 files or 1 new service? Acknowledge it explicitly.
89
+ - More than 3 components exchanging data? Draw an ASCII diagram. Look for cycles.
90
+ - Every meaningful test path listed: happy path, errors, edge cases.
91
+ - Can this be rolled back without touching data?
92
+ - Every API key, token, and third-party account the plan requires listed with one-line explanations. No credential requests mid-implementation.
93
+ - Every MCP server, external API, and third-party CLI the plan depends on verified as reachable before approval.
94
+
95
+ **No placeholders in approved plans.** Every step must be concrete before approval. Forbidden patterns: TBD, TODO, "implement later," "similar to step N," "details to be determined." A plan with placeholders is a promise to plan later.
96
+
97
+ **Phase independence.** If the plan has multiple phases, each phase must be independently mergeable: after Phase N ships, the system is in a usable state, even if N+1 never lands. Plans that require all phases to complete before anything works are fragile (one stuck phase blocks the whole release) and waste review effort. If the work cannot be cut into mergeable phases, say so and ship it as one phase instead of pretending it is staged.
98
+
99
+ **Plan red flags (self-check before handoff):**
100
+ - A phase depends on the next phase to be useful (cannot ship alone).
101
+ - A "Phase 0: investigate / spike" exists. Investigation belongs before the plan, not inside it.
102
+
103
+ Either red flag means the plan is not ready. Resolve it before handing off.
104
+
105
+ ## Implementation Handoff
106
+
107
+ A finished plan must be executable by another engineer or agent without re-deciding the direction. Include:
108
+
109
+ - Scope and non-scope.
110
+ - The chosen approach and the one rejected alternative, if the tradeoff was close.
111
+ - Public API, schema, command, config, or file-interface changes, if any.
112
+ - Verification commands and manual acceptance checks.
113
+ - Release, publish, migration, or issue/PR follow-through steps, if the task naturally continues there.
114
+ - Rollback or failure handling for any step that can leave external state changed.
115
+
116
+ When the user asks to export a handoff, or when the environment prevents further execution, make the handoff execution-ready instead of explaining the limitation. Include file targets, key constants or selectors, exact commands, runtime or visual checklist, and risk boundaries. If the work depends on a screenshot or artifact, name the artifact and the pass/fail delta.
117
+
118
+ When the user later says "Implement the plan", "可以干", "直接改", "整", or equivalent, treat that as approval of the written plan. Do not re-litigate the design. State which plan is being executed, check for obvious drift in the repo, and proceed. If the environment has changed enough that the plan is unsafe, name the specific drift and stop before editing.
119
+
120
+ ## Gotchas
121
+
122
+ | What happened | Rule |
123
+ |---------------|------|
124
+ | Moved files to `~/project`, repo was at `~/www/project` | Run `pwd` before the first filesystem operation |
125
+ | Asked for API key after 3 implementation steps | List every dependency before handing off |
126
+ | User said "just do it" or equivalent approval | Treat as approval of the recommended option. State which option was selected, finish the plan. Do not implement inside `/think`. |
127
+ | Planned MCP workflow without checking if MCP was loaded | Verify tool availability before handing off, not mid-implementation |
128
+ | Rejected design restarted from scratch | Ask what specifically failed, re-enter with narrowed constraints |
129
+ | User said "just fix X" and skipped /think | If the fix touches 3+ files or needs a method choice, pause and run Lightweight Mode |
130
+ | User approved a concrete plan and the agent debated the plan again | Execute the approved plan. Only stop for repo drift, missing permissions, or unsafe external state |
131
+ | Picked a regional or locale-specific API variant without checking | List all regional or locale differences before writing integration code |
132
+ | Introduced a second language or runtime into a single-stack project | Never add a new language or runtime without explicit approval |
133
+ | User said "判断一下这个报错" and got Evaluation Mode | "判断一下" + error/bug context = debugging, route to `/hunt`. Evaluation Mode is for value/existence judgments only |
134
+ | User asked to "沉淀到 Waza" after a project review | First separate transferable Waza capability from project facts. Do not import that project's commands, paths, or release rules into Waza |
135
+
136
+ ## Output
137
+
138
+ **Approved design summary:**
139
+ - **Building**: what this is (1 paragraph)
140
+ - **Not building**: explicit out-of-scope list
141
+ - **Approach**: chosen option with rationale
142
+ - **Key decisions**: 3-5 with reasoning
143
+ - **Unknowns**: only items that are explicitly deferred with a stated reason and a clear owner. Not vague gaps. If an unknown blocks a decision, loop back before approval.
144
+
145
+ After the user approves the design, stop. Implementation starts only when requested.
146
+
147
+ ## After Approval
148
+
149
+ When the plan is approved, output this guidance:
150
+
151
+ ```
152
+ Plan approved. To implement: say "implement this plan". After implementation, run `/check` to review before merging or release follow-through.
153
+ ```
154
+
155
+ Keep it concise (2-3 sentences max). The user decides when to start implementation.
@@ -0,0 +1,129 @@
1
+ ---
2
+ name: write
3
+ description: "Rewrites and polishes prose in Chinese or English, removing AI-like wording while preserving intent for drafts, docs, release notes, launch copy, and social posts. Use when users ask 帮我写/改稿/润色/去AI味/写一段/审稿/tweet/rewrite/proofread. Not for code comments, commit messages, or inline docs."
4
+ when_to_use: "帮我写, 改稿, 润色, 去AI味, 写一段, 审稿, 文档review, check this document, 推特, twitter, X推文, tweet, social post, 连贯性, 段落连贯, draft, edit text, proofread, sound natural, polish, rewrite"
5
+ dispatch_intent: "Writing, editing prose, polish, release notes, launch/social copy, remove AI tone"
6
+ ---
7
+
8
+ # Write: Cut the AI Taste
9
+
10
+ Prefix your first line with 🥷 inline, not as its own paragraph.
11
+
12
+ Strip AI patterns from prose and rewrite it to sound human. Do not improve vocabulary; remove the performance of improvement.
13
+
14
+ ## Pre-flight
15
+
16
+ 1. **Text present?** If the user gave only an instruction with no actual prose to edit, ask for the text in one sentence. Do not proceed.
17
+ 2. **Audience locked?** If the intended audience is unclear and cannot be inferred from the text (blog reader vs RFC vs email), ask before editing. Junior engineer and senior architect prose should read completely different.
18
+ 3. **Language detected from the text being edited**, not the user's command:
19
+ - Contains Chinese characters + release notes or social post mode → load `references/write-zh-release-notes.md`
20
+ - Contains Chinese characters + bilingual or translation review → load `references/write-zh-bilingual.md`
21
+ - Contains Chinese characters (default prose) → load `references/write-zh-prose.md` (quick rules); load `references/write-zh.md` for the full AI-taste pattern catalog
22
+ - Otherwise → load `references/write-en.md`
23
+
24
+ Read the loaded reference file. Then edit. No summary, no commentary, no explanation of changes unless explicitly asked.
25
+
26
+ ## Durable Context Preflight
27
+
28
+ See [rules/durable-context.md](../../rules/durable-context.md) for when to read durable context, the read-order budget, and the memory-type mapping.
29
+
30
+ For `/write`, voice and format constraints are `decision`, `preference`, and `principle` entries; editing checks are `pattern` and `learning`. The supplied text, audience, project docs, current release state, and source material override memory. Durable preferences can set brevity, tone, and social-post shape. They do not override the hard rule to edit in place, keep meaning intact, and avoid change lists unless the user explicitly asks.
31
+
32
+ ## Hard Rules
33
+
34
+ - **Meaning first, style second.** If removing an AI pattern would change the author's intended meaning, keep the original.
35
+ - **No silent restructuring.** Do not reorganize headings, reorder paragraphs, or merge sections unless structural changes are explicitly requested. Edit in place.
36
+ - **Artifact-grounded claims.** For launch copy, release notes, social posts, product pages, and public replies, ground factual claims in real source material: current app behavior, screenshots, product page, release page, changelog, issue/PR, or user-provided draft. Do not turn concrete product evidence into generic marketing language.
37
+ - **Stop after output.** Deliver the rewritten text. Do not append a list of changes, a justification, or a closer.
38
+
39
+ ## Bilingual Review Mode
40
+
41
+ Activate when: mixed Chinese/English, "Chinese copywriting", "bilingual consistency", "release notes"
42
+
43
+ **Chinese rules** (from https://github.com/mzlogin/chinese-copywriting-guidelines):
44
+ - Space between Chinese and English characters (CN文字EN → CN 文字 EN)
45
+ - No mixing of punctuation (Chinese uses 、。?!;:, not commas/periods)
46
+ - Consistent terminology across all instances
47
+
48
+ **English in Chinese documents**: Flag unexplained English, suggest translation or add context.
49
+
50
+ **Bilingual pairs**: Confirm EN and CN versions convey the same meaning; mark translation loss.
51
+
52
+ ## Release Note Template Mode
53
+
54
+ Activate when: "release", "changelog", "version", "release notes"
55
+
56
+ Generate from commit messages:
57
+ - **Breaking Changes**
58
+ - **New Features**
59
+ - **Fixes & Improvements**
60
+ - **Deprecations**
61
+
62
+ Format: target-project style by default. If no project style is available, use numbered items with bold labels, one sentence on user effect, and bilingual output only when the project already uses bilingual release notes.
63
+
64
+ ### Release Notes Pre-flight
65
+
66
+ Before drafting, gather style references:
67
+
68
+ 1. Read the target project's `CLAUDE.md` for its Release Convention / Release Flow section.
69
+ 2. Run `gh release view --json body -R <owner>/<repo>` to read the most recent release as a style, length, and density reference.
70
+ 3. If the user mentions comparing with a sibling project's release style, ask for the `owner/repo` to fetch it: `gh release view --json body -R <owner>/<sibling>`.
71
+ 4. Match the reference release's item count, sentence length, and tone. Do not invent a new format.
72
+ 5. Keep each release-note item to one sentence unless the reference project clearly does otherwise. Do not add emoji to release prose unless the target surface is explicitly a reaction or celebratory social surface.
73
+
74
+ ## Document Review Mode
75
+
76
+ Activate when: PDF, document, white paper, "review this document", "check this document", "审稿"
77
+
78
+ Review checklist:
79
+ - **Privacy scan**: Detect PII (names, companies, employment dates, salary hints, location details). Hard stop if any text implies job seeking, competitor info, or personal data leakage.
80
+ - **Tone consistency**: Flag voice shifts, register mismatches, formulaic phrasing. Check for AI patterns using the loaded `write-zh.md` or `write-en.md` rules.
81
+ - **Bilingual validation**: For CN/EN pairs, confirm translation accuracy and terminology consistency. Apply Bilingual Review Mode rules.
82
+ - **Rendering check**: Placeholder text remaining (`Lorem ipsum`, `TODO`, `[TBD]`), broken image links.
83
+ - **Durable-doc scan**: If the document is a review report, scorecard, or diagnostic snapshot, flag dated claims, stale line references, private paths, repo-specific commands, and current-score framing. Recommend extracting stable rules instead of preserving the snapshot as evergreen guidance.
84
+
85
+ Output format: same as prose rewrite, but append `privacy: clear / N issues found` after the reviewed text.
86
+
87
+ ## Paragraph Coherence Mode
88
+
89
+ Activate when: "连贯性", "段落连贯", "可读性", "coherence", "flow check", "段落顺不顺"
90
+
91
+ Do not rewrite. Instead, work through each paragraph in sequence:
92
+ 1. Flag transitions that abruptly shift topic without a signal.
93
+ 2. Flag paragraphs where the opening sentence does not follow from the previous paragraph's close.
94
+ 3. Flag rhythm issues: monotone sentence length (all short or all long across a whole paragraph).
95
+ 4. Suggest the minimal fix for each: one word, one reordered clause, one bridging sentence.
96
+
97
+ Output: a numbered list of issues, each with the paragraph location and a one-line fix suggestion. Then ask if the user wants any applied.
98
+
99
+ ## Tweet / Social Post Mode
100
+
101
+ Activate when: "推特", "twitter", "X推文", "tweet", "social post", "折叠长度", "长文推特", "发文"
102
+
103
+ Apply the five announcement rules for product-engineer projects when the project context or prior artifact shows this style:
104
+ 1. **Lead with community**: open with the social anchor (star count, user thanks, whose feedback drove the fix). Changes follow, not lead.
105
+ 2. **Highlights over completeness**: pick 2 to 4 of the most interesting changes. Dropping whole items is fine.
106
+ 3. **UX framing**: phrase each point as "你用它的时候..." or "有一种...的感觉", not "这个工具做了...".
107
+ 4. **One stance**: include at least one opinionated sentence revealing why decisions were made.
108
+ 5. **Native Chinese rhythm**: use idiomatic phrasing. Avoid translation-sounding terms.
109
+
110
+ Close casually with an invitation, not a CTA. End with one short sentence inviting readers to try, not "立即升级".
111
+
112
+ For other engineering projects or English posts, apply the same structure (community lead, highlights, UX framing, one stance, casual close) adapted to the project's voice.
113
+
114
+ ## Gotchas
115
+
116
+ | What happened | Rule |
117
+ |---------------|------|
118
+ | Reorganized headings without being asked | Do not restructure; edit in place unless structure changes are explicitly requested |
119
+ | Appended a "changes made" list after the rewrite | Output is the edited text only. No changelog, no commentary. |
120
+ | Used formal register for a blog draft | Match the target audience's register. Blog is conversational, not academic. |
121
+ | Applied Chinese/English spacing rules to a pure-English text | Bilingual spacing rules (半角/全角) only apply when the text mixes Chinese and English |
122
+ | Polished the user's voice into generic launch copy | Preserve the author's cadence and stance. Use real product artifacts to sharpen facts, not to replace the voice. |
123
+ | Drafted release or social copy from memory | Read the current release page, changelog, issue/PR, product page, screenshot, or supplied source before making factual claims. |
124
+ | Wrote launch copy in one pass without checking the live screenshots | Iterate: draft, compare against the real product screenshot or page, tighten wording to match what ships, repeat until copy and artifact agree |
125
+ | Polished a review report until it sounded timeless | Keep snapshots labeled as snapshots, or distill them into stable rules. Do not make dated claims sound evergreen |
126
+
127
+ ## Output
128
+
129
+ Return only the edited prose. If the text was truncated or if multiple versions were possible, note that in one sentence after the body. Otherwise, no wrapper, no preamble, no postscript.