Skill 方案导入1252 字·2026/11/14·被检索 0 次

Skill 方案 S7 · 项目架构勘查与文档生成

裁剪到三层的目录树、端口与进程、Kaoyan任务动作、依赖与路由、环境事实五路采集,产出七节environment.md,并用指纹做增量。两段勘查的1.37亿token可压到0.20亿,第二次几乎免费。

挂靠在《二、重复操作与 Skill 方案》之下

版本
使用说明
v1reused-preview2026/11/14 11:16:53

Skill 方案 S7 · 项目架构勘查与文档生成

一句话:把「这个项目到底跑着什么、端口怎么分、任务怎么起、依赖是什么」的勘查过程固化成一次扫描,直接产出可提交的 environment.md;两段勘查会话的 1.37 亿 token 可压到 0.20 亿。

一、为什么需要它

11 月 13 日两段勘查会话合计 1.37 亿 token:扫描项目结构 8450 万,环境安装与验证 5217 万。

会话token工具调用产出
扫描项目结构8450 万数百次目录树、模块关系
环境安装与验证5217 万数百次依赖版本、任务定义
合计1.37 亿—environment.md + 架构认知
指标数值
勘查次数2 次(同类任务,重复劳动)
累计 token1.37 亿,占两个月 8.7%
最终文档environment.md
复用情况写完就沉底,下次勘查又从零开始

痛点集中在"广度"上:一次全量 tree /F 会把 node_modules、.next、generated 全部吐出来,几十万行;模型为了不漏,只能一层层读,读了再总结,总结完再补读。没有裁剪规则的勘查,成本随目录规模线性爆炸。

二、触发词与边界

触发词不适用场景
「摸一下这个项目」「架构勘查」「项目结构」只想知道某个文件在哪 → Glob 就够
「生成 environment.md」「环境文档」要改代码/重构 → 不动手,只记录
「端口怎么分的」「谁占着 3000」要修端口冲突 → S2
「依赖是什么版本」「路由有哪些」要升级依赖 → 单独评审
「更新一下环境文档」首次安装环境 → 走安装流程,本 skill 只记录

边界:只读。勘查过程不启动、不停止、不安装任何东西;发现缺失(比如某任务不存在)只记录,不代劳修复。

三、输入与前置检查

项目值
项目根C:\Users\cag\WorkBuddy\2026-10-11-06-00-16
子项目portal / kaoyan-vocab / notes / c-lab / ops
排除目录node_modules、.next、generated、.git、.shot、.fonttmp、__pycache__
输出项目根 environment.md
状态文件ops/.scan-state.json(记录上次扫描的指纹)

前置检查三条命令,确认勘查对象在线:

Get-NetTCPConnection -State Listen | Where-Object { $_.LocalPort -in 3000,3001,3102,3103 } |
  Select-Object LocalPort, OwningProcess
Get-Process node, cloudflared -ErrorAction SilentlyContinue | Select-Object Id, ProcessName, Path
Get-ScheduledTask -TaskName "Kaoyan*" | Select-Object TaskName, State

若端口全空、任务全 Ready,说明服务没起,勘查结果里必须写"当前未运行",不能用历史印象代替实测。

四、执行步骤

步骤 1 · 裁剪目录树。 只到三层,且排除构建产物:

$R = "C:\Users\cag\WorkBuddy\2026-10-11-06-00-16"
Get-ChildItem $R -Directory -Depth 2 -ErrorAction SilentlyContinue |
  Where-Object { $_.FullName -notmatch '\\(node_modules|\.next|generated|\.git|\.shot|\.fonttmp|__pycache__)(\\|$)' } |
  ForEach-Object { $_.FullName.Substring($R.Length + 1) } |
  Sort-Object

裁剪后通常 60–120 行,可直接贴进文档;未裁剪是数万行。目录树的价值在"有哪些模块",不在"每个文件叫什么",第四层以后按需单独看。

步骤 2 · 采集端口与进程。 端口是架构的第一手证据:

Get-NetTCPConnection -State Listen |
  Where-Object { $_.LocalPort -ge 3000 -and $_.LocalPort -le 3200 } |
  ForEach-Object {
    $p = Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue
    [pscustomobject]@{ Port = $_.LocalPort; Pid = $_.OwningProcess; Name = $p.ProcessName; Path = $p.Path }
  } | Sort-Object Port | Format-Table -AutoSize

步骤 3 · 采集计划任务。 任务名、状态、动作三者都要,动作里藏着启动器:

Get-ScheduledTask -TaskName "Kaoyan*" | ForEach-Object {
  [pscustomobject]@{
    Task  = $_.TaskName
    State = $_.State
    Exec  = ($_.Actions | ForEach-Object { "$($_.Execute) $($_.Arguments)" }) -join ' ; '
  }
} | Format-List

本机已知结论可直接对照:KaoyanPortal(3000)、KaoyanNextServer(3001)、KaoyanNotes(3102)、KaoyanCLab(3103)、KaoyanTunnel、KaoyanSelfHeal、KaoyanNatapp(Disabled)。对不上就是发现,要写进文档的"异常"一节。

步骤 4 · 提取依赖与路由。 依赖只取顶层版本,路由按框架各自的约定扫:

node -e "
const fs=require('fs');
for (const p of ['portal','kaoyan-vocab','notes','c-lab']) {
  const f=p+'/package.json';
  if(!fs.existsSync(f)) { console.log(p,'(no package.json)'); continue; }
  const j=JSON.parse(fs.readFileSync(f,'utf8'));
  console.log('##',p,j.name,'next='+(j.dependencies?.next||'-'),'prisma='+(j.dependencies?.['@prisma/client']||'-'));
}"
cd "C:/Users/cag/WorkBuddy/2026-10-11-06-00-16" && \
find notes/app kaoyan-vocab/app -name "page.tsx" -o -name "route.ts" 2>/dev/null | head -60

门户是零依赖 Node,路由写在 portal/server.js 的注释与 urlPath 分支里,用 grep -n "urlPath ===" portal/server.js 取,不要靠猜。

步骤 5 · 采集环境事实。 这一节是上次 5217 万 token 换来的教训,必须固化:

事实采集方式
Node 版本与绝对路径node -v、(Get-Command node).Source
代理变量(双份会炸)`Get-ChildItem Env:
Prisma 生成目录grep output notes/prisma/schema.prisma(当前 ../generated/db3)
提权限制本机注册 S4U 任务报 0x80070005

步骤 6 · 生成 environment.md。

# 运行环境
> 生成时间 / 扫描耗时 / 指纹

## 1. 服务与端口        (表:服务、端口、启动器、日志、探针)
## 2. 计划任务          (表:任务名、状态、动作、触发器)
## 3. 目录结构          (裁剪后的树,三层)
## 4. 依赖版本          (表:子项目、框架、关键依赖)
## 5. 路由清单          (表:路径、类型、处理位置)
## 6. 环境事实与已知坑  (Node 路径、代理、Prisma 目录、权限限制)
## 7. 本次异常          (对不上的项,逐条列,不解释)

步骤 7 · 增量更新。 用指纹判断是否需要重扫,避免每次全量:

node -e "
const fs=require('fs'),c=require('crypto');
const files=['portal/server.js','notes/package.json','kaoyan-vocab/package.json','notes/prisma/schema.prisma'];
const h=c.createHash('sha1');
for(const f of files){ if(fs.existsSync(f)) h.update(fs.readFileSync(f)); }
const fp=h.digest('hex').slice(0,12);
const prev=fs.existsSync('ops/.scan-state.json')?JSON.parse(fs.readFileSync('ops/.scan-state.json','utf8')).fingerprint:null;
console.log(JSON.stringify({fingerprint:fp,changed:fp!==prev}));
fs.writeFileSync('ops/.scan-state.json',JSON.stringify({fingerprint:fp,at:new Date().toISOString()},null,2));
"

changed=false 时只更新"本次异常"与时间戳,其余章节原样保留——这一条能把第二次勘查的成本压到接近零。

五、输出与验收

产出 environment.md(约 150–250 行)+ 一段 JSON 摘要:

{"services":5,"tasks":7,"routes":38,"changed":true,"anomalies":1,"elapsedSec":42}

三条硬断言:

  1. 每个处于 Listen 的 3000–3200 端口,必须在文档里有对应行;有端口没记录即失败。
  2. 每个 Kaoyan* 任务必须在文档里有状态,Disabled 的也要写(KaoyanNatapp 就属于这一类)。
  3. portal/server.js 里每一处 urlPath === 分支,都必须在路由表出现;缺一条说明扫描是抽样而非全量。

六、失败处理与回滚

现象根因动作
目录树几千行排除规则没生效检查正则转义,\\ 在 PowerShell 字符串里要写对
端口有监听但查不到进程权限不足(SYSTEM 进程)记录端口与 PID,进程名写「需提权查看」
任务动作是乱码输出编码chcp 65001 或改用 PowerShell 工具直接读对象
路由数明显偏少find 被 -o 优先级坑了加括号 \( -name a -o -name b \)
文档与实况不符用了历史印象重跑步骤 2–4,一切以实测为准

回滚:勘查只读,唯一产物是 environment.md。写坏了用 Move-Item environment.md environment.md.bak-<ts> 后重生成;ops/.scan-state.json 删掉即触发一次全量重扫。

七、收益测算

项目现状改造后
单次 token6850 万1000 万
次数2 次2 次(第二次走增量,约 200 万)
累计1.37 亿0.20 亿
单次耗时40–90 分钟1–3 分钟
文档时效一次性指纹变化才重扫

省的是"逐层读目录 + 反复确认版本"。裁剪规则把可读行数从数万压到百行,增量机制让第二次勘查几乎免费。节省 1.17 亿,约 85%,是七类里绝对金额最大的一项。