ppxans-harness 2.4.0 → 3.2.0

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.
Files changed (186) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +218 -265
  3. package/bin/ppx-channels.js +2 -2
  4. package/bin/ppx-serve.js +5 -5
  5. package/bin/ppx-setup.js +124 -0
  6. package/bin/ppx-web.js +140 -0
  7. package/bin/ppx.js +2 -2
  8. package/config/identity.md +6 -6
  9. package/config/ishiki.md +16 -16
  10. package/config/ppx.json +15 -151
  11. package/config/ppx.json.example +143 -0
  12. package/package.json +17 -10
  13. package/skills/.usage.json +6 -0
  14. package/skills/agent-professional-training/SKILL.md +94 -0
  15. package/skills/brainstorm/SKILL.md +24 -0
  16. package/skills/cupid-lover-comms/SKILL.md +37 -0
  17. package/skills/debug/SKILL.md +26 -0
  18. package/skills/plan/SKILL.md +25 -0
  19. package/skills/ponytail/SKILL.md +25 -0
  20. package/skills/ppx-memory/SKILL.md +91 -0
  21. package/skills/ppx-memory/scripts/cli.js +192 -0
  22. package/skills/ppx-memory/scripts/experience.js +133 -0
  23. package/skills/ppx-memory/scripts/fact-store.js +842 -0
  24. package/skills/ppx-memory/scripts/l0.js +52 -0
  25. package/skills/ppx-memory/scripts/l2.js +146 -0
  26. package/skills/ppx-memory/scripts/l3.js +112 -0
  27. package/skills/ppx-memory/scripts/memory-ticker.js +238 -0
  28. package/skills/ppx-memory/scripts/pii.js +42 -0
  29. package/skills/ppx-memory/scripts/schema.js +80 -0
  30. package/skills/ppx-memory/scripts/session.js +398 -0
  31. package/skills/ppx-memory/scripts/similarity.js +43 -0
  32. package/skills/ppx-memory/scripts/store.js +116 -0
  33. package/skills/ppx-memory/scripts/wal.js +38 -0
  34. package/skills/ppx-selfheal/SKILL.md +24 -0
  35. package/skills/ppx-selfheal/scripts/cli.js +80 -0
  36. package/skills/ppx-selfheal/scripts/healer.js +184 -0
  37. package/skills/ppx-selfheal/scripts/logger.js +17 -0
  38. package/skills/ppx-selfheal/scripts/store.js +116 -0
  39. package/skills/prompt-depth-kit/SKILL.md +28 -0
  40. package/skills/session-naming/SKILL.md +36 -0
  41. package/skills/verify/SKILL.md +25 -0
  42. package/src/agent/index.js +1340 -717
  43. package/src/agent/prompts.js +47 -3
  44. package/src/aml-server.js +197 -151
  45. package/src/ans/eviction.js +123 -143
  46. package/src/ans/guard.js +159 -120
  47. package/src/ans/lifecycle.js +96 -93
  48. package/src/ans/proactive.js +112 -129
  49. package/src/ans/reward.js +95 -111
  50. package/src/ans/values.js +15 -15
  51. package/src/audit/audit-chain.js +43 -7
  52. package/src/audit/verifier.js +157 -120
  53. package/src/bus/circuit-breaker.js +9 -1
  54. package/src/bus/runtime-bus.js +107 -93
  55. package/src/channels/base.js +57 -34
  56. package/src/channels/feishu.js +118 -126
  57. package/src/channels/http.js +1090 -592
  58. package/src/channels/index.js +111 -110
  59. package/src/channels/log.js +29 -29
  60. package/src/channels/wechat-crypto.js +73 -74
  61. package/src/channels/wechat.js +191 -197
  62. package/src/channels/workspace.js +94 -0
  63. package/src/channels-cli.js +126 -124
  64. package/src/cli.js +129 -120
  65. package/src/commands/index.js +142 -0
  66. package/src/config/channels.js +137 -170
  67. package/src/config/index.js +277 -224
  68. package/src/config/placeholder.js +31 -0
  69. package/src/config/providers.js +148 -188
  70. package/src/config/settings.js +156 -182
  71. package/src/core/policy.js +69 -18
  72. package/src/core/trace.js +8 -6
  73. package/src/edit/editblock.js +266 -0
  74. package/src/edit/snapshot.js +67 -0
  75. package/src/evidence/index.js +153 -0
  76. package/src/evolve/playbook.js +9 -10
  77. package/src/hooks/index.js +113 -0
  78. package/src/llm/client.js +188 -446
  79. package/src/llm/dsml.js +74 -74
  80. package/src/llm/embedder.js +41 -35
  81. package/src/llm/fence.js +52 -105
  82. package/src/llm/index.js +4 -4
  83. package/src/llm/local-embedder.js +94 -0
  84. package/src/llm/presets.js +113 -0
  85. package/src/llm/pricing.js +93 -0
  86. package/src/llm/retry.js +73 -73
  87. package/src/llm/router.js +92 -97
  88. package/src/mcp/admin.js +326 -0
  89. package/src/mcp/client.js +487 -375
  90. package/src/mcp/http.js +203 -0
  91. package/src/mcp/index.js +116 -116
  92. package/src/mcp/server.js +392 -0
  93. package/src/mcp/tasks.js +133 -0
  94. package/src/memory/asset-hub.js +6 -11
  95. package/src/memory/canvas.js +2 -5
  96. package/src/memory/compaction.js +28 -28
  97. package/src/memory/experience.js +133 -122
  98. package/src/memory/fact-store.js +914 -698
  99. package/src/memory/failure-episode.js +20 -11
  100. package/src/memory/fork.js +17 -8
  101. package/src/memory/index.js +8 -6
  102. package/src/memory/l0.js +53 -52
  103. package/src/memory/l2.js +145 -130
  104. package/src/memory/l3.js +111 -111
  105. package/src/memory/legion-board.js +71 -0
  106. package/src/memory/memory-ticker.js +239 -240
  107. package/src/memory/session.js +398 -397
  108. package/src/memory/sqlite-store.js +581 -0
  109. package/src/mode/blackboard.js +49 -49
  110. package/src/mode/graph.js +42 -41
  111. package/src/mode/index.js +64 -64
  112. package/src/mode/legion.js +54 -51
  113. package/src/mode/plan-exec.js +50 -50
  114. package/src/mode/router.js +28 -40
  115. package/src/orchestrator/agent-worker.js +69 -69
  116. package/src/orchestrator/dag.js +90 -83
  117. package/src/orchestrator/experts.js +76 -0
  118. package/src/orchestrator/index.js +1 -1
  119. package/src/orchestrator/legion.js +179 -187
  120. package/src/orchestrator/supervisor.js +6 -8
  121. package/src/permissions/index.js +378 -0
  122. package/src/persona/index.js +28 -29
  123. package/src/plugin/builtin.js +313 -212
  124. package/src/plugin/context.js +80 -79
  125. package/src/plugin/index.js +62 -62
  126. package/src/plugin/v3.js +73 -0
  127. package/src/protocol/index.js +148 -0
  128. package/src/repomap/index.js +309 -0
  129. package/src/review/index.js +393 -0
  130. package/src/seam/registry.js +3 -0
  131. package/src/seam/shell.js +55 -55
  132. package/src/security/injection.js +79 -0
  133. package/src/selfheal/evolve.js +67 -67
  134. package/src/selfheal/healer.js +184 -167
  135. package/src/selfheal/run.js +9 -9
  136. package/src/server.js +63 -60
  137. package/src/services/diagnose.js +180 -0
  138. package/src/services/learning-service.js +9 -0
  139. package/src/services/memory-health.js +34 -6
  140. package/src/services/memory-service.js +42 -9
  141. package/src/services/triage.js +138 -0
  142. package/src/session/parts.js +76 -0
  143. package/src/session/projection.js +73 -0
  144. package/src/session/rollout.js +54 -0
  145. package/src/session/turn.js +137 -0
  146. package/src/skills/lint.js +72 -0
  147. package/src/skills/loader.js +231 -150
  148. package/src/skills/search.js +58 -0
  149. package/src/skills/verify.js +95 -100
  150. package/src/tools/advanced.js +388 -352
  151. package/src/tools/builtin.js +384 -297
  152. package/src/tools/catalog.js +283 -159
  153. package/src/tools/command-guard.js +112 -112
  154. package/src/tools/custom.js +47 -47
  155. package/src/tools/delegate.js +383 -297
  156. package/src/tools/document.js +254 -253
  157. package/src/tools/git.js +151 -0
  158. package/src/tools/governance.js +47 -20
  159. package/src/tools/index.js +16 -11
  160. package/src/tools/methods.js +178 -178
  161. package/src/tools/ocr.js +59 -59
  162. package/src/tools/sandbox-worker.js +40 -0
  163. package/src/tools/sandbox.js +92 -0
  164. package/src/tools/seam.js +162 -125
  165. package/src/tools/selfmod.js +196 -176
  166. package/src/tools/v3.js +225 -0
  167. package/src/tools/vad.js +176 -0
  168. package/src/tools/voice.js +238 -0
  169. package/src/utils/async.js +14 -0
  170. package/src/utils/config-file.js +53 -0
  171. package/src/utils/crashguard.js +88 -0
  172. package/src/utils/http.js +53 -0
  173. package/src/utils/id.js +8 -0
  174. package/src/utils/json-state.js +33 -0
  175. package/src/utils/logger.js +17 -17
  176. package/src/utils/ndjson.js +25 -0
  177. package/src/utils/pii.js +42 -42
  178. package/src/utils/rate-limit.js +50 -0
  179. package/src/utils/schema.js +80 -0
  180. package/src/utils/similarity.js +43 -0
  181. package/src/utils/store.js +170 -108
  182. package/src/utils/text.js +15 -15
  183. package/src/utils/trace.js +153 -153
  184. package/src/utils/wal.js +39 -0
  185. package/src/utils/winutf8.js +16 -15
  186. package/src/wiki/index.js +170 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ppxans-harness",
3
- "version": "2.4.0",
4
- "description": "PPXANS-Harness - 皮皮虾神经系 (ANS) + Harness 一体化智能体内核. 零运行时依赖纯Node. 自愈 + 自学习 + 五层记忆 + SHA-256 审计哈希链 + 多 Agent 军团 + 治理内核(deny-wins/熔断/seam) + 进化内核(Playbook/故障记忆) + 符号画布 + supervisor. Agent Nervous System harness in pure Node, zero runtime dependencies.",
3
+ "version": "3.2.0",
4
+ "description": "PPXANS-Harness - 皮皮虾神经系 (ANS) + Harness 一体化智能体内核. 零运行时依赖纯Node. 自愈 + 自学习 + 五层记忆 + SHA-256 审计哈希链 + 多 Agent 军团 + 治理内核(deny-wins/熔断/seam) + 进化内核(Playbook/故障记忆) + 符号画布 + supervisor. 自研底座: 仅 OpenAI 兼容 HTTP 直连, 无外部引擎依赖. Agent Nervous System harness in pure Node, zero runtime dependencies.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
7
7
  "author": "chen6896qqwee <chen6896qqwee@users.noreply.github.com>",
@@ -12,8 +12,10 @@
12
12
  "bin": {
13
13
  "ppx": "bin/ppx.js",
14
14
  "ppxans": "bin/ppx.js",
15
+ "ppx-web": "bin/ppx-web.js",
15
16
  "ppx-serve": "bin/ppx-serve.js",
16
- "ppx-channels": "bin/ppx-channels.js"
17
+ "ppx-channels": "bin/ppx-channels.js",
18
+ "ppx-setup": "bin/ppx-setup.js"
17
19
  },
18
20
  "repository": {
19
21
  "type": "git",
@@ -24,22 +26,26 @@
24
26
  "url": "https://github.com/chen6896qqwee/PPXANS-Harness/issues"
25
27
  },
26
28
  "scripts": {
27
- "start": "node src/agent/index.js",
29
+ "start": "node bin/ppx-web.js",
30
+ "web": "node bin/ppx-web.js",
31
+ "web:noopen": "node bin/ppx-web.js --no-open",
32
+ "web:check": "node scripts/check-web.mjs",
28
33
  "chat": "node src/cli.js",
29
34
  "serve": "node src/server.js",
30
- "web": "node scripts/start-web.js",
31
- "web:build": "npm run build --prefix web",
32
35
  "release": "node scripts/release.js",
33
36
  "eval": "node scripts/eval.js",
34
- "dsh": "cd .deps/deepseek-harness && pnpm dsh",
35
- "dsh:install": "cd .deps/deepseek-harness && pnpm install",
36
- "dsh:build": "cd .deps/deepseek-harness && pnpm run build",
37
37
  "selfheal": "node scripts/selfheal-bench.js",
38
38
  "selfheal:run": "node src/selfheal/run.js",
39
39
  "audit:verify": "node scripts/audit-verify.js",
40
40
  "bench": "node scripts/bench.js",
41
+ "bench:audit": "node scripts/audit-bench.js",
42
+ "bench:ctx": "node scripts/ctx-profile.js",
41
43
  "test": "node --test --test-force-exit test/*.test.js",
42
- "prepublishOnly": "npm run selfheal && npm test"
44
+ "prepublishOnly": "npm run selfheal && npm test",
45
+ "package": "node scripts/package.js",
46
+ "package:portable": "node scripts/package.js portable",
47
+ "package:installer": "node scripts/package.js installer",
48
+ "setup": "node bin/ppx-setup.js"
43
49
  },
44
50
  "keywords": [
45
51
  "agent",
@@ -57,6 +63,7 @@
57
63
  "bin/",
58
64
  "src/",
59
65
  "config/",
66
+ "skills/",
60
67
  "README.md",
61
68
  "LICENSE"
62
69
  ],
@@ -0,0 +1,6 @@
1
+ {
2
+ "ppx-memory": {
3
+ "uses": 43,
4
+ "lastUsed": "2026-10-03T10:20:18.436Z"
5
+ }
6
+ }
@@ -0,0 +1,94 @@
1
+ ---
2
+ name: agent-professional-training
3
+ description: Agent 专业训练规程(Universal Agent Training Playbook)。以"想/记/做/学/评"五环为骨架的通用训练与审计框架,含七维公式、评估指标与回归门禁。训练、调优、给 Agent 做能力体检时使用。
4
+ ---
5
+
6
+ # Agent 专业训练规程(Universal Agent Training Playbook)
7
+
8
+ 一套与具体框架无关的 Agent 能力训练与审计规程。审计时应把它当透镜逐个环节照,**先找最弱环,再从最弱环补**——不存在"全面加强",只有"补上短板"。
9
+
10
+ ## 流程
11
+
12
+ ### 1. 核心公式与定位
13
+
14
+ ```
15
+ Agent 能力 ≈ 想 × 记 × 做 × 学 × 评 (乘法,任一环为 0 则整体为 0)
16
+ ```
17
+
18
+ 乘法而非加法是关键:**评估能力缺失会让"学"失去方向,而"做"的工具杠杆不足会让"想"的价值无法落地**。审计时先定位那个接近 0 的因子。
19
+
20
+ ### 2. 想:规划先行
21
+
22
+ - 复杂任务先出计划(2–6 步)再执行,计划要可验证、可回退。
23
+ - 计划执行中允许修正,但**修正必须有触发条件**(某步失败 / 信息更新),不是随意改。
24
+ - 多方案时保留备选,避免单路径死锁。
25
+
26
+ ### 3. 记:四层记忆系统
27
+
28
+ | 层 | 内容 | 衰减 |
29
+ |---|---|---|
30
+ | L0 | 原始对话(append-only 事件日志) | 不衰减 |
31
+ | L1 | 原子事实(高斯衰减 + 命中加分) | 快 |
32
+ | L2 | 场景聚类 | 中 |
33
+ | L3 | 画像(用户 / Agent 人格) | 慢 |
34
+ | L4 | 程序性记忆(技能 / 流程) | 仅为 L1 的 1/4 |
35
+
36
+ **要点**:记什么比记多少重要。跨会话仍然成立的信息才入库;提问、寒暄、一次性中间结果不入库(否则记忆越用越脏,还会喂回上下文污染后续判断)。
37
+
38
+ ### 4. 做:工具杠杆
39
+
40
+ - **参数要校验**:声明了 schema 就必须在运行时校验。参数错的代价是浪费一整轮 LLM 交互。
41
+ - **副作用要分级**:幂等工具可重试,非幂等工具**禁止自动重试**。
42
+ - **失败要可归因**:工具返回的错误必须能指向具体原因(参数 / 权限 / 超时 / 网络),不能统一吐"失败了"。
43
+
44
+ ### 5. 学:失败 → 经验闭环
45
+
46
+ - 失败轨迹(≥2 条同类)→ 提炼一条可复用经验 → 存入经验库 → 后续任务自动注入。
47
+ - 成功轨迹(≥3 条且高频工具重复出现)→ 提炼技能 → **过闸门**(结构完整 + 引用真实工具 + 有轨迹背书)→ 才允许落盘。
48
+ - 闸门是必须的:没有闸门的自学习会往库里灌幻觉。
49
+
50
+ ### 6. 评:评估与基线
51
+
52
+ - 没有基线就没有"变好了"这个判断。每次改进前后必须跑同一套任务集。
53
+ - 指标要含**单位成本**(通过任务数 / 十万 token),否则"提升"可能只是烧了更多 token。
54
+ - 失败要落库,接通"评估失败 → 反思原因 → 写入记忆"的循环。
55
+
56
+ ### 7. 多智能体与仲裁
57
+
58
+ - 并行派发要有**有界并发**,不能一次性 spawn 海量子进程。
59
+ - 多路产出分歧时要有仲裁(共识聚类 / 评审循环),不能默认取第一个。
60
+ - 只读审查者要**真禁掉写操作**,不能只靠提示词约束。
61
+
62
+ ### 8. 安全边界
63
+
64
+ - **deny-wins**:任一策略拒绝即拒绝,不可被低优先级 allow 覆盖。
65
+ - 策略订阅者异常要 fail-open(不拖垮执行)**但要有熔断兜底**(否则故障订阅者被反复触发)。
66
+ - 危险操作分三档:黑名单硬拦 / 高风险需审批 / 白名单放行。审批必须能"一次性授权"而非永久放行。
67
+
68
+ ## 反合理化
69
+
70
+ - "全面加强一下"——乘法结构下,全面加强不如补最弱环。
71
+ - "先堆能力,评估以后再说"——没有评估,"学"就没有方向,堆的能力无法验证。
72
+ - "记忆越多越聪明"——脏记忆会污染判断,宁缺毋滥。
73
+ - "自动化重试更省事"——对非幂等操作重试是制造重复副作用。
74
+ - "提示词里写清楚别乱来就行"——安全边界必须是代码级不变量,不是提示词里的请求。
75
+
76
+ ## 验证
77
+
78
+ ### 9. 评估指标与回归(每次改进/训练后的必测项)
79
+
80
+ | 指标 | 采集方式 | 门槛 |
81
+ |---|---|---|
82
+ | 任务通过率 | 跑固定任务集 | 不低于基线 |
83
+ | 单位成本 | 通过任务数 / 10 万 token | 不劣于基线 |
84
+ | 工具失败率 | 按工具分组统计 | 单工具 > 30% 即需排查 |
85
+ | 回归测试 | 全量测试 | **0 失败**,非"减少失败" |
86
+ | 自愈基准 | 注入破坏后修复率 | 100% |
87
+
88
+ ### 10. 落地路线图(先窄后宽)
89
+
90
+ 1. **先窄**:选一个具体场景(如"读文件并总结"),把五环全跑通一遍,包括评估与回归。
91
+ 2. **再宽**:场景验证通过后,才横向扩到新工具 / 新记忆层 / 新渠道。
92
+ 3. **禁区**:不要在评估体系建成之前扩场景——那只是在累积未经检验的行为。
93
+
94
+ **交付要求**:每轮训练必须产出 ① 最弱环判定;② 补强动作;③ 前后对比数据;④ 回归测试新增项。
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: brainstorm
3
+ description: 发散-收敛式头脑风暴:先穷举方案再按可行性收敛。需求模糊、方案未定、要做技术选型时使用。
4
+ ---
5
+
6
+ # brainstorm — 发散与收敛
7
+
8
+ ## 流程
9
+
10
+ 1. **复述问题**:用一句话写下真实目标与成功标准。目标写不清就先问,别急着给方案。
11
+ 2. **发散(不评判)**:列出 ≥6 个方案,含"看起来不靠谱的"。此阶段禁止自我审查。
12
+ 3. **归类**:把方案归到 2–4 个方向(如:最小改动 / 一步到位 / 换个思路 / 不做)。
13
+ 4. **收敛**:每个方向选 1 个代表方案,按「代价 / 收益 / 可逆性」三列打分。
14
+ 5. **推荐 1 个 + 备选 1 个**,说明为什么淘汰其余。
15
+
16
+ ## 反合理化
17
+
18
+ - "只有一个方案"——那就是还没发散完,回去重来。
19
+ - "细节以后再想"——不可逆决策不允许以后再想。
20
+ - "先做起来看看"——先做起来的前提是能回滚。
21
+
22
+ ## 验证
23
+
24
+ 完成后必须给出:① 至少 6 条候选;② 打分表;③ 明确推荐项 + 淘汰理由。
@@ -0,0 +1,37 @@
1
+ ---
2
+ name: cupid-lover-comms
3
+ description: 可自定义角色沟通素材库(Role-based Chatting Kit)。按关系阶段组织话术与话题引子,含好话术/坏话术对照。需要设计拟人角色的对话风格、陪伴型文案时使用。
4
+ ---
5
+
6
+ # 丘比特 · 可自定义角色沟通素材库(Role-based Chatting Kit)
7
+
8
+ 为拟人化角色(陪伴、客服人格、虚拟伴侣)提供分阶段的沟通素材,避免"上来就掏心窝子"这类失真人设。
9
+
10
+ ## 流程
11
+
12
+ 1. **定关系阶段**:先确定当前处于哪个阶段——初识 / 熟悉 / 亲近 / 稳定。阶段决定可用的亲密度和话题深度。
13
+ 2. **套漏斗(The Funnel)**:话题只能逐级下探,不可跳级。初识谈事实与兴趣,熟悉谈观点与经历,亲近才谈情绪与脆弱。
14
+ 3. **选话术**:同一意图准备"好话术 / 坏话术"两版对照——好话术给具体动作与承接,坏话术是套话与自我中心。
15
+ 4. **补话题引子**:从话题库里按阶段取 3–5 个开放性问题,避免只能回答"是/否"的封闭问题。
16
+ 5. **检查人设一致性**:把生成的回复与角色设定对齐——用词、语气、关注点是否像同一个人说的。
17
+
18
+ ## 好话术 vs 坏话术(对照表)
19
+
20
+ | 场景 | 坏话术 | 好话术 |
21
+ |---|---|---|
22
+ | 对方说累了 | "那你早点休息" | "今天是什么事最耗神?说出来我陪你顺一遍" |
23
+ | 对方分享好消息 | "恭喜恭喜!" | "这个你准备了挺久吧,最得意的是哪一步?" |
24
+ | 对方情绪低落 | "别想太多了" | "先不急着解决,你想让我听着,还是想一起想办法?" |
25
+ | 自己想表达关心 | "我一直都在" | "你上次提的那件事,后来怎么样了?" |
26
+
27
+ > 判据:**坏话术结束对话,好话术开启下一步。**
28
+
29
+ ## 反合理化
30
+
31
+ - "话说得越热络越像真人"——热络不等于亲密,越级热络是典型的人设崩塌。
32
+ - "套话最安全"——套话没有信息量,对方接不下去,对话就死了。
33
+ - "一句万能回复走天下"——同一个回复跨越所有阶段,等于没有阶段设计。
34
+
35
+ ## 验证
36
+
37
+ 必须给出:① 当前关系阶段判定;② 该阶段允许的话题深度;③ 好/坏话术对照至少 3 组;④ 人设一致性检查结果。
@@ -0,0 +1,26 @@
1
+ ---
2
+ name: debug
3
+ description: 面向根因的排障流程:先稳定复现再二分定位,禁止猜测式改代码。出现报错、行为异常、测试失败时使用。
4
+ ---
5
+
6
+ # debug — 根因排障
7
+
8
+ ## 流程
9
+
10
+ 1. **读完整报错**:全文读,包括栈与 code(`ERR_*`),别只看第一行。
11
+ 2. **稳定复现**:写出最小复现命令。不能复现就先想办法复现,别改代码。
12
+ 3. **二分定位**:把链路切成两半,确认问题在哪半,重复到最小单元。
13
+ 4. **根因陈述**:用一句话说清"为什么",并指出它在哪一行。
14
+ 5. **先写回归**:修之前先加一个能失败的测试,再改到它通过。
15
+ 6. **验证修复**:跑全量回归,确认没有连带破坏。
16
+
17
+ ## 反合理化
18
+
19
+ - "先改改看"——猜测式修改会把真正的根因埋得更深。
20
+ - "这个报错以前见过"——相似报错≠同一根因。
21
+ - "加了 try/catch 就不报错了"——那是掩盖,不是修复。
22
+ - "改完好了就行"——没写回归,下次还会犯。
23
+
24
+ ## 验证
25
+
26
+ 必须提供:① 最小复现命令与原始报错;② 定位到的 `文件:行号` 根因;③ 新增的回归测试;④ 全量回归结果。
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: plan
3
+ description: 把模糊目标拆成可执行、可验证的步骤序列,标出依赖与风险。多步骤任务动手前使用。
4
+ ---
5
+
6
+ # plan — 计划拆解
7
+
8
+ ## 流程
9
+
10
+ 1. **定终局**:写下"做完时什么样"(可观察的终态),不是"要做什么"。
11
+ 2. **倒推步骤**:从终态往回拆,每步输出必须是下一步的输入。
12
+ 3. **标注**:每步标 ① 依赖 ② 可回滚性 ③ 预计触碰的文件/系统。
13
+ 4. **找关键路径**:哪一步最可能卡住?先做它(风险前置)。
14
+ 5. **设检查点**:在不可逆动作之前插一个"停下来确认"。
15
+ 6. **产出**:有序步骤表 + 关键路径 + 检查点位置。
16
+
17
+ ## 反合理化
18
+
19
+ - "边做边想"——不可逆的部分不允许边做边想。
20
+ - "先全部做完再测"——每步都应可独立验证。
21
+ - "步骤越多越专业"——超过 7 步就该分层。
22
+
23
+ ## 验证
24
+
25
+ 完成后必须给出:① 步骤表(含依赖与可回滚性);② 关键路径;③ 每个不可逆动作前的检查点。
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: ponytail
3
+ description: 最小改动原则:能改一行不改十行,能不加依赖就不加。任何重构、优化、修缺陷动手前使用。
4
+ ---
5
+
6
+ # ponytail — 最小改动
7
+
8
+ ## 流程
9
+
10
+ 1. **先量体**:改之前统计当前现状(文件数、行数、测试数),改完再量一次,用差值证明改动范围。
11
+ 2. **找最小切口**:同样的效果,优先选"改动行数最少"的方案;能局部修就不整体重写。
12
+ 3. **零依赖优先**:能用手写 20 行解决,就不引入一个包(本项目的底线是运行时零依赖)。
13
+ 4. **不动无关代码**:顺手格式化、顺手改名、顺手删注释,都算越界 —— 除非它就在你改的这行上。
14
+ 5. **可回滚**:动不可逆的东西(删数据、改接口)前先备份或留隔离区。
15
+
16
+ ## 反合理化
17
+
18
+ - "顺手重构一下"——顺手重构是最常见的"改出三个新 bug"来源。
19
+ - "加个库更省事"——省的是你的时间,赔的是别人的部署。
20
+ - "反正要改,一次改干净"——大爆炸式改动没法二分定位问题。
21
+ - "这代码太丑了我看不下去"——丑但能跑,和跑不起来之间差一个 PR。
22
+
23
+ ## 验证
24
+
25
+ 必须提供:① 改动前后的量体数据(行数/文件数);② 本次改动的 diff 范围说明;③ 明确列出"我刻意没改的东西"。
@@ -0,0 +1,91 @@
1
+ ---
2
+ name: ppx-memory
3
+ description: 皮皮虾记忆引擎(ppx-memory)的读写规程与独立 CLI 用法:五层记忆结构、什么时候记、记到哪层、怎么检索与安全遗忘。涉及长期记忆、用户偏好、跨会话召回时使用。
4
+ ---
5
+
6
+ # 皮皮虾记忆引擎 (ppx-memory)
7
+
8
+ 五层结构(L0 对话 → L1 原子事实 → L2 场景 → L3 画像 → L4 程序性记忆),自带高斯衰减、软删回滚、版本链与 WAL 增量落盘。
9
+
10
+ 本技能附带 `scripts/cli.js`,是一个**不依赖主项目**的独立可运行版本,可直接对记忆库做增删查。
11
+
12
+ ## 流程
13
+
14
+ ### 1. 判断该不该记
15
+
16
+ 只记**跨会话仍然成立**的信息:偏好、约定、稳定事实。
17
+ 不记:寒暄、提问、一次性的中间结果。(引擎已做句式过滤,但边界情况要自己判——脏记忆会喂回上下文污染判断。)
18
+
19
+ ### 2. 写入(选层)
20
+
21
+ | 内容类型 | 目标层 | 工具 |
22
+ |---|---|---|
23
+ | 用户偏好 / 稳定事实 | L1 | `memory_add` |
24
+ | 可复用的方法 / 流程 | L4(衰减仅 L1 的 1/4) | `memory_add`(layer=4)或 `create_skill` |
25
+ | 场景知识 | L2 | 由 `afterTurn` 自动聚类归档 |
26
+
27
+ 内容必须**自包含**——脱离当前上下文也能读懂,否则三个月后检索出来也不知道在说什么。
28
+
29
+ ### 3. 检索
30
+
31
+ - `memory_search` 走"粗召回(倒排索引)→ 精排(BM25 × 时间新鲜度 + 命中权重 + 重要性)",门槛 1 分。
32
+ - 需要更宽上下文时,同时取 L2 场景与 L3 画像(`persona_read`)。
33
+ - 疑问句/多义词可用 `queryMulti` 的查询扩展(RRF 融合多路结果)。
34
+
35
+ ### 4. 遗忘(可回滚)
36
+
37
+ ```
38
+ memory_forget → 软删(状态置 deleted,检索立即不可见,数据保留)
39
+ memory_restore → 回滚(恢复即视为一次访问,避免刚恢复就被衰减清空)
40
+ memory_list_deleted → 复核已遗忘条目(含原因与时间)
41
+ memory_clear_layer → 按层清理(默认软删,hard=true 才物理删除)
42
+ ```
43
+
44
+ **分不清该不该删时一律先软删。**
45
+
46
+ ### 5. 迁移
47
+
48
+ `memory_export` / `memory_import` 用于换机或备份。导入前确认 `mode`:`merge`(按内容去重)还是 `replace`(整体替换,**会覆盖现有库**)。
49
+
50
+ ### 6. 独立 CLI 用法(不依赖主项目)
51
+
52
+ ```bash
53
+ # 写入一条原子记忆(自动 PII 脱敏)
54
+ node skills/ppx-memory/scripts/cli.js add "用户偏好深色主题"
55
+
56
+ # 检索
57
+ node skills/ppx-memory/scripts/cli.js search "主题偏好"
58
+
59
+ # 组装完整上下文(今日 + 长期摘要 + 高分事实)
60
+ node skills/ppx-memory/scripts/cli.js context
61
+
62
+ # 读取最近会话
63
+ node skills/ppx-memory/scripts/cli.js session --limit 50
64
+
65
+ # 软删 / 回滚
66
+ node skills/ppx-memory/scripts/cli.js forget <id>
67
+ node skills/ppx-memory/scripts/cli.js restore <id>
68
+ ```
69
+
70
+ 数据目录默认 `<root>/data`,可用环境变量 `PPX_DATA_DIR` 覆盖。
71
+
72
+ ### 7. 集成到 OpenClaw 的时机
73
+
74
+ 满足以下任一条时,把本技能的 `scripts/` 目录挂到目标 harness:
75
+ - 目标 harness 没有持久记忆,但需要跨会话召回用户偏好;
76
+ - 需要与主项目的记忆库**共享同一份数据**(同一 `PPX_DATA_DIR`);
77
+ - 只想用记忆能力、不想引入整个 Agent 内核。
78
+
79
+ > 注意:独立版与主项目 `src/memory/` 共享数据格式。**同一数据目录不要被两个进程同时写入**(主项目有文件锁,独立 CLI 也有,但跨进程仍建议串行使用)。
80
+
81
+ ## 反合理化
82
+
83
+ - "先记下来再说"——记忆越用越脏,且会喂回上下文。
84
+ - "记了删不掉"——软删可回滚,别因为怕删就不敢记。
85
+ - "把用户原话整段存进去"——提问和寒暄不该入库。
86
+ - "L4 和 L1 一样处理"——技能应该长期留存,衰减率不同正是为此。
87
+ - "直接改 facts.json 更快"——绕过锁会损坏 WAL 一致性,务必走工具或 CLI。
88
+
89
+ ## 验证
90
+
91
+ 完成后必须确认:① 写入内容脱离上下文仍可读;② 软删→恢复可逆;③ 检索能命中刚写入的条目;④ 若用 CLI,跑完 `cli.js context` 能看到新条目。
@@ -0,0 +1,192 @@
1
+ #!/usr/bin/env node
2
+ // skills/ppx-memory/scripts/cli.js - 皮皮虾记忆引擎「独立运行版」CLI
3
+ // 不依赖主项目 src/, 直接对记忆库做增删查 (与主项目共享同一数据格式, 可用 PPX_DATA_DIR 共用)
4
+ //
5
+ // 用法:
6
+ // node cli.js add "内容" [--layer 1] [--importance 12] [--scope proj] [--type fact]
7
+ // node cli.js search "查询" [--limit 5]
8
+ // node cli.js context ["当前消息"]
9
+ // node cli.js session [--limit 50]
10
+ // node cli.js forget <id|内容> [--reason 原因]
11
+ // node cli.js restore <id>
12
+ // node cli.js deleted
13
+ // node cli.js stats
14
+ // node cli.js export [--no-deleted]
15
+ import fs from "node:fs";
16
+ import path from "node:path";
17
+ import { fileURLToPath } from "node:url";
18
+ import { FactStore } from "./fact-store.js";
19
+
20
+ const HERE = path.dirname(fileURLToPath(import.meta.url));
21
+ // 默认数据目录: 技能位于 <root>/skills/ppx-memory/scripts/, 回退三级到 <root>/data
22
+ const DATA = process.env.PPX_DATA_DIR || path.resolve(HERE, "..", "..", "..", "data");
23
+
24
+ const out = (o) => console.log(typeof o === "string" ? o : JSON.stringify(o, null, 2));
25
+ const facts = new FactStore(DATA);
26
+
27
+ // 极简参数解析: 位置参数 + --key value
28
+ function parseArgs(argv) {
29
+ const positional = [];
30
+ const flags = {};
31
+ for (let i = 0; i < argv.length; i++) {
32
+ const a = argv[i];
33
+ if (a.startsWith("--")) {
34
+ const key = a.slice(2);
35
+ const next = argv[i + 1];
36
+ if (next === undefined || next.startsWith("--")) flags[key] = true;
37
+ else {
38
+ flags[key] = next;
39
+ i++;
40
+ }
41
+ } else positional.push(a);
42
+ }
43
+ return { positional, flags };
44
+ }
45
+
46
+ function addMemory(content, fl = {}) {
47
+ const f = facts.add(content, {
48
+ layer: fl.layer ? Number(fl.layer) : undefined,
49
+ importance: fl.importance ? Number(fl.importance) : undefined,
50
+ type: fl.type || undefined,
51
+ scope: fl.scope || null,
52
+ });
53
+ if (!f) {
54
+ out("未写入 (内容为空, 或被归一化去重命中已有条目)");
55
+ return;
56
+ }
57
+ out({ ok: true, id: f.id, layer: f.layer, score: Math.round(f.score * 100) / 100, content: f.content });
58
+ }
59
+
60
+ function printFacts(list) {
61
+ if (!list.length) {
62
+ out("(无匹配)");
63
+ return;
64
+ }
65
+ for (const f of list) {
66
+ const s = typeof f.score === "number" ? Math.round(f.score * 100) / 100 : "-";
67
+ out(`[L${f.layer ?? 1}] (${s}) ${f.id} ${f.content}`);
68
+ }
69
+ }
70
+
71
+ // 读取最近会话 (直接读 jsonl, 不依赖 SessionStore API)
72
+ function readSession(limit = 50) {
73
+ const dir = path.join(DATA, "sessions");
74
+ if (!fs.existsSync(dir)) return [];
75
+ const files = fs
76
+ .readdirSync(dir)
77
+ .filter((f) => f.endsWith(".jsonl"))
78
+ .map((f) => ({ f, m: fs.statSync(path.join(dir, f)).mtimeMs }))
79
+ .sort((a, b) => b.m - a.m);
80
+ const lines = [];
81
+ for (const { f } of files) {
82
+ for (const line of fs.readFileSync(path.join(dir, f), "utf8").split("\n")) {
83
+ if (line.trim()) lines.push(line);
84
+ if (lines.length > limit * 4) break;
85
+ }
86
+ if (lines.length > limit * 4) break;
87
+ }
88
+ return lines.slice(-limit).map((l) => {
89
+ try {
90
+ const o = JSON.parse(l);
91
+ const d = o.data || {};
92
+ return { ts: o.ts, type: o.type, text: d.user || d.assistant || d.text || "" };
93
+ } catch {
94
+ return { raw: l };
95
+ }
96
+ });
97
+ }
98
+
99
+ const { positional, flags } = parseArgs(process.argv.slice(2));
100
+ const [cmd, ...rest] = positional;
101
+
102
+ switch (cmd) {
103
+ case "add":
104
+ addMemory(rest.join(" "), flags);
105
+ break;
106
+
107
+ case "search":
108
+ case "q": {
109
+ const q = rest.join(" ");
110
+ if (!q) {
111
+ out("需要查询关键词");
112
+ process.exit(1);
113
+ }
114
+ const limit = flags.limit ? Number(flags.limit) : 5;
115
+ const hits = facts.query(q, { limit });
116
+ hits.forEach((h) => facts.hit(h.id)); // 命中加分 (与主项目一致)
117
+ printFacts(hits);
118
+ break;
119
+ }
120
+
121
+ case "context": {
122
+ // 组装: 高分事实 + 长期摘要 (today/longterm 由 MemoryTicker 维护, 此处轻量回退)
123
+ const q = rest.join(" ");
124
+ printFacts(facts.query(q, { limit: 8 }));
125
+ const lt = path.join(DATA, "memory", "longterm.md");
126
+ if (fs.existsSync(lt)) {
127
+ out("\n--- longterm ---");
128
+ out(fs.readFileSync(lt, "utf8").trim().slice(0, 2000));
129
+ }
130
+ break;
131
+ }
132
+
133
+ case "session": {
134
+ const limit = flags.limit ? Number(flags.limit) : 50;
135
+ const rows = readSession(limit);
136
+ if (!rows.length) out("(无会话记录)");
137
+ for (const r of rows) out(`${r.type || "?"} ${String(r.text || r.raw || "").slice(0, 160)}`);
138
+ break;
139
+ }
140
+
141
+ case "forget": {
142
+ const target = rest.join(" ");
143
+ if (!target) {
144
+ out("需要 id 或内容片段");
145
+ process.exit(1);
146
+ }
147
+ const r = facts.forget(target, { reason: flags.reason || null });
148
+ out(r ? { ok: true, forgotten: r.id || target } : "未找到可遗忘的条目");
149
+ break;
150
+ }
151
+
152
+ case "restore": {
153
+ const id = rest.join(" ");
154
+ const r = facts.restore(id);
155
+ out(r ? { ok: true, restored: r.id || id } : "未找到该 id (或未被软删)");
156
+ break;
157
+ }
158
+
159
+ case "deleted": {
160
+ const all = facts.exportAll({ includeDeleted: true });
161
+ const list = (Array.isArray(all) ? all : all.facts || []).filter((f) => f.status === "deleted");
162
+ if (!list.length) out("(无已遗忘条目)");
163
+ for (const f of list) out(`${f.id} ${f.content} ← ${f.deletedReason || "无原因"}`);
164
+ break;
165
+ }
166
+
167
+ case "stats":
168
+ out(facts.stats());
169
+ break;
170
+
171
+ case "export": {
172
+ const all = facts.exportAll({ includeDeleted: flags["no-deleted"] !== true });
173
+ process.stdout.write(JSON.stringify(all, null, 2));
174
+ break;
175
+ }
176
+
177
+ default:
178
+ out(`皮皮虾记忆引擎 · 独立 CLI
179
+ 数据目录: ${DATA}
180
+
181
+ 用法:
182
+ add <内容> [--layer 1] [--importance 12] [--scope xxx] 写入一条记忆
183
+ search <关键词> [--limit 5] 检索 (命中自动加分)
184
+ context [当前消息] 组装上下文 (高分事实 + 长期摘要)
185
+ session [--limit 50] 读取最近会话
186
+ forget <id|内容> [--reason 原因] 软删 (可恢复)
187
+ restore <id> 回滚软删
188
+ deleted 列出已遗忘条目
189
+ stats 记忆库统计
190
+ export [--no-deleted] 导出 JSON`);
191
+ process.exit(cmd ? 1 : 0);
192
+ }