---
name: Readme Profile
slug: readme-profile
category: Data
description: Readme Profile generates a shareable, anonymized AI-native developer README from local Claude Code, Codex CLI, Kiro, Trae, Gemini Antigravity, and Cursor data. It is used to summarize tool usage, collaboration style, project distribution, and monthly coding activity.
github: "https://github.com/study8677/Readme.skill/tree/main/skills/readme-skill"
stars: 168
forks: 9
install: "npx degit https://github.com/study8677/Readme.skill/tree/main/skills/readme-skill ~/.claude/skills/readme-skill"
installs_to: ~/.claude/skills/readme-skill
source_path: skills/readme-skill/SKILL.md
collection_size: 1
category_size: 812
added: 2026-09-08T05:34:05.993Z
last_synced: 2026-09-08T05:34:05.993Z
canonical_url: "https://dirskills.com/skills/readme-profile"
---

# Readme Profile

Readme Profile generates a shareable, anonymized AI-native developer README from local Claude Code, Codex CLI, Kiro, Trae, Gemini Antigravity, and Cursor data. It is used to summarize tool usage, collaboration style, project distribution, and monthly coding activity.

**Install:**

```bash
npx degit https://github.com/study8677/Readme.skill/tree/main/skills/readme-skill ~/.claude/skills/readme-skill
```

## README

# Readme.skill — AI-Native 开发者档案生成器

You (the AI agent invoking this skill) will read local Claude Code + Codex CLI
+ Kiro (AWS) + Trae (ByteDance) + Gemini Antigravity (Google) + Cursor data,
compute a fixed set of dimensions, and render both a Markdown profile and a
validated SVG poster under `./output/` in the user's requested language (Chinese
by default; English when the user asks in English or explicitly requests
English). The profile and poster can cover the default history view or an
explicit month / date range. **You do all of the work** — read the files with
`Read`, query sqlite via `Bash`, synthesize the prose yourself, then write and
validate the SVG. Do **not** write helper scripts; the skill is the recipe.

> 支持的 6 个 AI 编程工具（任一缺失都自动降级跳过）：
> 1. **Claude Code** (`~/.claude/`) — Step 2
> 2. **Codex CLI** (`~/.codex/`) — Step 3
> 3. **Kiro CLI / IDE** (`~/.kiro/` + `~/.local/share/kiro-cli/`) — Step 3b
> 4. **Trae IDE** (`~/Library/Application Support/Trae/` + 项目 `.trae/`) — Step 3c
> 5. **Gemini Antigravity** (`~/.gemini/antigravity/brain/`) — Step 3d
> 6. **Cursor** (`~/Library/Application Support/Cursor/` + 项目 `.cursor/`) — Step 3e

> 默认行为：**对外分享版** —— 项目名匿名、敏感信息脱敏。
> 如果用户明确说"私人版 / 不要脱敏 / show real names"，跳过匿名步骤。

---

## Step 1 — 准备

```bash
cd <repo-with-this-skill>   # e.g. ~/Projects/Readme.skill
mkdir -p output
DATE=$(date +%Y%m%d)
```

Decide anonymization mode (default = on). Build an in-memory mapping
`real_path → "项目 A/B/C"` as you encounter project paths in later steps.
Use the same mapping consistently across all sections.

### 1.1 时间窗口 / 月度报告模式

If the user asks for a month, quarter, stage, date range, "月度报告",
"按月份分析", "time range", "monthly report", or similar, set a report window
before reading any data. The window is a half-open local-date interval:
`[REPORT_START, REPORT_END_EXCL)`.

Supported phrases:
- Single month: `2026-05`, `2026年5月`, `May 2026` → `REPORT_START=2026-05-01`,
  `REPORT_END_EXCL=2026-06-01`, `REPORT_LABEL=2026-05`,
  `REPORT_SLUG=202605`, `REPORT_MODE=monthly`
- Month range: `2026-04 到 2026-05`, `Apr-May 2026` → start at the first day of
  the first month, end at the first day after the last month,
  `REPORT_MODE=range`
- Explicit dates: `2026-05-03 到 2026-05-19` / `2026-05-03..2026-05-19` →
  include both named dates by setting `REPORT_END_EXCL` to the day after the
  final date, `REPORT_MODE=range`
- Relative range: `最近30天` / `last 30 days` → compute from today's local date,
  `REPORT_MODE=range`

If no explicit time window is requested, keep the existing default profile
behavior: AI tool totals may use all available local history, while GitHub and
local git use their existing 365-day windows. Set `WINDOW_REQUESTED=0`.

If a window is requested, set:

```bash
WINDOW_REQUESTED=1
REPORT_START=<YYYY-MM-DD>
REPORT_END_EXCL=<YYYY-MM-DD>   # exclusive
REPORT_LABEL=<human-readable label, e.g. "2026-05" or "2026-04..2026-05">
REPORT_SLUG=<filesystem-safe slug, e.g. "202605" or "202604-202605">
```

For every source below, include only records whose timestamp is
`>= REPORT_START 00:00:00` and `< REPORT_END_EXCL 00:00:00` in local time.
Never mix all-time counts into a windowed report unless the metric is explicitly
labeled "all-time context" or "fallback, not window-filtered".

For windowed reports, also compute a previous comparison window of the same
length when possible:

```bash
# macOS date syntax. Use equivalent date math on other systems.
window_start_ts=$(date -j -f "%Y-%m-%d" "$REPORT_START" +%s)
window_end_ts=$(date -j -f "%Y-%m-%d" "$REPORT_END_EXCL" +%s)
WINDOW_DAYS=$(( (window_end_ts - window_start_ts) / 86400 ))
PREV_END_EXCL="$REPORT_START"
PREV_START=$(date -j -v-"${WINDOW_DAYS}"d -f "%Y-%m-%d" "$REPORT_START" +%Y-%m-%d)
```

---

## Step 2 — 读取 Claude Code 数据 (`~/.claude/` + 项目 `.claude/`)

### 2.1 预聚合统计（最权威，先看这个）

Read `~/.claude/stats-cache.json`. Extract:

| 字段 | 含义 |
| --- | --- |
| `totalSessions` | session 总数 |
| `totalMessages` | 消息总数 |
| `firstSessionDate` | 首个 session ISO 时间 |
| `longestSession.{duration,messageCount,timestamp}` | 最长 session |
| `hourCounts` | `{hour: count}` 24h 热力 |
| `modelUsage[model].{inputTokens,outputTokens,cacheReadInputTokens,cacheCreationInputTokens}` | 每模型 token 细分 |
| `dailyActivity[].{date,messageCount,sessionCount,toolCallCount}` | 每日活跃 |
| `dailyModelTokens[].{date,tokensByModel}` | 每日按模型 token |

**派生量（你来算）**:
- `claude_tokens_spent = Σ (inputTokens + outputTokens + cacheCreationInputTokens)` —— 真实新付费 token
- `claude_cache_read = Σ cacheReadInputTokens` —— 缓存复用，反映 prompt-caching 熟练度
- `cache_to_spent_ratio = claude_cache_read / claude_tokens_spent` —— 比值越大越熟

**时间窗口模式**：如果 `WINDOW_REQUESTED=1`，优先从 `dailyActivity` 与
`dailyModelTokens` 中按 `REPORT_START <= date < REPORT_END_EXCL` 过滤后汇总
Claude sessions / messages / tokens / cache。`modelUsage` 是全局聚合；只有默认
profile 模式才能直接当总量使用。若某个 Claude 字段只有全局聚合、无法按日期切分，
在月度报告里写 `—` 或标注「仅有 all-time 聚合，未纳入窗口统计」，不要把全局值混进
月度值。

### 2.2 Slash-command 热度

`~/.claude/history.jsonl` —— 每行 `{display, timestamp, project, sessionId}`。

```bash
# Top 15 slash commands
jq -r 'select(.display | startswith("/")) | (.display | split(" ")[0])' \
   ~/.claude/history.jsonl | sort | uniq -c | sort -rn | head -15

# 总条数 vs 命令条数 vs 直接 prompt 条数
total=$(wc -l < ~/.claude/history.jsonl)
cmd=$(jq -r 'select(.display | startswith("/")) | .display' ~/.claude/history.jsonl | wc -l)
echo "total=$total cmd=$cmd plain=$((total - cmd))"
```

时间窗口模式下，所有 `history.jsonl` 统计先过滤：

```bash
jq --arg start "$REPORT_START" --arg end "$REPORT_END_EXCL" '
  select((.timestamp // "")[0:10] >= $start and (.timestamp // "")[0:10] < $end)
' ~/.claude/history.jsonl
```

记录：`/effort`、`/plan`、`/skill*`、`/usage`、`/clear`、`/resume`、`/compact`、`/init` 各自次数。

### 2.3 项目分布 (`~/.claude/projects/`)

Each subdir is one project; per-project `*.jsonl` files = sessions.
The dir name encodes the absolute path with `/` → `-` (ambiguous when the
original path itself contains `-`).

```bash
# Top 15 by session-file count
for d in ~/.claude/projects/*/; do
  n=$(ls "$d"*.jsonl 2>/dev/null | wc -l | tr -d ' ')
  echo "$n $(basename "$d")"
done | sort -rn | head -15
```

To recover the canonical real path (so you can run `git log` later), read
the `cwd` field from the first JSONL in each dir:

```bash
head -1 ~/.claude/projects/<encoded>/*.jsonl 2>/dev/null \
  | jq -r 'select(.cwd) | .cwd' | head -1
```

### 2.4 计划与 skill 自研

Claude Code 的 plan 文件目录不是固定值。默认在 `~/.claude/plans`,
但用户可以通过 `plansDirectory` 改到项目工作目录下，例如
`"./.claude/plans"`。统计 plans 时必须先解析候选 plan 目录，不能只枚举
`~/.claude/plans/*.md`。

解析规则：
- 先从 `~/.claude/projects/*/*.jsonl` 的 `cwd` 字段恢复 Claude Code 访问过的项目根目录。
- 对每个项目根目录，按 Claude Code settings 优先级读取：
  `.claude/settings.local.json` > `.claude/settings.json` > `~/.claude/settings.json` > default。
- 如果有效 settings 中存在 `plansDirectory`：
  - 绝对路径保持不变；
  - `~/...` 展开为 `$HOME/...`；
  - `./...` 或其他相对路径按该项目根目录解析。
- 如果没有配置，使用默认 `~/.claude/plans`。
- 把所有候选目录下的 `*.md` 真实路径去重后，再统计 plan 数量和标题。

```bash
# Plan titles (first # heading of each plan) from all resolved plan dirs.
# Include ~/.claude/plans plus any per-project plansDirectory targets.
# Count plan files by file count, not by title extraction success.
plan_count=<resolved-plan-file-count>
for f in <resolved-plan-files>; do
  awk '/^# / { sub(/^# /, ""); print; exit }' "$f"
done

ls ~/.claude/skills/ | wc -l       # skills installed / authored
ls ~/.claude/tasks/  | wc -l        # tasks tracked
ls ~/.claude/todos/  | wc -l
```

### 2.4b Skill 清单（AI 基础设施采集）

For each `~/.claude/skills/*/SKILL.md` and `~/.codex/skills/*/SKILL.md`,
**use the `Read` tool to inspect the frontmatter** (top of file, between `---` markers). Extract `name` and the full `description` as YAML semantics dictate.

Support all four YAML scalar styles：

| 写法 | 处理 |
| --- | --- |
| 单行: `description: foo bar` | 直接取冒号后内容 |
| 引号: `description: "foo bar"` 或 `'foo bar'` | 去掉首尾引号 |
| `>` folded（多行折叠） | join indented continuation lines with spaces |
| `\|` literal（多行保留） | preserve line breaks |

停止条件：遇到下一个**未缩进的 frontmatter key**（行首无空格且形如 `key:`），或遇到关闭的 `---` 行。如果 `description` 字段缺失，回落到 `<目录名> (no description)`。

**绝不使用 `head \| grep`** —— 那会把 `>`/`\|` 多行风格静默截断到只剩 `>`，这是 v2.2 之前的真实 bug。务必 `Read` 完整 frontmatter 后按 YAML 语义解析。

枚举候选 skill 目录：

```bash
ls -d ~/.claude/skills/*/ ~/.codex/skills/*/ 2>/dev/null
```

然后对每个目录：`Read` 它的 `SKILL.md` 头部 ~30 行 → 按上表解析 YAML → 输出 `<source>|<name>|<full_description>`。

记录每个 skill 是「自建」还是「安装」。如果 skill 目录下有 git remote 指向用户自己的 repo，标记为自建；否则标记为安装。

### 2.5 配置深度

Read `~/.claude/settings.json`. Count:
- `hooks` 个数（结构化自动化能力）
- `mcpServers` 个数（外部能力接入）
- `permissions.defaultMode`

---

## Step 3 — 读取 Codex CLI 数据 (`~/.codex/`)

### 3.1 SQLite (read-only)

The primary analytics store is `~/.codex/state_5.sqlite`, table `threads`.
**Always open with `mode=ro`** so you can never write:

```bash
SQ='sqlite3 file:'"$HOME"'/.codex/state_5.sqlite?mode=ro&immutable=1'

# If WINDOW_REQUESTED=1, compute unix-second bounds once and add the filter to
# every threads query below. For queries that already have WHERE, append `AND`.
FROM_TS=$(date -j -f "%Y-%m-%d" "$REPORT_START" +%s 2>/dev/null || true)
TO_TS=$(date -j -f "%Y-%m-%d" "$REPORT_END_EXCL" +%s 2>/dev/null || true)
# created_at >= FROM_TS AND created_at < TO_TS

# Aggregate
$SQ "SELECT COUNT(*), SUM(tokens_used), MIN(created_at), MAX(created_at) FROM threads;"

# Model breakdown (note: empty/NULL model = older sessions, label as 'Codex (未标注)')
$SQ "SELECT COALESCE(NULLIF(model,''),'Codex(未标注)'), COUNT(*), SUM(tokens_used) \
     FROM threads GROUP BY 1 ORDER BY 3 DESC;"

# Reasoning effort distribution (xhigh / high / medium / low / unspecified)
$SQ "SELECT COALESCE(NULLIF(reasoning_effort,''),'unspecified'), COUNT(*) \
     FROM threads GROUP BY 1 ORDER BY 2 DESC;"

# Top 15 working dirs
$SQ "SELECT cwd, COUNT(*), SUM(tokens_used) FROM threads \
     WHERE cwd != '' GROUP BY cwd ORDER BY 2 DESC LIMIT 15;"

# Hour-of-day heatmap
$SQ "SELECT strftime('%H', datetime(created_at,'unixepoch')), COUNT(*) \
     FROM threads GROUP BY 1 ORDER BY 1;"

# Day-of-activity timeseries
$SQ "SELECT date(created_at,'unixepoch'), COUNT(*) FROM threads GROUP BY 1;"

# Sample titles + first user messages for keyword extraction (titles only — no body)
$SQ "SELECT title FROM threads WHERE title != '' ORDER BY created_at DESC LIMIT 200;"
$SQ "SELECT first_user_message FROM threads WHERE first_user_message != '' \
     ORDER BY created_at DESC LIMIT 200;"

# CLI versions used (Codex evolution signal)
$SQ "SELECT cli_version, COUNT(*) FROM threads WHERE cli_version != '' \
     GROUP BY 1 ORDER BY 2 DESC LIMIT 10;"

# --- 以下为 v2.0 新增查询 ---

# 月度聚合（Evolution 曲线用）
$SQ "SELECT strftime('%Y-%m', datetime(created_at,'unixepoch')), COUNT(*), \
     SUM(tokens_used), COALESCE(NULLIF(model,''),'unknown') \
     FROM threads GROUP BY 1,4 ORDER BY 1,3 DESC;"

# CLI 版本时间线（Evolution 曲线用）
$SQ "SELECT cli_version, MIN(date(created_at,'unixepoch','localtime')), \
     MAX(date(created_at,'unixepoch','localtime')), COUNT(*) \
     FROM threads WHERE cli_version != '' GROUP BY 1 ORDER BY 2;"

# 每项目 token 消耗（双工具编排分析用）
$SQ "SELECT cwd, COALESCE(NULLIF(model,''),'unknown'), COUNT(*), SUM(tokens_used) \
     FROM threads WHERE cwd != '' GROUP BY 1,2 ORDER BY 1,4 DESC;"
```

### 3.2 Codex 全局历史

`~/.codex/history.jsonl` — `{session_id, ts, text}`. Sample for keywords:

```bash
wc -l ~/.codex/history.jsonl                                 # total prompts
jq -r '.text' ~/.codex/history.jsonl | head -300 > /tmp/codex_text.txt   # corpus
jq -r '.session_id' ~/.codex/history.jsonl | sort -u | wc -l # distinct sessions
```

时间窗口模式下，先按 `.ts` 过滤再做计数、关键词采样和 distinct sessions：

```bash
jq --arg start "$REPORT_START" --arg end "$REPORT_END_EXCL" '
  select((.ts // "")[0:10] >= $start and (.ts // "")[0:10] < $end)
' ~/.codex/history.jsonl
```

### 3.3 自研 artifacts

```bash
ls ~/.codex/skills/      | wc -l   # codex skills
ls ~/.codex/automations/ | wc -l   # scheduled automations
ls ~/.codex/rules/       | wc -l   # custom rules
```

---

## Step 3b — 读取 Kiro 数据 (`~/.kiro/` + `~/.local/share/kiro-cli/`)

Kiro 是 AWS 出的 agentic IDE / CLI（kirodotdev/Kiro）。Kiro CLI 把 ACP
session 存到 `~/.kiro/sessions/cli/`（每个 session 两个文件：`<id>.json`
元数据 + `<id>.jsonl` 事件流），把 token / model / provider 细分存到
`~/.local/share/kiro-cli/data.sqlite3`。Steering / Agents / Skills / Prompts
等基础设施在 `~/.kiro/` 下，跟 Claude Code 风格一致。

**所有读取必须只读**：SQLite 用 `mode=ro&immutable=1`；JSON / JSONL 只
`Read` / `jq`，不要修改。本步骤先检测 `~/.kiro/` 是否存在，不存在直接跳过本节。

### 3b.1 总量与 token 细分 (SQLite, read-only)

```bash
[ -d "$HOME/.kiro" ] || { echo "Kiro not installed; skip Step 3b"; }

KIRO_DB="$HOME/.local/share/kiro-cli/data.sqlite3"
if [ -f "$KIRO_DB" ]; then
  KSQ='sqlite3 file:'"$KIRO_DB"'?mode=ro&immutable=1'

  # 先 dump schema 再决定查询列名 —— Kiro CLI 仍在迭代，表名可能演进
  $KSQ ".schema" | head -80
  $KSQ ".tables"
fi
```

读 schema 后，按实际表名（常见为 `messages` / `sessions` / `usage` 等）
**自适应**编写聚合 SQL。期望提取的字段：

| 字段 | 含义 | 来源（按 schema 自适应）|
| --- | --- | --- |
| `kiro_sessions` | 总 session 数 | `COUNT(DISTINCT session_id)` |
| `kiro_messages` | 总消息数 | `COUNT(*)` from message-like 表 |
| `kiro_input_tokens` / `kiro_output_tokens` | 每模型 token | `SUM(input_tokens)` / `SUM(output_tokens)` |
| `kiro_model_breakdown` | 按 `model` / `provider` 分组 | `GROUP BY model, provider` |
| `kiro_by_date` | 按 `date(created_at)` 聚合 | 每日活跃 |
| `kiro_by_hour` | 按 `strftime('%H', created_at)` | 24h 热力 |

**降级**：如果 schema 找不到 token / model 列，仅按 session 计数即可，并在报告里说明
「Kiro 早期版本未持久化 token 细分，本节按 session 总量给出」。

时间窗口模式下，所有 Kiro SQL 聚合必须按实际 schema 的 `created_at` /
`updated_at` / timestamp-like 字段过滤到 `[REPORT_START, REPORT_END_EXCL)`。
如果 schema 没有可靠时间列，只把该表用于 all-time context，不参与月度指标。

### 3b.2 ACP Session 文件 (JSON + JSONL)

```bash
KIRO_SESS="$HOME/.kiro/sessions/cli"
if [ -d "$KIRO_SESS" ]; then
  # session 总数
  ls "$KIRO_SESS"/*.json 2>/dev/null | wc -l

  # 每个 session 抽元数据：cwd、agent、起止时间
  for f in "$KIRO_SESS"/*.json; do
    jq -r '[.cwd // "", .agent // "", .created_at // "", .updated_at // ""] | @tsv' "$f"
  done | sort -u

  # 项目分布（按 cwd 聚合）
  for f in "$KIRO_SESS"/*.json; do
    jq -r '.cwd // empty' "$f"
  done | sort | uniq -c | sort -rn | head -15
fi
```

`*.jsonl` 是事件流（user/assistant/tool-call 逐条）。**只采样前若干行用于
关键词语料**（同 Claude `projects/*/*.jsonl` 的处理方式），不要把原文写进
report：

```bash
for f in "$KIRO_SESS"/*.jsonl; do
  head -50 "$f" | jq -r 'select(.role == "user") | .content // empty' 2>/dev/null
done | head -300 > /tmp/kiro_corpus.txt   # 关键词语料
```

### 3b.3 Kiro 基础设施层（agents / skills / steering / prompts / mcp）

跟 Claude / Codex 的 skills 体系**一一对应**，扫法一致：

```bash
# 全局 agents（每个文件是一个 .json，filename 即 agent 名）
ls ~/.kiro/agents/*.json 2>/dev/null | wc -l

# 全局 skills（每个目录一个，含 SKILL.md，frontmatter 同 Agent Skills 标准）
ls -d ~/.kiro/skills/*/ 2>/dev/null

# Steering 文件（项目规范 / 架构决策，markdown）
ls ~/.kiro/steering/*.md 2>/dev/null | wc -l

# Prompts 模板
ls ~/.kiro/prompts/ 2>/dev/null | wc -l

# Settings & MCP
[ -f ~/.kiro/settings/cli.json ] && cat ~/.kiro/settings/cli.json | jq 'keys'
[ -f ~/.kiro/settings/mcp.json ] && cat ~/.kiro/settings/mcp.json | jq '.mcpServers | keys'
```

对每个 `~/.kiro/skills/*/SKILL.md`，**沿用 Step 2.4b 的 YAML frontmatter 解析逻辑**
（`Read` 完整 frontmatter，按 `>` / `|` / 引号 / 单行四种 scalar 处理）。
Kiro skills 用的就是 Agent Skills 开放标准，跟 Claude / Codex 字段完全相同
（`name` + `description`）。

把 `~/.kiro/skills/` 合并进 Step 2.4b 的 skill 总表，新增一列「来源 = Kiro」。

### 3b.4 Knowledge bases（实验功能，可选）

```bash
KIRO_KB="$HOME/.local/share/kiro-cli/knowledge_bases"
if [ -d "$KIRO_KB" ]; then
  ls -d "$KIRO_KB"/*/ 2>/dev/null   # 每个 agent 一个独立 KB
fi
```

知识库属于「AI 基础设施层」高级信号 —— 用户主动给 agent 喂资料。统计有几个
KB、覆盖哪些 agent 即可，不读 `data.json` 原文。

### 3b.5 工作区 `.kiro/` 配置（按项目）

对 Step 5 候选目录路径列表里的每个项目根，再检查项目内的 workspace-level
Kiro 配置（这往往是用户日常工作的真实证据）：

```bash
for path in <candidate-paths>; do
  for kind in agents skills steering prompts; do
    if [ -d "$path/.kiro/$kind" ]; then
      echo "$path::$kind::$(ls "$path/.kiro/$kind" 2>/dev/null | wc -l)"
    fi
  done
done
```

合并到 6.4 「项目与领域」时，给配置了 `.kiro/` 的项目打 `Kiro+` 标记。

### 3b.6 Kiro 数据来源不可读时的诚实声明

如果 Kiro 安装但 `data.sqlite3` 不存在（用户只用过 IDE 桌面版，未跑 CLI），
本步骤仅能采集到 Steering / Agents / Skills 配置数，**不要编造 session / token 数字**。
在最终报告的「Kiro 章节」明确写：「Kiro CLI 数据未生成，本节仅展示 Steering /
Agents / Skills 配置；如需完整 session/token 统计请先运行 Kiro CLI。」

---

## Step 3c — 读取 Trae 数据 (`~/Library/Application Support/Trae/` + 项目 `.trae/`)

Trae 是字节跳动出的 AI IDE，基于 VS Code fork（Electron）。**chat 对话存在
本地 SQLite**（`User/workspaceStorage/<hash>/state.vscdb`，与 Cursor 同款机制），
**但 token 用量统计走云端 API**（`query_user_usage_group_by_session`），
本机不持久化。所以本步骤只读两类本地数据：

1. 工作区 `state.vscdb` 里的 chat 元数据（数量、cwd、关键词）
2. 项目 `.trae/` 与 home 配置里的 rules / skills / settings

**所有读取必须只读**：SQLite 强制 `mode=ro&immutable=1`；不要触发任何 Trae
进程写操作。先检测目录是否存在，不存在直接跳过本节。

### 3c.1 工作区数量与项目分布

```bash
# macOS 路径（Linux 类似在 ~/.config/Trae/，Windows 在 %APPDATA%\Trae\）
TRAE_BASE="$HOME/Library/Application Support/Trae"
TRAE_WS="$TRAE_BASE/User/workspaceStorage"

[ -d "$TRAE_WS" ] || { echo "Trae not installed or no workspaces; skip Step 3c"; }

# 工作区数（每个 hash 目录 = 一个被打开过的项目）
ls -d "$TRAE_WS"/*/ 2>/dev/null | wc -l

# 每个工作区对应的真实项目路径（workspace.json 里有 folder/uri）
for d in "$TRAE_WS"/*/; do
  if [ -f "$d/workspace.json" ]; then
    jq -r '.folder // .configuration // empty' "$d/workspace.json"
  fi
done | sort -u
```

### 3c.2 Chat 元数据（SQLite, read-only）

每个工作区有自己的 `state.vscdb`；另外 `~/Library/Application Support/Trae/User/globalStorage/state.vscdb` 是全局聚合库。**Trae 的 chat 表名 / key 前缀
在版本间会变化**（早期沿用 VS Code 的 `ItemTable`，新版本可能新增 Trae 专用表），
**先 dump 一下结构再下查询**：

```bash
TRAE_GLOBAL="$TRAE_BASE/User/globalStorage/state.vscdb"

if [ -f "$TRAE_GLOBAL" ]; then
  TSQ='sqlite3 file:'"$TRAE_GLOBAL"'?mode=ro&immutable=1'
  $TSQ ".tables"
  $TSQ "SELECT name FROM sqlite_master WHERE type='table';"

  # 常见结构：ItemTable(key TEXT, value BLOB) —— 类 VS Code KV
  # Trae 把 chat 存为 key='trae.chat.*' 或 'composer.*' 形式（版本不同前缀不同）
  $TSQ "SELECT key, length(value) FROM ItemTable \
        WHERE key LIKE '%chat%' OR key LIKE '%conversation%' OR key LIKE '%composer%' \
        ORDER BY length(value) DESC LIMIT 30;" 2>/dev/null
fi

# 工作区级 chat
for d in "$TRAE_WS"/*/; do
  db="$d/state.vscdb"
  [ -f "$db" ] || continue
  ws_chat_keys=$(sqlite3 "file:$db?mode=ro&immutable=1" \
    "SELECT COUNT(*) FROM ItemTable WHERE key LIKE '%chat%' OR key LIKE '%composer%';" 2>/dev/null)
  echo "$(basename "$d") chat_keys=$ws_chat_keys"
done
```

**期望提取**：

| 字段 | 含义 | 备注 |
| --- | --- | --- |
| `trae_workspaces` | 打开过的项目数 | `ls workspaceStorage/*/` 计数 |
| `trae_chat_session_count` | 估算的 chat session 数 | 按 chat-related key 数估算 |
| `trae_active_projects` | 有 chat 的项目数 | `ws_chat_keys > 0` 的工作区数 |
| `trae_corpus` | chat 标题 / 首条 user message | 仅采样若干条，用于关键词，不入报告原文 |

时间窗口模式下，Trae workspace / chat 只能在存在可靠 timestamp 或文件 mtime
落入窗口时计入窗口活跃。否则只作为「检测到 Trae 配置 / all-time context」展示，
不要计入月度 sessions、active projects 或关键词。

**强烈降级提示**：
- Trae chat 的 key 格式**没有公开稳定文档**。如果 `LIKE` 没匹中任何 row，
  老老实实在报告里写「Trae 本地 chat 仅检测到 workspace 数量 N，对话内容
  key 命名约定本工具暂不解析」，**不要编造 session 数**。
- 如果工作区目录为空或 `state.vscdb` 文件不存在，直接跳过该工作区。

### 3c.3 Token 用量 —— 仅云端，本地无法读

Trae 的 token / 模型用量走云端 API。第三方工具（如 tokscale）的做法是：
用户先 `tokscale trae login`，再调 `query_user_usage_group_by_session` 拉数据
缓存到 `~/.config/tokscale/trae-cache/sessions/*.json`。

**本 skill 不发起任何网络请求**，所以 Trae 的 token 数字无法被采集。
最终报告里诚实写：「Trae 的 token 用量数据由 ByteDance 云端 API 持有，
本 skill 出于『100% 本地 + 只读』原则不接入；如需 Trae token，请使用
tokscale 等第三方工具单独采集后人工补入。」

可选：如果用户**已经**在 `~/.config/tokscale/trae-cache/sessions/` 里有
导出的 JSON 缓存，可以读它（只读、本地）：

```bash
TOKSCALE_TRAE="$HOME/.config/tokscale/trae-cache/sessions"
if [ -d "$TOKSCALE_TRAE" ]; then
  jq -s 'map(.token_count // 0) | add' "$TOKSCALE_TRAE"/*.json 2>/dev/null
  jq -r '.model // empty' "$TOKSCALE_TRAE"/*.json 2>/dev/null | sort | uniq -c
fi
```

### 3c.4 项目 `.trae/` 配置（rules / skills / .ignore）

跟 Kiro `.kiro/`、Claude 项目 `.claude/` 一样，Trae 在项目内提供 `.trae/`
工作区目录
