Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e70b228af3 | ||
|
|
dd80147f39 | ||
|
|
fe140fbd9f | ||
|
|
1524b15cd0 | ||
|
|
1d0a04c158 | ||
|
|
8e7abb2092 | ||
|
|
211c0f05d8 | ||
|
|
23c7037b57 | ||
|
|
484a9225f3 | ||
|
|
d99ac3a142 | ||
|
|
e99b5fe482 | ||
|
|
04efa2d72e | ||
|
|
ef183636fc | ||
|
|
0a5d283dfd | ||
|
|
bc16d00ea7 |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
repomix-output.xml
|
||||
21
CLAUDE.md
21
CLAUDE.md
@@ -8,7 +8,7 @@ Behavioral guidelines to reduce common LLM coding mistakes. Merge with project-s
|
||||
|
||||
- **Address the user as**: Charles
|
||||
- **Reply language**: Chinese for prose; keep code, commands, and technical terms in English
|
||||
- **Git push policy**: push by default when there are commits. Only skip if the user says not to, or the repo lacks a remote / credentials
|
||||
- **Git push policy**: push by default when there are commits — **don't ask first, just push**. Only skip if the user explicitly says not to, or the repo lacks a remote / credentials
|
||||
- **Version-control hygiene**: commit messages must explain *why*, not just *what*. Confirm before risky ops (`push --force`, `reset --hard`, `rm -rf`, branch deletion)
|
||||
- **Default git remote**: `git.deepknow.site` (credentials stored in memory)
|
||||
- **Gitea management** (`git.deepknow.site/Knowit`, API via `curl`):
|
||||
@@ -16,7 +16,8 @@ Behavioral guidelines to reduce common LLM coding mistakes. Merge with project-s
|
||||
- ⚠️ Confirm first: rename repo, change visibility, add/remove collaborators, delete branches, change default branch
|
||||
- ❌ Require explicit command every time: delete repo, force-push to `main`/`master`, rewrite published history, change org permissions
|
||||
- Prefer a scoped API token over username/password when one becomes available
|
||||
- **Package managers**: `pnpm` (Node), `uv` (Python), `cargo` (Rust)
|
||||
- **Package managers**: `pnpm` (Node), `uv` (Python), `cargo` (Rust), `apt` (Linux)
|
||||
- **Web stack**: prefer TypeScript over JavaScript (frontend frameworks, Node backends, scripts); follow the existing project's language choice
|
||||
- **Indentation**: 4 spaces by default; follow project convention if different
|
||||
|
||||
## 1. Think Before Coding
|
||||
@@ -25,8 +26,8 @@ Behavioral guidelines to reduce common LLM coding mistakes. Merge with project-s
|
||||
|
||||
**Workflow: Locate → Plan → Execute.** Never jump straight to edits.
|
||||
|
||||
1. **Locate**: find the relevant files, functions, call sites, and tests. Quote or cite the existing code before proposing changes. If you can't locate it, say so — don't guess.
|
||||
2. **Plan**: state the intended change in one or two sentences. List assumptions and open questions. If uncertain, ask before writing code.
|
||||
1. **Locate**: find the relevant files, functions, call sites, and tests. Quote or cite the existing code before proposing changes. If you can't locate it, say so — don't guess. Tooling details and known pitfalls live in `note.md` / `debug.md` (auto-imported below).
|
||||
2. **Plan**: state the intended change in one or two sentences. List assumptions and open questions. Give a rough estimate of **token consumption** (reads + writes + tool calls) and **wall-clock time** so the user can redirect early if the scope is off. If uncertain, ask before writing code.
|
||||
3. **Execute**: make the minimal edit that matches the plan. Deviations require a new plan, not silent improvisation.
|
||||
|
||||
Before implementing:
|
||||
@@ -71,6 +72,18 @@ For multi-step tasks, state a brief plan:
|
||||
|
||||
Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification.
|
||||
|
||||
## 5. Extended references (auto-imported)
|
||||
|
||||
These files expand into context at session start:
|
||||
|
||||
- Tool catalog: @~/.claude/tool.md
|
||||
- Practice notes: @~/.claude/note.md
|
||||
- Debug pitfalls: @~/.claude/debug.md
|
||||
|
||||
Not auto-imported (read on demand):
|
||||
|
||||
- Session log: `~/.claude/log.md` — appended by SessionEnd hook, grows unboundedly so kept out of context to save tokens
|
||||
|
||||
---
|
||||
|
||||
**These guidelines are working if:** fewer unnecessary changes in diffs, fewer rewrites due to overcomplication, and clarifying questions come before implementation rather than after mistakes.
|
||||
|
||||
51
hooks/session-end-log/README.md
Normal file
51
hooks/session-end-log/README.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# session-end-log
|
||||
|
||||
Claude Code SessionEnd hook:每次会话结束时在 `~/.claude/log.md` 追加一行元数据 + token 用量。
|
||||
|
||||
用 Python 编写,零依赖(Ubuntu 自带 `python3`)。
|
||||
|
||||
## 输出格式
|
||||
|
||||
```
|
||||
- 2026-04-21T00:55:30 | session=353cbdc1 | cwd=/home/charles | reason=clear | tokens=total:592.7k in:39 out:3.7k cache_r:558.2k cache_w:30.7k
|
||||
```
|
||||
|
||||
字段:
|
||||
- `reason`:`clear` / `logout` / `resume` / `prompt_input_exit` 之一
|
||||
- `session`:session_id 前 8 位
|
||||
- `tokens`:读取该会话的 transcript(`~/.claude/projects/<slug>/<sid>.jsonl`)按 `type=assistant` 的 usage 累加;transcript 读不到时降级为 `tokens=unavailable`,不阻塞会话退出
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.claude/hooks
|
||||
cp hooks/session-end-log/session-end-log.py ~/.claude/hooks/
|
||||
chmod +x ~/.claude/hooks/session-end-log.py
|
||||
```
|
||||
|
||||
然后在 `~/.claude/settings.json` 的 `hooks` 下加入(与现有 `Stop` 等共存):
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"SessionEnd": [
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "python3 ~/.claude/hooks/session-end-log.py 2>/dev/null || true"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 测试
|
||||
|
||||
```bash
|
||||
echo '{"cwd":"/home/charles","reason":"test","session_id":"<real-session-id>"}' \
|
||||
| python3 ~/.claude/hooks/session-end-log.py
|
||||
tail -1 ~/.claude/log.md
|
||||
```
|
||||
75
hooks/session-end-log/session-end-log.py
Executable file
75
hooks/session-end-log/session-end-log.py
Executable file
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env python3
|
||||
"""SessionEnd hook: append one metadata + token-usage line to ~/.claude/log.md."""
|
||||
import json, sys, pathlib
|
||||
from datetime import datetime
|
||||
|
||||
try:
|
||||
data = json.load(sys.stdin)
|
||||
except Exception:
|
||||
data = {}
|
||||
|
||||
ts = datetime.now().strftime("%Y-%m-%dT%H:%M:%S")
|
||||
cwd = data.get("cwd", "?")
|
||||
reason = data.get("reason", "?")
|
||||
sid = data.get("session_id") or "?"
|
||||
sid_short = sid[:8]
|
||||
|
||||
|
||||
def find_transcript():
|
||||
tp = data.get("transcript_path")
|
||||
if tp and pathlib.Path(tp).exists():
|
||||
return pathlib.Path(tp)
|
||||
if cwd == "?" or sid == "?":
|
||||
return None
|
||||
slug = cwd.replace("/", "-")
|
||||
candidate = pathlib.Path.home() / ".claude" / "projects" / slug / f"{sid}.jsonl"
|
||||
return candidate if candidate.exists() else None
|
||||
|
||||
|
||||
def sum_tokens(path):
|
||||
totals = {"input": 0, "output": 0, "cache_read": 0, "cache_write": 0}
|
||||
try:
|
||||
with path.open() as f:
|
||||
for line in f:
|
||||
try:
|
||||
rec = json.loads(line)
|
||||
except Exception:
|
||||
continue
|
||||
if rec.get("type") != "assistant":
|
||||
continue
|
||||
u = rec.get("message", {}).get("usage") or {}
|
||||
totals["input"] += u.get("input_tokens", 0)
|
||||
totals["output"] += u.get("output_tokens", 0)
|
||||
totals["cache_read"] += u.get("cache_read_input_tokens", 0)
|
||||
totals["cache_write"] += u.get("cache_creation_input_tokens", 0)
|
||||
except Exception:
|
||||
pass
|
||||
return totals
|
||||
|
||||
|
||||
def fmt(n):
|
||||
if n >= 1_000_000:
|
||||
return f"{n/1_000_000:.1f}M"
|
||||
if n >= 1_000:
|
||||
return f"{n/1_000:.1f}k"
|
||||
return str(n)
|
||||
|
||||
|
||||
tpath = find_transcript()
|
||||
if tpath:
|
||||
t = sum_tokens(tpath)
|
||||
total = sum(t.values())
|
||||
tok_str = (
|
||||
f"tokens=total:{fmt(total)} "
|
||||
f"in:{fmt(t['input'])} out:{fmt(t['output'])} "
|
||||
f"cache_r:{fmt(t['cache_read'])} cache_w:{fmt(t['cache_write'])}"
|
||||
)
|
||||
else:
|
||||
tok_str = "tokens=unavailable"
|
||||
|
||||
line = f"- {ts} | session={sid_short} | cwd={cwd} | reason={reason} | {tok_str}\n"
|
||||
log = pathlib.Path.home() / ".claude" / "log.md"
|
||||
if not log.exists():
|
||||
log.write_text("# Session Log\n\n")
|
||||
with log.open("a") as f:
|
||||
f.write(line)
|
||||
58
mdTemplet/debug.md
Normal file
58
mdTemplet/debug.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# Debug / Pitfalls
|
||||
|
||||
按工具 / 主题分节:`## <tool>` 为二级分组,具体坑用 `### YYYY-MM-DD 简述` + `症状 / 原因 / 规避` 三联。同工具的坑逐步往下追加。
|
||||
|
||||
## eza
|
||||
|
||||
### 2026-04-21 --tree 无路径参数静默空输出
|
||||
- 症状: `eza --tree --git-ignore --level=2` 输出空, exit 0
|
||||
- 原因: eza tree 模式需要显式路径参数
|
||||
- 规避: 总是加 `.`(或其他路径)
|
||||
|
||||
## broot
|
||||
|
||||
### 2026-04-21 无法在非交互环境使用
|
||||
- 症状: `broot --cmd ":pt;:q"` 报 `Termimad Error: IO error: No such device`
|
||||
- 原因: broot 需要 TTY, 设计就是交互工具
|
||||
- 规避: CLI/Claude Code 场景直接用 eza + fd + rg
|
||||
- 附注: 首次运行会自动 patch `~/.bashrc` 和 `~/.zshrc` 注入 `br` 函数
|
||||
|
||||
## repomix
|
||||
|
||||
### 2026-04-21 大仓库 token 预算
|
||||
- 症状: nexus4cc (203M 磁盘) 经 .gitignore 过滤后仍 144k tokens
|
||||
- 原因: 前端单文件(如 Terminal.tsx 21k tokens)累积
|
||||
- 规避: > 100k tokens 的仓库按子目录切片 (`repomix frontend/src -o /tmp/fe.xml`)
|
||||
|
||||
## sd
|
||||
|
||||
### 2026-04-21 捕获组引用是 $1 不是 ${$1},字面量 $ 要写 $$
|
||||
- 症状: `sd 'pat (\w+)' '${$1}' file` 输出把 `$1` 位置变成空字符串,替换结果不对
|
||||
- 原因: sd replacement 里 `$1` 或 `${1}` 才是捕获组引用,`${$1}` 解析失败;字面 `$` 需要写 `$$`
|
||||
- 规避: 想生成 `` `/api/users/${id}` `` 这类带字面 `${...}` 的输出,replacement 写作 `` `/api/users/$${$1}` ``(`$$` = 字面 `$`,`$1` = 捕获值);不确定时先用 stream 模式 `sd ... < file` 预览再 in-place
|
||||
|
||||
## pkill / bash
|
||||
|
||||
### 2026-04-21 pkill -f 匹配自身命令行导致 shell 退出
|
||||
- 症状: `pkill -f cdp-proxy.mjs` 后整个 Bash 块 exit 144,没有错误信息
|
||||
- 原因: `-f` 按完整命令行匹配,Bash tool 执行 `-c "pkill -f cdp-proxy.mjs ..."` 时 argv 里包含 "cdp-proxy.mjs",pkill 把自己的父 shell 一并杀了
|
||||
- 规避: 用 `pgrep -af <pattern>` 先列出 PID 再按 PID kill;或用更窄的 regex 如 `'cdp\S*proxy'`(regex 元字符不在自己的命令行里出现)
|
||||
|
||||
## lightpanda
|
||||
|
||||
### 2026-04-21 Beta 能力边界
|
||||
- 症状: 多个看似标准的 CDP 操作失败:第二次 `/new` 返回空对象、`/screenshot` 报 `UnknownTargetId`、关闭最后一个 tab 后所有请求 `BrowserContextNotLoaded`
|
||||
- 原因: v1.0.0-nightly.5674 当前实现受限 ——(1)只维护单 target/BrowserContext(targetId 永远是 `FID-0000000001`)(2)`Page.captureScreenshot` 未实现(3)没有 tab 自动重生机制
|
||||
- 规避: 同时多目标时用 A 模式(`lightpanda fetch`)或多进程 serve;需要截图走 web-access 默认 Chrome 模式;避免 close 最后一个 tab(或 close 后立即 `/new` 重建)
|
||||
|
||||
### 2026-04-21 强反爬 SPA 被挡在 noscript 页
|
||||
- 症状: 导航到 x.com 等站点,`document.body.innerText` 返回 `<noscript>` 错误页内容而不是真实页面
|
||||
- 原因: lightpanda 覆盖率不足,被站点的反爬/浏览器指纹检测识别为非真浏览器
|
||||
- 规避: 需要反爬能力强的场景切换到 web-access 连真 Chrome;或提前测试目标站点可行性
|
||||
|
||||
## web-access skill
|
||||
|
||||
### 2026-04-21 cdp-proxy.mjs 硬编码 Chrome 专用 ws 路径,不兼容 lightpanda
|
||||
- 症状: `lightpanda serve --port 9222` 起来后 `check-deps.mjs` 报 "连接超时",proxy 日志循环 "连接错误: 连接失败"
|
||||
- 原因: `scripts/cdp-proxy.mjs` `getWebSocketUrl()` fallback 到 `/devtools/browser`(Chrome 专用),而 lightpanda 的 `webSocketDebuggerUrl` 是 `ws://host:port/`(根路径)
|
||||
- 规避: 端口扫描分支加入 `/json/version` 探测(CDP 标准 discovery endpoint),从响应的 `webSocketDebuggerUrl` 取 `pathname`。通用修复,Chrome 也受益。已本地 patch,skill 升级会被覆盖,需重新应用
|
||||
2
mdTemplet/log.md
Normal file
2
mdTemplet/log.md
Normal file
@@ -0,0 +1,2 @@
|
||||
# Session Log
|
||||
|
||||
21
mdTemplet/note.md
Normal file
21
mdTemplet/note.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Practice Notes
|
||||
|
||||
按工具 / 主题分节。跨工具的工作流放在前面(如 `## Locate workflow`),单工具的具体实践放各自 `## <tool>` 节下。
|
||||
|
||||
## Locate workflow (for mature/unfamiliar repos)
|
||||
|
||||
- `repomix -o /tmp/x.xml` (or `repomix <subdir>`) — full-repo LLM pack; slice by subdir if > 100k tokens
|
||||
- `eza --tree --git-ignore --level=3 .` for layout (path arg required)
|
||||
- `fd <pat>` for files; `rg <sym>` for call sites
|
||||
- `git ls-files` when tokens are tight
|
||||
|
||||
## lightpanda
|
||||
|
||||
- 关掉遥测:`export LIGHTPANDA_DISABLE_TELEMETRY=true`
|
||||
- 快速抓 markdown(A 模式):`lightpanda fetch --dump markdown --obey-robots <url>`;`--wait-until` / `--wait-ms` / `--wait-selector` 调节等待
|
||||
- 作 web-access skill 的 CDP 后端(B 模式):
|
||||
1. `lightpanda serve --host 127.0.0.1 --port 9222` 后台跑
|
||||
2. `node ~/.claude/skills/web-access/scripts/cdp-proxy.mjs` 后台跑(自动扫 9222)
|
||||
3. 用 `curl http://localhost:3456/new?url=...` 等 API;`/targets` 列 tab,`/eval?target=ID` 执行 JS,`/info?target=ID` 查标题/URL
|
||||
- 区分 A vs B:公开静态页用 A(快、无状态);需要点击/上传/多 tab/交互取 DOM 用 B
|
||||
- 不具备登录态(对比 web-access 连用户日常 Chrome);需要登录的站点仍走用户 Chrome 模式
|
||||
34
mdTemplet/tool.md
Normal file
34
mdTemplet/tool.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Tool Catalog
|
||||
|
||||
额外安装的 CLI 工具速查。详细用法见 `note.md`,踩坑见 `debug.md`。
|
||||
|
||||
## 定位 / 搜索
|
||||
- `repomix` — 整仓打包为 LLM 友好的 XML(pnpm global)
|
||||
- `eza` — 现代化 `ls` / `tree`(带 git 状态、`.gitignore` 过滤)
|
||||
- `fd` — 快速文件搜索(默认尊重 `.gitignore`)
|
||||
- `rg` — 内容搜索(ripgrep)
|
||||
- `broot` — 交互式目录浏览(仅 TTY,CLI/pipeline 不用)
|
||||
|
||||
## 协作
|
||||
- `gh` — GitHub CLI(已登录)
|
||||
- `curl` — Gitea API 交互(见 CLAUDE.md §0)
|
||||
|
||||
## 浏览器 / 联网
|
||||
- `lightpanda` — Zig 写的无头浏览器,CDP 兼容,~1/16 内存 / ~9x 速度 vs headless Chrome(Beta,Web API 覆盖率不完整)
|
||||
|
||||
## 数据 / 文本处理
|
||||
- `jq` — JSON 流式处理与查询
|
||||
- `mlr` (miller) — CSV/TSV/JSON/JSONL 结构化数据瑞士军刀(比 awk/csvkit 强)
|
||||
- `sd` — sed 替代,语法直观(`sd 'foo' 'bar' file`)
|
||||
- `ast-grep` — 按 AST 模式搜索/替换代码(`sg -p 'console.log($X)' -r 'logger.debug($X)' --lang js`);二进制也叫 `sg` 但 /usr/bin/sg 冲突,用 `ast-grep` 调用
|
||||
|
||||
## 开发体验
|
||||
- `delta` — git diff/log 彩色优化渲染(配 `git config --global core.pager delta`)
|
||||
- `hyperfine` — 命令 benchmark,多次采样统计分布
|
||||
|
||||
## AI / LLM
|
||||
- `llm` (simonw) — CLI 调 LLM(多 provider,支持 OpenAI/Anthropic/本地模型),可作为子进程进行独立查询/对比
|
||||
|
||||
## MCP servers(~/.claude.json,user scope)
|
||||
- `chrome-devtools` — 完整浏览器调试能力(补 lightpanda 缺的多 tab / 截图 / 强反爬场景)
|
||||
- `context7` — 第三方库最新文档检索,防止 LLM 用过时 API
|
||||
Reference in New Issue
Block a user