@wwkit/harness 1.0.25 → 1.0.27

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.
@@ -1,145 +1,128 @@
1
1
  ---
2
2
  name: extract
3
3
  description: |
4
- 自包含内容提取 skill:解析入参(JSON/key=value/prose)→ 按 format 分发到 references/ 流程 → schema 校验 → 写 output 文件或 stdout。
4
+ 自包含内容提取 skill:每次调用 = 一个固定 Sprint——Sprint Planning(解析入参、定义 Sprint Goal、todowrite 落固定 Sprint Backlog)→ Sprint Execution(逐项执行并验证 DoD)→ Sprint Review(对照 Sprint Goal 校验交付 + 简要回顾)。
5
5
  format=list/detail/text/navi。调用方直接传原始任务消息,skill 自解析自包含。
6
- 内部用 todowrite 管理 6 步。禁止 WebFetch/网络请求。
6
+ 内部用 todowrite 管理固定 6 项 Sprint Backlog(每项带 DoD)。禁止 WebFetch/网络请求。
7
7
  适用:列表页/详情页/纯文本/结构化 JSON 列表/导航 XPath 等各类网页内容提取。
8
8
  license: MIT
9
9
  metadata:
10
10
  workflow: sequential
11
11
  ---
12
12
 
13
- # extract 技能
13
+ # extract 技能(固定 Sprint 冲刺)
14
14
 
15
- ## 核心约束(最高优先级)
15
+ ## 执行范式
16
16
 
17
- - **MUST**:收到任务消息后,先 todowrite 落单 6 步,再逐步执行。
18
- - **MUST**:每步完成立即 todowrite 勾单。
19
- - **禁止**:使用 WebFetch 或任何网络请求获取内容。
20
- - **禁止**:写入 output 以外的任何文件;中间产物用临时文件,完成后清理。
21
- - **禁止**:以任何形式使用未声明字段(count/max_length/max_image_count/language 等)。
17
+ 每次调用 = 一个固定 Sprint,三个事件:
22
18
 
23
- ## 第一步硬指令(自检)
19
+ 1. **Sprint Planning**:解析入参 → 定义 Sprint Goal → todowrite 落固定 6 项 Sprint Backlog(每项带 DoD)
20
+ 2. **Sprint Execution**:逐项执行,每项 = 执行 → 验证 DoD → todowrite 勾单 Done
21
+ 3. **Sprint Review**:对照 Sprint Goal 验证 Increment(JSON 数组)及输出语义,沉淀 1 条回顾
24
22
 
25
- 解析入参前,强制自检:
26
- > 我是否已用 todowrite 落单 6 步?
27
- > - 未落单 → 立即 todowrite 创建清单。
28
- > - 已落单 → 继续。
23
+ **Sprint Goal** = `从 {{source}} 提取符合 {{format}} 格式的 JSON 数组,并通过 schema 校验`。
29
24
 
30
25
  ## 输入参数
31
26
 
32
- 入参为调用方传入的**原始任务消息**,可能是以下任一形态:
33
- - **JSON 对象**:如 `{format, source, url, output}`,直接取字段值;
34
- - **key=value**:如 `format=list, source=xxx`,按 `,` 和 `=` 拆分为字段;
35
- - **纯文本 prose**:不做格式推断。仅当文本命中 `references/format-aliases.json5` 中某 format 的 `terms`(如"列表/导航/详情/纯文本")时才翻译为该 format 标准值,`source` 取文本本身。
27
+ 入参为调用方传入的**原始任务消息**,可为 JSON 对象、key=value 或自然语言等任意形态,agent 依据字段语义自主提取(详见 Item 1)。字段清单(字段/类型/必填/默认值)以 `references/input.schema.json5` 为准:
36
28
 
37
- 字段清单(字段/类型/必填)见 `references/input.schema.json5`。本技能仅使用 `source`、`format`、`url`、`output` 四个字段,忽略所有其他字段(如 `count`、`max_length`、`max_image_count`、`language`),不得读取、写入或据此推断任何行为。
29
+ | 字段 | 类型 | 必填 | 说明 |
30
+ |---|---|---|---|
31
+ | `format` | string | ✅ | 提取类型,标准值 `list`/`detail`/`text`/`navi`,可由别名表翻译 |
32
+ | `source` | string | ✅ | 网页 HTML / 文本 / 结构化 JSON,或本地文件路径 |
33
+ | `url` | string | ❌ | 页面 URL,**静态补充字段,仅供相对路径转绝对地址 / 图片 src 补全域名,禁止访问该地址** |
34
+ | `output` | string | ❌ | 输出文件路径(提供则写文件,否则 stdout) |
38
35
 
39
- ## 输出
36
+ 本技能仅使用上表四个字段,忽略所有其他字段(如 `count`、`max_length`、`max_image_count`、`language`),不得读取、写入或据此推断任何行为。
40
37
 
41
- - 提供 `output` 参数:将 JSON 数组用 `write` 工具写入该文件,stdout 输出文件路径。
42
- - 未提供 `output` 参数:将 JSON 数组直接输出到 stdout,**不写任何文件**。
43
- - 校验失败未能产出数组:不写文件、不输出数组,将错误信息输出到 stderr 并结束。
38
+ ## 固定 Sprint Backlog(todowrite 落单,覆盖历史 todos)
44
39
 
45
- ## 工作流程
40
+ 1. 解析入参(从任意形态任务消息自主提取 format/source/url/output) | DoD: 得到四个字段值(或按短路规则输出 `[]`/错误并结束)
41
+ 2. 加载 references(format 流程文件 + schema 文件) | DoD: 对应流程与 schema 已确认,schema 绝对路径已记录(或 format 无效/文件不存在时输出 `[]`)
42
+ 3. 按 format 执行提取 | DoD: 产出符合 format 的 JSON 数组
43
+ 4. Schema 校验 | DoD: `node validate-schema.js` 执行完成,返回通过/失败结果
44
+ 5. 校验失败修复重试(≤3 次) | DoD: 重试后校验通过,或重试 3 次耗尽后 stderr 输出错误
45
+ 6. 输出(写 output 文件或 stdout) | DoD: 按输出语义交付 JSON 数组(文件路径或 stdout),校验未通过时 stderr 报错
46
46
 
47
- ### 阶段 0:todowrite 落单
47
+ ## Sprint Execution
48
48
 
49
- 收到任务消息后,**先**用 `todowrite` 创建 6 步清单(status=pending):
49
+ 按固定 6 项逐项执行,每项周期 = 进度检查(刚完成什么/本项做什么/有无阻塞)→ 执行 → 验证 DoD → 勾单 Done。
50
50
 
51
- 1. 解析入参(JSON/key=value/prose → format/source/url/output)
52
- 2. 加载 references(format 流程文件 + schema 文件)
53
- 3. 按 format 执行提取
54
- 4. Schema 校验
55
- 5. 校验失败修复重试(≤3 次)
56
- 6. 输出(写 output 文件或 stdout)
51
+ ### Item 1:解析入参
57
52
 
58
- 每步完成立即 todowrite 勾单(status=completed)。
53
+ 将第 1 项标记 in_progress,从原始任务消息中**自主提取**四个字段。入参可为 JSON 对象、key=value 或自然语言等任意形态,依据字段语义理解提取即可,无需固定解析规则。提取原则:
59
54
 
60
- ### 阶段 1:解析入参
55
+ - **格式翻译**:若消息中以自然语言指定提取类型(如"列表/导航/详情/纯文本"),用 `read` 读取 `references/format-aliases.json5`,将命中的 `terms` 翻译为该 format 标准值;未命中则 `format` 取消息中明确给出的值。
61
56
 
62
- 将第 1 步标记为 in_progress,解析原始任务消息:
57
+ 解析后得到 `format`、`source`、`url`、`output` 四个字段(字段说明见上文输入参数表;`url`/`output` 缺省时留空由后续 Item 处理)。
63
58
 
64
- - **JSON 对象**:直接取 `format`/`source`/`url`/`output` 字段值。
65
- - **key=value**:按 `,` 分割、按 `=` 拆分为键值对,取上述四字段。
66
- - **纯文本 prose**:用 `read` 读取 `references/format-aliases.json5`,仅当文本命中某 format 的 `terms` 时翻译为该 format 标准值,`source` 取文本本身;未命中则 `format` 视为未提供。
59
+ **短路规则(按顺序执行,命中即结束):**
67
60
 
68
- 解析后得到:
69
- - `format`(必填,经别名表翻译为标准值;`list` 由阶段 2 自动检测 source 是 HTML 还是 JSON)
70
- - `source`(必填,HTML/文本或文件路径,原样透传由后续阶段解析)
71
- - `url`(可选,相对路径转绝对)
72
- - `output`(可选)
61
+ 1. **空 source 短路**:若 `source` 为空、null 或仅含空白:直接输出 `[]` 并结束,**禁止**继续执行。即使提供了 `url` 也**不得**用 WebFetch/网络请求访问该地址来获取内容——`url` 是静态补充字段,不能替代 `source`。
62
+ 2. **format 缺失校验**:若 `format` 未提供或经别名表翻译后仍为空:将错误信息输出到 stderr 并结束,**禁止**继续执行。
73
63
 
74
- **必填校验**:若无法解析出 `format` 或 `source`,将错误信息输出到 stderr 并结束,**禁止**继续执行。
64
+ **验证 DoD**:四个字段值已得到(或按短路规则结束)。通过后标记 Done。
75
65
 
76
- **空 source 短路**:若 `source` 为空、null 或仅含空白:直接输出 `[]` 并结束,**禁止**继续执行。
66
+ ### Item 2:加载 references
77
67
 
78
- 完成后 todowrite 勾单第 1 步。
68
+ 将第 2 项标记 in_progress,从技能目录的 `references/` 加载流程文件和 schema 文件:
79
69
 
80
- ### 阶段 2:加载 references
70
+ - `format=list` 时,直接使用 `references/list.md`(内部按 source 类型分三条分支处理)与 `references/list.schema.json5`
71
+ - 其他 format 直接使用 `references/{{ format }}.md` 与 `references/{{ format }}.schema.json5`
81
72
 
82
- 从技能目录的 `references/` 加载流程文件和 schema 文件:
73
+ 用 `read` 工具读取对应流程文件(list 为 `references/list.md`)与 schema 文件,并**记录 schema 文件的绝对路径**(Item 4 校验时需要)。若 `format` 为空或对应 references 文件不存在:直接输出 `[]` 并结束(`format` 缺失已在 Item 1 处理)。
83
74
 
84
- - `format=list` 时,先检测 `source` 类型:若值是现有文件路径则读取文件内容;否则以值作为输入。再判断内容类型:
85
- - 若能解析为 JSON 数组,使用 `list_from_json` 流程
86
- - 否则若包含 HTML 标签(形如 `<tag`),作为 HTML 源码,使用 `list_from_html` 流程
87
- - 否则作为纯文本,使用 `list_from_text` 流程
88
- - schema 统一使用 `references/list.schema.json5`
89
- - 其他 format 直接使用 `references/{{ format }}.md` 和 `references/{{ format }}.schema.json5`
75
+ `url` 按需透传给对应流程(相对路径转绝对)。
90
76
 
91
- 用 `read` 工具读取两个文件内容,并**记录 schema 文件的绝对路径**(阶段 4 校验时需要)。若 `format` 为空或对应 references 文件不存在:直接输出 `[]` 并结束。
77
+ **验证 DoD**:流程与 schema 文件已确认、schema 绝对路径已记录(或 references 文件不存在已短路)。通过后标记 Done。
92
78
 
93
- `url` 按需透传给对应 format 流程(相对路径转绝对)。
79
+ ### Item 3:按 format 执行提取
94
80
 
95
- 完成后 todowrite 勾单第 2 步。
81
+ 将第 3 项标记 in_progress,按 Item 2 确认的流程文件步骤执行提取(`list` 格式使用 `references/list.md` 内部按 source 类型选定的分支),得到 JSON 数组。**禁止使用 WebFetch 或任何网络请求获取内容。**
96
82
 
97
- ### 阶段 3:按 format 执行提取
83
+ **验证 DoD**:已产出符合 format 的 JSON 数组。通过后标记 Done。
98
84
 
99
- 按 `references/` 下对应流程文件的步骤执行提取(`list` 格式使用阶段 2 检测的 `list_from_html`/`list_from_json`/`list_from_text`),得到 JSON 数组。**禁止使用 WebFetch 或任何网络请求获取内容。**
85
+ ### Item 4:Schema 校验
100
86
 
101
- 完成后 todowrite 勾单第 3 步。
102
-
103
- ### 阶段 4:Schema 校验
104
-
105
- 用 `write` 工具将待校验的 JSON 数组写入临时文件,再用 `write` 工具将 `{"data": <JSON 数组>, "schema_path": "<schema 绝对路径>"}` 写入 JSON 输入文件,stdin 重定向交给 Node.js 校验:
87
+ 将第 4 项标记 in_progress,用 `write` 工具将待校验的 JSON 数组写入临时文件,再用 `write` 工具将 `{"data": <JSON 数组>, "schema_path": "<schema 绝对路径>"}` 写入 JSON 输入文件,stdin 重定向交给 Node.js 校验:
106
88
 
107
89
  ```bash
108
90
  node '<技能目录>/references/validate-schema.js' < <临时 JSON 输入文件>
109
91
  ```
110
92
 
111
- - 若校验通过,todowrite 勾单第 4 步,跳过阶段 5,进入阶段 6
112
- - 若校验失败,todowrite 勾单第 4 步,进入阶段 5 进行修复重试(最多 3 次)
93
+ - 若校验通过:**验证 DoD**(校验执行完成且返回通过),标记 Done,跳过 Item 5,进入 Item 6
94
+ - 若校验失败:**验证 DoD**(校验执行完成且返回失败),标记 Done,进入 Item 5 进行修复重试(最多 3 次)
113
95
 
114
- ### 阶段 5:校验失败时修复重试
96
+ ### Item 5:校验失败时修复重试
115
97
 
116
- 当 Schema 校验失败时,将错误信息反馈,重新执行阶段 3 提取并再次校验。**最多重试 3 次**,超过则将最后一次重试的 schema 校验错误信息及「重试 {N} 次后 schema 校验仍然失败」输出到 stderr 并结束。
98
+ 将第 5 项标记 in_progress,将错误信息反馈,重新执行 Item 3 提取并再次校验。**最多重试 3 次**。
117
99
 
118
- 重试成功后 todowrite 勾单第 5 步,进入阶段 6。
100
+ **验证 DoD**:重试后校验通过 → 标记 Done,进入 Item 6;重试 3 次耗尽 → stderr 输出错误并结束(**不进入 Item 6**)。
119
101
 
120
- ### 阶段 6:输出
102
+ ### Item 6:输出
121
103
 
122
- **若校验未通过(重试耗尽):** 将最后一次重试的 schema 校验错误信息及「重试 {N} 次后 schema 校验仍然失败」输出到 stderr 并结束,**不写任何文件**。
104
+ 将第 6 项标记 in_progress。进入本项时校验必已通过(重试耗尽场景已在 Item 5 结束):
123
105
 
124
- **若校验通过:**
125
106
  - 提供 `output` 参数:用 `write` 工具将最终 JSON 数组写入 `output` 指定文件(**禁止创建其他文件**),stdout 输出该文件路径。
126
107
  - 未提供 `output` 参数:将最终 JSON 数组直接输出到 stdout,**不写任何文件**。
127
108
 
128
- 完成后 todowrite 勾单第 6 步。
109
+ **验证 DoD**:按输出语义交付(文件路径或 stdout 数组)。通过后标记 Done。
129
110
 
130
- ## 工具使用约束
111
+ ## Sprint Review
131
112
 
132
- - 写文件一律用 `write` 工具;读文件用 `read` 工具。
133
- - 需要中间数据时,用 `write` 工具写入临时文件,再以 stdin 重定向传给 node。
134
- - 禁止使用未授权的 `cp`/`rm`/`mv` 等命令;需要复制、移动或删除临时文件时,一律用允许的 `node -e` 的 fs 模块完成。
135
- - 除技能校验/本地提取所需 node 外,禁止执行其他 shell。
113
+ 所有 Backlog Items 完成后:
114
+
115
+ - **对照 Sprint Goal 验证**:产出的是否为符合 `{{format}}` 格式的 JSON 数组且通过 schema 校验?输出语义是否正确(写文件输出路径 / stdout 输出数组)?
116
+ - **展示 Increment**:输出文件路径或 stdout 的 JSON 数组。
117
+ - **简要回顾(Retrospective)**:沉淀 1 条改进项供下一轮采纳。
136
118
 
137
119
  ## 约束
138
120
 
139
121
  - 只处理已声明字段(source/format/url/output),忽略所有其他传入参数(如 `count`、`max_length`、`max_image_count`、`language`),**禁止**以任何形式使用它们。
140
- - **禁止使用 WebFetch 或任何网络请求获取内容**;`source` 无正文或为空时必须输出 `[]`,绝不自行获取内容。
122
+ - **禁止使用 WebFetch 或任何网络请求、禁止访问外部网络**;`source` 无正文或为空时必须输出 `[]`,绝不自行获取内容。`url` 字段为静态补充字段,**禁止**通过 WebFetch/任何网络请求访问其指向地址——仅用于相对路径转绝对地址、图片 `src` 补全域名等纯文本处理。
123
+ - 写文件一律用 `write` 工具;读文件用 `read` 工具;需要中间数据时写入临时文件,以 stdin 重定向传给 node。
124
+ - 禁止使用未授权的 `cp`/`rm`/`mv` 等命令;需要复制、移动或删除临时文件时,一律用允许的 `node -e` 的 fs 模块完成。
141
125
  - 内部重试步骤的中间产物用临时文件,完成后清理,禁止写入 output 以外的任何持久文件。
142
- - 禁止访问外部网络。
143
126
 
144
127
  ## 资源目录
145
128
 
@@ -150,12 +133,12 @@ references/
150
133
  ├── extract-detail.js # 详情页正文提取(按 img 切分)
151
134
  ├── extract-sample.js # 列表页样本截取
152
135
  ├── extract-regex.js # 正则批量提取
136
+ ├── to-text.js # HTML 转纯文本
153
137
  ├── validate-schema.js # Schema 校验
154
138
  ├── input.schema.json5
155
139
  ├── list.schema.json5
156
- ├── list_from_html.md
157
- ├── list_from_json.md
158
- ├── list_from_text.md
140
+ ├── list.md
141
+ ├── list-rule-gen.md # list 分支 B 的 HTML 正则生成指导
159
142
  ├── detail.md + detail.schema.json5
160
143
  ├── text.md + text.schema.json5
161
144
  └── navi.md + navi.schema.json5
@@ -2,12 +2,7 @@
2
2
 
3
3
  从文章详情页的正文容器 HTML 中提取结构化信息(本地提取 + LLM 规范)。
4
4
 
5
- ## 输入
6
-
7
- - `source`:正文容器 HTML(已去除非正文内容)
8
- - `url`:页面 URL(可选,相对路径转绝对)
9
-
10
- ## 输出
5
+ ## 输出契约
11
6
 
12
7
  符合 `detail.schema.json5` 的 JSON 数组(仅含 1 项):
13
8
 
@@ -33,7 +28,7 @@
33
28
 
34
29
  ### Step 1 — 本地提取(按 img 切分)
35
30
 
36
- 用 `write` 工具将正文容器 HTML 写入临时文件,再用 stdin 重定向交给 Node.js 按 `<img>` 标签切分:
31
+ 将正文容器 HTML 写入临时文件,再用 stdin 重定向交给 Node.js 按 `<img>` 标签切分:
37
32
 
38
33
  ```bash
39
34
  node '<技能目录>/references/extract-detail.js' < <临时 HTML 文件>
@@ -57,4 +52,4 @@ node '<技能目录>/references/extract-detail.js' < <临时 HTML 文件>
57
52
 
58
53
  ### Step 3 — 验证
59
54
 
60
- 检查 `blocks` 非空,输出规范后的 JSON 数组(供 extract 技能阶段 4 校验)。
55
+ 检查 `blocks` 非空,输出规范后的 JSON 数组(供 extract 技能 Item 4 校验)。
@@ -0,0 +1,135 @@
1
+ # list 提取流程
2
+
3
+ 从列表页提取多条目结构化信息。按 `source` 形态分三条分支处理,输出契约统一。
4
+
5
+ ## 输出契约
6
+
7
+ 符合 `list.schema.json5` 的 JSON 数组:
8
+
9
+ ```json
10
+ [
11
+ {
12
+ "title": "标题",
13
+ "author": "作者",
14
+ "date": "2026-06-12",
15
+ "url": "https://example.com/article/123",
16
+ "thumb": "https://example.com/thumb.jpg"
17
+ }
18
+ ]
19
+ ```
20
+
21
+ 字段:`title`(必填,空则跳过本条)、`author` / `date` / `url` / `thumb`(可选,无则留空)。
22
+
23
+ ## Step 1 — 检测 source 类型
24
+
25
+ 若 `source` 为现有文件路径则读取文件内容;否则以值作为输入。再判断内容类型,进入对应分支:
26
+
27
+ - 若能解析为 JSON 数组 → **分支 A:JSON 结构化**
28
+ - 否则若包含 HTML 标签(形如 `<tag`)→ **分支 B:HTML 源码**
29
+ - 否则 → **分支 C:纯文本**
30
+
31
+ ## 分支 A:JSON 结构化(list_from_json)
32
+
33
+ `source` 为 JSON 数组,每项含三个字段:
34
+ - `text`:容器内纯文本(已去标签,末尾可能带时间如 `09:44` 或日期如 `29日`)
35
+ - `href`:第一个 `<a href>` 链接地址
36
+ - `src`:第一个 `<img src>` 图片地址
37
+
38
+ ### A1 — LLM 规范化
39
+
40
+ 1. 从 `text` 末尾提取时间/日期(`HH:MM` → 当天,`NN日` → 当月,跨月则月份-1),从 text 中移除
41
+ 2. 剩余 text 作为 `title`
42
+ 3. `href` 作为 `url` 字段(相对路径基于 `{{ url }}` 转为绝对)
43
+ 4. `src` 作为 `thumb` 字段(同上)
44
+ 5. **去重:基于 `url` 去重,重复的只保留第一条,移除后续相同 url 的条目**
45
+ 6. 保持条目相对顺序不变(去重后)
46
+ 7. 输出必须是 JSON 数组
47
+
48
+ ### A2 — 验证
49
+
50
+ 检查每项 title 非空(空时输出 Warning),输出规范后的 JSON 数组(供 extract 技能 Item 4 校验)。
51
+
52
+ ## 分支 B:HTML 源码(list_from_html)
53
+
54
+ 混合方案:本地提取 + 规则 + LLM 规范。
55
+
56
+ ### B1 — 样本截取(本地)
57
+
58
+ 将完整 HTML 写入临时文件(如 `extract_list.html`),再将 `{"html": "<HTML内容>", "keep_items": 3}` 写入 JSON 输入文件,stdin 重定向交给 Node.js 清洗并截取前 3 条:
59
+
60
+ ```bash
61
+ node '<技能目录>/references/extract-sample.js' < <临时 JSON 输入文件>
62
+ ```
63
+
64
+ 输出仅含前 3 条(或更少)的干净 HTML 样本。
65
+
66
+ ### B2 — 规则生成(LLM)
67
+
68
+ 先用 `read` 读取 `references/list-rule-gen.md`(HTML 正则生成指导,含编写规则与示例),按其中指导分析 B1 输出的样本 HTML,生成提取规则:
69
+
70
+ - 字段集固定为 `{"title": "新闻标题", "author": "作者名", "date": "发布日期", "url": "文章链接", "thumb": "缩略图地址"}`
71
+ - 输出 `{container_regex, fields: {title, author, date, url, thumb}}` 格式的 JSON 规则,**不写入文件**,直接在后续步骤内联使用
72
+
73
+ `container_regex` 用于定义每条记录的外层容器边界(如 `<li>...</li>`),Node.js 先用它切分 HTML 为单条容器,再对每条容器内部应用字段正则——避免跨边界匹配。字段正则若有捕获组,提取值取 `group(1)`;建议每个字段正则只含 1 个捕获组。
74
+
75
+ ### B3 — 批量提取(本地)
76
+
77
+ 对完整 HTML 用相同清洗逻辑处理后再提取(与 B1 清洗口径一致)。将输入 JSON 写入临时文件,再 stdin 重定向交给 Node.js:
78
+
79
+ ```bash
80
+ node '<技能目录>/references/extract-regex.js' < <临时输入文件>
81
+ ```
82
+
83
+ 输入 JSON:`{"html": "<完整HTML>", "rules": <B2 规则>}`
84
+
85
+ 输出:JSON 数组,每项含 `url`, `date`, `author`, `thumb`, `title` 五个字段(title 为空的条目已移除)。
86
+
87
+ ### B4 — LLM 数据规范
88
+
89
+ 将 B3 输出的数组交给 LLM 进行数据规范:
90
+
91
+ - URL 相对路径 → 基于 `{{ url }}` 转为绝对地址
92
+ - 日期统一格式 `yyyy-mm-dd`
93
+ - 作者清洗(去多余空白、特殊字符)
94
+ - **保持条目数量和顺序不变**
95
+ - 输出必须是 JSON 数组(不是对象包裹)
96
+
97
+ ### B5 — 验证
98
+
99
+ 检查每项 title 非空,输出规范后的 JSON 数组(供 extract 技能 Item 4 校验)。
100
+
101
+ ## 分支 C:纯文本(list_from_text)
102
+
103
+ 完全由 LLM 完成,不调用任何本地脚本。
104
+
105
+ ### C1 — 识别重复单元并切块
106
+
107
+ 分析源文本,找出重复出现的条目结构。常见形态:
108
+
109
+ - 每条记录由固定行序构成(如 标题/摘要/作者/日期/阅读量,各占一行,条目间以空行或紧邻分隔)
110
+ - 每条记录由空行分隔的多行块构成
111
+
112
+ 按识别出的边界把源文本切分为若干候选条目块,末尾的导航/分页类文本(如「加载更多」)不属于任何条目,丢弃。
113
+
114
+ ### C2 — 字段映射
115
+
116
+ 对每个块,依据语义把内容映射到字段:
117
+
118
+ - `title`:条目标题(必须非空;找不到则跳过该条)
119
+ - `author`:作者(无则留空)
120
+ - `date`:发布时间(无则留空)
121
+ - `thumb`:图片/缩略图地址(无则留空)
122
+ - `url`:链接地址(无则留空)
123
+
124
+ 无法确定归属的行(如摘要、阅读量等不在 schema 内的信息)直接丢弃,不进入输出。
125
+
126
+ ### C3 — 规范化
127
+
128
+ - 日期统一格式 `yyyy-mm-dd`(如「今天」→ 当天、「昨天」→ 前一天、`HH:MM` → 当天)
129
+ - `url` / `thumb` 若为相对路径,基于 `{{ url }}` 转为绝对地址
130
+ - **保持条目数量和顺序不变**
131
+ - 输出必须是 JSON 数组(不是对象包裹)
132
+
133
+ ### C4 — 验证
134
+
135
+ 检查每项 `title` 非空,输出规范后的 JSON 数组(供 extract 技能 Item 4 校验)。
@@ -2,11 +2,7 @@
2
2
 
3
3
  从列表页文本中提取标题并生成 XPath 选择器。LLM 只负责识别条目并输出 title,XPath 由内置脚本根据 title 构造(引号拆分 + XML 转义)。
4
4
 
5
- ## 输入
6
-
7
- - `source`:列表内容。可能是纯文本或 JSON 字符串;若为后者,自行识别并提取正文文本,忽略 url/screenshot 等非文本字段
8
-
9
- ## 输出
5
+ ## 输出契约
10
6
 
11
7
  符合 `navi.schema.json5` 的 JSON 数组:
12
8
 
@@ -40,10 +36,10 @@
40
36
 
41
37
  ### Step 3 — 构造 XPath
42
38
 
43
- 用 `write` 工具将 Step 2 的 title 数组写入临时文件,再 stdin 重定向给脚本转为最终输出(引号拆分 + XML 转义):
39
+ 将 Step 2 的 title 数组写入临时文件,再 stdin 重定向给脚本转为最终输出(引号拆分 + XML 转义):
44
40
 
45
41
  ```bash
46
42
  node '<技能目录>/references/build-xpath.js' < <临时 title 文件>
47
43
  ```
48
44
 
49
- 输出:`{selector, title}` 数组,供 extract 技能阶段 4 校验。
45
+ 输出:`{selector, title}` 数组,供 extract 技能 Item 4 校验。
@@ -2,12 +2,7 @@
2
2
 
3
3
  将 HTML 转换为纯文本,不做任何结构化提取。移除所有标签、解码实体、归一空白。
4
4
 
5
- ## 输入
6
-
7
- - `source`:网页 HTML 源码
8
- - `url`:页面 URL(透传至输出)
9
-
10
- ## 输出
5
+ ## 输出契约
11
6
 
12
7
  符合 `text.schema.json5` 的 JSON 数组(仅含 1 项):
13
8
 
@@ -26,7 +21,7 @@
26
21
 
27
22
  ### Step 1 — HTML 转纯文本
28
23
 
29
- 用 `write` 工具将 HTML 写入临时文件,再用 stdin 重定向交给 Node.js 去除所有 HTML 标签、解码实体、归一空白:
24
+ 将 HTML 写入临时文件,再用 stdin 重定向交给 Node.js 去除所有 HTML 标签、解码实体、归一空白:
30
25
 
31
26
  ```bash
32
27
  node '<技能目录>/references/to-text.js' < <临时 HTML 文件>
@@ -43,4 +38,4 @@ node '<技能目录>/references/to-text.js' < <临时 HTML 文件>
43
38
  "content": "<上一步输出的纯文本>"
44
39
  }
45
40
  ]
46
- ```
41
+ ```
@@ -1,49 +1,48 @@
1
1
  ---
2
2
  name: lint
3
3
  description: |
4
- 自包含多语言语法检查 skill:协调语言探测→适用性检查→环境检查→配置生成→规则分析→自动修复→AI修复的完整流程。
4
+ 自包含多语言语法检查 skill:每次调用 = 一个固定 Sprint——Sprint Planning(解析入参、定义 Sprint Goal、todowrite 落固定 Sprint Backlog)→ Sprint Execution(8 步 + 双层 loop 逐项执行并验证 DoD)→ Sprint Review(对照 Sprint Goal 校验交付 + 简要回顾)。
5
+ 协调语言探测→适用性检查→环境检查→配置生成→规则分析→自动修复→AI修复的完整流程。
5
6
  二元制评分:0 违规=100(达标),1+ 违规=0(不达标)。v1 支持 JS/TS 和 Python。
6
7
  子工作流(language-detect/suitability-check/env-ensure/config-setup/rules-analyze/tool-fix/ai-fix)位于 references/ 下,由主流程用 read 加载并按其指令执行,不再调用独立 skill。
7
- 调用方直接传原始任务消息,skill 自解析自包含。内部用 todowrite 管理 8 步。触发词:lint、语法检查、代码规范、eslint、ruff。
8
+ 调用方直接传原始任务消息,skill 自解析自包含。内部用 todowrite 管理固定 8 项 Sprint Backlog(每项带 DoD)。触发词:lint、语法检查、代码规范、eslint、ruff。
8
9
  license: MIT
9
10
  metadata:
10
11
  workflow: sequential
11
12
  ---
12
13
 
13
- # lint 技能
14
+ # lint 技能(固定 Sprint 冲刺)
14
15
 
15
- ## 核心约束(最高优先级)
16
+ ## 执行范式
16
17
 
17
- - **MUST**:收到任务消息后,先 todowrite 落单 8 步,再逐步执行。
18
- - **MUST**:每步完成立即 todowrite 勾单。
19
- - **MUST**:子工作流通过 `read` 加载 `references/xxx.md` 并按其指令执行,**不再调用独立 skill**(原 lint-* 子 skill 已合并入 references/)。
20
- - **禁止**:混合语言(v1 按主语言处理,不支持混合)。
21
- - **禁止**:修改 lint 配置文件(配置生成由 references/config-setup.md 负责)。
22
- - **禁止**:使用 WebFetch 或任何网络请求。
18
+ 每次调用 = 一个固定 Sprint,三个事件:
23
19
 
24
- ## 第一步硬指令(自检)
20
+ 1. **Sprint Planning**:解析入参 → 定义 Sprint Goal → todowrite 落固定 8 项 Sprint Backlog(每项带 DoD)
21
+ 2. **Sprint Execution**:8 步 + 双层 loop 逐项执行,每项 = 执行 → 验证 DoD → todowrite 勾单 Done
22
+ 3. **Sprint Review**:对照 Sprint Goal 验证 Increment(lint 报告)及输出语义,沉淀 1 条回顾
25
23
 
26
- 解析入参前,强制自检:
27
- > 我是否已用 todowrite 落单 8 步?
28
- > - 未落单 → 立即 todowrite 创建清单。
29
- > - 已落单 → 继续。
24
+ **Sprint Goal** = `对 {{target_dir}} 执行 {{primary_language}} 语法检查,产出 lint 报告(0 违规=100 达标)`。
30
25
 
31
- ## 输入参数(自包含)
26
+ **铁律(最高优先级):**
32
27
 
33
- 入参为调用方传入的**原始任务消息**,可能是以下任一形态:
28
+ - **没有 Sprint Backlog 不能开始执行**:收到任务消息后,先做 Sprint Planning(解析入参)再 todowrite 落固定 8 项 Sprint Backlog,然后才进入 Sprint Execution。
29
+ - **每项执行周期** = 进度检查(Daily Scrum 映射)→ 执行 → 验证 DoD → 勾单 Done。
30
+ - **子工作流通过 `read` 加载 `references/xxx.md` 并按其指令执行**,**不再调用独立 skill**(原 lint-* 子 skill 已合并入 references/)。
31
+ - **禁止**:混合语言(v1 按主语言处理,不支持混合)。
32
+ - **禁止**:修改 lint 配置文件(配置生成由 references/config-setup.md 负责)。
33
+ - **禁止**:使用 WebFetch 或任何网络请求。
34
34
 
35
- - **JSON 对象**:`{root_dir, target_dir}`,直接取字段值。
36
- - **key=value**:`root_dir=/path/to/project, target_dir=/path/to/project/src`,按 `,` 和 `=` 拆分为字段。
37
- - **纯文本 prose**:从文本中出现的路径推断 root_dir/target_dir。
38
- - **命令风格**:`lint /path/to/project` 或 `lint /path/to/project /path/to/project/src`,第一段为 root_dir,第二段(可选)为 target_dir。
35
+ ## 输入参数(自包含)
39
36
 
40
- 字段清单:
37
+ 入参为调用方传入的**原始任务消息**,可为 JSON 对象、key=value、自然语言或命令风格等任意形态,agent 依据字段语义自主提取(详见 Step 1)。字段清单:
41
38
 
42
39
  | 字段 | 类型 | 必填 | 说明 |
43
40
  |------|------|------|------|
44
41
  | root_dir | string | 否 | 工程根目录,默认当前工作目录 |
45
42
  | target_dir | string | 否 | 检查目标目录,默认 root_dir 全量 |
46
43
 
44
+ **提取原则**:从消息中自主识别两个路径参数——命令风格(`lint /path/to/project [/path/to/project/src]`,第一段为 root_dir,第二段可选为 target_dir)、JSON 对象(`{root_dir, target_dir}`)、key=value(`root_dir=..., target_dir=...`)、或自然语言中出现的路径。
45
+
47
46
  ## 你的职责
48
47
 
49
48
  1. 接收用户输入的工程根目录和检查目标目录
@@ -67,18 +66,18 @@ lint 流程固定 8 步 + 外层 loop(max 3),远超 3 步触发线,**必
67
66
 
68
67
  ### 初始建单(Step 1 完成后)
69
68
 
70
- Step 1 入参校验通过后,立即用 `todowrite` 一次性创建以下 8 项清单(第 1 项标记 `completed`,第 2-8 项 `pending`):
69
+ Step 1 入参校验通过后,立即用 `todowrite` 一次性创建以下 8 项清单(第 1 项标记 `completed`,第 2-8 项 `pending`),每项带 DoD:
71
70
 
72
- | # | 任务 | 对应 Step |
73
- |---|------|----------|
74
- | 1 | 入参校验 | Step 1 |
75
- | 2 | 语言探测 | Step 2 |
76
- | 3 | 适用性检查 | Step 3 |
77
- | 4 | 环境检查 | Step 4 |
78
- | 5 | 配置生成 | Step 5 |
79
- | 6 | 规则分析(基线) | Step 6 首轮 |
80
- | 7 | 工具修复 + AI修复(Round 1/3) | Step 7+8 |
81
- | 8 | 轮尾验证(Round 1/3) | Step 6 轮尾 |
71
+ | # | 任务 | 对应 Step | DoD |
72
+ |---|------|----------|-----|
73
+ | 1 | 入参校验 | Step 1 | root_dir/target_dir 已校验,report_dir/report_file/flow_start_time 已确定,8 项清单已建 |
74
+ | 2 | 语言探测 | Step 2 | 得到 primary_language(或未检测到主语言已退出) |
75
+ | 3 | 适用性检查 | Step 3 | 得到 lintable_files/file_count(或 file_count=0 已退出) |
76
+ | 4 | 环境检查 | Step 4 | 得到 linter_name/version/installed/config(或安装失败已退出) |
77
+ | 5 | 配置生成 | Step 5 | 得到 config_file_path/enabled_rules/total_rules(或生成失败已退出) |
78
+ | 6 | 规则分析(基线) | Step 6 首轮 | 得到 violation_count/score(=0 达标退出,>0 进入 Step 7) |
79
+ | 7 | 工具修复 + AI修复(Round 1/3) | Step 7+8 | 得到 tool_fixed_count/remaining_violations/ai_fixed_count/final_violations |
80
+ | 8 | 轮尾验证(Round 1/3) | Step 6 轮尾 | 独立调用 rules-analyze 得到 final_count,按退出条件结束或进入下一轮 |
82
81
 
83
82
  ### 使用纪律
84
83
 
@@ -393,6 +392,14 @@ Step 1 结束后,确定以下变量,传递给后续所有子工作流:
393
392
  - 内容:上述完整报告
394
393
  - 同时在 chat 中输出报告摘要
395
394
 
395
+ ## Sprint Review
396
+
397
+ 所有 Backlog Items 完成后:
398
+
399
+ - **对照 Sprint Goal 验证**:是否对 `{{target_dir}}` 完成 `{{primary_language}}` 语法检查并产出 lint 报告?得分是否符合二元制(0 违规=100 达标,1+ 违规=0)?报告是否写入 `report_file`?
400
+ - **展示 Increment**:lint 报告路径 + chat 摘要。
401
+ - **简要回顾(Retrospective)**:沉淀 1 条改进项供下一轮采纳。
402
+
396
403
  ## 规则
397
404
 
398
405
  1. v1 只处理 JS/TS(含 Vue)和 Python,按主语言处理,不支持混合语言