@hawk2048/oh-my-dsh 0.4.0 → 0.4.1

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # 变更记录
2
2
 
3
+ ## 0.4.1 — 2026-11-06
4
+
5
+ 按一次真实写作的反馈改的两处。
6
+
7
+ - `evidence_check.py`:不再取文件里第一张表,改为找带「编号」表头的那张。之前来源表放在文末、正文另有特征表时,会读错表并报出空结果。
8
+ - `omd-plain-writing`:新增「读者凭什么认定这是 AI 写的」一节,把五个特征按被识破的容易程度排成表,对偶句排第一,并补一条反向检查:如果读者要用这五条指认我,他会指向哪几句。
9
+
3
10
  ## 0.4.0 — 2026-11-04
4
11
 
5
12
  证据这一层从「写了规矩」推进到「能查」。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hawk2048/oh-my-dsh",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "oh-my-dsh: DeepSeek Harness multi-agent orchestration layer — OMC-style workflow skills, slash commands, and an agent preset.",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -34,31 +34,38 @@ HEAD_ALIASES = {
34
34
  VERIFIED = {"已开页", "已交叉", "已核", "verified", "checked"}
35
35
 
36
36
 
37
+ def table_blocks(text: str):
38
+ """把文件里所有连续的表行切成块,每块是一组行。"""
39
+ blocks, cur = [], []
40
+ for ln in text.splitlines():
41
+ if ln.strip().startswith("|"):
42
+ cur.append(ln.strip())
43
+ elif cur:
44
+ blocks.append(cur)
45
+ cur = []
46
+ if cur:
47
+ blocks.append(cur)
48
+ return blocks
49
+
50
+
37
51
  def parse_table(text: str):
38
- """取文件里第一张表(连续以 | 开头的行)。返回 (headers, rows)。
52
+ """找带「编号」表头的那张表。返回 (headers, rows)。
39
53
 
40
- 只取一张:文件后面可能还有别的表(比如机制登记),混进来会串行。
54
+ 文件里常有别的表(特征表、对比表),按第一张取会读错表。
41
55
  """
42
- lines = text.splitlines()
43
- start = next((i for i, ln in enumerate(lines) if ln.strip().startswith("|")), None)
44
- if start is None:
45
- return [], []
46
- block = []
47
- for ln in lines[start:]:
48
- if not ln.strip().startswith("|"):
49
- break
50
- block.append(ln.strip())
51
- if not block:
52
- return [], []
53
- header = [c.strip() for c in block[0].strip("|").split("|")]
54
- keys = [HEAD_ALIASES.get(h, h) for h in header]
55
- body = []
56
- for ln in block[1:]:
57
- if re.fullmatch(r"\|[\s:\-|]+\|", ln):
56
+ for block in table_blocks(text):
57
+ header = [c.strip() for c in block[0].strip("|").split("|")]
58
+ keys = [HEAD_ALIASES.get(h, h) for h in header]
59
+ if "id" not in keys:
58
60
  continue
59
- cells = [c.strip() for c in ln.strip("|").split("|")]
60
- body.append(dict(zip(keys, cells)))
61
- return keys, body
61
+ body = []
62
+ for ln in block[1:]:
63
+ if re.fullmatch(r"\|[\s:\-|]+\|", ln):
64
+ continue
65
+ cells = [c.strip() for c in ln.strip("|").split("|")]
66
+ body.append(dict(zip(keys, cells)))
67
+ return keys, body
68
+ return [], []
62
69
 
63
70
 
64
71
  def citations(text: str):
@@ -15,6 +15,24 @@ description: "说人话:生成期的写作纪律——落笔前先定具体事
15
15
  2. **判断句用动词,不用比喻**。写「成本降了 18%」,不写「成本打了个翻身仗」。
16
16
  3. **一段只讲一件事**,段首句就是这件事。
17
17
 
18
+ ## 读者凭什么认定这是 AI 写的
19
+
20
+ 五条,按被识破的容易程度排。写的时候一条一条避开。
21
+
22
+ | 特征 | 人写的样子 | 怎么改 |
23
+ |---|---|---|
24
+ | 对偶拔高 | 只留成立的那半句 | 「不是 A,而是 B」删掉否定半句 |
25
+ | 句长均匀 | 上一句八个字,下一句六十个字 | 长句拆开,短句留着,别都压到二十来字 |
26
+ | 段尾必总结 | 事实写完就停 | 删掉每段最后一句,还成立就别加回去 |
27
+ | 专名缺席 | 有公司名、人名、日期 | 每个判断至少落到一个能查的主体 |
28
+ | 名词化 | 「改顺了」「快了三成」 | 「进行了优化」改成动词 |
29
+
30
+ 排第一的是对偶句。它一句话里做两次断言,读者要读完后半句才知道作者想说什么。
31
+
32
+ 第四条最伤可信度。一句「头部厂商正在加速布局」,换成任何行业都成立,读者立刻知道作者没查过。
33
+
34
+ 写完之后倒过来检查一遍:如果读者要用这五条指认我,他会指向哪几句。指到的那几句就是该改的。
35
+
18
36
  ## 不写这四种句式
19
37
 
20
38
  句式比词更要紧:词能换,句式会反复长出新词。